From patchwork Wed Dec 15 21:47:38 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yannick Fertre X-Patchwork-Id: 12696337 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 68E57C433F5 for ; Wed, 15 Dec 2021 21:49:10 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:Message-ID:Date:Subject:To :From:Reply-To:Cc:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References: List-Owner; bh=coc4G+/DOmluujWPCSy9oAgBgqEX6u/9Y990KTRahZE=; b=UX/ZAwTVidaMPe q3ZIo0mhEcQz3/6kvIkfCSXRVAMIFavJpDYMpgih+uEk1cvjyJ/1KQS/7zJBTMT0MPHEJTlP9U+4R 0OFGlRWSZvpMgP5VdIg3vfRU4c7xfZQPi+c5t2omsHyQpPCIiM+k664U50OWx2y6SLCt4PT0Ikxsc U/Wie1TtQ87BGkgMf28WXdGK6duFjFIN985ZjKZaBLHRYqzDaekweqTBh/qLpW6H/fk3b19crr5us NptyxYfyFsiEuzc6WwRFMnb6ZI3zB8w4s5Wnl4/pj3u/6ErHxRyolVm9LwgfXVEKsEwVSWMVOV8nb ZIgbgIdArUriOAdbIzgA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1mxc7r-002pSb-D3; Wed, 15 Dec 2021 21:47:51 +0000 Received: from mx08-00178001.pphosted.com ([91.207.212.93] helo=mx07-00178001.pphosted.com) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1mxc7n-002pRM-0j for linux-arm-kernel@lists.infradead.org; Wed, 15 Dec 2021 21:47:49 +0000 Received: from pps.filterd (m0046661.ppops.net [127.0.0.1]) by mx07-00178001.pphosted.com (8.16.1.2/8.16.1.2) with ESMTP id 1BFHGe5Z009721; Wed, 15 Dec 2021 22:47:41 +0100 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=foss.st.com; h=from : to : subject : date : message-id : mime-version : content-type; s=selector1; bh=AeSey6slxSkNuNtvNVxQJC0kbdjpw+ypvzgm8JzDZgI=; b=2rS0jZDTS1MZwmSHRmtF13NDWx2Nb3LyGtPvjYo2qzwNFTica8LxyK7SkDCsA7+rOcK4 e2WXufIqFQINQxxXiW98hfhYkjOUWeXxWfi1daDmRJrTIZfp1mYGWxroiJmlqMNKRBc5 9OZkfywTf+uJT3O9jG2ubBV95gyNScKdL2HNrWth5ztwQ7CAm+NrL5lwBATkkCFqVq9F nT9F0/82QkVn3MGjRfAZBqH4oK45t74+49fipDwsiVU34/y+EDJXJbJmwpbDH9/j2Vib d8p0u3yS2TbnLBO4uW6++qBowc2+msYNUTqKUpWlD9zJJbz4bEjryv8ZgbbALdRqe712 8w== Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx07-00178001.pphosted.com (PPS) with ESMTPS id 3cyasncwpw-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 15 Dec 2021 22:47:41 +0100 Received: from euls16034.sgp.st.com (euls16034.sgp.st.com [10.75.44.20]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id AFDA9100034; Wed, 15 Dec 2021 22:47:40 +0100 (CET) Received: from Webmail-eu.st.com (sfhdag2node2.st.com [10.75.127.5]) by euls16034.sgp.st.com (STMicroelectronics) with ESMTP id A8CF820A74F; Wed, 15 Dec 2021 22:47:40 +0100 (CET) Received: from localhost (10.75.127.46) by SFHDAG2NODE2.st.com (10.75.127.5) with Microsoft SMTP Server (TLS) id 15.0.1497.26; Wed, 15 Dec 2021 22:47:40 +0100 From: Yannick Fertre To: Yannick Fertre , Philippe Cornu , Raphael Gallais-Pou , David Airlie , Daniel Vetter , Maxime Coquelin , Alexandre Torgue , , , , Subject: [PATCH 1/5] drm/stm: ltdc: switch to regmap Date: Wed, 15 Dec 2021 22:47:38 +0100 Message-ID: <20211215214738.19946-1-yannick.fertre@foss.st.com> X-Mailer: git-send-email 2.17.1 MIME-Version: 1.0 X-Originating-IP: [10.75.127.46] X-ClientProxiedBy: SFHDAG2NODE2.st.com (10.75.127.5) To SFHDAG2NODE2.st.com (10.75.127.5) X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.790,Hydra:6.0.425,FMLib:17.11.62.513 definitions=2021-12-15_13,2021-12-14_01,2021-12-02_01 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211215_134747_385245_6B0562D8 X-CRM114-Status: GOOD ( 28.25 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Replace the legacy register access by regmap API. Signed-off-by: Yannick Fertre Acked-by: Philippe Cornu Reviewed-by: Philippe Cornu Reviewed-by: Raphael Gallais-Pou Tested-by: Raphael Gallais-Pou --- drivers/gpu/drm/stm/ltdc.c | 138 ++++++++++++++++++------------------- drivers/gpu/drm/stm/ltdc.h | 1 + 2 files changed, 68 insertions(+), 71 deletions(-) diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c index c0619f372630..8dad3d00aa5c 100644 --- a/drivers/gpu/drm/stm/ltdc.c +++ b/drivers/gpu/drm/stm/ltdc.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -343,31 +344,14 @@ static const u64 ltdc_format_modifiers[] = { DRM_FORMAT_MOD_INVALID }; -static inline u32 reg_read(void __iomem *base, u32 reg) -{ - return readl_relaxed(base + reg); -} - -static inline void reg_write(void __iomem *base, u32 reg, u32 val) -{ - writel_relaxed(val, base + reg); -} - -static inline void reg_set(void __iomem *base, u32 reg, u32 mask) -{ - reg_write(base, reg, reg_read(base, reg) | mask); -} - -static inline void reg_clear(void __iomem *base, u32 reg, u32 mask) -{ - reg_write(base, reg, reg_read(base, reg) & ~mask); -} - -static inline void reg_update_bits(void __iomem *base, u32 reg, u32 mask, - u32 val) -{ - reg_write(base, reg, (reg_read(base, reg) & ~mask) | val); -} +static const struct regmap_config stm32_ltdc_regmap_cfg = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = sizeof(u32), + .max_register = 0x400, + .use_relaxed_mmio = true, + .cache_type = REGCACHE_NONE, +}; static inline struct ltdc_device *crtc_to_ltdc(struct drm_crtc *crtc) { @@ -494,9 +478,13 @@ static irqreturn_t ltdc_irq(int irq, void *arg) struct drm_device *ddev = arg; struct ltdc_device *ldev = ddev->dev_private; - /* Read & Clear the interrupt status */ - ldev->irq_status = reg_read(ldev->regs, LTDC_ISR); - reg_write(ldev->regs, LTDC_ICR, ldev->irq_status); + /* + * Read & Clear the interrupt status + * In order to write / read registers in this critical section + * very quickly, the regmap functions are not used. + */ + ldev->irq_status = readl_relaxed(ldev->regs + LTDC_ISR); + writel_relaxed(ldev->irq_status, ldev->regs + LTDC_ICR); return IRQ_WAKE_THREAD; } @@ -520,7 +508,7 @@ static void ltdc_crtc_update_clut(struct drm_crtc *crtc) for (i = 0; i < CLUT_SIZE; i++, lut++) { val = ((lut->red << 8) & 0xff0000) | (lut->green & 0xff00) | (lut->blue >> 8) | (i << 24); - reg_write(ldev->regs, LTDC_L1CLUTWR, val); + regmap_write(ldev->regmap, LTDC_L1CLUTWR, val); } } @@ -535,13 +523,13 @@ static void ltdc_crtc_atomic_enable(struct drm_crtc *crtc, pm_runtime_get_sync(ddev->dev); /* Sets the background color value */ - reg_write(ldev->regs, LTDC_BCCR, BCCR_BCBLACK); + regmap_write(ldev->regmap, LTDC_BCCR, BCCR_BCBLACK); /* Enable IRQ */ - reg_set(ldev->regs, LTDC_IER, IER_RRIE | IER_FUIE | IER_TERRIE); + regmap_set_bits(ldev->regmap, LTDC_IER, IER_RRIE | IER_FUIE | IER_TERRIE); /* Commit shadow registers = update planes at next vblank */ - reg_set(ldev->regs, LTDC_SRCR, SRCR_VBR); + regmap_set_bits(ldev->regmap, LTDC_SRCR, SRCR_VBR); drm_crtc_vblank_on(crtc); } @@ -557,10 +545,10 @@ static void ltdc_crtc_atomic_disable(struct drm_crtc *crtc, drm_crtc_vblank_off(crtc); /* disable IRQ */ - reg_clear(ldev->regs, LTDC_IER, IER_RRIE | IER_FUIE | IER_TERRIE); + regmap_clear_bits(ldev->regmap, LTDC_IER, IER_RRIE | IER_FUIE | IER_TERRIE); /* immediately commit disable of layers before switching off LTDC */ - reg_set(ldev->regs, LTDC_SRCR, SRCR_IMR); + regmap_set_bits(ldev->regmap, LTDC_SRCR, SRCR_IMR); pm_runtime_put_sync(ddev->dev); } @@ -708,26 +696,26 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) if (bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE) val |= GCR_PCPOL; - reg_update_bits(ldev->regs, LTDC_GCR, - GCR_HSPOL | GCR_VSPOL | GCR_DEPOL | GCR_PCPOL, val); + regmap_update_bits(ldev->regmap, LTDC_GCR, + GCR_HSPOL | GCR_VSPOL | GCR_DEPOL | GCR_PCPOL, val); /* Set Synchronization size */ val = (hsync << 16) | vsync; - reg_update_bits(ldev->regs, LTDC_SSCR, SSCR_VSH | SSCR_HSW, val); + regmap_update_bits(ldev->regmap, LTDC_SSCR, SSCR_VSH | SSCR_HSW, val); /* Set Accumulated Back porch */ val = (accum_hbp << 16) | accum_vbp; - reg_update_bits(ldev->regs, LTDC_BPCR, BPCR_AVBP | BPCR_AHBP, val); + regmap_update_bits(ldev->regmap, LTDC_BPCR, BPCR_AVBP | BPCR_AHBP, val); /* Set Accumulated Active Width */ val = (accum_act_w << 16) | accum_act_h; - reg_update_bits(ldev->regs, LTDC_AWCR, AWCR_AAW | AWCR_AAH, val); + regmap_update_bits(ldev->regmap, LTDC_AWCR, AWCR_AAW | AWCR_AAH, val); /* Set total width & height */ val = (total_width << 16) | total_height; - reg_update_bits(ldev->regs, LTDC_TWCR, TWCR_TOTALH | TWCR_TOTALW, val); + regmap_update_bits(ldev->regmap, LTDC_TWCR, TWCR_TOTALH | TWCR_TOTALW, val); - reg_write(ldev->regs, LTDC_LIPCR, (accum_act_h + 1)); + regmap_write(ldev->regmap, LTDC_LIPCR, (accum_act_h + 1)); } static void ltdc_crtc_atomic_flush(struct drm_crtc *crtc, @@ -742,7 +730,7 @@ static void ltdc_crtc_atomic_flush(struct drm_crtc *crtc, ltdc_crtc_update_clut(crtc); /* Commit shadow registers = update planes at next vblank */ - reg_set(ldev->regs, LTDC_SRCR, SRCR_VBR); + regmap_set_bits(ldev->regmap, LTDC_SRCR, SRCR_VBR); if (event) { crtc->state->event = NULL; @@ -784,10 +772,14 @@ static bool ltdc_crtc_get_scanout_position(struct drm_crtc *crtc, * simplify the code and only test if line > vactive_end */ if (pm_runtime_active(ddev->dev)) { - line = reg_read(ldev->regs, LTDC_CPSR) & CPSR_CYPOS; - vactive_start = reg_read(ldev->regs, LTDC_BPCR) & BPCR_AVBP; - vactive_end = reg_read(ldev->regs, LTDC_AWCR) & AWCR_AAH; - vtotal = reg_read(ldev->regs, LTDC_TWCR) & TWCR_TOTALH; + regmap_read(ldev->regmap, LTDC_CPSR, &line); + line &= CPSR_CYPOS; + regmap_read(ldev->regmap, LTDC_BPCR, &vactive_start); + vactive_start &= BPCR_AVBP; + regmap_read(ldev->regmap, LTDC_AWCR, &vactive_end); + vactive_end &= AWCR_AAH; + regmap_read(ldev->regmap, LTDC_TWCR, &vtotal); + vtotal &= TWCR_TOTALH; if (line > vactive_end) *vpos = line - vtotal - vactive_start; @@ -823,7 +815,7 @@ static int ltdc_crtc_enable_vblank(struct drm_crtc *crtc) DRM_DEBUG_DRIVER("\n"); if (state->enable) - reg_set(ldev->regs, LTDC_IER, IER_LIE); + regmap_set_bits(ldev->regmap, LTDC_IER, IER_LIE); else return -EPERM; @@ -835,7 +827,7 @@ static void ltdc_crtc_disable_vblank(struct drm_crtc *crtc) struct ltdc_device *ldev = crtc_to_ltdc(crtc); DRM_DEBUG_DRIVER("\n"); - reg_clear(ldev->regs, LTDC_IER, IER_LIE); + regmap_clear_bits(ldev->regmap, LTDC_IER, IER_LIE); } static const struct drm_crtc_funcs ltdc_crtc_funcs = { @@ -913,19 +905,20 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, newstate->crtc_w, newstate->crtc_h, newstate->crtc_x, newstate->crtc_y); - bpcr = reg_read(ldev->regs, LTDC_BPCR); + regmap_read(ldev->regmap, LTDC_BPCR, &bpcr); + ahbp = (bpcr & BPCR_AHBP) >> 16; avbp = bpcr & BPCR_AVBP; /* Configures the horizontal start and stop position */ val = ((x1 + 1 + ahbp) << 16) + (x0 + 1 + ahbp); - reg_update_bits(ldev->regs, LTDC_L1WHPCR + lofs, - LXWHPCR_WHSTPOS | LXWHPCR_WHSPPOS, val); + regmap_write_bits(ldev->regmap, LTDC_L1WHPCR + lofs, + LXWHPCR_WHSTPOS | LXWHPCR_WHSPPOS, val); /* Configures the vertical start and stop position */ val = ((y1 + 1 + avbp) << 16) + (y0 + 1 + avbp); - reg_update_bits(ldev->regs, LTDC_L1WVPCR + lofs, - LXWVPCR_WVSTPOS | LXWVPCR_WVSPPOS, val); + regmap_write_bits(ldev->regmap, LTDC_L1WVPCR + lofs, + LXWVPCR_WVSTPOS | LXWVPCR_WVSPPOS, val); /* Specifies the pixel format */ pf = to_ltdc_pixelformat(fb->format->format); @@ -938,19 +931,18 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, (char *)&fb->format->format); val = 0; /* set by default ARGB 32 bits */ } - reg_update_bits(ldev->regs, LTDC_L1PFCR + lofs, LXPFCR_PF, val); + regmap_write_bits(ldev->regmap, LTDC_L1PFCR + lofs, LXPFCR_PF, val); /* Configures the color frame buffer pitch in bytes & line length */ pitch_in_bytes = fb->pitches[0]; line_length = fb->format->cpp[0] * (x1 - x0 + 1) + (ldev->caps.bus_width >> 3) - 1; val = ((pitch_in_bytes << 16) | line_length); - reg_update_bits(ldev->regs, LTDC_L1CFBLR + lofs, - LXCFBLR_CFBLL | LXCFBLR_CFBP, val); + regmap_write_bits(ldev->regmap, LTDC_L1CFBLR + lofs, LXCFBLR_CFBLL | LXCFBLR_CFBP, val); /* Specifies the constant alpha value */ val = newstate->alpha >> 8; - reg_update_bits(ldev->regs, LTDC_L1CACR + lofs, LXCACR_CONSTA, val); + regmap_write_bits(ldev->regmap, LTDC_L1CACR + lofs, LXCACR_CONSTA, val); /* Specifies the blending factors */ val = BF1_PAXCA | BF2_1PAXCA; @@ -962,24 +954,22 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, plane->type != DRM_PLANE_TYPE_PRIMARY) val = BF1_PAXCA | BF2_1PAXCA; - reg_update_bits(ldev->regs, LTDC_L1BFCR + lofs, - LXBFCR_BF2 | LXBFCR_BF1, val); + regmap_write_bits(ldev->regmap, LTDC_L1BFCR + lofs, LXBFCR_BF2 | LXBFCR_BF1, val); /* Configures the frame buffer line number */ val = y1 - y0 + 1; - reg_update_bits(ldev->regs, LTDC_L1CFBLNR + lofs, LXCFBLNR_CFBLN, val); + regmap_write_bits(ldev->regmap, LTDC_L1CFBLNR + lofs, LXCFBLNR_CFBLN, val); /* Sets the FB address */ paddr = (u32)drm_fb_cma_get_gem_addr(fb, newstate, 0); DRM_DEBUG_DRIVER("fb: phys 0x%08x", paddr); - reg_write(ldev->regs, LTDC_L1CFBAR + lofs, paddr); + regmap_write(ldev->regmap, LTDC_L1CFBAR + lofs, paddr); /* Enable layer and CLUT if needed */ val = fb->format->format == DRM_FORMAT_C8 ? LXCR_CLUTEN : 0; val |= LXCR_LEN; - reg_update_bits(ldev->regs, LTDC_L1CR + lofs, - LXCR_LEN | LXCR_CLUTEN, val); + regmap_write_bits(ldev->regmap, LTDC_L1CR + lofs, LXCR_LEN | LXCR_CLUTEN, val); ldev->plane_fpsi[plane->index].counter++; @@ -1004,7 +994,7 @@ static void ltdc_plane_atomic_disable(struct drm_plane *plane, u32 lofs = plane->index * LAY_OFS; /* disable layer */ - reg_clear(ldev->regs, LTDC_L1CR + lofs, LXCR_LEN); + regmap_write_bits(ldev->regmap, LTDC_L1CR + lofs, LXCR_LEN, 0); DRM_DEBUG_DRIVER("CRTC:%d plane:%d\n", oldstate->crtc->base.id, plane->base.id); @@ -1172,7 +1162,7 @@ static void ltdc_encoder_disable(struct drm_encoder *encoder) DRM_DEBUG_DRIVER("\n"); /* Disable LTDC */ - reg_clear(ldev->regs, LTDC_GCR, GCR_LTDCEN); + regmap_clear_bits(ldev->regmap, LTDC_GCR, GCR_LTDCEN); /* Set to sleep state the pinctrl whatever type of encoder */ pinctrl_pm_select_sleep_state(ddev->dev); @@ -1186,7 +1176,7 @@ static void ltdc_encoder_enable(struct drm_encoder *encoder) DRM_DEBUG_DRIVER("\n"); /* Enable LTDC */ - reg_set(ldev->regs, LTDC_GCR, GCR_LTDCEN); + regmap_set_bits(ldev->regmap, LTDC_GCR, GCR_LTDCEN); } static void ltdc_encoder_mode_set(struct drm_encoder *encoder, @@ -1249,15 +1239,15 @@ static int ltdc_get_caps(struct drm_device *ddev) * at least 1 layer must be managed & the number of layers * must not exceed LTDC_MAX_LAYER */ - lcr = reg_read(ldev->regs, LTDC_LCR); + regmap_read(ldev->regmap, LTDC_LCR, &lcr); ldev->caps.nb_layers = clamp((int)lcr, 1, LTDC_MAX_LAYER); /* set data bus width */ - gc2r = reg_read(ldev->regs, LTDC_GC2R); + regmap_read(ldev->regmap, LTDC_GC2R, &gc2r); bus_width_log2 = (gc2r & GC2R_BW) >> 4; ldev->caps.bus_width = 8 << bus_width_log2; - ldev->caps.hw_version = reg_read(ldev->regs, LTDC_IDR); + regmap_read(ldev->regmap, LTDC_IDR, &ldev->caps.hw_version); switch (ldev->caps.hw_version) { case HWVER_10200: @@ -1410,9 +1400,15 @@ int ltdc_load(struct drm_device *ddev) goto err; } + ldev->regmap = devm_regmap_init_mmio(&pdev->dev, ldev->regs, &stm32_ltdc_regmap_cfg); + if (IS_ERR(ldev->regmap)) { + DRM_ERROR("Unable to regmap ltdc registers\n"); + ret = PTR_ERR(ldev->regmap); + goto err; + } + /* Disable interrupts */ - reg_clear(ldev->regs, LTDC_IER, - IER_LIE | IER_RRIE | IER_FUIE | IER_TERRIE); + regmap_clear_bits(ldev->regmap, LTDC_IER, IER_LIE | IER_RRIE | IER_FUIE | IER_TERRIE); ret = ltdc_get_caps(ddev); if (ret) { diff --git a/drivers/gpu/drm/stm/ltdc.h b/drivers/gpu/drm/stm/ltdc.h index 55a125f89af6..20b3dcc7817b 100644 --- a/drivers/gpu/drm/stm/ltdc.h +++ b/drivers/gpu/drm/stm/ltdc.h @@ -32,6 +32,7 @@ struct fps_info { struct ltdc_device { void __iomem *regs; + struct regmap *regmap; struct clk *pixel_clk; /* lcd pixel clock */ struct mutex err_lock; /* protecting error_status */ struct ltdc_caps caps; From patchwork Wed Dec 15 21:47:50 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yannick Fertre X-Patchwork-Id: 12696338 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id DF660C433EF for ; Wed, 15 Dec 2021 21:49:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:Message-ID:Date:Subject:To :From:Reply-To:Cc:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References: List-Owner; bh=EdAjRSgu+iBGYU7g5GMHsopRDLUoRLZnABaZF1OEpzQ=; b=3d113f4Jx+wSHh NxkFYxeUXoxN2o0PriSkva+2v3cKPT0SxpBufobX5a51uBAomzzBSq8dZJmJB4Zs65yrcNuMpSPAT +A6P76FrHAM0j1rLk2PKiC0Gb4/1VlHDziX+dgchTuEtdQG6I5ZQzhFqSLTfNHohw3z7gECGld0va eoeqUiW5f4YAdS8mYF10+TWVid4L1yBFGBI+YUi8dex4bwonh3e94Cx1ceQ9VoyiyBmHFzGQLvGJu ZLt3ke3c/e8W9HTkvjxeQr6KPfS8wDEvtq/dtkwyRDIEw0CKDriXMwajfnjs9qv0TGJYSymIH4CzK sC/4XERt4ceEcbuhtyTQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1mxc85-002pXW-HL; Wed, 15 Dec 2021 21:48:05 +0000 Received: from mx07-00178001.pphosted.com ([185.132.182.106]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1mxc81-002pVN-KA for linux-arm-kernel@lists.infradead.org; Wed, 15 Dec 2021 21:48:03 +0000 Received: from pps.filterd (m0241204.ppops.net [127.0.0.1]) by mx07-00178001.pphosted.com (8.16.1.2/8.16.1.2) with ESMTP id 1BFIqZER026248; Wed, 15 Dec 2021 22:47:53 +0100 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=foss.st.com; h=from : to : subject : date : message-id : mime-version : content-type; s=selector1; bh=YxCo4nuRd+6iaKOBccKLKGPQGwMm1A/BQjLGNy22RmA=; b=n7hunCu9AZS3oqI0eP2m6GtAPxav68zg+Xul/bVeuVLnO0mi/WsLe5Gf+wayU3WxRBnY b2Cfhpmm2X0jzdwOYFH1qmy9ZjMamLZCyjP3SrLW3oelPE+S2x1bt97xv/9MwoB+TIpW epKOv3Qcu1uebbHhdvK5aTR/saz+5R/BjhWA3fHNMFRXjnztcEbCU/XzWbG5uV6jl4H0 L3tIbT51DCKbOCDgA58UtACAzyWk9msKT4OF9F1dYp1hfTRkqN9lEhioQ2mU3mTY5WQn inRopt6FSdixP58+A8DpesmE4yRyUui+zXF+9OZ6yDr0kzRsdYClsUXngHVFZ8kwM1zA hA== Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx07-00178001.pphosted.com (PPS) with ESMTPS id 3cyfpxjhym-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 15 Dec 2021 22:47:53 +0100 Received: from euls16034.sgp.st.com (euls16034.sgp.st.com [10.75.44.20]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 8E6DB10002A; Wed, 15 Dec 2021 22:47:52 +0100 (CET) Received: from Webmail-eu.st.com (sfhdag2node2.st.com [10.75.127.5]) by euls16034.sgp.st.com (STMicroelectronics) with ESMTP id 843B420A74F; Wed, 15 Dec 2021 22:47:52 +0100 (CET) Received: from localhost (10.75.127.46) by SFHDAG2NODE2.st.com (10.75.127.5) with Microsoft SMTP Server (TLS) id 15.0.1497.26; Wed, 15 Dec 2021 22:47:51 +0100 From: Yannick Fertre To: Yannick Fertre , Philippe Cornu , Raphael Gallais-Pou , David Airlie , Daniel Vetter , Maxime Coquelin , Alexandre Torgue , , , , Subject: [PATCH 2/5] drm/stm: ltdc: add YCbCr 422 output support Date: Wed, 15 Dec 2021 22:47:50 +0100 Message-ID: <20211215214750.20105-1-yannick.fertre@foss.st.com> X-Mailer: git-send-email 2.17.1 MIME-Version: 1.0 X-Originating-IP: [10.75.127.46] X-ClientProxiedBy: SFHDAG1NODE3.st.com (10.75.127.3) To SFHDAG2NODE2.st.com (10.75.127.5) X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.790,Hydra:6.0.425,FMLib:17.11.62.513 definitions=2021-12-15_13,2021-12-14_01,2021-12-02_01 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211215_134801_983318_EA210FB8 X-CRM114-Status: GOOD ( 22.10 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org LTDC 40100 hw version supports the YCbCr 422 output, reducing the output pins from 24 to 16. This feature is useful for some external devices like HDMI bridges. Both ITU-R BT.601 & ITU-R BT.709 are supported. It is also possible to choose the chrominance order between * Cb is output first (Y0Cb, then Y1Cr, Y2Cb and so on). * Cr is output first (Y0Cr, then Y1Cb, Y2Cr and so on). Signed-off-by: Yannick Fertre Acked-by: Philippe Cornu Reviewed-by: Philippe Cornu Reviewed-by: Raphael Gallais-Pou --- drivers/gpu/drm/stm/ltdc.c | 44 +++++++++++++++++++++++++++++++++++++- drivers/gpu/drm/stm/ltdc.h | 1 + 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c index 8dad3d00aa5c..b819f4cbcc3d 100644 --- a/drivers/gpu/drm/stm/ltdc.c +++ b/drivers/gpu/drm/stm/ltdc.c @@ -76,6 +76,7 @@ #define LTDC_LIPCR 0x0040 /* Line Interrupt Position Conf. */ #define LTDC_CPSR 0x0044 /* Current Position Status */ #define LTDC_CDSR 0x0048 /* Current Display Status */ +#define LTDC_EDCR 0x0060 /* External Display Control */ #define LTDC_FUT 0x0090 /* Fifo underrun Threshold */ /* Layer register offsets */ @@ -170,6 +171,10 @@ #define ISR_TERRIF BIT(2) /* Transfer ERRor Interrupt Flag */ #define ISR_RRIF BIT(3) /* Register Reload Interrupt Flag */ +#define EDCR_OCYEN BIT(25) /* Output Conversion to YCbCr 422: ENable */ +#define EDCR_OCYSEL BIT(26) /* Output Conversion to YCbCr 422: SELection of the CCIR */ +#define EDCR_OCYCO BIT(27) /* Output Conversion to YCbCr 422: Chrominance Order */ + #define LXCR_LEN BIT(0) /* Layer ENable */ #define LXCR_COLKEN BIT(1) /* Color Keying Enable */ #define LXCR_CLUTEN BIT(4) /* Color Look-Up Table ENable */ @@ -625,6 +630,7 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) struct drm_display_mode *mode = &crtc->state->adjusted_mode; u32 hsync, vsync, accum_hbp, accum_vbp, accum_act_w, accum_act_h; u32 total_width, total_height; + u32 bus_formats = MEDIA_BUS_FMT_RGB888_1X24; u32 bus_flags = 0; u32 val; int ret; @@ -650,8 +656,11 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) if (bridge && bridge->timings) bus_flags = bridge->timings->input_bus_flags; - else if (connector) + else if (connector) { bus_flags = connector->display_info.bus_flags; + if (connector->display_info.num_bus_formats) + bus_formats = connector->display_info.bus_formats[0]; + } if (!pm_runtime_active(ddev->dev)) { ret = pm_runtime_get_sync(ddev->dev); @@ -716,6 +725,36 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) regmap_update_bits(ldev->regmap, LTDC_TWCR, TWCR_TOTALH | TWCR_TOTALW, val); regmap_write(ldev->regmap, LTDC_LIPCR, (accum_act_h + 1)); + + /* Configure the output format (hw version dependent) */ + if (ldev->caps.ycbcr_output) { + /* Input video dynamic_range & colorimetry */ + int vic = drm_match_cea_mode(mode); + u32 val; + + if (vic == 6 || vic == 7 || vic == 21 || vic == 22 || + vic == 2 || vic == 3 || vic == 17 || vic == 18) + /* ITU-R BT.601 */ + val = 0; + else + /* ITU-R BT.709 */ + val = EDCR_OCYSEL; + + switch (bus_formats) { + case MEDIA_BUS_FMT_YUYV8_1X16: + /* enable ycbcr output converter */ + regmap_write(ldev->regmap, LTDC_EDCR, EDCR_OCYEN | val); + break; + case MEDIA_BUS_FMT_YVYU8_1X16: + /* enable ycbcr output converter & invert chrominance order */ + regmap_write(ldev->regmap, LTDC_EDCR, EDCR_OCYEN | EDCR_OCYCO | val); + break; + default: + /* disable ycbcr output converter */ + regmap_write(ldev->regmap, LTDC_EDCR, 0); + break; + } + } } static void ltdc_crtc_atomic_flush(struct drm_crtc *crtc, @@ -1267,6 +1306,7 @@ static int ltdc_get_caps(struct drm_device *ddev) if (ldev->caps.hw_version == HWVER_10200) ldev->caps.pad_max_freq_hz = 65000000; ldev->caps.nb_irq = 2; + ldev->caps.ycbcr_output = false; break; case HWVER_20101: ldev->caps.layer_ofs = LAY_OFS_0; @@ -1275,6 +1315,7 @@ static int ltdc_get_caps(struct drm_device *ddev) ldev->caps.non_alpha_only_l1 = false; ldev->caps.pad_max_freq_hz = 150000000; ldev->caps.nb_irq = 4; + ldev->caps.ycbcr_output = false; break; case HWVER_40100: ldev->caps.layer_ofs = LAY_OFS_1; @@ -1283,6 +1324,7 @@ static int ltdc_get_caps(struct drm_device *ddev) ldev->caps.non_alpha_only_l1 = false; ldev->caps.pad_max_freq_hz = 90000000; ldev->caps.nb_irq = 2; + ldev->caps.ycbcr_output = true; break; default: return -ENODEV; diff --git a/drivers/gpu/drm/stm/ltdc.h b/drivers/gpu/drm/stm/ltdc.h index 20b3dcc7817b..f04fcebb5223 100644 --- a/drivers/gpu/drm/stm/ltdc.h +++ b/drivers/gpu/drm/stm/ltdc.h @@ -21,6 +21,7 @@ struct ltdc_caps { bool non_alpha_only_l1; /* non-native no-alpha formats on layer 1 */ int pad_max_freq_hz; /* max frequency supported by pad */ int nb_irq; /* number of hardware interrupts */ + bool ycbcr_output; /* ycbcr output converter supported */ }; #define LTDC_MAX_LAYER 4 From patchwork Wed Dec 15 21:48:17 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yannick Fertre X-Patchwork-Id: 12696339 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 989AFC433EF for ; Wed, 15 Dec 2021 21:49:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:Message-ID:Date:Subject:To :From:Reply-To:Cc:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References: List-Owner; bh=rWY5jwKQlqYMU9mWMj8Pj9DFxj05oygQCcBlEFH3SYQ=; b=DD8yvn5JouKAqR yH4pe1XfMgFNbQzob3MPsydTv/s+hKA3+cobqO0jvXdUsqmT29l7z9+dEmaSYA+4PstKo3A7f3mwt gmBg19AWc2+/8Uj8zf/ZtwTi3bNofLT5dOLHhgstt5PlBf2JHIThd5jLr354s9gPUNJhLLF11DT+R n3KNO2Oy7mcULLcBhUofqFzeXjDrV/mHVUwuUsnfHJKIr3Aet2gWQCewaIsjzgMdYHK4/bLrnAzNc wB2KnyyRupfn9NCEmA5wyv+twMW858hh5AmlfmdjmR07W4CctAXEuDoZRuMKuQ+mrzzwSqsdC6r2x scjyfnjUEQvb3prtv0wg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1mxc8T-002pjG-JE; Wed, 15 Dec 2021 21:48:29 +0000 Received: from mx08-00178001.pphosted.com ([91.207.212.93] helo=mx07-00178001.pphosted.com) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1mxc8P-002phJ-D4 for linux-arm-kernel@lists.infradead.org; Wed, 15 Dec 2021 21:48:27 +0000 Received: from pps.filterd (m0046660.ppops.net [127.0.0.1]) by mx07-00178001.pphosted.com (8.16.1.2/8.16.1.2) with ESMTP id 1BFF2cfV011435; Wed, 15 Dec 2021 22:48:20 +0100 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=foss.st.com; h=from : to : subject : date : message-id : mime-version : content-type; s=selector1; bh=TuPgsiRrJ7CEkwzlT3BG+2xG5KFUoOpxKTkrihEVGs4=; b=k4AJZFXVGOVXA2UCn5uARPNPLnyoKZyAGDf5uPro9UPZEdD7/6Uf3Wm1QyG9ZL1hZQ7f 0qJ5eAYm04Ph9Gw68yaKDaJgqKfu89vVdMI7w9YopTV0MeK9n8+yxnsirQSyURkYdmS0 1UotT2WBRBUSa9BTLR97FflolKPLEhuYVooNXjjqCxJbu5lu6wzKlusVYykrhCZ9Ke3G 5yOnOvXPPwGOwgcbbRkE7V4cDqpvMloZR30raDKhFEq3N4COCQ7RM1FHOrtlIF5HLtI/ 9T7b96LOxk07WWY4j+Km9++MKuYtPMhPyQ3rir6DBNmDci2vsTtdqyeVNI74V58ibMrS iA== Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx07-00178001.pphosted.com (PPS) with ESMTPS id 3cy79j6180-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 15 Dec 2021 22:48:20 +0100 Received: from euls16034.sgp.st.com (euls16034.sgp.st.com [10.75.44.20]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 5777210002A; Wed, 15 Dec 2021 22:48:19 +0100 (CET) Received: from Webmail-eu.st.com (sfhdag2node2.st.com [10.75.127.5]) by euls16034.sgp.st.com (STMicroelectronics) with ESMTP id 4D87420A74E; Wed, 15 Dec 2021 22:48:19 +0100 (CET) Received: from localhost (10.75.127.44) by SFHDAG2NODE2.st.com (10.75.127.5) with Microsoft SMTP Server (TLS) id 15.0.1497.26; Wed, 15 Dec 2021 22:48:18 +0100 From: Yannick Fertre To: Yannick Fertre , Philippe Cornu , Raphael Gallais-Pou , David Airlie , Daniel Vetter , Maxime Coquelin , Alexandre Torgue , , , , Subject: [PATCH 3/5] drm/stm: ltdc: add per plane update support Date: Wed, 15 Dec 2021 22:48:17 +0100 Message-ID: <20211215214817.20310-1-yannick.fertre@foss.st.com> X-Mailer: git-send-email 2.17.1 MIME-Version: 1.0 X-Originating-IP: [10.75.127.44] X-ClientProxiedBy: SFHDAG1NODE3.st.com (10.75.127.3) To SFHDAG2NODE2.st.com (10.75.127.5) X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.790,Hydra:6.0.425,FMLib:17.11.62.513 definitions=2021-12-15_13,2021-12-14_01,2021-12-02_01 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211215_134825_753420_D39FEF12 X-CRM114-Status: GOOD ( 18.29 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Recent ltdc hardware versions offer the ability to update a plane independently of others planes. This is could be useful especially if a plane is assigned to another OS. Signed-off-by: Yannick Fertre Acked-by: Philippe Cornu Reviewed-by: Philippe Cornu Reviewed-by: Raphael Gallais-Pou --- drivers/gpu/drm/stm/ltdc.c | 26 +++++++++++++++++++++++--- drivers/gpu/drm/stm/ltdc.h | 1 + 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c index b819f4cbcc3d..862d43fe3087 100644 --- a/drivers/gpu/drm/stm/ltdc.c +++ b/drivers/gpu/drm/stm/ltdc.c @@ -197,6 +197,10 @@ #define LXCFBLNR_CFBLN GENMASK(10, 0) /* Color Frame Buffer Line Number */ +#define LXRCR_IMR BIT(0) /* IMmediate Reload */ +#define LXRCR_VBR BIT(1) /* Vertical Blanking Reload */ +#define LXRCR_GRMSK BIT(2) /* Global (centralized) Reload MaSKed */ + #define CLUT_SIZE 256 #define CONSTA_MAX 0xFF /* CONSTant Alpha MAX= 1.0 */ @@ -534,7 +538,8 @@ static void ltdc_crtc_atomic_enable(struct drm_crtc *crtc, regmap_set_bits(ldev->regmap, LTDC_IER, IER_RRIE | IER_FUIE | IER_TERRIE); /* Commit shadow registers = update planes at next vblank */ - regmap_set_bits(ldev->regmap, LTDC_SRCR, SRCR_VBR); + if (!ldev->caps.plane_reg_shadow) + regmap_set_bits(ldev->regmap, LTDC_SRCR, SRCR_VBR); drm_crtc_vblank_on(crtc); } @@ -553,7 +558,8 @@ static void ltdc_crtc_atomic_disable(struct drm_crtc *crtc, regmap_clear_bits(ldev->regmap, LTDC_IER, IER_RRIE | IER_FUIE | IER_TERRIE); /* immediately commit disable of layers before switching off LTDC */ - regmap_set_bits(ldev->regmap, LTDC_SRCR, SRCR_IMR); + if (!ldev->caps.plane_reg_shadow) + regmap_set_bits(ldev->regmap, LTDC_SRCR, SRCR_IMR); pm_runtime_put_sync(ddev->dev); } @@ -769,7 +775,8 @@ static void ltdc_crtc_atomic_flush(struct drm_crtc *crtc, ltdc_crtc_update_clut(crtc); /* Commit shadow registers = update planes at next vblank */ - regmap_set_bits(ldev->regmap, LTDC_SRCR, SRCR_VBR); + if (!ldev->caps.plane_reg_shadow) + regmap_set_bits(ldev->regmap, LTDC_SRCR, SRCR_VBR); if (event) { crtc->state->event = NULL; @@ -1010,6 +1017,11 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, val |= LXCR_LEN; regmap_write_bits(ldev->regmap, LTDC_L1CR + lofs, LXCR_LEN | LXCR_CLUTEN, val); + /* Commit shadow registers = update plane at next vblank */ + if (ldev->caps.plane_reg_shadow) + regmap_write_bits(ldev->regmap, LTDC_L1RCR + lofs, + LXRCR_IMR | LXRCR_VBR | LXRCR_GRMSK, LXRCR_VBR); + ldev->plane_fpsi[plane->index].counter++; mutex_lock(&ldev->err_lock); @@ -1035,6 +1047,11 @@ static void ltdc_plane_atomic_disable(struct drm_plane *plane, /* disable layer */ regmap_write_bits(ldev->regmap, LTDC_L1CR + lofs, LXCR_LEN, 0); + /* Commit shadow registers = update plane at next vblank */ + if (ldev->caps.plane_reg_shadow) + regmap_write_bits(ldev->regmap, LTDC_L1RCR + lofs, + LXRCR_IMR | LXRCR_VBR | LXRCR_GRMSK, LXRCR_VBR); + DRM_DEBUG_DRIVER("CRTC:%d plane:%d\n", oldstate->crtc->base.id, plane->base.id); } @@ -1307,6 +1324,7 @@ static int ltdc_get_caps(struct drm_device *ddev) ldev->caps.pad_max_freq_hz = 65000000; ldev->caps.nb_irq = 2; ldev->caps.ycbcr_output = false; + ldev->caps.plane_reg_shadow = false; break; case HWVER_20101: ldev->caps.layer_ofs = LAY_OFS_0; @@ -1316,6 +1334,7 @@ static int ltdc_get_caps(struct drm_device *ddev) ldev->caps.pad_max_freq_hz = 150000000; ldev->caps.nb_irq = 4; ldev->caps.ycbcr_output = false; + ldev->caps.plane_reg_shadow = false; break; case HWVER_40100: ldev->caps.layer_ofs = LAY_OFS_1; @@ -1325,6 +1344,7 @@ static int ltdc_get_caps(struct drm_device *ddev) ldev->caps.pad_max_freq_hz = 90000000; ldev->caps.nb_irq = 2; ldev->caps.ycbcr_output = true; + ldev->caps.plane_reg_shadow = true; break; default: return -ENODEV; diff --git a/drivers/gpu/drm/stm/ltdc.h b/drivers/gpu/drm/stm/ltdc.h index f04fcebb5223..68a5a199e320 100644 --- a/drivers/gpu/drm/stm/ltdc.h +++ b/drivers/gpu/drm/stm/ltdc.h @@ -22,6 +22,7 @@ struct ltdc_caps { int pad_max_freq_hz; /* max frequency supported by pad */ int nb_irq; /* number of hardware interrupts */ bool ycbcr_output; /* ycbcr output converter supported */ + bool plane_reg_shadow; /* plane shadow registers ability */ }; #define LTDC_MAX_LAYER 4 From patchwork Wed Dec 15 21:48:35 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yannick Fertre X-Patchwork-Id: 12696340 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 76949C433EF for ; Wed, 15 Dec 2021 21:50:05 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:Message-ID:Date:Subject:To :From:Reply-To:Cc:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References: List-Owner; bh=xH5hKPhhjpdUPJapXG+xN+CA+CiO7Og2vEI8IAssblc=; b=2oMXLm/eAkXrgb rFc5L6ntSsbgdJiJ1+2ksyceYbYU4XWzJyWe/XkTHAroCi4b4PQbNv2zcAz2DAOJfmrITA9vzTW+k JNP1aPuudicUY/Hmaq7upgSlQjatwryj2f5XdwdOhjlQCXQNwqEtovWOlwHZ/DDgSZ7DCfpcq5efM KKmc/F+CTgq9t3t6Cy5PyeQoYhiWWFmFmJIApMKZdQ4TaKNXkBngt0Vz2zSjg9euFMGecl5Zo1P48 SZ0iWPvPau1LlNqZfVGe/vvI48orNnOhK0C1OlHCxOVrM/ZKJqzQWuPDQ2AQ+JdHTybwmsPqp63F0 J9NzzFiftkSnsgs387LQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1mxc8n-002pv2-Bi; Wed, 15 Dec 2021 21:48:49 +0000 Received: from mx07-00178001.pphosted.com ([185.132.182.106]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1mxc8h-002pqR-ON for linux-arm-kernel@lists.infradead.org; Wed, 15 Dec 2021 21:48:46 +0000 Received: from pps.filterd (m0288072.ppops.net [127.0.0.1]) by mx07-00178001.pphosted.com (8.16.1.2/8.16.1.2) with ESMTP id 1BFGovrE014145; Wed, 15 Dec 2021 22:48:37 +0100 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=foss.st.com; h=from : to : subject : date : message-id : mime-version : content-type; s=selector1; bh=TyYszRzQ2m1nRNhciRZ/mqckhI7cCMaqiGLLDRCBa38=; b=CDyYO+oNpv30L7p/FMFX51cKDhHNsX4lcNMa77L+atvm3NKzK2MpVbef4gFcACaJAo5m lD2/d0I5yrlze9ogMykkCca+KqnScn2ugU0xZcSZToFp0vxktd1xiaTfXfHdTMqD/09Y 1J5Yj1mKQ4YUwXDkhhSw26ja3AcSoAyho/B6jR1gBN+/4zDLItdHkLNDccNXFvqdux3W s6uRVE2/lwt7+hibjhWRVmM/aPmXDH/rinBN5Fsr0K5g43BYuKg9N1sv/+kRDlGwBRKY xQGpsM4kofxlrve0ou+PEzkKO+RTULRiGKrAxqikkVYyzZdPWfaMtlP4Zd0H/eVH7vGq Vw== Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx07-00178001.pphosted.com (PPS) with ESMTPS id 3cyekaaxna-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 15 Dec 2021 22:48:37 +0100 Received: from euls16034.sgp.st.com (euls16034.sgp.st.com [10.75.44.20]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 1CBC110002A; Wed, 15 Dec 2021 22:48:37 +0100 (CET) Received: from Webmail-eu.st.com (sfhdag2node2.st.com [10.75.127.5]) by euls16034.sgp.st.com (STMicroelectronics) with ESMTP id 1435D20A74F; Wed, 15 Dec 2021 22:48:37 +0100 (CET) Received: from localhost (10.75.127.45) by SFHDAG2NODE2.st.com (10.75.127.5) with Microsoft SMTP Server (TLS) id 15.0.1497.26; Wed, 15 Dec 2021 22:48:36 +0100 From: Yannick Fertre To: Yannick Fertre , Philippe Cornu , Raphael Gallais-Pou , David Airlie , Daniel Vetter , Maxime Coquelin , Alexandre Torgue , , , , Subject: [PATCH 4/5] drm/stm: ltdc: add support of flexible pixel formats Date: Wed, 15 Dec 2021 22:48:35 +0100 Message-ID: <20211215214835.20593-1-yannick.fertre@foss.st.com> X-Mailer: git-send-email 2.17.1 MIME-Version: 1.0 X-Originating-IP: [10.75.127.45] X-ClientProxiedBy: SFHDAG2NODE2.st.com (10.75.127.5) To SFHDAG2NODE2.st.com (10.75.127.5) X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.790,Hydra:6.0.425,FMLib:17.11.62.513 definitions=2021-12-15_13,2021-12-14_01,2021-12-02_01 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211215_134844_163374_697E52CC X-CRM114-Status: GOOD ( 29.37 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org This feature allows the generation of any RGB pixel format. The list of supported formats is no longer linked to the register LXPFCR_PF, that the reason why a list of drm formats is defined for each display controller version. Signed-off-by: Yannick Fertre Acked-by: Philippe Cornu Reviewed-by: Philippe Cornu Reviewed-by: Raphael Gallais-Pou Tested-by: Raphael Gallais-Pou --- drivers/gpu/drm/stm/ltdc.c | 196 ++++++++++++++++++++++++++----------- drivers/gpu/drm/stm/ltdc.h | 5 +- 2 files changed, 145 insertions(+), 56 deletions(-) diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c index 862d43fe3087..4d249bc99894 100644 --- a/drivers/gpu/drm/stm/ltdc.c +++ b/drivers/gpu/drm/stm/ltdc.c @@ -186,6 +186,7 @@ #define LXWVPCR_WVSPPOS GENMASK(26, 16) /* Window Vertical StoP POSition */ #define LXPFCR_PF GENMASK(2, 0) /* Pixel Format */ +#define PF_FLEXIBLE 0x7 /* Flexible Pixel Format selected */ #define LXCACR_CONSTA GENMASK(7, 0) /* CONSTant Alpha */ @@ -216,17 +217,18 @@ enum ltdc_pix_fmt { /* RGB formats */ PF_ARGB8888, /* ARGB [32 bits] */ PF_RGBA8888, /* RGBA [32 bits] */ + PF_ABGR8888, /* ABGR [32 bits] */ + PF_BGRA8888, /* BGRA [32 bits] */ PF_RGB888, /* RGB [24 bits] */ + PF_BGR888, /* BGR [24 bits] */ PF_RGB565, /* RGB [16 bits] */ + PF_BGR565, /* BGR [16 bits] */ PF_ARGB1555, /* ARGB A:1 bit RGB:15 bits [16 bits] */ PF_ARGB4444, /* ARGB A:4 bits R/G/B: 4 bits each [16 bits] */ /* Indexed formats */ PF_L8, /* Indexed 8 bits [8 bits] */ PF_AL44, /* Alpha:4 bits + indexed 4 bits [8 bits] */ - PF_AL88, /* Alpha:8 bits + indexed 8 bits [16 bits] */ - PF_ABGR8888, /* ABGR [32 bits] */ - PF_BGRA8888, /* BGRA [32 bits] */ - PF_BGR565 /* RGB [16 bits] */ + PF_AL88 /* Alpha:8 bits + indexed 8 bits [16 bits] */ }; /* The index gives the encoding of the pixel format for an HW version */ @@ -260,7 +262,53 @@ static const enum ltdc_pix_fmt ltdc_pix_fmt_a2[NB_PF] = { PF_RGB565, /* 0x04 */ PF_BGR565, /* 0x05 */ PF_RGB888, /* 0x06 */ - PF_ARGB1555 /* 0x07 */ + PF_NONE /* 0x07 */ +}; + +static const u32 ltdc_drm_fmt_a0[] = { + DRM_FORMAT_ARGB8888, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_RGB888, + DRM_FORMAT_RGB565, + DRM_FORMAT_ARGB1555, + DRM_FORMAT_XRGB1555, + DRM_FORMAT_ARGB4444, + DRM_FORMAT_XRGB4444, + DRM_FORMAT_C8 +}; + +static const u32 ltdc_drm_fmt_a1[] = { + DRM_FORMAT_ARGB8888, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_RGB888, + DRM_FORMAT_RGB565, + DRM_FORMAT_RGBA8888, + DRM_FORMAT_RGBX8888, + DRM_FORMAT_ARGB1555, + DRM_FORMAT_XRGB1555, + DRM_FORMAT_ARGB4444, + DRM_FORMAT_XRGB4444, + DRM_FORMAT_C8 +}; + +static const u32 ltdc_drm_fmt_a2[] = { + DRM_FORMAT_ARGB8888, + DRM_FORMAT_XRGB8888, + DRM_FORMAT_ABGR8888, + DRM_FORMAT_XBGR8888, + DRM_FORMAT_RGBA8888, + DRM_FORMAT_RGBX8888, + DRM_FORMAT_BGRA8888, + DRM_FORMAT_BGRX8888, + DRM_FORMAT_RGB565, + DRM_FORMAT_BGR565, + DRM_FORMAT_RGB888, + DRM_FORMAT_BGR888, + DRM_FORMAT_ARGB1555, + DRM_FORMAT_XRGB1555, + DRM_FORMAT_ARGB4444, + DRM_FORMAT_XRGB4444, + DRM_FORMAT_C8 }; /* Layer register offsets */ @@ -386,16 +434,30 @@ static inline enum ltdc_pix_fmt to_ltdc_pixelformat(u32 drm_fmt) case DRM_FORMAT_XRGB8888: pf = PF_ARGB8888; break; + case DRM_FORMAT_ABGR8888: + case DRM_FORMAT_XBGR8888: + pf = PF_ABGR8888; + break; case DRM_FORMAT_RGBA8888: case DRM_FORMAT_RGBX8888: pf = PF_RGBA8888; break; + case DRM_FORMAT_BGRA8888: + case DRM_FORMAT_BGRX8888: + pf = PF_BGRA8888; + break; case DRM_FORMAT_RGB888: pf = PF_RGB888; break; + case DRM_FORMAT_BGR888: + pf = PF_BGR888; + break; case DRM_FORMAT_RGB565: pf = PF_RGB565; break; + case DRM_FORMAT_BGR565: + pf = PF_BGR565; + break; case DRM_FORMAT_ARGB1555: case DRM_FORMAT_XRGB1555: pf = PF_ARGB1555; @@ -416,49 +478,66 @@ static inline enum ltdc_pix_fmt to_ltdc_pixelformat(u32 drm_fmt) return pf; } -static inline u32 to_drm_pixelformat(enum ltdc_pix_fmt pf) +static inline u32 ltdc_set_flexible_pixel_format(struct drm_plane *plane, enum ltdc_pix_fmt pix_fmt) { - switch (pf) { - case PF_ARGB8888: - return DRM_FORMAT_ARGB8888; - case PF_RGBA8888: - return DRM_FORMAT_RGBA8888; - case PF_RGB888: - return DRM_FORMAT_RGB888; - case PF_RGB565: - return DRM_FORMAT_RGB565; + struct ltdc_device *ldev = plane_to_ltdc(plane); + u32 lofs = plane->index * LAY_OFS, ret = PF_FLEXIBLE; + int psize, alen, apos, rlen, rpos, glen, gpos, blen, bpos; + + switch (pix_fmt) { + case PF_BGR888: + psize = 3; + alen = 0; apos = 0; rlen = 8; rpos = 0; + glen = 8; gpos = 8; blen = 8; bpos = 16; + break; case PF_ARGB1555: - return DRM_FORMAT_ARGB1555; + psize = 2; + alen = 1; apos = 15; rlen = 5; rpos = 10; + glen = 5; gpos = 5; blen = 5; bpos = 0; + break; case PF_ARGB4444: - return DRM_FORMAT_ARGB4444; + psize = 2; + alen = 4; apos = 12; rlen = 4; rpos = 8; + glen = 4; gpos = 4; blen = 4; bpos = 0; + break; case PF_L8: - return DRM_FORMAT_C8; - case PF_AL44: /* No DRM support */ - case PF_AL88: /* No DRM support */ - case PF_NONE: + psize = 1; + alen = 0; apos = 0; rlen = 8; rpos = 0; + glen = 8; gpos = 0; blen = 8; bpos = 0; + break; + case PF_AL44: + psize = 1; + alen = 4; apos = 4; rlen = 4; rpos = 0; + glen = 4; gpos = 0; blen = 4; bpos = 0; + break; + case PF_AL88: + psize = 2; + alen = 8; apos = 8; rlen = 8; rpos = 0; + glen = 8; gpos = 0; blen = 8; bpos = 0; + break; default: - return 0; + ret = NB_PF; /* error case, trace msg is handled by the caller */ + break; + } + + if (ret == PF_FLEXIBLE) { + regmap_write(ldev->regmap, LTDC_L1FPF0R + lofs, + (rlen << 14) + (rpos << 9) + (alen << 5) + apos); + + regmap_write(ldev->regmap, LTDC_L1FPF1R + lofs, + (psize << 18) + (blen << 14) + (bpos << 9) + (glen << 5) + gpos); } + + return ret; } -static inline u32 get_pixelformat_without_alpha(u32 drm) +/* + * All non-alpha color formats derived from native alpha color formats are + * either characterized by a FourCC format code + */ +static inline u32 is_xrgb(u32 drm) { - switch (drm) { - case DRM_FORMAT_ARGB4444: - return DRM_FORMAT_XRGB4444; - case DRM_FORMAT_RGBA4444: - return DRM_FORMAT_RGBX4444; - case DRM_FORMAT_ARGB1555: - return DRM_FORMAT_XRGB1555; - case DRM_FORMAT_RGBA5551: - return DRM_FORMAT_RGBX5551; - case DRM_FORMAT_ARGB8888: - return DRM_FORMAT_XRGB8888; - case DRM_FORMAT_RGBA8888: - return DRM_FORMAT_RGBX8888; - default: - return 0; - } + return ((drm & 0xFF) == 'X' || ((drm >> 8) & 0xFF) == 'X'); } static irqreturn_t ltdc_irq_thread(int irq, void *arg) @@ -972,6 +1051,10 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, if (ldev->caps.pix_fmt_hw[val] == pf) break; + /* Use the flexible color format feature if necessary and available */ + if (ldev->caps.pix_fmt_flex && val == NB_PF) + val = ltdc_set_flexible_pixel_format(plane, pf); + if (val == NB_PF) { DRM_ERROR("Pixel format %.4s not supported\n", (char *)&fb->format->format); @@ -1110,29 +1193,23 @@ static struct drm_plane *ltdc_plane_create(struct drm_device *ddev, struct device *dev = ddev->dev; struct drm_plane *plane; unsigned int i, nb_fmt = 0; - u32 formats[NB_PF * 2]; - u32 drm_fmt, drm_fmt_no_alpha; + u32 *formats; + u32 drm_fmt; const u64 *modifiers = ltdc_format_modifiers; int ret; - /* Get supported pixel formats */ - for (i = 0; i < NB_PF; i++) { - drm_fmt = to_drm_pixelformat(ldev->caps.pix_fmt_hw[i]); - if (!drm_fmt) - continue; - formats[nb_fmt++] = drm_fmt; + formats = devm_kzalloc(dev, ldev->caps.pix_fmt_nb * sizeof(*formats), GFP_KERNEL); - /* Add the no-alpha related format if any & supported */ - drm_fmt_no_alpha = get_pixelformat_without_alpha(drm_fmt); - if (!drm_fmt_no_alpha) - continue; + for (i = 0; i < ldev->caps.pix_fmt_nb; i++) { + drm_fmt = ldev->caps.pix_fmt_drm[i]; /* Manage hw-specific capabilities */ - if (ldev->caps.non_alpha_only_l1 && - type != DRM_PLANE_TYPE_PRIMARY) - continue; + if (ldev->caps.non_alpha_only_l1) + /* XR24 & RX24 like formats supported only on primary layer */ + if (type != DRM_PLANE_TYPE_PRIMARY && is_xrgb(drm_fmt)) + continue; - formats[nb_fmt++] = drm_fmt_no_alpha; + formats[nb_fmt++] = drm_fmt; } plane = devm_kzalloc(dev, sizeof(*plane), GFP_KERNEL); @@ -1311,6 +1388,9 @@ static int ltdc_get_caps(struct drm_device *ddev) ldev->caps.layer_ofs = LAY_OFS_0; ldev->caps.layer_regs = ltdc_layer_regs_a0; ldev->caps.pix_fmt_hw = ltdc_pix_fmt_a0; + ldev->caps.pix_fmt_drm = ltdc_drm_fmt_a0; + ldev->caps.pix_fmt_nb = ARRAY_SIZE(ltdc_drm_fmt_a0); + ldev->caps.pix_fmt_flex = false; /* * Hw older versions support non-alpha color formats derived * from native alpha color formats only on the primary layer. @@ -1330,6 +1410,9 @@ static int ltdc_get_caps(struct drm_device *ddev) ldev->caps.layer_ofs = LAY_OFS_0; ldev->caps.layer_regs = ltdc_layer_regs_a1; ldev->caps.pix_fmt_hw = ltdc_pix_fmt_a1; + ldev->caps.pix_fmt_drm = ltdc_drm_fmt_a1; + ldev->caps.pix_fmt_nb = ARRAY_SIZE(ltdc_drm_fmt_a1); + ldev->caps.pix_fmt_flex = false; ldev->caps.non_alpha_only_l1 = false; ldev->caps.pad_max_freq_hz = 150000000; ldev->caps.nb_irq = 4; @@ -1340,6 +1423,9 @@ static int ltdc_get_caps(struct drm_device *ddev) ldev->caps.layer_ofs = LAY_OFS_1; ldev->caps.layer_regs = ltdc_layer_regs_a2; ldev->caps.pix_fmt_hw = ltdc_pix_fmt_a2; + ldev->caps.pix_fmt_drm = ltdc_drm_fmt_a2; + ldev->caps.pix_fmt_nb = ARRAY_SIZE(ltdc_drm_fmt_a2); + ldev->caps.pix_fmt_flex = true; ldev->caps.non_alpha_only_l1 = false; ldev->caps.pad_max_freq_hz = 90000000; ldev->caps.nb_irq = 2; diff --git a/drivers/gpu/drm/stm/ltdc.h b/drivers/gpu/drm/stm/ltdc.h index 68a5a199e320..adc4f9cf7f95 100644 --- a/drivers/gpu/drm/stm/ltdc.h +++ b/drivers/gpu/drm/stm/ltdc.h @@ -17,7 +17,10 @@ struct ltdc_caps { u32 layer_ofs; /* layer offset for applicable regs */ const u32 *layer_regs; /* layer register offset */ u32 bus_width; /* bus width (32 or 64 bits) */ - const u32 *pix_fmt_hw; /* supported pixel formats */ + const u32 *pix_fmt_hw; /* supported hw pixel formats */ + const u32 *pix_fmt_drm; /* supported drm pixel formats */ + int pix_fmt_nb; /* number of pixel format */ + bool pix_fmt_flex; /* pixel format flexibility supported */ bool non_alpha_only_l1; /* non-native no-alpha formats on layer 1 */ int pad_max_freq_hz; /* max frequency supported by pad */ int nb_irq; /* number of hardware interrupts */ From patchwork Wed Dec 15 21:48:43 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Yannick Fertre X-Patchwork-Id: 12696341 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 34FE8C433F5 for ; Wed, 15 Dec 2021 21:50:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:Message-ID:Date:Subject:To :From:Reply-To:Cc:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References: List-Owner; bh=mJJ07dW6x2Y4FnilcK+hym88814q9uXjGr3tbJuphmA=; b=uUrmVLDBwhv30H zyiMhR64qGNkBLpQGufJKV8nAv9ogbdLsCk0q7x1flaeuRzq+lu4DYMoslAj7M2rNofA5KWC2f9rB V3GCfnFDOeTMUI7HOFzOGfIy4oHP0IQnrgJ+aSuMYCaB2VzNWWZVw+lzA86sAei85JiUv8ekqycmM uxf31squE/PpvnsA7fcNt1fYfbv9yZaIHMkzSgaM8uuZZZtdfa8TBapQ6cyF9gMd/Er4uIDRd8xwQ TkLY+o9bX15wl4S9Z5XrOw+eswAMIgbuVv0WiAOxUfZvCQBTyWypNpzteIgYKAekgVAiyrXALsZ+q Nphyusqi8G52xqyKvczg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1mxc9A-002q6z-M0; Wed, 15 Dec 2021 21:49:13 +0000 Received: from mx07-00178001.pphosted.com ([185.132.182.106]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1mxc8o-002pvR-Kh for linux-arm-kernel@lists.infradead.org; Wed, 15 Dec 2021 21:48:53 +0000 Received: from pps.filterd (m0241204.ppops.net [127.0.0.1]) by mx07-00178001.pphosted.com (8.16.1.2/8.16.1.2) with ESMTP id 1BFIjXQb026335; Wed, 15 Dec 2021 22:48:46 +0100 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=foss.st.com; h=from : to : subject : date : message-id : mime-version : content-type; s=selector1; bh=KDBBSC2Jp0beHPBPjDebpa/g/sde3MElNeSyHWIo9O0=; b=V/I0QUjJ8VMHjgu+zXByyzXAGVjy2XC3KRgxhx7eq9mVqn6wDcuDVD/X/rROEUftMi4J qItSVK3n01tEvvOjHG1eU0gca2UuxrQJYC4sikz+ZRyI583TIwKmZerya3+/i7SKYPAq 7j+31+2hF37trNvk2Yji12efP9IVir+685pCHA392+SRMOpt9LsVtfLO9x3+O7Ur8vAI uSB+lljYU9oeqUE6O+SWZA3HLmNgu/5nV1G5S67KaMuhDv8KX1tzrVarTooSV4JD4dAL IObkSHURg/yOdiRxCA+izdXnlqo1vPp4atevcl6RoVUI5M8KxEdbPC67tV/dg4u0jbN/ 6A== Received: from beta.dmz-eu.st.com (beta.dmz-eu.st.com [164.129.1.35]) by mx07-00178001.pphosted.com (PPS) with ESMTPS id 3cyfpxjj3k-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=NOT); Wed, 15 Dec 2021 22:48:46 +0100 Received: from euls16034.sgp.st.com (euls16034.sgp.st.com [10.75.44.20]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id A546610002A; Wed, 15 Dec 2021 22:48:45 +0100 (CET) Received: from Webmail-eu.st.com (sfhdag2node2.st.com [10.75.127.5]) by euls16034.sgp.st.com (STMicroelectronics) with ESMTP id 9BB2620A74F; Wed, 15 Dec 2021 22:48:45 +0100 (CET) Received: from localhost (10.75.127.47) by SFHDAG2NODE2.st.com (10.75.127.5) with Microsoft SMTP Server (TLS) id 15.0.1497.26; Wed, 15 Dec 2021 22:48:45 +0100 From: Yannick Fertre To: Yannick Fertre , Philippe Cornu , Raphael Gallais-Pou , David Airlie , Daniel Vetter , Maxime Coquelin , Alexandre Torgue , , , , Subject: [PATCH 5/5] drm/stm: ltdc: add support of ycbcr pixel formats Date: Wed, 15 Dec 2021 22:48:43 +0100 Message-ID: <20211215214843.20703-1-yannick.fertre@foss.st.com> X-Mailer: git-send-email 2.17.1 MIME-Version: 1.0 X-Originating-IP: [10.75.127.47] X-ClientProxiedBy: SFHDAG1NODE3.st.com (10.75.127.3) To SFHDAG2NODE2.st.com (10.75.127.5) X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.205,Aquarius:18.0.790,Hydra:6.0.425,FMLib:17.11.62.513 definitions=2021-12-15_13,2021-12-14_01,2021-12-02_01 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211215_134851_048737_29C68BC6 X-CRM114-Status: GOOD ( 28.97 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org This patch adds the following YCbCr input pixel formats on the latest LTDC hardware version: 1 plane (co-planar) : YUYV, YVYU, UYVY, VYUY 2 planes (semi-planar): NV12, NV21 3 planes (full-planar): YU12=I420=DRM YUV420, YV12=DRM YVU420 Signed-off-by: Yannick Fertre Acked-by: Philippe Cornu Reviewed-by: Philippe Cornu --- drivers/gpu/drm/stm/ltdc.c | 251 +++++++++++++++++++++++++++++++++++-- drivers/gpu/drm/stm/ltdc.h | 1 + 2 files changed, 245 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c index 4d249bc99894..7fd173390b9f 100644 --- a/drivers/gpu/drm/stm/ltdc.c +++ b/drivers/gpu/drm/stm/ltdc.c @@ -198,6 +198,21 @@ #define LXCFBLNR_CFBLN GENMASK(10, 0) /* Color Frame Buffer Line Number */ +#define LXCR_C1R_YIA BIT(0) /* Ycbcr 422 Interleaved Ability */ +#define LXCR_C1R_YSPA BIT(1) /* Ycbcr 420 Semi-Planar Ability */ +#define LXCR_C1R_YFPA BIT(2) /* Ycbcr 420 Full-Planar Ability */ +#define LXCR_C1R_SCA BIT(31) /* SCaling Ability*/ + +#define LxPCR_YREN BIT(9) /* Y Rescale Enable for the color dynamic range */ +#define LxPCR_OF BIT(8) /* Odd pixel First */ +#define LxPCR_CBF BIT(7) /* CB component First */ +#define LxPCR_YF BIT(6) /* Y component First */ +#define LxPCR_YCM GENMASK(5, 4) /* Ycbcr Conversion Mode */ +#define YCM_I 0x0 /* Interleaved 422 */ +#define YCM_SP 0x1 /* Semi-Planar 420 */ +#define YCM_FP 0x2 /* Full-Planar 420 */ +#define LxPCR_YCEN BIT(3) /* YCbCr-to-RGB Conversion Enable */ + #define LXRCR_IMR BIT(0) /* IMmediate Reload */ #define LXRCR_VBR BIT(1) /* Vertical Blanking Reload */ #define LXRCR_GRMSK BIT(2) /* Global (centralized) Reload MaSKed */ @@ -311,6 +326,23 @@ static const u32 ltdc_drm_fmt_a2[] = { DRM_FORMAT_C8 }; +static const u32 ltdc_drm_fmt_ycbcr_cp[] = { + DRM_FORMAT_YUYV, + DRM_FORMAT_YVYU, + DRM_FORMAT_UYVY, + DRM_FORMAT_VYUY +}; + +static const u32 ltdc_drm_fmt_ycbcr_sp[] = { + DRM_FORMAT_NV12, + DRM_FORMAT_NV21 +}; + +static const u32 ltdc_drm_fmt_ycbcr_fp[] = { + DRM_FORMAT_YUV420, + DRM_FORMAT_YVU420 +}; + /* Layer register offsets */ static const u32 ltdc_layer_regs_a0[] = { 0x80, /* L1 configuration 0 */ @@ -410,6 +442,26 @@ static const struct regmap_config stm32_ltdc_regmap_cfg = { .cache_type = REGCACHE_NONE, }; +static const u32 ltdc_ycbcr2rgb_coeffs[DRM_COLOR_ENCODING_MAX][DRM_COLOR_RANGE_MAX][2] = { + [DRM_COLOR_YCBCR_BT601][DRM_COLOR_YCBCR_LIMITED_RANGE] = { + 0x02040199, /* (b_cb = 516 / r_cr = 409) */ + 0x006400D0 /* (g_cb = 100 / g_cr = 208) */ + }, + [DRM_COLOR_YCBCR_BT601][DRM_COLOR_YCBCR_FULL_RANGE] = { + 0x01C60167, /* (b_cb = 454 / r_cr = 359) */ + 0x005800B7 /* (g_cb = 88 / g_cr = 183) */ + }, + [DRM_COLOR_YCBCR_BT709][DRM_COLOR_YCBCR_LIMITED_RANGE] = { + 0x021D01CB, /* (b_cb = 541 / r_cr = 459) */ + 0x00370089 /* (g_cb = 55 / g_cr = 137) */ + }, + [DRM_COLOR_YCBCR_BT709][DRM_COLOR_YCBCR_FULL_RANGE] = { + 0x01DB0193, /* (b_cb = 475 / r_cr = 403) */ + 0x00300078 /* (g_cb = 48 / g_cr = 120) */ + } + /* BT2020 not supported */ +}; + static inline struct ltdc_device *crtc_to_ltdc(struct drm_crtc *crtc) { return (struct ltdc_device *)crtc->dev->dev_private; @@ -540,6 +592,78 @@ static inline u32 is_xrgb(u32 drm) return ((drm & 0xFF) == 'X' || ((drm >> 8) & 0xFF) == 'X'); } +static inline void ltdc_set_ycbcr_config(struct drm_plane *plane, u32 drm_pix_fmt) +{ + struct ltdc_device *ldev = plane_to_ltdc(plane); + struct drm_plane_state *state = plane->state; + u32 lofs = plane->index * LAY_OFS; + u32 val; + + switch (drm_pix_fmt) { + case DRM_FORMAT_YUYV: + val = (YCM_I << 4) | LxPCR_YF | LxPCR_CBF; + break; + case DRM_FORMAT_YVYU: + val = (YCM_I << 4) | LxPCR_YF; + break; + case DRM_FORMAT_UYVY: + val = (YCM_I << 4) | LxPCR_CBF; + break; + case DRM_FORMAT_VYUY: + val = (YCM_I << 4); + break; + case DRM_FORMAT_NV12: + val = (YCM_SP << 4) | LxPCR_CBF; + break; + case DRM_FORMAT_NV21: + val = (YCM_SP << 4); + break; + case DRM_FORMAT_YUV420: + case DRM_FORMAT_YVU420: + val = (YCM_FP << 4); + break; + default: + /* RGB or not a YCbCr supported format */ + break; + } + + /* Enable limited range */ + if (state->color_range == DRM_COLOR_YCBCR_LIMITED_RANGE) + val |= LxPCR_YREN; + + /* enable ycbcr conversion */ + val |= LxPCR_YCEN; + + regmap_write(ldev->regmap, LTDC_L1PCR + lofs, val); +} + +static inline void ltdc_set_ycbcr_coeffs(struct drm_plane *plane) +{ + struct ltdc_device *ldev = plane_to_ltdc(plane); + struct drm_plane_state *state = plane->state; + enum drm_color_encoding enc = state->color_encoding; + enum drm_color_range ran = state->color_range; + u32 lofs = plane->index * LAY_OFS; + + if (enc != DRM_COLOR_YCBCR_BT601 && enc != DRM_COLOR_YCBCR_BT709) { + DRM_ERROR("color encoding %d not supported, use bt601 by default\n", enc); + /* set by default color encoding to DRM_COLOR_YCBCR_BT601 */ + enc = DRM_COLOR_YCBCR_BT601; + } + + if (ran != DRM_COLOR_YCBCR_LIMITED_RANGE && ran != DRM_COLOR_YCBCR_FULL_RANGE) { + DRM_ERROR("color range %d not supported, use limited range by default\n", ran); + /* set by default color range to DRM_COLOR_YCBCR_LIMITED_RANGE */ + ran = DRM_COLOR_YCBCR_LIMITED_RANGE; + } + + DRM_DEBUG_DRIVER("Color encoding=%d, range=%d\n", enc, ran); + regmap_write(ldev->regmap, LTDC_L1CYR0R + lofs, + ltdc_ycbcr2rgb_coeffs[enc][ran][0]); + regmap_write(ldev->regmap, LTDC_L1CYR1R + lofs, + ltdc_ycbcr2rgb_coeffs[enc][ran][1]); +} + static irqreturn_t ltdc_irq_thread(int irq, void *arg) { struct drm_device *ddev = arg; @@ -1010,7 +1134,7 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, u32 y0 = newstate->crtc_y; u32 y1 = newstate->crtc_y + newstate->crtc_h - 1; u32 src_x, src_y, src_w, src_h; - u32 val, pitch_in_bytes, line_length, paddr, ahbp, avbp, bpcr; + u32 val, pitch_in_bytes, line_length, line_number, paddr, ahbp, avbp, bpcr; enum ltdc_pix_fmt pf; if (!newstate->crtc || !fb) { @@ -1086,8 +1210,8 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, regmap_write_bits(ldev->regmap, LTDC_L1BFCR + lofs, LXBFCR_BF2 | LXBFCR_BF1, val); /* Configures the frame buffer line number */ - val = y1 - y0 + 1; - regmap_write_bits(ldev->regmap, LTDC_L1CFBLNR + lofs, LXCFBLNR_CFBLN, val); + line_number = y1 - y0 + 1; + regmap_write_bits(ldev->regmap, LTDC_L1CFBLNR + lofs, LXCFBLNR_CFBLN, line_number); /* Sets the FB address */ paddr = (u32)drm_fb_cma_get_gem_addr(fb, newstate, 0); @@ -1095,6 +1219,77 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, DRM_DEBUG_DRIVER("fb: phys 0x%08x", paddr); regmap_write(ldev->regmap, LTDC_L1CFBAR + lofs, paddr); + if (ldev->caps.ycbcr_input) { + if (fb->format->is_yuv) { + switch (fb->format->format) { + case DRM_FORMAT_NV12: + case DRM_FORMAT_NV21: + /* Configure the auxiliary frame buffer address 0 & 1 */ + paddr = (u32)drm_fb_cma_get_gem_addr(fb, newstate, 1); + regmap_write(ldev->regmap, LTDC_L1AFBA0R + lofs, paddr); + regmap_write(ldev->regmap, LTDC_L1AFBA1R + lofs, paddr + 1); + + /* Configure the buffer length */ + val = ((pitch_in_bytes << 16) | line_length); + regmap_write(ldev->regmap, LTDC_L1AFBLR + lofs, val); + + /* Configure the frame buffer line number */ + val = (line_number >> 1); + regmap_write(ldev->regmap, LTDC_L1AFBLNR + lofs, val); + break; + case DRM_FORMAT_YUV420: + /* Configure the auxiliary frame buffer address 0 */ + paddr = (u32)drm_fb_cma_get_gem_addr(fb, newstate, 1); + regmap_write(ldev->regmap, LTDC_L1AFBA0R + lofs, paddr); + + /* Configure the auxiliary frame buffer address 1 */ + paddr = (u32)drm_fb_cma_get_gem_addr(fb, newstate, 2); + regmap_write(ldev->regmap, LTDC_L1AFBA1R + lofs, paddr); + + line_length = ((fb->format->cpp[0] * (x1 - x0 + 1)) >> 1) + + (ldev->caps.bus_width >> 3) - 1; + + /* Configure the buffer length */ + val = (((pitch_in_bytes >> 1) << 16) | line_length); + regmap_write(ldev->regmap, LTDC_L1AFBLR + lofs, val); + + /* Configure the frame buffer line number */ + val = (line_number >> 1); + regmap_write(ldev->regmap, LTDC_L1AFBLNR + lofs, val); + break; + case DRM_FORMAT_YVU420: + /* Configure the auxiliary frame buffer address 0 */ + paddr = (u32)drm_fb_cma_get_gem_addr(fb, newstate, 2); + regmap_write(ldev->regmap, LTDC_L1AFBA0R + lofs, paddr); + + /* Configure the auxiliary frame buffer address 1 */ + paddr = (u32)drm_fb_cma_get_gem_addr(fb, newstate, 1); + regmap_write(ldev->regmap, LTDC_L1AFBA1R + lofs, paddr); + + line_length = ((fb->format->cpp[0] * (x1 - x0 + 1)) >> 1) + + (ldev->caps.bus_width >> 3) - 1; + + /* Configure the buffer length */ + val = (((pitch_in_bytes >> 1) << 16) | line_length); + regmap_write(ldev->regmap, LTDC_L1AFBLR + lofs, val); + + /* Configure the frame buffer line number */ + val = (line_number >> 1); + regmap_write(ldev->regmap, LTDC_L1AFBLNR + lofs, val); + break; + } + + /* Configure YCbC conversion coefficient */ + ltdc_set_ycbcr_coeffs(plane); + + /* Configure YCbCr format and enable/disable conversion */ + ltdc_set_ycbcr_config(plane, fb->format->format); + } else { + /* disable ycbcr conversion */ + regmap_write(ldev->regmap, LTDC_L1PCR + lofs, 0); + } + } + /* Enable layer and CLUT if needed */ val = fb->format->format == DRM_FORMAT_C8 ? LXCR_CLUTEN : 0; val |= LXCR_LEN; @@ -1186,7 +1381,8 @@ static const struct drm_plane_helper_funcs ltdc_plane_helper_funcs = { }; static struct drm_plane *ltdc_plane_create(struct drm_device *ddev, - enum drm_plane_type type) + enum drm_plane_type type, + int index) { unsigned long possible_crtcs = CRTC_MASK; struct ltdc_device *ldev = ddev->dev_private; @@ -1196,9 +1392,16 @@ static struct drm_plane *ltdc_plane_create(struct drm_device *ddev, u32 *formats; u32 drm_fmt; const u64 *modifiers = ltdc_format_modifiers; + u32 lofs = index * LAY_OFS; + u32 val; int ret; - formats = devm_kzalloc(dev, ldev->caps.pix_fmt_nb * sizeof(*formats), GFP_KERNEL); + /* Allocate the biggest size according to supported color formats */ + formats = devm_kzalloc(dev, (ldev->caps.pix_fmt_nb + + ARRAY_SIZE(ltdc_drm_fmt_ycbcr_cp) + + ARRAY_SIZE(ltdc_drm_fmt_ycbcr_sp) + + ARRAY_SIZE(ltdc_drm_fmt_ycbcr_fp)) * + sizeof(*formats), GFP_KERNEL); for (i = 0; i < ldev->caps.pix_fmt_nb; i++) { drm_fmt = ldev->caps.pix_fmt_drm[i]; @@ -1212,6 +1415,26 @@ static struct drm_plane *ltdc_plane_create(struct drm_device *ddev, formats[nb_fmt++] = drm_fmt; } + /* Add YCbCr supported pixel formats */ + if (ldev->caps.ycbcr_input) { + regmap_read(ldev->regmap, LTDC_L1C1R + lofs, &val); + if (val & LXCR_C1R_YIA) { + memcpy(&formats[nb_fmt], ltdc_drm_fmt_ycbcr_cp, + ARRAY_SIZE(ltdc_drm_fmt_ycbcr_cp) * sizeof(*formats)); + nb_fmt += ARRAY_SIZE(ltdc_drm_fmt_ycbcr_cp); + } + if (val & LXCR_C1R_YSPA) { + memcpy(&formats[nb_fmt], ltdc_drm_fmt_ycbcr_sp, + ARRAY_SIZE(ltdc_drm_fmt_ycbcr_sp) * sizeof(*formats)); + nb_fmt += ARRAY_SIZE(ltdc_drm_fmt_ycbcr_sp); + } + if (val & LXCR_C1R_YFPA) { + memcpy(&formats[nb_fmt], ltdc_drm_fmt_ycbcr_fp, + ARRAY_SIZE(ltdc_drm_fmt_ycbcr_fp) * sizeof(*formats)); + nb_fmt += ARRAY_SIZE(ltdc_drm_fmt_ycbcr_fp); + } + } + plane = devm_kzalloc(dev, sizeof(*plane), GFP_KERNEL); if (!plane) return NULL; @@ -1222,6 +1445,17 @@ static struct drm_plane *ltdc_plane_create(struct drm_device *ddev, if (ret < 0) return NULL; + if (ldev->caps.ycbcr_input) { + if (val & (LXCR_C1R_YIA | LXCR_C1R_YSPA | LXCR_C1R_YFPA)) + drm_plane_create_color_properties(plane, + BIT(DRM_COLOR_YCBCR_BT601) | + BIT(DRM_COLOR_YCBCR_BT709), + BIT(DRM_COLOR_YCBCR_LIMITED_RANGE) | + BIT(DRM_COLOR_YCBCR_FULL_RANGE), + DRM_COLOR_YCBCR_BT601, + DRM_COLOR_YCBCR_LIMITED_RANGE); + } + drm_plane_helper_add(plane, <dc_plane_helper_funcs); drm_plane_create_alpha_property(plane); @@ -1247,7 +1481,7 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc) unsigned int i; int ret; - primary = ltdc_plane_create(ddev, DRM_PLANE_TYPE_PRIMARY); + primary = ltdc_plane_create(ddev, DRM_PLANE_TYPE_PRIMARY, 0); if (!primary) { DRM_ERROR("Can not create primary plane\n"); return -EINVAL; @@ -1271,7 +1505,7 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc) /* Add planes. Note : the first layer is used by primary plane */ for (i = 1; i < ldev->caps.nb_layers; i++) { - overlay = ltdc_plane_create(ddev, DRM_PLANE_TYPE_OVERLAY); + overlay = ltdc_plane_create(ddev, DRM_PLANE_TYPE_OVERLAY, i); if (!overlay) { ret = -ENOMEM; DRM_ERROR("Can not create overlay plane %d\n", i); @@ -1403,6 +1637,7 @@ static int ltdc_get_caps(struct drm_device *ddev) if (ldev->caps.hw_version == HWVER_10200) ldev->caps.pad_max_freq_hz = 65000000; ldev->caps.nb_irq = 2; + ldev->caps.ycbcr_input = false; ldev->caps.ycbcr_output = false; ldev->caps.plane_reg_shadow = false; break; @@ -1416,6 +1651,7 @@ static int ltdc_get_caps(struct drm_device *ddev) ldev->caps.non_alpha_only_l1 = false; ldev->caps.pad_max_freq_hz = 150000000; ldev->caps.nb_irq = 4; + ldev->caps.ycbcr_input = false; ldev->caps.ycbcr_output = false; ldev->caps.plane_reg_shadow = false; break; @@ -1429,6 +1665,7 @@ static int ltdc_get_caps(struct drm_device *ddev) ldev->caps.non_alpha_only_l1 = false; ldev->caps.pad_max_freq_hz = 90000000; ldev->caps.nb_irq = 2; + ldev->caps.ycbcr_input = true; ldev->caps.ycbcr_output = true; ldev->caps.plane_reg_shadow = true; break; diff --git a/drivers/gpu/drm/stm/ltdc.h b/drivers/gpu/drm/stm/ltdc.h index adc4f9cf7f95..6968d1ca5149 100644 --- a/drivers/gpu/drm/stm/ltdc.h +++ b/drivers/gpu/drm/stm/ltdc.h @@ -24,6 +24,7 @@ struct ltdc_caps { bool non_alpha_only_l1; /* non-native no-alpha formats on layer 1 */ int pad_max_freq_hz; /* max frequency supported by pad */ int nb_irq; /* number of hardware interrupts */ + bool ycbcr_input; /* ycbcr input converter supported */ bool ycbcr_output; /* ycbcr output converter supported */ bool plane_reg_shadow; /* plane shadow registers ability */ };