Hi Inki,
GSCALERs in Exynos SoCs support conversion between wide range of image formats, plus scaling and rotation. Driver already supports mem2mem mode - via ExynosDRM IPP framework. This patchset adds support for mem to display mode - framebuffers can be converted, scaled and send directly to Display Controller. From DRM framework's point of view every GSCALER exposes drm_plane which can be connected to display controller (display panel or TV). The feature is not well documented so the development was quite difficult - a process of trial and error, vendor code analysis, guessing from datasheets. Hopefully most of the issues were solved. I have developed and tested it on TM2 device with panel and TV paths.
The patchset contains three parts: 1. Preparatory patches - mostly cleanup and refactoring of drm_crtc and drm_plane related structures, to allow usage of planes which are not physically bound to crtcs (01-13). 2. Adding local path support to GSCALER and DECON (14-20). 3. Few fixes of bugs existing already in the code but discovered due to added local path support (21-23).
The patchset is based on exynos_drm_next plus my patchset adding zpos to DECON and FIMD - 'drm/exynos: add support for dynamic zpos in DECON and FIMD' - it is required to allow set z-pos position of GSCALER planes. To simplify tests I have also created branch containing all required patches: Repo: https://git.tizen.org/cgit/platform/kernel/linux-exynos Branch: sandbox/ahajda/dev/exynos-drm-local-path
This is v2 version of the patchset. In this version I have moved code setting cursor plane in crtc to separate patch together with code disabling fast cursor updates - hardware does not support it. To keep bisectability DTS patches should be applied before subsequent ones. It is rebased on today's exynos-drm-next.
Please be aware that DTS patches has been already applied to samsung-soc tree, I left them here to simplify testing on exynos-drm-next, which is not in sync with samsung-soc, for this reason I have moved them on the beginning of the patchset.
Regards Andrzej
Andrzej Hajda (24): arm64: dts: exynos: configure GSCALER related clocks arm64: dts: exynos: add DSD/GSD clocks to DECONs and GSCALERs drm/exynos: remove exynos_drm_plane.h header drm/exynos: remove spare macro drm/exynos: drop exynos_drm_plane_config structure drm/exynos: add exynos_drm_crtc_init function drm/exynos/decon5433: embed exynos_drm_crtc directly into context drm/exynos/decon7: embed exynos_drm_crtc directly into context drm/exynos/fimd: embed exynos_drm_crtc directly into context drm/exynos/mixer: embed exynos_drm_crtc directly into context drm/exynos/vidi: embed exynos_drm_crtc directly into context drm/exynos: remove standalone exynos_drm_crtc leftovers drm/exynos/vidi: remove encoder_to_vidi helper drm/exynos: unify plane type assignment drm/exynos: set primary plane in exynos_drm_crtc_init drm/exynos: set cursor plane in exynos_drm_crtc_init drm/exynos: add plane update/disable callbacks for planes drm/exynos: add GSCALER plane capability drm/exynos/gscaler: fix id assignement drm/exynos/gscaler: add local path support drm/exynos/decon5433: add local path support drm/exynos/decon5433: wait for finish previous update drm/exynos/gscaler: change supported color format BGRX8888 to XBGR8888 drm/exynos/gscaler: fix handling YVU420 pixel format
.../dts/exynos/exynos5433-tm2-common.dtsi | 6 + arch/arm64/boot/dts/exynos/exynos5433-tm2.dts | 6 +- arch/arm64/boot/dts/exynos/exynos5433.dtsi | 25 +- drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 162 ++++++++----- drivers/gpu/drm/exynos/exynos7_drm_decon.c | 66 +++-- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 46 ++-- drivers/gpu/drm/exynos/exynos_drm_crtc.h | 7 +- drivers/gpu/drm/exynos/exynos_drm_drv.c | 1 - drivers/gpu/drm/exynos/exynos_drm_drv.h | 50 ++-- drivers/gpu/drm/exynos/exynos_drm_fb.c | 10 +- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 85 +++---- drivers/gpu/drm/exynos/exynos_drm_gsc.c | 229 ++++++++++++++---- drivers/gpu/drm/exynos/exynos_drm_plane.c | 84 ++++--- drivers/gpu/drm/exynos/exynos_drm_plane.h | 14 -- drivers/gpu/drm/exynos/exynos_drm_vidi.c | 48 ++-- drivers/gpu/drm/exynos/exynos_mixer.c | 95 +++----- drivers/gpu/drm/exynos/regs-decon5433.h | 6 + drivers/gpu/drm/exynos/regs-gsc.h | 6 + 18 files changed, 538 insertions(+), 408 deletions(-) delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_plane.h
GSCALER should be feed with clock at certain rates.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com --- Already merged !!! --- arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi | 6 ++++++ arch/arm64/boot/dts/exynos/exynos5433-tm2.dts | 6 ++++-- 2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi b/arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi index d88e2f0e179a..d2de16645e10 100644 --- a/arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi +++ b/arch/arm64/boot/dts/exynos/exynos5433-tm2-common.dtsi @@ -289,6 +289,12 @@ assigned-clock-parents = <&cmu_top CLK_ACLK_MFC_400>; };
+&cmu_mif { + assigned-clocks = <&cmu_mif CLK_MOUT_SCLK_DSD_A>, <&cmu_mif CLK_DIV_SCLK_DSD>; + assigned-clock-parents = <&cmu_mif CLK_MOUT_MFC_PLL_DIV2>; + assigned-clock-rates = <0>, <333000000>; +}; + &cmu_mscl { assigned-clocks = <&cmu_mscl CLK_MOUT_ACLK_MSCL_400_USER>, <&cmu_mscl CLK_MOUT_SCLK_JPEG_USER>, diff --git a/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts b/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts index 3d7e0a782243..dda5d2746a74 100644 --- a/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts +++ b/arch/arm64/boot/dts/exynos/exynos5433-tm2.dts @@ -33,7 +33,8 @@ <&cmu_disp CLK_MOUT_DISP_PLL>, <&cmu_mif CLK_MOUT_SCLK_DECON_TV_ECLK_A>, <&cmu_disp CLK_MOUT_SCLK_DECON_TV_ECLK_USER>, - <&cmu_disp CLK_MOUT_SCLK_DECON_TV_ECLK>; + <&cmu_disp CLK_MOUT_SCLK_DECON_TV_ECLK>, + <&cmu_disp CLK_MOUT_SCLK_DSD_USER>; assigned-clock-parents = <0>, <0>, <&cmu_mif CLK_ACLK_DISP_333>, <&cmu_mif CLK_SCLK_DSIM0_DISP>, @@ -45,7 +46,8 @@ <&cmu_disp CLK_FOUT_DISP_PLL>, <&cmu_mif CLK_MOUT_BUS_PLL_DIV2>, <&cmu_mif CLK_SCLK_DECON_TV_ECLK_DISP>, - <&cmu_disp CLK_MOUT_SCLK_DECON_TV_ECLK_USER>; + <&cmu_disp CLK_MOUT_SCLK_DECON_TV_ECLK_USER>, + <&cmu_mif CLK_SCLK_DSD_DISP>; assigned-clock-rates = <250000000>, <400000000>; };
On Mon, 25 Mar 2019 at 08:13, Andrzej Hajda a.hajda@samsung.com wrote:
GSCALER should be feed with clock at certain rates.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com
Already merged !!!
Then you should skip it because someone might not notice it and apply second time.
Best regards, Krzysztof
On 25.03.2019 08:50, Krzysztof Kozlowski wrote:
On Mon, 25 Mar 2019 at 08:13, Andrzej Hajda a.hajda@samsung.com wrote:
GSCALER should be feed with clock at certain rates.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com
Already merged !!!
Then you should skip it because someone might not notice it and apply second time.
I was asked to rebase the patchset on exynos-drm-next, but it does not contains yet these patches,
so without adding it here "someone might not notice it and" can complain that patchset is broken :)
Maybe better solution would be point to point out samsung-soc tree tag which should exynos-drm-next be based on? Next time I will try this way.
Regards
Andrzej
Best regards, Krzysztof
On Mon, 25 Mar 2019 at 09:32, Andrzej Hajda a.hajda@samsung.com wrote:
On 25.03.2019 08:50, Krzysztof Kozlowski wrote:
On Mon, 25 Mar 2019 at 08:13, Andrzej Hajda a.hajda@samsung.com wrote:
GSCALER should be feed with clock at certain rates.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com
Already merged !!!
Then you should skip it because someone might not notice it and apply second time.
I was asked to rebase the patchset on exynos-drm-next, but it does not contains yet these patches,
so without adding it here "someone might not notice it and" can complain that patchset is broken :)
Maybe better solution would be point to point out samsung-soc tree tag which should exynos-drm-next be based on? Next time I will try this way.
Yes, I see. If needed, I can provide stable tag with DTS patches however in general this is discouraged because it means that you break the ABI. Updated driver does not work with old DTBs... so the best way is to split the patchset and bring in the second part of driver changes later. :)
Best regards, Krzysztof
To support local paths both DECON and GSCALER should enable respective Smart Deck clocks DSD and GSD.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com --- Already merged!!! --- arch/arm64/boot/dts/exynos/exynos5433.dtsi | 25 +++++++++++++--------- 1 file changed, 15 insertions(+), 10 deletions(-)
diff --git a/arch/arm64/boot/dts/exynos/exynos5433.dtsi b/arch/arm64/boot/dts/exynos/exynos5433.dtsi index a04e80327b6e..4bc55ee25bfe 100644 --- a/arch/arm64/boot/dts/exynos/exynos5433.dtsi +++ b/arch/arm64/boot/dts/exynos/exynos5433.dtsi @@ -848,12 +848,13 @@ <&cmu_disp CLK_ACLK_XIU_DECON1X>, <&cmu_disp CLK_PCLK_SMMU_DECON1X>, <&cmu_disp CLK_SCLK_DECON_VCLK>, - <&cmu_disp CLK_SCLK_DECON_ECLK>; + <&cmu_disp CLK_SCLK_DECON_ECLK>, + <&cmu_disp CLK_SCLK_DSD>; clock-names = "pclk", "aclk_decon", "aclk_smmu_decon0x", "aclk_xiu_decon0x", "pclk_smmu_decon0x", "aclk_smmu_decon1x", "aclk_xiu_decon1x", "pclk_smmu_decon1x", "sclk_decon_vclk", - "sclk_decon_eclk"; + "sclk_decon_eclk", "dsd"; power-domains = <&pd_disp>; interrupt-names = "fifo", "vsync", "lcd_sys"; interrupts = <GIC_SPI 201 IRQ_TYPE_LEVEL_HIGH>, @@ -890,12 +891,13 @@ <&cmu_disp CLK_ACLK_XIU_TV1X>, <&cmu_disp CLK_PCLK_SMMU_TV1X>, <&cmu_disp CLK_SCLK_DECON_TV_VCLK>, - <&cmu_disp CLK_SCLK_DECON_TV_ECLK>; + <&cmu_disp CLK_SCLK_DECON_TV_ECLK>, + <&cmu_disp CLK_SCLK_DSD>; clock-names = "pclk", "aclk_decon", "aclk_smmu_decon0x", "aclk_xiu_decon0x", "pclk_smmu_decon0x", "aclk_smmu_decon1x", "aclk_xiu_decon1x", "pclk_smmu_decon1x", "sclk_decon_vclk", - "sclk_decon_eclk"; + "sclk_decon_eclk", "dsd"; samsung,disp-sysreg = <&syscon_disp>; power-domains = <&pd_disp>; interrupt-names = "fifo", "vsync", "lcd_sys"; @@ -1022,11 +1024,12 @@ reg = <0x13c00000 0x1000>; interrupts = <GIC_SPI 297 IRQ_TYPE_LEVEL_HIGH>; clock-names = "pclk", "aclk", "aclk_xiu", - "aclk_gsclbend"; + "aclk_gsclbend", "gsd"; clocks = <&cmu_gscl CLK_PCLK_GSCL0>, <&cmu_gscl CLK_ACLK_GSCL0>, <&cmu_gscl CLK_ACLK_XIU_GSCLX>, - <&cmu_gscl CLK_ACLK_GSCLBEND_333>; + <&cmu_gscl CLK_ACLK_GSCLBEND_333>, + <&cmu_gscl CLK_ACLK_GSD>; iommus = <&sysmmu_gscl0>; power-domains = <&pd_gscl>; }; @@ -1036,11 +1039,12 @@ reg = <0x13c10000 0x1000>; interrupts = <GIC_SPI 298 IRQ_TYPE_LEVEL_HIGH>; clock-names = "pclk", "aclk", "aclk_xiu", - "aclk_gsclbend"; + "aclk_gsclbend", "gsd"; clocks = <&cmu_gscl CLK_PCLK_GSCL1>, <&cmu_gscl CLK_ACLK_GSCL1>, <&cmu_gscl CLK_ACLK_XIU_GSCLX>, - <&cmu_gscl CLK_ACLK_GSCLBEND_333>; + <&cmu_gscl CLK_ACLK_GSCLBEND_333>, + <&cmu_gscl CLK_ACLK_GSD>; iommus = <&sysmmu_gscl1>; power-domains = <&pd_gscl>; }; @@ -1050,11 +1054,12 @@ reg = <0x13c20000 0x1000>; interrupts = <GIC_SPI 299 IRQ_TYPE_LEVEL_HIGH>; clock-names = "pclk", "aclk", "aclk_xiu", - "aclk_gsclbend"; + "aclk_gsclbend", "gsd"; clocks = <&cmu_gscl CLK_PCLK_GSCL2>, <&cmu_gscl CLK_ACLK_GSCL2>, <&cmu_gscl CLK_ACLK_XIU_GSCLX>, - <&cmu_gscl CLK_ACLK_GSCLBEND_333>; + <&cmu_gscl CLK_ACLK_GSCLBEND_333>, + <&cmu_gscl CLK_ACLK_GSD>; iommus = <&sysmmu_gscl2>; power-domains = <&pd_gscl>; };
The header contains only declaration of one function, the rest of exynos plane declaration is in exynos_drm_drv.h. Let's merge it together.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com --- drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 1 - drivers/gpu/drm/exynos/exynos7_drm_decon.c | 1 - drivers/gpu/drm/exynos/exynos_drm_crtc.c | 1 - drivers/gpu/drm/exynos/exynos_drm_drv.c | 1 - drivers/gpu/drm/exynos/exynos_drm_drv.h | 4 ++++ drivers/gpu/drm/exynos/exynos_drm_fimd.c | 1 - drivers/gpu/drm/exynos/exynos_drm_plane.c | 1 - drivers/gpu/drm/exynos/exynos_drm_plane.h | 14 -------------- drivers/gpu/drm/exynos/exynos_drm_vidi.c | 1 - drivers/gpu/drm/exynos/exynos_mixer.c | 1 - 10 files changed, 4 insertions(+), 22 deletions(-) delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_plane.h
diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index bdfec5f977e9..24df0b307b2f 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -24,7 +24,6 @@ #include "exynos_drm_drv.h" #include "exynos_drm_crtc.h" #include "exynos_drm_fb.h" -#include "exynos_drm_plane.h" #include "regs-decon5433.h"
#define DSD_CFG_MUX 0x1004 diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index 381aa3d60e37..812941b84287 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c @@ -27,7 +27,6 @@ #include <video/of_videomode.h>
#include "exynos_drm_crtc.h" -#include "exynos_drm_plane.h" #include "exynos_drm_drv.h" #include "exynos_drm_fb.h" #include "regs-decon7.h" diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 96ee83a798c4..1eebfa3fa8da 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -20,7 +20,6 @@
#include "exynos_drm_crtc.h" #include "exynos_drm_drv.h" -#include "exynos_drm_plane.h"
static void exynos_drm_crtc_atomic_enable(struct drm_crtc *crtc, struct drm_crtc_state *old_state) diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index e1ef9dc9ebf3..2155586646dc 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -26,7 +26,6 @@ #include "exynos_drm_fbdev.h" #include "exynos_drm_fb.h" #include "exynos_drm_gem.h" -#include "exynos_drm_plane.h" #include "exynos_drm_ipp.h" #include "exynos_drm_vidi.h" #include "exynos_drm_g2d.h" diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 71eb240bc1f4..6e38d0dc4457 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -113,6 +113,10 @@ struct exynos_drm_plane_config { unsigned int capabilities; };
+int exynos_plane_init(struct drm_device *dev, + struct exynos_drm_plane *exynos_plane, unsigned int index, + const struct exynos_drm_plane_config *config); + /* * Exynos drm crtc ops * diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 46588a14f0c3..b1a9502a4140 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -31,7 +31,6 @@ #include "exynos_drm_drv.h" #include "exynos_drm_fb.h" #include "exynos_drm_crtc.h" -#include "exynos_drm_plane.h"
/* * FIMD stands for Fully Interactive Mobile Display and diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index df0508e0e49e..8af0eba3f362 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -19,7 +19,6 @@ #include "exynos_drm_crtc.h" #include "exynos_drm_fb.h" #include "exynos_drm_gem.h" -#include "exynos_drm_plane.h"
/* * This function is to get X or Y size shown via screen. This needs length and diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.h b/drivers/gpu/drm/exynos/exynos_drm_plane.h deleted file mode 100644 index 497047b19614..000000000000 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (C) 2011 Samsung Electronics Co.Ltd - * Authors: Joonyoung Shim jy0922.shim@samsung.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - */ - -int exynos_plane_init(struct drm_device *dev, - struct exynos_drm_plane *exynos_plane, unsigned int index, - const struct exynos_drm_plane_config *config); diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index 29f4c1932aed..ec30d5aca9aa 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -26,7 +26,6 @@ #include "exynos_drm_drv.h" #include "exynos_drm_crtc.h" #include "exynos_drm_fb.h" -#include "exynos_drm_plane.h" #include "exynos_drm_vidi.h"
/* VIDI uses fixed refresh rate of 50Hz */ diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index f35e4ab55b27..ef50943cc9eb 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -40,7 +40,6 @@ #include "exynos_drm_drv.h" #include "exynos_drm_crtc.h" #include "exynos_drm_fb.h" -#include "exynos_drm_plane.h"
#define MIXER_WIN_NR 3 #define VP_DEFAULT_WIN 2
MAX_CRTC macro is not used at all.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com --- drivers/gpu/drm/exynos/exynos_drm_drv.h | 1 - 1 file changed, 1 deletion(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 6e38d0dc4457..1f6bb5516170 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -18,7 +18,6 @@ #include <drm/drmP.h> #include <linux/module.h>
-#define MAX_CRTC 3 #define MAX_PLANE 5 #define MAX_FB_BUFFER 4
exynos_drm_plane_config must be present for every plane, and most fields are redundant with exynos_drm_plane: - pixel_formats, num_pixel_formats are stored in plane.base.format_*, - type is stored in plane.base.type, - zpos is always equal to plane.index. The only non-redundant field capabilities can be moved to exynos_drm_plane. As consequence of removing the structure some code should be refactored. The patch should not have functional changes.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com --- drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 18 +++--- drivers/gpu/drm/exynos/exynos7_drm_decon.c | 11 +--- drivers/gpu/drm/exynos/exynos_drm_drv.h | 39 ++++--------- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 17 ++---- drivers/gpu/drm/exynos/exynos_drm_plane.c | 56 +++++++++--------- drivers/gpu/drm/exynos/exynos_drm_vidi.c | 11 +--- drivers/gpu/drm/exynos/exynos_mixer.c | 58 +++++++------------ 7 files changed, 76 insertions(+), 134 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index 24df0b307b2f..ae0f475eb633 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -56,7 +56,6 @@ struct decon_context { struct drm_device *drm_dev; struct exynos_drm_crtc *crtc; struct exynos_drm_plane planes[WINDOWS_NR]; - struct exynos_drm_plane_config configs[WINDOWS_NR]; void __iomem *addr; struct regmap *sysreg; struct clk *clks[ARRAY_SIZE(decon_clks_name)]; @@ -608,22 +607,19 @@ static int decon_bind(struct device *dev, struct device *master, void *data) struct drm_device *drm_dev = data; struct exynos_drm_plane *exynos_plane; enum exynos_drm_output_type out_type; - unsigned int win; + unsigned int i; int ret;
ctx->drm_dev = drm_dev;
- for (win = ctx->first_win; win < WINDOWS_NR; win++) { - ctx->configs[win].pixel_formats = decon_formats; - ctx->configs[win].num_pixel_formats = ARRAY_SIZE(decon_formats); - ctx->configs[win].zpos = win - ctx->first_win; - ctx->configs[win].type = decon_win_types[win]; - ctx->configs[win].capabilities = EXYNOS_DRM_PLANE_CAP_ZPOS + for (i = ctx->first_win; i < WINDOWS_NR; i++) { + ctx->planes[i].index = i - ctx->first_win; + ctx->planes[i].capabilities = EXYNOS_DRM_PLANE_CAP_ZPOS | EXYNOS_DRM_PLANE_CAP_WIN_BLEND | EXYNOS_DRM_PLANE_CAP_PIX_BLEND; - - ret = exynos_plane_init(drm_dev, &ctx->planes[win], win, - &ctx->configs[win]); + ret = exynos_plane_init(drm_dev, &ctx->planes[i], + decon_formats, ARRAY_SIZE(decon_formats), + decon_win_types[i]); if (ret) return ret; } diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index 812941b84287..6d462f057531 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c @@ -44,7 +44,6 @@ struct decon_context { struct drm_device *drm_dev; struct exynos_drm_crtc *crtc; struct exynos_drm_plane planes[WINDOWS_NR]; - struct exynos_drm_plane_config configs[WINDOWS_NR]; struct clk *pclk; struct clk *aclk; struct clk *eclk; @@ -626,13 +625,9 @@ static int decon_bind(struct device *dev, struct device *master, void *data) }
for (i = 0; i < WINDOWS_NR; i++) { - ctx->configs[i].pixel_formats = decon_formats; - ctx->configs[i].num_pixel_formats = ARRAY_SIZE(decon_formats); - ctx->configs[i].zpos = i; - ctx->configs[i].type = decon_win_types[i]; - - ret = exynos_plane_init(drm_dev, &ctx->planes[i], i, - &ctx->configs[i]); + ctx->planes[i].index = i; + ret = exynos_plane_init(drm_dev, &ctx->planes[i], decon_formats, + ARRAY_SIZE(decon_formats), decon_win_types[i]); if (ret) return ret; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 1f6bb5516170..1d4ef0245958 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -71,11 +71,19 @@ to_exynos_plane_state(struct drm_plane_state *state) return container_of(state, struct exynos_drm_plane_state, base); }
+#define EXYNOS_DRM_PLANE_CAP_DOUBLE (1 << 0) +#define EXYNOS_DRM_PLANE_CAP_SCALE (1 << 1) +#define EXYNOS_DRM_PLANE_CAP_ZPOS (1 << 2) +#define EXYNOS_DRM_PLANE_CAP_TILE (1 << 3) +#define EXYNOS_DRM_PLANE_CAP_PIX_BLEND (1 << 4) +#define EXYNOS_DRM_PLANE_CAP_WIN_BLEND (1 << 5) + /* * Exynos drm common overlay structure. * * @base: plane object * @index: hardware index of the overlay layer + * @capabilities: supported features (see EXYNOS_DRM_PLANE_CAP_*) * * this structure is common to exynos SoC and its contents would be copied * to hardware specific overlay info. @@ -83,38 +91,13 @@ to_exynos_plane_state(struct drm_plane_state *state)
struct exynos_drm_plane { struct drm_plane base; - const struct exynos_drm_plane_config *config; unsigned int index; -}; - -#define EXYNOS_DRM_PLANE_CAP_DOUBLE (1 << 0) -#define EXYNOS_DRM_PLANE_CAP_SCALE (1 << 1) -#define EXYNOS_DRM_PLANE_CAP_ZPOS (1 << 2) -#define EXYNOS_DRM_PLANE_CAP_TILE (1 << 3) -#define EXYNOS_DRM_PLANE_CAP_PIX_BLEND (1 << 4) -#define EXYNOS_DRM_PLANE_CAP_WIN_BLEND (1 << 5) - -/* - * Exynos DRM plane configuration structure. - * - * @zpos: initial z-position of the plane. - * @type: type of the plane (primary, cursor or overlay). - * @pixel_formats: supported pixel formats. - * @num_pixel_formats: number of elements in 'pixel_formats'. - * @capabilities: supported features (see EXYNOS_DRM_PLANE_CAP_*) - */ - -struct exynos_drm_plane_config { - unsigned int zpos; - enum drm_plane_type type; - const uint32_t *pixel_formats; - unsigned int num_pixel_formats; unsigned int capabilities; };
-int exynos_plane_init(struct drm_device *dev, - struct exynos_drm_plane *exynos_plane, unsigned int index, - const struct exynos_drm_plane_config *config); +int exynos_plane_init(struct drm_device *dev, struct exynos_drm_plane *plane, + const uint32_t *pixel_formats, int num_pixel_formats, + enum drm_plane_type type);
/* * Exynos drm crtc ops diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index b1a9502a4140..2d34ca375ee1 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -171,7 +171,6 @@ struct fimd_context { struct drm_device *drm_dev; struct exynos_drm_crtc *crtc; struct exynos_drm_plane planes[WINDOWS_NR]; - struct exynos_drm_plane_config configs[WINDOWS_NR]; struct clk *bus_clk; struct clk *lcd_clk; void __iomem *regs; @@ -1044,16 +1043,12 @@ static int fimd_bind(struct device *dev, struct device *master, void *data) ctx->drm_dev = drm_dev;
for (i = 0; i < WINDOWS_NR; i++) { - ctx->configs[i].pixel_formats = fimd_formats; - ctx->configs[i].num_pixel_formats = ARRAY_SIZE(fimd_formats); - ctx->configs[i].zpos = i; - ctx->configs[i].type = fimd_win_types[i]; - ctx->configs[i].capabilities = EXYNOS_DRM_PLANE_CAP_ZPOS - | EXYNOS_DRM_PLANE_CAP_WIN_BLEND - | EXYNOS_DRM_PLANE_CAP_PIX_BLEND; - - ret = exynos_plane_init(drm_dev, &ctx->planes[i], i, - &ctx->configs[i]); + ctx->planes[i].index = i; + ctx->planes[i].capabilities = EXYNOS_DRM_PLANE_CAP_ZPOS + | EXYNOS_DRM_PLANE_CAP_WIN_BLEND + | EXYNOS_DRM_PLANE_CAP_PIX_BLEND; + ret = exynos_plane_init(drm_dev, &ctx->planes[i], fimd_formats, + ARRAY_SIZE(fimd_formats), fimd_win_types[i]); if (ret) return ret; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index 8af0eba3f362..e1aa504539fa 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -138,7 +138,7 @@ static void exynos_drm_plane_reset(struct drm_plane *plane) exynos_state = kzalloc(sizeof(*exynos_state), GFP_KERNEL); if (exynos_state) { __drm_atomic_helper_plane_reset(plane, &exynos_state->base); - plane->state->zpos = exynos_plane->config->zpos; + plane->state->zpos = exynos_plane->index; } }
@@ -176,14 +176,14 @@ static struct drm_plane_funcs exynos_plane_funcs = { };
static int -exynos_drm_plane_check_format(const struct exynos_drm_plane_config *config, - struct exynos_drm_plane_state *state) +exynos_drm_plane_check_format(struct exynos_drm_plane_state *state) { + struct exynos_drm_plane *plane = to_exynos_plane(state->base.plane); struct drm_framebuffer *fb = state->base.fb;
switch (fb->modifier) { case DRM_FORMAT_MOD_SAMSUNG_64_32_TILE: - if (!(config->capabilities & EXYNOS_DRM_PLANE_CAP_TILE)) + if (!(plane->capabilities & EXYNOS_DRM_PLANE_CAP_TILE)) return -ENOTSUPP; break;
@@ -199,12 +199,12 @@ exynos_drm_plane_check_format(const struct exynos_drm_plane_config *config, }
static int -exynos_drm_plane_check_size(const struct exynos_drm_plane_config *config, - struct exynos_drm_plane_state *state) +exynos_drm_plane_check_size(struct exynos_drm_plane_state *state) { + struct exynos_drm_plane *plane = to_exynos_plane(state->base.plane); bool width_ok = false, height_ok = false;
- if (config->capabilities & EXYNOS_DRM_PLANE_CAP_SCALE) + if (plane->capabilities & EXYNOS_DRM_PLANE_CAP_SCALE) return 0;
if (state->src.w == state->crtc.w) @@ -213,11 +213,11 @@ exynos_drm_plane_check_size(const struct exynos_drm_plane_config *config, if (state->src.h == state->crtc.h) height_ok = true;
- if ((config->capabilities & EXYNOS_DRM_PLANE_CAP_DOUBLE) && + if ((plane->capabilities & EXYNOS_DRM_PLANE_CAP_DOUBLE) && state->h_ratio == (1 << 15)) width_ok = true;
- if ((config->capabilities & EXYNOS_DRM_PLANE_CAP_DOUBLE) && + if ((plane->capabilities & EXYNOS_DRM_PLANE_CAP_DOUBLE) && state->v_ratio == (1 << 15)) height_ok = true;
@@ -231,7 +231,6 @@ exynos_drm_plane_check_size(const struct exynos_drm_plane_config *config, static int exynos_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *state) { - struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane); struct exynos_drm_plane_state *exynos_state = to_exynos_plane_state(state); int ret = 0; @@ -242,11 +241,11 @@ static int exynos_plane_atomic_check(struct drm_plane *plane, /* translate state into exynos_state */ exynos_plane_mode_set(exynos_state);
- ret = exynos_drm_plane_check_format(exynos_plane->config, exynos_state); + ret = exynos_drm_plane_check_format(exynos_state); if (ret) return ret;
- ret = exynos_drm_plane_check_size(exynos_plane->config, exynos_state); + ret = exynos_drm_plane_check_size(exynos_state); return ret; }
@@ -292,40 +291,37 @@ static void exynos_plane_attach_zpos_property(struct drm_plane *plane, drm_plane_create_zpos_property(plane, zpos, 0, MAX_PLANE - 1); }
-int exynos_plane_init(struct drm_device *dev, - struct exynos_drm_plane *exynos_plane, unsigned int index, - const struct exynos_drm_plane_config *config) +int exynos_plane_init(struct drm_device *dev, struct exynos_drm_plane *plane, + const uint32_t *pixel_formats, int num_pixel_formats, + enum drm_plane_type type) { int err; unsigned int supported_modes = BIT(DRM_MODE_BLEND_PIXEL_NONE) | BIT(DRM_MODE_BLEND_PREMULTI) | BIT(DRM_MODE_BLEND_COVERAGE); - struct drm_plane *plane = &exynos_plane->base; + struct drm_plane *bplane = &plane->base;
- err = drm_universal_plane_init(dev, &exynos_plane->base, + err = drm_universal_plane_init(dev, bplane, 1 << dev->mode_config.num_crtc, &exynos_plane_funcs, - config->pixel_formats, - config->num_pixel_formats, - NULL, config->type, NULL); + pixel_formats, + num_pixel_formats, + NULL, type, NULL); if (err) { DRM_ERROR("failed to initialize plane\n"); return err; }
- drm_plane_helper_add(&exynos_plane->base, &plane_helper_funcs); - - exynos_plane->index = index; - exynos_plane->config = config; + drm_plane_helper_add(bplane, &plane_helper_funcs);
- exynos_plane_attach_zpos_property(&exynos_plane->base, config->zpos, - !(config->capabilities & EXYNOS_DRM_PLANE_CAP_ZPOS)); + exynos_plane_attach_zpos_property(bplane, plane->index, + !(plane->capabilities & EXYNOS_DRM_PLANE_CAP_ZPOS));
- if (config->capabilities & EXYNOS_DRM_PLANE_CAP_PIX_BLEND) - drm_plane_create_blend_mode_property(plane, supported_modes); + if (plane->capabilities & EXYNOS_DRM_PLANE_CAP_PIX_BLEND) + drm_plane_create_blend_mode_property(bplane, supported_modes);
- if (config->capabilities & EXYNOS_DRM_PLANE_CAP_WIN_BLEND) - drm_plane_create_alpha_property(plane); + if (plane->capabilities & EXYNOS_DRM_PLANE_CAP_WIN_BLEND) + drm_plane_create_alpha_property(bplane);
return 0; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index ec30d5aca9aa..b61ae3415b8c 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -378,21 +378,14 @@ static int vidi_bind(struct device *dev, struct device *master, void *data) struct drm_device *drm_dev = data; struct drm_encoder *encoder = &ctx->encoder; struct exynos_drm_plane *exynos_plane; - struct exynos_drm_plane_config plane_config = { 0 }; unsigned int i; int ret;
ctx->drm_dev = drm_dev;
- plane_config.pixel_formats = formats; - plane_config.num_pixel_formats = ARRAY_SIZE(formats); - for (i = 0; i < WINDOWS_NR; i++) { - plane_config.zpos = i; - plane_config.type = vidi_win_types[i]; - - ret = exynos_plane_init(drm_dev, &ctx->planes[i], i, - &plane_config); + ret = exynos_plane_init(drm_dev, &ctx->planes[i], formats, + ARRAY_SIZE(formats), vidi_win_types[i]); if (ret) return ret; } diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index ef50943cc9eb..1c82265acf0a 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -123,37 +123,6 @@ struct mixer_drv_data { bool has_sclk; };
-static const struct exynos_drm_plane_config plane_configs[MIXER_WIN_NR] = { - { - .zpos = 0, - .type = DRM_PLANE_TYPE_PRIMARY, - .pixel_formats = mixer_formats, - .num_pixel_formats = ARRAY_SIZE(mixer_formats), - .capabilities = EXYNOS_DRM_PLANE_CAP_DOUBLE | - EXYNOS_DRM_PLANE_CAP_ZPOS | - EXYNOS_DRM_PLANE_CAP_PIX_BLEND | - EXYNOS_DRM_PLANE_CAP_WIN_BLEND, - }, { - .zpos = 1, - .type = DRM_PLANE_TYPE_CURSOR, - .pixel_formats = mixer_formats, - .num_pixel_formats = ARRAY_SIZE(mixer_formats), - .capabilities = EXYNOS_DRM_PLANE_CAP_DOUBLE | - EXYNOS_DRM_PLANE_CAP_ZPOS | - EXYNOS_DRM_PLANE_CAP_PIX_BLEND | - EXYNOS_DRM_PLANE_CAP_WIN_BLEND, - }, { - .zpos = 2, - .type = DRM_PLANE_TYPE_OVERLAY, - .pixel_formats = vp_formats, - .num_pixel_formats = ARRAY_SIZE(vp_formats), - .capabilities = EXYNOS_DRM_PLANE_CAP_SCALE | - EXYNOS_DRM_PLANE_CAP_ZPOS | - EXYNOS_DRM_PLANE_CAP_TILE | - EXYNOS_DRM_PLANE_CAP_WIN_BLEND, - }, -}; - static const u8 filter_y_horiz_tap8[] = { 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, @@ -1173,18 +1142,33 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data) struct exynos_drm_plane *exynos_plane; unsigned int i; int ret; + static enum drm_plane_type types[] = { DRM_PLANE_TYPE_PRIMARY, + DRM_PLANE_TYPE_CURSOR, DRM_PLANE_TYPE_OVERLAY };
ret = mixer_initialize(ctx, drm_dev); if (ret) return ret;
- for (i = 0; i < MIXER_WIN_NR; i++) { - if (i == VP_DEFAULT_WIN && !test_bit(MXR_BIT_VP_ENABLED, - &ctx->flags)) - continue; + for (i = 0; i < VP_DEFAULT_WIN; i++) { + ctx->planes[i].index = i; + ctx->planes[i].capabilities = EXYNOS_DRM_PLANE_CAP_DOUBLE | + EXYNOS_DRM_PLANE_CAP_ZPOS | + EXYNOS_DRM_PLANE_CAP_PIX_BLEND | + EXYNOS_DRM_PLANE_CAP_WIN_BLEND; + ret = exynos_plane_init(drm_dev, &ctx->planes[i], mixer_formats, + ARRAY_SIZE(mixer_formats), types[i]); + if (ret) + return ret; + }
- ret = exynos_plane_init(drm_dev, &ctx->planes[i], i, - &plane_configs[i]); + if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) { + ctx->planes[i].index = i; + ctx->planes[i].capabilities = EXYNOS_DRM_PLANE_CAP_SCALE | + EXYNOS_DRM_PLANE_CAP_ZPOS | + EXYNOS_DRM_PLANE_CAP_TILE | + EXYNOS_DRM_PLANE_CAP_WIN_BLEND; + ret = exynos_plane_init(drm_dev, &ctx->planes[i], vp_formats, + ARRAY_SIZE(vp_formats), types[i]); if (ret) return ret; }
Since exynos_drm_crtc is a struct which maps 1:1 to underlying device it is better to put it directly into device's context instead of allocating it separately. Another benefit is possibility of initialisation of its fields directly, without expanding exynos_drm_crtc_create which is already overloaded with number of arguments. As a first step of the transition initialisation function should be created.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com --- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 10 ++++++++++ drivers/gpu/drm/exynos/exynos_drm_crtc.h | 2 ++ 2 files changed, 12 insertions(+)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 1eebfa3fa8da..4ff1e0ff2255 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -172,6 +172,16 @@ static const struct drm_crtc_funcs exynos_crtc_funcs = { .disable_vblank = exynos_drm_crtc_disable_vblank, };
+int exynos_drm_crtc_init(struct exynos_drm_crtc *exynos_crtc, + struct drm_device *drm_dev) +{ + struct drm_crtc *crtc = &exynos_crtc->base; + + drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs); + return drm_crtc_init_with_planes(drm_dev, crtc, NULL, NULL, + &exynos_crtc_funcs, NULL); +} + struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, struct drm_plane *plane, enum exynos_drm_output_type type, diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.h b/drivers/gpu/drm/exynos/exynos_drm_crtc.h index dec446109e6c..9e35a9e02332 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.h +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.h @@ -18,6 +18,8 @@
#include "exynos_drm_drv.h"
+int exynos_drm_crtc_init(struct exynos_drm_crtc *exynos_crtc, + struct drm_device *drm_dev); struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, struct drm_plane *plane, enum exynos_drm_output_type out_type,
Since crtc maps 1:1 to the device there is no point in allocating it separately, another benefit is possibility of direct initialisation of its fields which is more readable and allows further expansion.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com --- drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 52 +++++++++---------- 1 file changed, 26 insertions(+), 26 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index ae0f475eb633..0d409f453923 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -54,7 +54,7 @@ static const char * const decon_clks_name[] = { struct decon_context { struct device *dev; struct drm_device *drm_dev; - struct exynos_drm_crtc *crtc; + struct exynos_drm_crtc crtc; struct exynos_drm_plane planes[WINDOWS_NR]; void __iomem *addr; struct regmap *sysreg; @@ -69,6 +69,8 @@ struct decon_context { u32 frame_id; };
+#define to_decon(ptr) container_of(ptr, struct decon_context, ptr) + static const uint32_t decon_formats[] = { DRM_FORMAT_XRGB1555, DRM_FORMAT_RGB565, @@ -90,7 +92,7 @@ static inline void decon_set_bits(struct decon_context *ctx, u32 reg, u32 mask,
static int decon_enable_vblank(struct exynos_drm_crtc *crtc) { - struct decon_context *ctx = crtc->ctx; + struct decon_context *ctx = to_decon(crtc); u32 val;
val = VIDINTCON0_INTEN; @@ -110,7 +112,7 @@ static int decon_enable_vblank(struct exynos_drm_crtc *crtc)
static void decon_disable_vblank(struct exynos_drm_crtc *crtc) { - struct decon_context *ctx = crtc->ctx; + struct decon_context *ctx = to_decon(crtc);
if (!(ctx->out_type & I80_HW_TRG)) disable_irq_nosync(ctx->te_irq); @@ -143,7 +145,7 @@ static u32 decon_get_frame_count(struct decon_context *ctx, bool end)
switch (status & (VIDCON1_VSTATUS_MASK | VIDCON1_I80_ACTIVE)) { case VIDCON1_VSTATUS_VS: - if (!(ctx->crtc->i80_mode)) + if (!(ctx->crtc.i80_mode)) --frm; break; case VIDCON1_VSTATUS_BP: @@ -163,7 +165,7 @@ static u32 decon_get_frame_count(struct decon_context *ctx, bool end)
static void decon_setup_trigger(struct decon_context *ctx) { - if (!ctx->crtc->i80_mode && !(ctx->out_type & I80_HW_TRG)) + if (!ctx->crtc.i80_mode && !(ctx->out_type & I80_HW_TRG)) return;
if (!(ctx->out_type & I80_HW_TRG)) { @@ -183,7 +185,7 @@ static void decon_setup_trigger(struct decon_context *ctx)
static void decon_commit(struct exynos_drm_crtc *crtc) { - struct decon_context *ctx = crtc->ctx; + struct decon_context *ctx = to_decon(crtc); struct drm_display_mode *m = &crtc->base.mode; bool interlaced = false; u32 val; @@ -377,7 +379,7 @@ static void decon_shadow_protect(struct decon_context *ctx, bool protect)
static void decon_atomic_begin(struct exynos_drm_crtc *crtc) { - struct decon_context *ctx = crtc->ctx; + struct decon_context *ctx = to_decon(crtc);
decon_shadow_protect(ctx, true); } @@ -391,7 +393,7 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, { struct exynos_drm_plane_state *state = to_exynos_plane_state(plane->base.state); - struct decon_context *ctx = crtc->ctx; + struct decon_context *ctx = to_decon(crtc); struct drm_framebuffer *fb = state->base.fb; unsigned int win = state->base.normalized_zpos + ctx->first_win; unsigned int cpp = fb->format->cpp[0]; @@ -445,7 +447,7 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc,
static void decon_atomic_flush(struct exynos_drm_crtc *crtc) { - struct decon_context *ctx = crtc->ctx; + struct decon_context *ctx = to_decon(crtc); unsigned long flags; int win = hweight32(crtc->base.state->plane_mask) + ctx->first_win;
@@ -502,7 +504,7 @@ static void decon_swreset(struct decon_context *ctx)
static void decon_enable(struct exynos_drm_crtc *crtc) { - struct decon_context *ctx = crtc->ctx; + struct decon_context *ctx = to_decon(crtc);
pm_runtime_get_sync(ctx->dev);
@@ -510,12 +512,12 @@ static void decon_enable(struct exynos_drm_crtc *crtc)
decon_swreset(ctx);
- decon_commit(ctx->crtc); + decon_commit(&ctx->crtc); }
static void decon_disable(struct exynos_drm_crtc *crtc) { - struct decon_context *ctx = crtc->ctx; + struct decon_context *ctx = to_decon(crtc); int i;
if (!(ctx->out_type & I80_HW_TRG)) @@ -548,7 +550,7 @@ static irqreturn_t decon_te_irq_handler(int irq, void *dev_id)
static void decon_clear_channels(struct exynos_drm_crtc *crtc) { - struct decon_context *ctx = crtc->ctx; + struct decon_context *ctx = to_decon(crtc); int win, i, ret;
DRM_DEBUG_KMS("%s\n", __FILE__); @@ -577,7 +579,7 @@ static void decon_clear_channels(struct exynos_drm_crtc *crtc) static enum drm_mode_status decon_mode_valid(struct exynos_drm_crtc *crtc, const struct drm_display_mode *mode) { - struct decon_context *ctx = crtc->ctx; + struct decon_context *ctx = to_decon(crtc);
ctx->irq = crtc->i80_mode ? ctx->irq_lcd_sys : ctx->irq_vsync;
@@ -605,8 +607,6 @@ static int decon_bind(struct device *dev, struct device *master, void *data) { struct decon_context *ctx = dev_get_drvdata(dev); struct drm_device *drm_dev = data; - struct exynos_drm_plane *exynos_plane; - enum exynos_drm_output_type out_type; unsigned int i; int ret;
@@ -624,15 +624,15 @@ static int decon_bind(struct device *dev, struct device *master, void *data) return ret; }
- exynos_plane = &ctx->planes[PRIMARY_WIN]; - out_type = (ctx->out_type & IFTYPE_HDMI) ? EXYNOS_DISPLAY_TYPE_HDMI - : EXYNOS_DISPLAY_TYPE_LCD; - ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, - out_type, &decon_crtc_ops, ctx); - if (IS_ERR(ctx->crtc)) - return PTR_ERR(ctx->crtc); + ctx->crtc.type = (ctx->out_type & IFTYPE_HDMI) + ? EXYNOS_DISPLAY_TYPE_HDMI : EXYNOS_DISPLAY_TYPE_LCD; + ctx->crtc.ops = &decon_crtc_ops; + ret = exynos_drm_crtc_init(&ctx->crtc, drm_dev); + if (ret) + return ret; + ctx->crtc.base.primary = &ctx->planes[PRIMARY_WIN].base;
- decon_clear_channels(ctx->crtc); + decon_clear_channels(&ctx->crtc);
return exynos_drm_register_dma(drm_dev, dev); } @@ -641,7 +641,7 @@ static void decon_unbind(struct device *dev, struct device *master, void *data) { struct decon_context *ctx = dev_get_drvdata(dev);
- decon_disable(ctx->crtc); + decon_disable(&ctx->crtc);
/* detach this sub driver from iommu mapping if supported. */ exynos_drm_unregister_dma(ctx->drm_dev, ctx->dev); @@ -663,7 +663,7 @@ static void decon_handle_vblank(struct decon_context *ctx) if (frm != ctx->frame_id) { /* handle only if incremented, take care of wrap-around */ if ((s32)(frm - ctx->frame_id) > 0) - drm_crtc_handle_vblank(&ctx->crtc->base); + drm_crtc_handle_vblank(&ctx->crtc.base); ctx->frame_id = frm; }
Since crtc maps 1:1 to the device there is no point in allocating it separately, another benefit is possibility of direct initialisation of its fields which is more readable and allows further expansion.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com --- drivers/gpu/drm/exynos/exynos7_drm_decon.c | 50 +++++++++++----------- 1 file changed, 26 insertions(+), 24 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index 6d462f057531..22659f2da755 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c @@ -42,7 +42,7 @@ struct decon_context { struct device *dev; struct drm_device *drm_dev; - struct exynos_drm_crtc *crtc; + struct exynos_drm_crtc crtc; struct exynos_drm_plane planes[WINDOWS_NR]; struct clk *pclk; struct clk *aclk; @@ -58,6 +58,8 @@ struct decon_context { struct drm_encoder *encoder; };
+#define to_decon(ptr) container_of(ptr, struct decon_context, ptr) + static const struct of_device_id decon_driver_dt_match[] = { {.compatible = "samsung,exynos7-decon"}, {}, @@ -83,7 +85,7 @@ static const enum drm_plane_type decon_win_types[WINDOWS_NR] = {
static void decon_wait_for_vblank(struct exynos_drm_crtc *crtc) { - struct decon_context *ctx = crtc->ctx; + struct decon_context *ctx = to_decon(crtc);
if (ctx->suspended) return; @@ -102,7 +104,7 @@ static void decon_wait_for_vblank(struct exynos_drm_crtc *crtc)
static void decon_clear_channels(struct exynos_drm_crtc *crtc) { - struct decon_context *ctx = crtc->ctx; + struct decon_context *ctx = to_decon(crtc); unsigned int win, ch_enabled = 0;
DRM_DEBUG_KMS("%s\n", __FILE__); @@ -120,7 +122,7 @@ static void decon_clear_channels(struct exynos_drm_crtc *crtc)
/* Wait for vsync, as disable channel takes effect at next vsync */ if (ch_enabled) - decon_wait_for_vblank(ctx->crtc); + decon_wait_for_vblank(&ctx->crtc); }
static int decon_ctx_initialize(struct decon_context *ctx, @@ -128,7 +130,7 @@ static int decon_ctx_initialize(struct decon_context *ctx, { ctx->drm_dev = drm_dev;
- decon_clear_channels(ctx->crtc); + decon_clear_channels(&ctx->crtc);
return exynos_drm_register_dma(drm_dev, ctx->dev); } @@ -153,7 +155,7 @@ static u32 decon_calc_clkdiv(struct decon_context *ctx,
static void decon_commit(struct exynos_drm_crtc *crtc) { - struct decon_context *ctx = crtc->ctx; + struct decon_context *ctx = to_decon(crtc); struct drm_display_mode *mode = &crtc->base.state->adjusted_mode; u32 val, clkdiv;
@@ -218,7 +220,7 @@ static void decon_commit(struct exynos_drm_crtc *crtc)
static int decon_enable_vblank(struct exynos_drm_crtc *crtc) { - struct decon_context *ctx = crtc->ctx; + struct decon_context *ctx = to_decon(crtc); u32 val;
if (ctx->suspended) @@ -243,7 +245,7 @@ static int decon_enable_vblank(struct exynos_drm_crtc *crtc)
static void decon_disable_vblank(struct exynos_drm_crtc *crtc) { - struct decon_context *ctx = crtc->ctx; + struct decon_context *ctx = to_decon(crtc); u32 val;
if (ctx->suspended) @@ -368,7 +370,7 @@ static void decon_shadow_protect_win(struct decon_context *ctx,
static void decon_atomic_begin(struct exynos_drm_crtc *crtc) { - struct decon_context *ctx = crtc->ctx; + struct decon_context *ctx = to_decon(crtc); int i;
if (ctx->suspended) @@ -383,7 +385,7 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, { struct exynos_drm_plane_state *state = to_exynos_plane_state(plane->base.state); - struct decon_context *ctx = crtc->ctx; + struct decon_context *ctx = to_decon(crtc); struct drm_framebuffer *fb = state->base.fb; int padding; unsigned long val, alpha; @@ -479,7 +481,7 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, static void decon_disable_plane(struct exynos_drm_crtc *crtc, struct exynos_drm_plane *plane) { - struct decon_context *ctx = crtc->ctx; + struct decon_context *ctx = to_decon(crtc); unsigned int win = plane->index; u32 val;
@@ -501,7 +503,7 @@ static void decon_disable_plane(struct exynos_drm_crtc *crtc,
static void decon_atomic_flush(struct exynos_drm_crtc *crtc) { - struct decon_context *ctx = crtc->ctx; + struct decon_context *ctx = to_decon(crtc); int i;
if (ctx->suspended) @@ -531,7 +533,7 @@ static void decon_init(struct decon_context *ctx)
static void decon_enable(struct exynos_drm_crtc *crtc) { - struct decon_context *ctx = crtc->ctx; + struct decon_context *ctx = to_decon(crtc);
if (!ctx->suspended) return; @@ -542,16 +544,16 @@ static void decon_enable(struct exynos_drm_crtc *crtc)
/* if vblank was enabled status, enable it again. */ if (test_and_clear_bit(0, &ctx->irq_flags)) - decon_enable_vblank(ctx->crtc); + decon_enable_vblank(&ctx->crtc);
- decon_commit(ctx->crtc); + decon_commit(&ctx->crtc);
ctx->suspended = false; }
static void decon_disable(struct exynos_drm_crtc *crtc) { - struct decon_context *ctx = crtc->ctx; + struct decon_context *ctx = to_decon(crtc); int i;
if (ctx->suspended) @@ -598,7 +600,7 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id) goto out;
if (!ctx->i80_if) { - drm_crtc_handle_vblank(&ctx->crtc->base); + drm_crtc_handle_vblank(&ctx->crtc.base);
/* set wait vsync event to zero and wake up queue. */ if (atomic_read(&ctx->wait_vsync_event)) { @@ -614,7 +616,6 @@ static int decon_bind(struct device *dev, struct device *master, void *data) { struct decon_context *ctx = dev_get_drvdata(dev); struct drm_device *drm_dev = data; - struct exynos_drm_plane *exynos_plane; unsigned int i; int ret;
@@ -632,13 +633,14 @@ static int decon_bind(struct device *dev, struct device *master, void *data) return ret; }
- exynos_plane = &ctx->planes[DEFAULT_WIN]; - ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, - EXYNOS_DISPLAY_TYPE_LCD, &decon_crtc_ops, ctx); - if (IS_ERR(ctx->crtc)) { + ctx->crtc.type = EXYNOS_DISPLAY_TYPE_LCD; + ctx->crtc.ops = &decon_crtc_ops; + ret = exynos_drm_crtc_init(&ctx->crtc, drm_dev); + if (ret) { decon_ctx_remove(ctx); - return PTR_ERR(ctx->crtc); + return ret; } + ctx->crtc.base.primary = &ctx->planes[DEFAULT_WIN].base;
if (ctx->encoder) exynos_dpi_bind(drm_dev, ctx->encoder); @@ -652,7 +654,7 @@ static void decon_unbind(struct device *dev, struct device *master, { struct decon_context *ctx = dev_get_drvdata(dev);
- decon_disable(ctx->crtc); + decon_disable(&ctx->crtc);
if (ctx->encoder) exynos_dpi_remove(ctx->encoder);
Since crtc maps 1:1 to the device there is no point in allocating it separately, another benefit is possibility of direct initialisation of its fields which is more readable and allows further expansion.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com --- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 60 ++++++++++++------------ 1 file changed, 31 insertions(+), 29 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 2d34ca375ee1..8ea1cfd51736 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -169,7 +169,7 @@ static struct fimd_driver_data exynos5420_fimd_driver_data = { struct fimd_context { struct device *dev; struct drm_device *drm_dev; - struct exynos_drm_crtc *crtc; + struct exynos_drm_crtc crtc; struct exynos_drm_plane planes[WINDOWS_NR]; struct clk *bus_clk; struct clk *lcd_clk; @@ -193,6 +193,8 @@ struct fimd_context { struct exynos_drm_clk dp_clk; };
+#define to_fimd(ptr) container_of(ptr, struct fimd_context, ptr) + static const struct of_device_id fimd_driver_dt_match[] = { { .compatible = "samsung,s3c6400-fimd", .data = &s3c64xx_fimd_driver_data }, @@ -235,7 +237,7 @@ static inline void fimd_set_bits(struct fimd_context *ctx, u32 reg, u32 mask,
static int fimd_enable_vblank(struct exynos_drm_crtc *crtc) { - struct fimd_context *ctx = crtc->ctx; + struct fimd_context *ctx = to_fimd(crtc); u32 val;
if (ctx->suspended) @@ -267,7 +269,7 @@ static int fimd_enable_vblank(struct exynos_drm_crtc *crtc)
static void fimd_disable_vblank(struct exynos_drm_crtc *crtc) { - struct fimd_context *ctx = crtc->ctx; + struct fimd_context *ctx = to_fimd(crtc); u32 val;
if (ctx->suspended) @@ -291,7 +293,7 @@ static void fimd_disable_vblank(struct exynos_drm_crtc *crtc)
static void fimd_wait_for_vblank(struct exynos_drm_crtc *crtc) { - struct fimd_context *ctx = crtc->ctx; + struct fimd_context *ctx = to_fimd(crtc);
if (ctx->suspended) return; @@ -345,7 +347,7 @@ static void fimd_disable_win(struct fimd_context *ctx, int win)
static void fimd_clear_channels(struct exynos_drm_crtc *crtc) { - struct fimd_context *ctx = crtc->ctx; + struct fimd_context *ctx = to_fimd(crtc); unsigned int win, ch_enabled = 0;
DRM_DEBUG_KMS("%s\n", __FILE__); @@ -370,9 +372,9 @@ static void fimd_clear_channels(struct exynos_drm_crtc *crtc) if (ch_enabled) { ctx->suspended = false;
- fimd_enable_vblank(ctx->crtc); - fimd_wait_for_vblank(ctx->crtc); - fimd_disable_vblank(ctx->crtc); + fimd_enable_vblank(&ctx->crtc); + fimd_wait_for_vblank(&ctx->crtc); + fimd_disable_vblank(&ctx->crtc);
ctx->suspended = true; } @@ -388,7 +390,7 @@ static int fimd_atomic_check(struct exynos_drm_crtc *crtc, struct drm_crtc_state *state) { struct drm_display_mode *mode = &state->adjusted_mode; - struct fimd_context *ctx = crtc->ctx; + struct fimd_context *ctx = to_fimd(crtc); unsigned long ideal_clk, lcd_rate; u32 clkdiv;
@@ -448,7 +450,7 @@ static void fimd_setup_trigger(struct fimd_context *ctx)
static void fimd_commit(struct exynos_drm_crtc *crtc) { - struct fimd_context *ctx = crtc->ctx; + struct fimd_context *ctx = to_fimd(crtc); struct drm_display_mode *mode = &crtc->base.state->adjusted_mode; const struct fimd_driver_data *driver_data = ctx->driver_data; void *timing_base = ctx->regs + driver_data->timing_base; @@ -754,7 +756,7 @@ static void fimd_shadow_protect_win(struct fimd_context *ctx,
static void fimd_atomic_begin(struct exynos_drm_crtc *crtc) { - struct fimd_context *ctx = crtc->ctx; + struct fimd_context *ctx = to_fimd(crtc); int i;
if (ctx->suspended) @@ -766,7 +768,7 @@ static void fimd_atomic_begin(struct exynos_drm_crtc *crtc)
static void fimd_atomic_flush(struct exynos_drm_crtc *crtc) { - struct fimd_context *ctx = crtc->ctx; + struct fimd_context *ctx = to_fimd(crtc); int i;
if (ctx->suspended) @@ -789,7 +791,7 @@ static void fimd_update_plane(struct exynos_drm_crtc *crtc, { struct exynos_drm_plane_state *state = to_exynos_plane_state(plane->base.state); - struct fimd_context *ctx = crtc->ctx; + struct fimd_context *ctx = to_fimd(crtc); struct drm_framebuffer *fb = state->base.fb; dma_addr_t dma_addr; unsigned long val, size, offset; @@ -878,7 +880,7 @@ static void fimd_update_plane(struct exynos_drm_crtc *crtc,
static void fimd_enable(struct exynos_drm_crtc *crtc) { - struct fimd_context *ctx = crtc->ctx; + struct fimd_context *ctx = to_fimd(crtc);
if (!ctx->suspended) return; @@ -889,14 +891,14 @@ static void fimd_enable(struct exynos_drm_crtc *crtc)
/* if vblank was enabled status, enable it again. */ if (test_and_clear_bit(0, &ctx->irq_flags)) - fimd_enable_vblank(ctx->crtc); + fimd_enable_vblank(&ctx->crtc);
- fimd_commit(ctx->crtc); + fimd_commit(&ctx->crtc); }
static void fimd_disable(struct exynos_drm_crtc *crtc) { - struct fimd_context *ctx = crtc->ctx; + struct fimd_context *ctx = to_fimd(crtc); int i;
if (ctx->suspended) @@ -951,7 +953,7 @@ static void fimd_trigger(struct device *dev)
static void fimd_te_handler(struct exynos_drm_crtc *crtc) { - struct fimd_context *ctx = crtc->ctx; + struct fimd_context *ctx = to_fimd(crtc); u32 trg_type = ctx->driver_data->trg_type;
/* Checks the crtc is detached already from encoder */ @@ -976,7 +978,7 @@ static void fimd_te_handler(struct exynos_drm_crtc *crtc) }
if (test_bit(0, &ctx->irq_flags)) - drm_crtc_handle_vblank(&ctx->crtc->base); + drm_crtc_handle_vblank(&ctx->crtc.base); }
static void fimd_dp_clock_enable(struct exynos_drm_clk *clk, bool enable) @@ -1015,7 +1017,7 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id) goto out;
if (!ctx->i80_if) - drm_crtc_handle_vblank(&ctx->crtc->base); + drm_crtc_handle_vblank(&ctx->crtc.base);
if (ctx->i80_if) { /* Exits triggering mode */ @@ -1036,7 +1038,6 @@ static int fimd_bind(struct device *dev, struct device *master, void *data) { struct fimd_context *ctx = dev_get_drvdata(dev); struct drm_device *drm_dev = data; - struct exynos_drm_plane *exynos_plane; unsigned int i; int ret;
@@ -1053,22 +1054,23 @@ static int fimd_bind(struct device *dev, struct device *master, void *data) return ret; }
- exynos_plane = &ctx->planes[DEFAULT_WIN]; - ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, - EXYNOS_DISPLAY_TYPE_LCD, &fimd_crtc_ops, ctx); - if (IS_ERR(ctx->crtc)) - return PTR_ERR(ctx->crtc); + ctx->crtc.type = EXYNOS_DISPLAY_TYPE_LCD; + ctx->crtc.ops = &fimd_crtc_ops; + ret = exynos_drm_crtc_init(&ctx->crtc, drm_dev); + if (ret) + return ret; + ctx->crtc.base.primary = &ctx->planes[DEFAULT_WIN].base;
if (ctx->driver_data->has_dp_clk) { ctx->dp_clk.enable = fimd_dp_clock_enable; - ctx->crtc->pipe_clk = &ctx->dp_clk; + ctx->crtc.pipe_clk = &ctx->dp_clk; }
if (ctx->encoder) exynos_dpi_bind(drm_dev, ctx->encoder);
if (is_drm_iommu_supported(drm_dev)) - fimd_clear_channels(ctx->crtc); + fimd_clear_channels(&ctx->crtc);
return exynos_drm_register_dma(drm_dev, dev); } @@ -1078,7 +1080,7 @@ static void fimd_unbind(struct device *dev, struct device *master, { struct fimd_context *ctx = dev_get_drvdata(dev);
- fimd_disable(ctx->crtc); + fimd_disable(&ctx->crtc);
exynos_drm_unregister_dma(ctx->drm_dev, ctx->dev);
Since crtc maps 1:1 to the device there is no point in allocating it separately, another benefit is possibility of direct initialisation of its fields which is more readable and allows further expansion.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com --- drivers/gpu/drm/exynos/exynos_mixer.c | 39 ++++++++++++++------------- 1 file changed, 20 insertions(+), 19 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 1c82265acf0a..7fcefcbe68db 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -99,7 +99,7 @@ struct mixer_context { struct platform_device *pdev; struct device *dev; struct drm_device *drm_dev; - struct exynos_drm_crtc *crtc; + struct exynos_drm_crtc crtc; struct exynos_drm_plane planes[MIXER_WIN_NR]; unsigned long flags;
@@ -117,6 +117,8 @@ struct mixer_context { int scan_value; };
+#define to_mixer(ptr) container_of(ptr, struct mixer_context, ptr) + struct mixer_drv_data { enum mixer_version_id version; bool is_vp_enabled; @@ -474,7 +476,7 @@ static void mixer_stop(struct mixer_context *ctx)
static void mixer_commit(struct mixer_context *ctx) { - struct drm_display_mode *mode = &ctx->crtc->base.state->adjusted_mode; + struct drm_display_mode *mode = &ctx->crtc.base.state->adjusted_mode;
mixer_cfg_scan(ctx, mode->hdisplay, mode->vdisplay); mixer_cfg_rgb_fmt(ctx, mode); @@ -732,7 +734,7 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg) && !mixer_is_synced(ctx)) goto out;
- drm_crtc_handle_vblank(&ctx->crtc->base); + drm_crtc_handle_vblank(&ctx->crtc.base); }
out: @@ -876,7 +878,7 @@ static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
static int mixer_enable_vblank(struct exynos_drm_crtc *crtc) { - struct mixer_context *mixer_ctx = crtc->ctx; + struct mixer_context *mixer_ctx = to_mixer(crtc);
__set_bit(MXR_BIT_VSYNC, &mixer_ctx->flags); if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags)) @@ -891,7 +893,7 @@ static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
static void mixer_disable_vblank(struct exynos_drm_crtc *crtc) { - struct mixer_context *mixer_ctx = crtc->ctx; + struct mixer_context *mixer_ctx = to_mixer(crtc);
__clear_bit(MXR_BIT_VSYNC, &mixer_ctx->flags);
@@ -905,7 +907,7 @@ static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
static void mixer_atomic_begin(struct exynos_drm_crtc *crtc) { - struct mixer_context *ctx = crtc->ctx; + struct mixer_context *ctx = to_mixer(crtc);
if (!test_bit(MXR_BIT_POWERED, &ctx->flags)) return; @@ -918,7 +920,7 @@ static void mixer_atomic_begin(struct exynos_drm_crtc *crtc) static void mixer_update_plane(struct exynos_drm_crtc *crtc, struct exynos_drm_plane *plane) { - struct mixer_context *mixer_ctx = crtc->ctx; + struct mixer_context *mixer_ctx = to_mixer(crtc);
DRM_DEBUG_KMS("win: %d\n", plane->index);
@@ -934,7 +936,7 @@ static void mixer_update_plane(struct exynos_drm_crtc *crtc, static void mixer_disable_plane(struct exynos_drm_crtc *crtc, struct exynos_drm_plane *plane) { - struct mixer_context *mixer_ctx = crtc->ctx; + struct mixer_context *mixer_ctx = to_mixer(crtc); unsigned long flags;
DRM_DEBUG_KMS("win: %d\n", plane->index); @@ -949,7 +951,7 @@ static void mixer_disable_plane(struct exynos_drm_crtc *crtc,
static void mixer_atomic_flush(struct exynos_drm_crtc *crtc) { - struct mixer_context *mixer_ctx = crtc->ctx; + struct mixer_context *mixer_ctx = to_mixer(crtc);
if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags)) return; @@ -960,7 +962,7 @@ static void mixer_atomic_flush(struct exynos_drm_crtc *crtc)
static void mixer_enable(struct exynos_drm_crtc *crtc) { - struct mixer_context *ctx = crtc->ctx; + struct mixer_context *ctx = to_mixer(crtc);
if (test_bit(MXR_BIT_POWERED, &ctx->flags)) return; @@ -989,7 +991,7 @@ static void mixer_enable(struct exynos_drm_crtc *crtc)
static void mixer_disable(struct exynos_drm_crtc *crtc) { - struct mixer_context *ctx = crtc->ctx; + struct mixer_context *ctx = to_mixer(crtc); int i;
if (!test_bit(MXR_BIT_POWERED, &ctx->flags)) @@ -1011,7 +1013,7 @@ static void mixer_disable(struct exynos_drm_crtc *crtc) static int mixer_mode_valid(struct exynos_drm_crtc *crtc, const struct drm_display_mode *mode) { - struct mixer_context *ctx = crtc->ctx; + struct mixer_context *ctx = to_mixer(crtc); u32 w = mode->hdisplay, h = mode->vdisplay;
DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n", w, h, @@ -1037,7 +1039,7 @@ static bool mixer_mode_fixup(struct exynos_drm_crtc *crtc, const struct drm_display_mode *mode, struct drm_display_mode *adjusted_mode) { - struct mixer_context *ctx = crtc->ctx; + struct mixer_context *ctx = to_mixer(crtc); int width = mode->hdisplay, height = mode->vdisplay, i;
struct { @@ -1139,7 +1141,6 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data) { struct mixer_context *ctx = dev_get_drvdata(dev); struct drm_device *drm_dev = data; - struct exynos_drm_plane *exynos_plane; unsigned int i; int ret; static enum drm_plane_type types[] = { DRM_PLANE_TYPE_PRIMARY, @@ -1173,14 +1174,14 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data) return ret; }
- exynos_plane = &ctx->planes[DEFAULT_WIN]; - ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, - EXYNOS_DISPLAY_TYPE_HDMI, &mixer_crtc_ops, ctx); - if (IS_ERR(ctx->crtc)) { + ctx->crtc.type = EXYNOS_DISPLAY_TYPE_HDMI; + ctx->crtc.ops = &mixer_crtc_ops; + ret = exynos_drm_crtc_init(&ctx->crtc, drm_dev); + if (ret) { mixer_ctx_remove(ctx); - ret = PTR_ERR(ctx->crtc); goto free_ctx; } + ctx->crtc.base.primary = &ctx->planes[DEFAULT_WIN].base;
return 0;
Since crtc maps 1:1 to the device there is no point in allocating it separately, another benefit is possibility of direct initialisation of its fields which is more readable and allows further expansion.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com --- drivers/gpu/drm/exynos/exynos_drm_vidi.c | 26 +++++++++++++----------- 1 file changed, 14 insertions(+), 12 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index b61ae3415b8c..377aae5f7631 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -41,7 +41,7 @@ struct vidi_context { struct drm_encoder encoder; struct platform_device *pdev; struct drm_device *drm_dev; - struct exynos_drm_crtc *crtc; + struct exynos_drm_crtc crtc; struct drm_connector connector; struct exynos_drm_plane planes[WINDOWS_NR]; struct edid *raw_edid; @@ -57,6 +57,8 @@ static inline struct vidi_context *encoder_to_vidi(struct drm_encoder *e) return container_of(e, struct vidi_context, encoder); }
+#define to_vidi(ptr) container_of(ptr, struct vidi_context, ptr) + static const char fake_edid_info[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x4c, 0x2d, 0x05, 0x05, 0x00, 0x00, 0x00, 0x00, 0x30, 0x12, 0x01, 0x03, 0x80, 0x10, 0x09, 0x78, @@ -96,7 +98,7 @@ static const enum drm_plane_type vidi_win_types[WINDOWS_NR] = {
static int vidi_enable_vblank(struct exynos_drm_crtc *crtc) { - struct vidi_context *ctx = crtc->ctx; + struct vidi_context *ctx = to_vidi(crtc);
if (ctx->suspended) return -EPERM; @@ -115,7 +117,7 @@ static void vidi_update_plane(struct exynos_drm_crtc *crtc, struct exynos_drm_plane *plane) { struct drm_plane_state *state = plane->base.state; - struct vidi_context *ctx = crtc->ctx; + struct vidi_context *ctx = to_vidi(crtc); dma_addr_t addr;
if (ctx->suspended) @@ -127,7 +129,7 @@ static void vidi_update_plane(struct exynos_drm_crtc *crtc,
static void vidi_enable(struct exynos_drm_crtc *crtc) { - struct vidi_context *ctx = crtc->ctx; + struct vidi_context *ctx = to_vidi(crtc);
mutex_lock(&ctx->lock);
@@ -140,7 +142,7 @@ static void vidi_enable(struct exynos_drm_crtc *crtc)
static void vidi_disable(struct exynos_drm_crtc *crtc) { - struct vidi_context *ctx = crtc->ctx; + struct vidi_context *ctx = to_vidi(crtc);
drm_crtc_vblank_off(&crtc->base);
@@ -164,7 +166,7 @@ static void vidi_fake_vblank_timer(struct timer_list *t) { struct vidi_context *ctx = from_timer(ctx, t, timer);
- if (drm_crtc_handle_vblank(&ctx->crtc->base)) + if (drm_crtc_handle_vblank(&ctx->crtc.base)) mod_timer(&ctx->timer, jiffies + msecs_to_jiffies(VIDI_REFRESH_TIME) - 1); } @@ -377,7 +379,6 @@ static int vidi_bind(struct device *dev, struct device *master, void *data) struct vidi_context *ctx = dev_get_drvdata(dev); struct drm_device *drm_dev = data; struct drm_encoder *encoder = &ctx->encoder; - struct exynos_drm_plane *exynos_plane; unsigned int i; int ret;
@@ -390,13 +391,14 @@ static int vidi_bind(struct device *dev, struct device *master, void *data) return ret; }
- exynos_plane = &ctx->planes[DEFAULT_WIN]; - ctx->crtc = exynos_drm_crtc_create(drm_dev, &exynos_plane->base, - EXYNOS_DISPLAY_TYPE_VIDI, &vidi_crtc_ops, ctx); - if (IS_ERR(ctx->crtc)) { + ctx->crtc.type = EXYNOS_DISPLAY_TYPE_VIDI; + ctx->crtc.ops = &vidi_crtc_ops; + ret = exynos_drm_crtc_init(&ctx->crtc, drm_dev); + if (ret) { DRM_ERROR("failed to create crtc.\n"); - return PTR_ERR(ctx->crtc); + return ret; } + ctx->crtc.base.primary = &ctx->planes[DEFAULT_WIN].base;
drm_encoder_init(drm_dev, encoder, &exynos_vidi_encoder_funcs, DRM_MODE_ENCODER_TMDS, NULL);
Since exynos_drm_crtc is always embedded exynos_drm_crtc_create helper and ctx field can be removed.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com --- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 35 ------------------------ drivers/gpu/drm/exynos/exynos_drm_crtc.h | 5 ---- drivers/gpu/drm/exynos/exynos_drm_drv.h | 2 -- 3 files changed, 42 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 4ff1e0ff2255..72e224e80565 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -182,41 +182,6 @@ int exynos_drm_crtc_init(struct exynos_drm_crtc *exynos_crtc, &exynos_crtc_funcs, NULL); }
-struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, - struct drm_plane *plane, - enum exynos_drm_output_type type, - const struct exynos_drm_crtc_ops *ops, - void *ctx) -{ - struct exynos_drm_crtc *exynos_crtc; - struct drm_crtc *crtc; - int ret; - - exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL); - if (!exynos_crtc) - return ERR_PTR(-ENOMEM); - - exynos_crtc->type = type; - exynos_crtc->ops = ops; - exynos_crtc->ctx = ctx; - - crtc = &exynos_crtc->base; - - ret = drm_crtc_init_with_planes(drm_dev, crtc, plane, NULL, - &exynos_crtc_funcs, NULL); - if (ret < 0) - goto err_crtc; - - drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs); - - return exynos_crtc; - -err_crtc: - plane->funcs->destroy(plane); - kfree(exynos_crtc); - return ERR_PTR(ret); -} - struct exynos_drm_crtc *exynos_drm_crtc_get_by_type(struct drm_device *drm_dev, enum exynos_drm_output_type out_type) { diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.h b/drivers/gpu/drm/exynos/exynos_drm_crtc.h index 9e35a9e02332..7b0c964521fa 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.h +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.h @@ -20,11 +20,6 @@
int exynos_drm_crtc_init(struct exynos_drm_crtc *exynos_crtc, struct drm_device *drm_dev); -struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev, - struct drm_plane *plane, - enum exynos_drm_output_type out_type, - const struct exynos_drm_crtc_ops *ops, - void *context); void exynos_drm_crtc_wait_pending_update(struct exynos_drm_crtc *exynos_crtc); void exynos_drm_crtc_finish_update(struct exynos_drm_crtc *exynos_crtc, struct exynos_drm_plane *exynos_plane); diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 1d4ef0245958..82af112be03d 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -147,14 +147,12 @@ struct exynos_drm_clk { * @base: crtc object. * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI. * @ops: pointer to callbacks for exynos drm specific functionality - * @ctx: A pointer to the crtc's implementation specific context * @pipe_clk: A pointer to the crtc's pipeline clock. */ struct exynos_drm_crtc { struct drm_crtc base; enum exynos_drm_output_type type; const struct exynos_drm_crtc_ops *ops; - void *ctx; struct exynos_drm_clk *pipe_clk; bool i80_mode : 1; };
It can be replaced by recently introduced to_vidi helper.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com --- drivers/gpu/drm/exynos/exynos_drm_vidi.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index 377aae5f7631..2579462aec70 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -52,11 +52,6 @@ struct vidi_context { struct mutex lock; };
-static inline struct vidi_context *encoder_to_vidi(struct drm_encoder *e) -{ - return container_of(e, struct vidi_context, encoder); -} - #define to_vidi(ptr) container_of(ptr, struct vidi_context, ptr)
static const char fake_edid_info[] = { @@ -331,7 +326,7 @@ static const struct drm_connector_helper_funcs vidi_connector_helper_funcs = {
static int vidi_create_connector(struct drm_encoder *encoder) { - struct vidi_context *ctx = encoder_to_vidi(encoder); + struct vidi_context *ctx = to_vidi(encoder); struct drm_connector *connector = &ctx->connector; int ret;
Since all Exynos CRTCs uses the first plane as primary plane and the last one as cursor plane we can drop custom assignments per CRTC and replace it with common code.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com --- drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 7 +------ drivers/gpu/drm/exynos/exynos7_drm_decon.c | 7 +------ drivers/gpu/drm/exynos/exynos_drm_drv.h | 2 +- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 10 +--------- drivers/gpu/drm/exynos/exynos_drm_plane.c | 19 +++++++++++++------ drivers/gpu/drm/exynos/exynos_drm_vidi.c | 8 +------- drivers/gpu/drm/exynos/exynos_mixer.c | 6 ++---- 7 files changed, 20 insertions(+), 39 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index 0d409f453923..663446ca2d09 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -78,11 +78,6 @@ static const uint32_t decon_formats[] = { DRM_FORMAT_ARGB8888, };
-static const enum drm_plane_type decon_win_types[WINDOWS_NR] = { - [PRIMARY_WIN] = DRM_PLANE_TYPE_PRIMARY, - [CURSON_WIN] = DRM_PLANE_TYPE_CURSOR, -}; - static inline void decon_set_bits(struct decon_context *ctx, u32 reg, u32 mask, u32 val) { @@ -619,7 +614,7 @@ static int decon_bind(struct device *dev, struct device *master, void *data) | EXYNOS_DRM_PLANE_CAP_PIX_BLEND; ret = exynos_plane_init(drm_dev, &ctx->planes[i], decon_formats, ARRAY_SIZE(decon_formats), - decon_win_types[i]); + WINDOWS_NR - ctx->first_win); if (ret) return ret; } diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index 22659f2da755..b6ad2faed159 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c @@ -78,11 +78,6 @@ static const uint32_t decon_formats[] = { DRM_FORMAT_BGRA8888, };
-static const enum drm_plane_type decon_win_types[WINDOWS_NR] = { - DRM_PLANE_TYPE_PRIMARY, - DRM_PLANE_TYPE_CURSOR, -}; - static void decon_wait_for_vblank(struct exynos_drm_crtc *crtc) { struct decon_context *ctx = to_decon(crtc); @@ -628,7 +623,7 @@ static int decon_bind(struct device *dev, struct device *master, void *data) for (i = 0; i < WINDOWS_NR; i++) { ctx->planes[i].index = i; ret = exynos_plane_init(drm_dev, &ctx->planes[i], decon_formats, - ARRAY_SIZE(decon_formats), decon_win_types[i]); + ARRAY_SIZE(decon_formats), WINDOWS_NR); if (ret) return ret; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 82af112be03d..23b27b82de6e 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -97,7 +97,7 @@ struct exynos_drm_plane {
int exynos_plane_init(struct drm_device *dev, struct exynos_drm_plane *plane, const uint32_t *pixel_formats, int num_pixel_formats, - enum drm_plane_type type); + int win_count);
/* * Exynos drm crtc ops diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 8ea1cfd51736..b3c11bca5aed 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -212,14 +212,6 @@ static const struct of_device_id fimd_driver_dt_match[] = { }; MODULE_DEVICE_TABLE(of, fimd_driver_dt_match);
-static const enum drm_plane_type fimd_win_types[WINDOWS_NR] = { - DRM_PLANE_TYPE_PRIMARY, - DRM_PLANE_TYPE_OVERLAY, - DRM_PLANE_TYPE_OVERLAY, - DRM_PLANE_TYPE_OVERLAY, - DRM_PLANE_TYPE_CURSOR, -}; - static const uint32_t fimd_formats[] = { DRM_FORMAT_C8, DRM_FORMAT_XRGB1555, @@ -1049,7 +1041,7 @@ static int fimd_bind(struct device *dev, struct device *master, void *data) | EXYNOS_DRM_PLANE_CAP_WIN_BLEND | EXYNOS_DRM_PLANE_CAP_PIX_BLEND; ret = exynos_plane_init(drm_dev, &ctx->planes[i], fimd_formats, - ARRAY_SIZE(fimd_formats), fimd_win_types[i]); + ARRAY_SIZE(fimd_formats), WINDOWS_NR); if (ret) return ret; } diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index e1aa504539fa..5f8f56b69369 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -291,9 +291,18 @@ static void exynos_plane_attach_zpos_property(struct drm_plane *plane, drm_plane_create_zpos_property(plane, zpos, 0, MAX_PLANE - 1); }
+static inline enum drm_plane_type exynos_plane_type(int index, int count) +{ + if (count && !index) + return DRM_PLANE_TYPE_PRIMARY; + if (index == count - 1) + return DRM_PLANE_TYPE_CURSOR; + return DRM_PLANE_TYPE_OVERLAY; +} + int exynos_plane_init(struct drm_device *dev, struct exynos_drm_plane *plane, const uint32_t *pixel_formats, int num_pixel_formats, - enum drm_plane_type type) + int win_count) { int err; unsigned int supported_modes = BIT(DRM_MODE_BLEND_PIXEL_NONE) | @@ -302,11 +311,9 @@ int exynos_plane_init(struct drm_device *dev, struct exynos_drm_plane *plane, struct drm_plane *bplane = &plane->base;
err = drm_universal_plane_init(dev, bplane, - 1 << dev->mode_config.num_crtc, - &exynos_plane_funcs, - pixel_formats, - num_pixel_formats, - NULL, type, NULL); + 1 << dev->mode_config.num_crtc, + &exynos_plane_funcs, pixel_formats, num_pixel_formats,NULL, + exynos_plane_type(plane->index, win_count), NULL); if (err) { DRM_ERROR("failed to initialize plane\n"); return err; diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index 2579462aec70..eb1fd3a2cdf3 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -85,12 +85,6 @@ static const uint32_t formats[] = { DRM_FORMAT_NV12, };
-static const enum drm_plane_type vidi_win_types[WINDOWS_NR] = { - DRM_PLANE_TYPE_PRIMARY, - DRM_PLANE_TYPE_OVERLAY, - DRM_PLANE_TYPE_CURSOR, -}; - static int vidi_enable_vblank(struct exynos_drm_crtc *crtc) { struct vidi_context *ctx = to_vidi(crtc); @@ -381,7 +375,7 @@ static int vidi_bind(struct device *dev, struct device *master, void *data)
for (i = 0; i < WINDOWS_NR; i++) { ret = exynos_plane_init(drm_dev, &ctx->planes[i], formats, - ARRAY_SIZE(formats), vidi_win_types[i]); + ARRAY_SIZE(formats), WINDOWS_NR); if (ret) return ret; } diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 7fcefcbe68db..a61fb2069e32 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -1143,8 +1143,6 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data) struct drm_device *drm_dev = data; unsigned int i; int ret; - static enum drm_plane_type types[] = { DRM_PLANE_TYPE_PRIMARY, - DRM_PLANE_TYPE_CURSOR, DRM_PLANE_TYPE_OVERLAY };
ret = mixer_initialize(ctx, drm_dev); if (ret) @@ -1157,7 +1155,7 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data) EXYNOS_DRM_PLANE_CAP_PIX_BLEND | EXYNOS_DRM_PLANE_CAP_WIN_BLEND; ret = exynos_plane_init(drm_dev, &ctx->planes[i], mixer_formats, - ARRAY_SIZE(mixer_formats), types[i]); + ARRAY_SIZE(mixer_formats), VP_DEFAULT_WIN); if (ret) return ret; } @@ -1169,7 +1167,7 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data) EXYNOS_DRM_PLANE_CAP_TILE | EXYNOS_DRM_PLANE_CAP_WIN_BLEND; ret = exynos_plane_init(drm_dev, &ctx->planes[i], vp_formats, - ARRAY_SIZE(vp_formats), types[i]); + ARRAY_SIZE(vp_formats), VP_DEFAULT_WIN); if (ret) return ret; }
exynos_drm_crtc_init has all information necessary to discover primary plane. Let's move logic for setting primary plane into this function.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com --- drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 3 --- drivers/gpu/drm/exynos/exynos7_drm_decon.c | 1 - drivers/gpu/drm/exynos/exynos_drm_crtc.c | 10 +++++++++- drivers/gpu/drm/exynos/exynos_drm_drv.h | 2 -- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 1 - drivers/gpu/drm/exynos/exynos_drm_vidi.c | 1 - drivers/gpu/drm/exynos/exynos_mixer.c | 1 - 7 files changed, 9 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index 663446ca2d09..958972e3ee1e 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -30,8 +30,6 @@ #define DSD_CFG_MUX_TE_UNMASK_GLOBAL BIT(13)
#define WINDOWS_NR 5 -#define PRIMARY_WIN 2 -#define CURSON_WIN 4
#define MIN_FB_WIDTH_FOR_16WORD_BURST 128
@@ -625,7 +623,6 @@ static int decon_bind(struct device *dev, struct device *master, void *data) ret = exynos_drm_crtc_init(&ctx->crtc, drm_dev); if (ret) return ret; - ctx->crtc.base.primary = &ctx->planes[PRIMARY_WIN].base;
decon_clear_channels(&ctx->crtc);
diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c index b6ad2faed159..3d8c96f0b02a 100644 --- a/drivers/gpu/drm/exynos/exynos7_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c @@ -635,7 +635,6 @@ static int decon_bind(struct device *dev, struct device *master, void *data) decon_ctx_remove(ctx); return ret; } - ctx->crtc.base.primary = &ctx->planes[DEFAULT_WIN].base;
if (ctx->encoder) exynos_dpi_bind(drm_dev, ctx->encoder); diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index 72e224e80565..ec1319781b8b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -176,9 +176,17 @@ int exynos_drm_crtc_init(struct exynos_drm_crtc *exynos_crtc, struct drm_device *drm_dev) { struct drm_crtc *crtc = &exynos_crtc->base; + struct drm_plane *primary = NULL, *plane; + + drm_for_each_plane(plane, drm_dev) { + if (plane->possible_crtcs != BIT(drm_dev->mode_config.num_crtc)) + continue; + if (!primary && plane->type == DRM_PLANE_TYPE_PRIMARY) + primary = plane; + }
drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs); - return drm_crtc_init_with_planes(drm_dev, crtc, NULL, NULL, + return drm_crtc_init_with_planes(drm_dev, crtc, primary, NULL, &exynos_crtc_funcs, NULL); }
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 23b27b82de6e..6643db865500 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -21,8 +21,6 @@ #define MAX_PLANE 5 #define MAX_FB_BUFFER 4
-#define DEFAULT_WIN 0 - #define to_exynos_crtc(x) container_of(x, struct exynos_drm_crtc, base) #define to_exynos_plane(x) container_of(x, struct exynos_drm_plane, base)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index b3c11bca5aed..14e70971547a 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c @@ -1051,7 +1051,6 @@ static int fimd_bind(struct device *dev, struct device *master, void *data) ret = exynos_drm_crtc_init(&ctx->crtc, drm_dev); if (ret) return ret; - ctx->crtc.base.primary = &ctx->planes[DEFAULT_WIN].base;
if (ctx->driver_data->has_dp_clk) { ctx->dp_clk.enable = fimd_dp_clock_enable; diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index eb1fd3a2cdf3..19cd7275b20f 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c @@ -387,7 +387,6 @@ static int vidi_bind(struct device *dev, struct device *master, void *data) DRM_ERROR("failed to create crtc.\n"); return ret; } - ctx->crtc.base.primary = &ctx->planes[DEFAULT_WIN].base;
drm_encoder_init(drm_dev, encoder, &exynos_vidi_encoder_funcs, DRM_MODE_ENCODER_TMDS, NULL); diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index a61fb2069e32..efc7d7a2d5b1 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -1179,7 +1179,6 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data) mixer_ctx_remove(ctx); goto free_ctx; } - ctx->crtc.base.primary = &ctx->planes[DEFAULT_WIN].base;
return 0;
The patch configures cursor plane in exynos_drm_crtc_init. Since Exynos DRM does not support fast/async path for cursor update, it must be disabled.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com --- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 6 ++++-- drivers/gpu/drm/exynos/exynos_drm_fb.c | 10 +++++++++- 2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c index ec1319781b8b..303df018f0a1 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c @@ -176,17 +176,19 @@ int exynos_drm_crtc_init(struct exynos_drm_crtc *exynos_crtc, struct drm_device *drm_dev) { struct drm_crtc *crtc = &exynos_crtc->base; - struct drm_plane *primary = NULL, *plane; + struct drm_plane *primary = NULL, *cursor = NULL, *plane;
drm_for_each_plane(plane, drm_dev) { if (plane->possible_crtcs != BIT(drm_dev->mode_config.num_crtc)) continue; if (!primary && plane->type == DRM_PLANE_TYPE_PRIMARY) primary = plane; + if (!cursor && plane->type == DRM_PLANE_TYPE_CURSOR) + cursor = plane; }
drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs); - return drm_crtc_init_with_planes(drm_dev, crtc, primary, NULL, + return drm_crtc_init_with_planes(drm_dev, crtc, primary, cursor, &exynos_crtc_funcs, NULL); }
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fb.c b/drivers/gpu/drm/exynos/exynos_drm_fb.c index 1f11ab0f8e9d..d705e363f703 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fb.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fb.c @@ -155,11 +155,19 @@ static struct drm_mode_config_helper_funcs exynos_drm_mode_config_helpers = { .atomic_commit_tail = drm_atomic_helper_commit_tail_rpm, };
+int exynos_drm_atomic_helper_commit(struct drm_device *dev, + struct drm_atomic_state *state, + bool nonblock) +{ + state->legacy_cursor_update = false; + return drm_atomic_helper_commit(dev, state, nonblock); +} + static const struct drm_mode_config_funcs exynos_drm_mode_config_funcs = { .fb_create = exynos_user_fb_create, .output_poll_changed = drm_fb_helper_output_poll_changed, .atomic_check = drm_atomic_helper_check, - .atomic_commit = drm_atomic_helper_commit, + .atomic_commit = exynos_drm_atomic_helper_commit, };
void exynos_drm_mode_config_init(struct drm_device *dev)
Display controllers in Exynos beside native planes/windows can use external planes provided by other IPs - GSCALER, FIMD, VPP. To add support to them we will need plane specific callbacks.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com --- drivers/gpu/drm/exynos/exynos_drm_drv.h | 7 +++++++ 1 file changed, 7 insertions(+)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 6643db865500..5d06e796dc80 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -76,6 +76,12 @@ to_exynos_plane_state(struct drm_plane_state *state) #define EXYNOS_DRM_PLANE_CAP_PIX_BLEND (1 << 4) #define EXYNOS_DRM_PLANE_CAP_WIN_BLEND (1 << 5)
+struct exynos_drm_plane; +struct exynos_drm_plane_ops { + void (*update_plane)(struct exynos_drm_plane *plane); + void (*disable_plane)(struct exynos_drm_plane *plane); +}; + /* * Exynos drm common overlay structure. * @@ -89,6 +95,7 @@ to_exynos_plane_state(struct drm_plane_state *state)
struct exynos_drm_plane { struct drm_plane base; + const struct exynos_drm_plane_ops *ops; unsigned int index; unsigned int capabilities; };
This bit will indicate the plane is provided by GSCALER. Tests shows that GSCALER does not like to convert from/to too small buffers. Since exact constraints are not provided by documentation rough estimate of 64 pixel has been applied.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com --- drivers/gpu/drm/exynos/exynos_drm_drv.h | 1 + drivers/gpu/drm/exynos/exynos_drm_plane.c | 14 +++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h index 5d06e796dc80..7bdbac639b2b 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.h +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h @@ -75,6 +75,7 @@ to_exynos_plane_state(struct drm_plane_state *state) #define EXYNOS_DRM_PLANE_CAP_TILE (1 << 3) #define EXYNOS_DRM_PLANE_CAP_PIX_BLEND (1 << 4) #define EXYNOS_DRM_PLANE_CAP_WIN_BLEND (1 << 5) +#define EXYNOS_DRM_PLANE_CAP_GSCALER (1 << 6)
struct exynos_drm_plane; struct exynos_drm_plane_ops { diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c index 5f8f56b69369..89168157e1e2 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_plane.c +++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c @@ -198,6 +198,11 @@ exynos_drm_plane_check_format(struct exynos_drm_plane_state *state) return 0; }
+static bool is_in_range(int val, int min, int max) +{ + return (val >= min) && (val < max); +} + static int exynos_drm_plane_check_size(struct exynos_drm_plane_state *state) { @@ -205,7 +210,7 @@ exynos_drm_plane_check_size(struct exynos_drm_plane_state *state) bool width_ok = false, height_ok = false;
if (plane->capabilities & EXYNOS_DRM_PLANE_CAP_SCALE) - return 0; + width_ok = height_ok = true;
if (state->src.w == state->crtc.w) width_ok = true; @@ -221,6 +226,13 @@ exynos_drm_plane_check_size(struct exynos_drm_plane_state *state) state->v_ratio == (1 << 15)) height_ok = true;
+ if (plane->capabilities & EXYNOS_DRM_PLANE_CAP_GSCALER) { + width_ok = is_in_range(state->src.w, 64, 4800) && + is_in_range(state->crtc.w, 64, 4800); + height_ok = is_in_range(state->src.h, 64, 3344) && + is_in_range(state->crtc.h, 64, 3344); + } + if (width_ok && height_ok) return 0;
Id should be assigned based on OF alias.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com --- drivers/gpu/drm/exynos/exynos_drm_gsc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c index f048d97fe9e2..8d5aa70c8ab8 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c @@ -1287,7 +1287,7 @@ static int gsc_probe(struct platform_device *pdev) }
/* context initailization */ - ctx->id = pdev->id; + ctx->id = of_alias_get_id(dev->of_node, "gsc");
platform_set_drvdata(pdev, ctx);
GSCALERs in Exynos5433 have local path to DECON and DECON_TV. They can be used as extra planes with support for non-RGB formats and scaling. To enable it GSCALER must expose exynos_plane with associated plane callbacks and bind it to DECONs CRTCs. Moreover device locking should be added to prevent simultanous device usage by IPP and DRM.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com --- drivers/gpu/drm/exynos/exynos_drm_gsc.c | 179 ++++++++++++++++++++---- drivers/gpu/drm/exynos/regs-gsc.h | 6 + 2 files changed, 156 insertions(+), 29 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c index 8d5aa70c8ab8..28a738a68a82 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c @@ -16,14 +16,16 @@ #include <linux/platform_device.h> #include <linux/clk.h> #include <linux/pm_runtime.h> -#include <linux/mfd/syscon.h> #include <linux/of_device.h> #include <linux/regmap.h>
+#include <drm/drm_atomic.h> #include <drm/drmP.h> #include <drm/exynos_drm.h> #include "regs-gsc.h" +#include "exynos_drm_crtc.h" #include "exynos_drm_drv.h" +#include "exynos_drm_fb.h" #include "exynos_drm_ipp.h"
/* @@ -98,11 +100,13 @@ struct gsc_scaler { */ struct gsc_context { struct exynos_drm_ipp ipp; + struct exynos_drm_plane plane; struct drm_device *drm_dev; struct device *dev; struct exynos_drm_ipp_task *task; struct exynos_drm_ipp_formats *formats; unsigned int num_formats; + struct spinlock lock;
struct resource *regs_res; void __iomem *regs; @@ -113,8 +117,12 @@ struct gsc_context { int id; int irq; bool rotation; + bool enabled; + bool use_local_path; };
+#define to_gsc(ptr) container_of(ptr, struct gsc_context, ptr) + /** * struct gsc_driverdata - per device type driver data for init time. * @@ -127,6 +135,7 @@ struct gsc_driverdata { int num_limits; const char *clk_names[GSC_MAX_CLOCKS]; int num_clocks; + bool use_local_path; };
/* 8-tap Filter Coefficient */ @@ -377,6 +386,32 @@ static const int v_coef_4t[GSC_COEF_RATIO][GSC_COEF_ATTR][GSC_COEF_V_4T] = { } };
+static int gsc_dev_lock(struct gsc_context *ctx, void *task) +{ + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&ctx->lock, flags); + if (ctx->task) + ret = -EBUSY; + else + ctx->task = task; + spin_unlock_irqrestore(&ctx->lock, flags); + return ret; +} + +static void *gsc_dev_unlock(struct gsc_context *ctx) +{ + unsigned long flags; + void *task; + + spin_lock_irqsave(&ctx->lock, flags); + task = ctx->task; + ctx->task = NULL; + spin_unlock_irqrestore(&ctx->lock, flags); + return task; +} + static int gsc_sw_reset(struct gsc_context *ctx) { u32 cfg; @@ -1021,6 +1056,7 @@ static int gsc_get_dst_buf_index(struct gsc_context *ctx) static irqreturn_t gsc_irq_handler(int irq, void *dev_id) { struct gsc_context *ctx = dev_id; + struct exynos_drm_ipp_task *task; u32 status; int err = 0;
@@ -1049,10 +1085,8 @@ static irqreturn_t gsc_irq_handler(int irq, void *dev_id) err = -EINVAL; }
- if (ctx->task) { - struct exynos_drm_ipp_task *task = ctx->task; - - ctx->task = NULL; + task = gsc_dev_unlock(ctx); + if (!IS_ERR_OR_NULL(task)) { pm_runtime_mark_last_busy(ctx->dev); pm_runtime_put_autosuspend(ctx->dev); exynos_drm_ipp_task_done(task, err); @@ -1117,13 +1151,15 @@ static int gsc_commit(struct exynos_drm_ipp *ipp, struct gsc_context *ctx = container_of(ipp, struct gsc_context, ipp); int ret;
- pm_runtime_get_sync(ctx->dev); - ctx->task = task; + ret = gsc_dev_lock(ctx, task); + if (ret) + return ret;
+ pm_runtime_get_sync(ctx->dev); ret = gsc_reset(ctx); if (ret) { pm_runtime_put_autosuspend(ctx->dev); - ctx->task = NULL; + gsc_dev_unlock(ctx); return ret; }
@@ -1147,10 +1183,8 @@ static void gsc_abort(struct exynos_drm_ipp *ipp, container_of(ipp, struct gsc_context, ipp);
gsc_reset(ctx); - if (ctx->task) { - struct exynos_drm_ipp_task *task = ctx->task; - - ctx->task = NULL; + task = gsc_dev_unlock(ctx); + if (!IS_ERR_OR_NULL(task)) { pm_runtime_mark_last_busy(ctx->dev); pm_runtime_put_autosuspend(ctx->dev); exynos_drm_ipp_task_done(task, -EIO); @@ -1162,11 +1196,97 @@ static struct exynos_drm_ipp_funcs ipp_funcs = { .abort = gsc_abort, };
+static const unsigned int gsc_formats[] = { + DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888, DRM_FORMAT_BGRX8888, + DRM_FORMAT_RGB565, + DRM_FORMAT_NV12, DRM_FORMAT_NV16, DRM_FORMAT_NV21, DRM_FORMAT_NV61, + DRM_FORMAT_UYVY, DRM_FORMAT_VYUY, DRM_FORMAT_YUYV, DRM_FORMAT_YVYU, + DRM_FORMAT_YUV420, DRM_FORMAT_YVU420, DRM_FORMAT_YUV422, +}; + +static const unsigned int gsc_tiled_formats[] = { + DRM_FORMAT_NV12, DRM_FORMAT_NV21, +}; + +static void gsc_update_plane(struct exynos_drm_plane *plane) +{ + struct gsc_context *ctx = to_gsc(plane); + struct exynos_drm_plane_state *state = + to_exynos_plane_state(plane->base.state); + struct drm_framebuffer *fb = plane->base.state->fb; + u32 src_w = fb->pitches[0] / fb->format->cpp[0], src_h = state->src.h; + u32 src_x = state->src.x, src_y = state->src.y; + u32 cropped_w = state->src.w, cropped_h = state->src.h; + u32 scaled_w = state->crtc.w, scaled_h = state->crtc.h; + int i; + + if (!ctx->enabled) { + while (gsc_dev_lock(ctx, ERR_PTR(-EBUSY)) < 0) + usleep_range(1000, 2000); + pm_runtime_get_sync(ctx->dev); + gsc_sw_reset(ctx); + gsc_src_set_buf_seq(ctx, 0, true); + gsc_write(GSC_SMART_IF_EN | GSC_HIERARCHICAL_MODE, GSC_SMART_IF_CON); + ctx->enabled = true; + } + gsc_write(GSC_POINT(src_x, src_y), GSC_SRCIMG_OFFSET); + gsc_write(GSC_POINT(src_w, src_h), GSC_SRCIMG_SIZE); + gsc_write(GSC_POINT(cropped_w, cropped_h), GSC_CROPPED_SIZE); + gsc_write(GSC_POINT(scaled_w, scaled_h), GSC_SCALED_SIZE); + gsc_write(GSC_OUT_PATH_LOCAL | GSC_OUT_RGB_HD_WIDE, GSC_OUT_CON); + gsc_write(GSC_POINT(1, 1), GSC_PRE_SCALE_RATIO); + gsc_write(BIT(16) * cropped_w / scaled_w, GSC_MAIN_H_RATIO); + gsc_write(BIT(16) * cropped_h / scaled_h, GSC_MAIN_V_RATIO); + gsc_write(exynos_drm_fb_dma_addr(fb, 0), GSC_IN_BASE_ADDR_Y(0)); + if (fb->format->num_planes > 1) + gsc_write(exynos_drm_fb_dma_addr(fb, 1), GSC_IN_BASE_ADDR_CB(0)); + if (fb->format->num_planes > 2) + gsc_write(exynos_drm_fb_dma_addr(fb, 2), GSC_IN_BASE_ADDR_CR(0)); + gsc_src_set_fmt(ctx, fb->format->format, fb->modifier); + gsc_write(scaled_w * scaled_h, GSC_SMART_IF_PIXEL_NUM); + gsc_write(GSC_ENABLE_SFR_UPDATE | GSC_ENABLE_ON, GSC_ENABLE); +} + +static void gsc_disable_plane(struct exynos_drm_plane *plane) +{ + struct gsc_context *ctx = to_gsc(plane); + u32 val; + + val = gsc_read(GSC_ENABLE); + val |= GSC_ENABLE_SFR_UPDATE; + val &= ~GSC_ENABLE_ON; + gsc_write(val, GSC_ENABLE); + pm_runtime_mark_last_busy(ctx->dev); + pm_runtime_put_autosuspend(ctx->dev); + ctx->enabled = false; + gsc_dev_unlock(ctx); +} + +const struct exynos_drm_plane_ops gsc_plane_ops = { + .update_plane = gsc_update_plane, + .disable_plane = gsc_disable_plane +}; + +static void gsc_set_possible_crtcs(struct gsc_context *ctx) +{ + struct exynos_drm_crtc *crtc; + u32 mask = 0; + + crtc = exynos_drm_crtc_get_by_type(ctx->drm_dev, EXYNOS_DISPLAY_TYPE_HDMI); + if (crtc) + mask |= drm_crtc_mask(&crtc->base); + crtc = exynos_drm_crtc_get_by_type(ctx->drm_dev, EXYNOS_DISPLAY_TYPE_LCD); + if (crtc) + mask |= drm_crtc_mask(&crtc->base); + ctx->plane.base.possible_crtcs = mask; +} + static int gsc_bind(struct device *dev, struct device *master, void *data) { struct gsc_context *ctx = dev_get_drvdata(dev); struct drm_device *drm_dev = data; struct exynos_drm_ipp *ipp = &ctx->ipp; + int ret;
ctx->drm_dev = drm_dev; exynos_drm_register_dma(drm_dev, dev); @@ -1176,9 +1296,19 @@ static int gsc_bind(struct device *dev, struct device *master, void *data) DRM_EXYNOS_IPP_CAP_SCALE | DRM_EXYNOS_IPP_CAP_CONVERT, ctx->formats, ctx->num_formats, "gsc");
- dev_info(dev, "The exynos gscaler has been probed successfully\n"); - - return 0; + if (!ctx->use_local_path) + return 0; + + ctx->plane.index = ctx->id; + ctx->plane.capabilities = EXYNOS_DRM_PLANE_CAP_GSCALER | + EXYNOS_DRM_PLANE_CAP_ZPOS | + EXYNOS_DRM_PLANE_CAP_SCALE | + EXYNOS_DRM_PLANE_CAP_WIN_BLEND; + ctx->plane.ops = &gsc_plane_ops; + ret = exynos_plane_init(drm_dev, &ctx->plane, gsc_formats, + ARRAY_SIZE(gsc_formats), 0); + gsc_set_possible_crtcs(ctx); + return ret; }
static void gsc_unbind(struct device *dev, struct device *master, @@ -1197,18 +1327,6 @@ static const struct component_ops gsc_component_ops = { .unbind = gsc_unbind, };
-static const unsigned int gsc_formats[] = { - DRM_FORMAT_ARGB8888, - DRM_FORMAT_XRGB8888, DRM_FORMAT_RGB565, DRM_FORMAT_BGRX8888, - DRM_FORMAT_NV12, DRM_FORMAT_NV16, DRM_FORMAT_NV21, DRM_FORMAT_NV61, - DRM_FORMAT_UYVY, DRM_FORMAT_VYUY, DRM_FORMAT_YUYV, DRM_FORMAT_YVYU, - DRM_FORMAT_YUV420, DRM_FORMAT_YVU420, DRM_FORMAT_YUV422, -}; - -static const unsigned int gsc_tiled_formats[] = { - DRM_FORMAT_NV12, DRM_FORMAT_NV21, -}; - static int gsc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -1226,6 +1344,8 @@ static int gsc_probe(struct platform_device *pdev) ctx->dev = dev; ctx->num_clocks = driver_data->num_clocks; ctx->clk_names = driver_data->clk_names; + ctx->use_local_path = driver_data->use_local_path; + spin_lock_init(&ctx->lock);
/* construct formats/limits array */ num_formats = ARRAY_SIZE(gsc_formats) + ARRAY_SIZE(gsc_tiled_formats); @@ -1395,10 +1515,11 @@ static struct gsc_driverdata gsc_exynos5420_drvdata = { };
static struct gsc_driverdata gsc_exynos5433_drvdata = { - .clk_names = {"pclk", "aclk", "aclk_xiu", "aclk_gsclbend"}, - .num_clocks = 4, + .clk_names = {"pclk", "aclk", "aclk_xiu", "aclk_gsclbend", "gsd"}, + .num_clocks = 5, .limits = gsc_5433_limits, .num_limits = ARRAY_SIZE(gsc_5433_limits), + .use_local_path = true, };
static const struct of_device_id exynos_drm_gsc_of_match[] = { diff --git a/drivers/gpu/drm/exynos/regs-gsc.h b/drivers/gpu/drm/exynos/regs-gsc.h index 16b39734115c..7c23a79085e2 100644 --- a/drivers/gpu/drm/exynos/regs-gsc.h +++ b/drivers/gpu/drm/exynos/regs-gsc.h @@ -91,6 +91,7 @@ #define GSC_IN_PATH_LOCAL (1 << 0) #define GSC_IN_PATH_MEMORY (0 << 0)
+#define GSC_POINT(x, y) ((x) + ((y) << 16)) /* G-Scaler source image size */ #define GSC_SRCIMG_SIZE 0x14 #define GSC_SRCIMG_HEIGHT_MASK (0x1fff << 16) @@ -264,6 +265,11 @@ #define GSC_VPOSITION 0xA7C #define GSC_VPOS_F(x) ((x) << 0)
+#define GSC_SMART_IF_PIXEL_NUM 0xAF0 + +#define GSC_SMART_IF_CON 0xAF4 +#define GSC_SMART_IF_EN (1 << 0) +#define GSC_HIERARCHICAL_MODE (0x3 << 1)
/* G-Scaler clock initial count */ #define GSC_CLK_INIT_COUNT 0xC00
GSCALERs in Exynos5433 have local path to DECON and DECON_TV. They can be used as extra planes with support for non-RGB formats and scaling. To enable it on DECON update_plane and disable_plane callback should be modified. Moreover DSD mux should be set accordingly, and finally atomic_check callback should be used to limit the number of active planes.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com --- drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 80 +++++++++++++++---- drivers/gpu/drm/exynos/regs-decon5433.h | 6 ++ 2 files changed, 72 insertions(+), 14 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index 958972e3ee1e..b0332763594e 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -26,6 +26,10 @@ #include "exynos_drm_fb.h" #include "regs-decon5433.h"
+#define DSD_CFG 0x1000 +#define DSD_CFG_GSCL_MODE(gsc, decon, wb) (((wb) << 1) | decon) << (3 + ((gsc) << 1)) +#define DSD_CFG_GSCL_MODE_MASK(gsc) DSD_CFG_GSCL_MODE(gsc, 1, 1) + #define DSD_CFG_MUX 0x1004 #define DSD_CFG_MUX_TE_UNMASK_GLOBAL BIT(13)
@@ -47,6 +51,7 @@ static const char * const decon_clks_name[] = { "pclk_smmu_decon1x", "sclk_decon_vclk", "sclk_decon_eclk", + "dsd" };
struct decon_context { @@ -370,11 +375,40 @@ static void decon_shadow_protect(struct decon_context *ctx, bool protect) protect ? ~0 : 0); }
+static int decon_atomic_check(struct exynos_drm_crtc *crtc, + struct drm_crtc_state *state) +{ + struct decon_context *ctx = to_decon(crtc); + + if (hweight32(state->plane_mask) > WINDOWS_NR - ctx->first_win) + return -EINVAL; + return 0; +} + +static void decon_set_gscl_mode(struct decon_context *ctx) +{ + u32 plane_mask = ctx->crtc.base.state->plane_mask; + struct drm_plane *bplane; + u32 mask = 0, val = 0; + bool decon_id = ctx->out_type & IFTYPE_HDMI; + + drm_for_each_plane_mask(bplane, ctx->drm_dev, plane_mask) { + struct exynos_drm_plane *plane = to_exynos_plane(bplane); + + if (!(plane->capabilities & EXYNOS_DRM_PLANE_CAP_GSCALER)) + continue; + mask |= DSD_CFG_GSCL_MODE_MASK(plane->index); + val |= DSD_CFG_GSCL_MODE(plane->index, decon_id, 0); + } + regmap_update_bits(ctx->sysreg, DSD_CFG, mask, val); +} + static void decon_atomic_begin(struct exynos_drm_crtc *crtc) { struct decon_context *ctx = to_decon(crtc);
decon_shadow_protect(ctx, true); + decon_set_gscl_mode(ctx); }
#define BIT_VAL(x, e, s) (((x) & ((1 << ((e) - (s) + 1)) - 1)) << (s)) @@ -394,6 +428,9 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, dma_addr_t dma_addr = exynos_drm_fb_dma_addr(fb, 0); u32 val;
+ if (plane->ops && plane->ops->update_plane) + plane->ops->update_plane(plane); + if (crtc->base.mode.flags & DRM_MODE_FLAG_INTERLACE) { val = COORDINATE_X(state->crtc.x) | COORDINATE_Y(state->crtc.y / 2); @@ -419,25 +456,38 @@ static void decon_update_plane(struct exynos_drm_crtc *crtc, VIDOSD_Wx_ALPHA_B_F(0x0); writel(val, ctx->addr + DECON_VIDOSDxD(win));
- writel(dma_addr, ctx->addr + DECON_VIDW0xADD0B0(win)); - - val = dma_addr + pitch * state->src.h; - writel(val, ctx->addr + DECON_VIDW0xADD1B0(win)); - - if (!(ctx->out_type & IFTYPE_HDMI)) - val = BIT_VAL(pitch - state->crtc.w * cpp, 27, 14) - | BIT_VAL(state->crtc.w * cpp, 13, 0); - else - val = BIT_VAL(pitch - state->crtc.w * cpp, 29, 15) - | BIT_VAL(state->crtc.w * cpp, 14, 0); - writel(val, ctx->addr + DECON_VIDW0xADD2(win)); - decon_win_set_pixfmt(ctx, plane);
+ if (plane->capabilities & EXYNOS_DRM_PLANE_CAP_GSCALER) { + writel(UPDATE_SCHEME_OTF_PER_FRAME, + ctx->addr + DECON_UPDATE_SCHEME); + decon_set_bits(ctx, DECON_WINCONx(win), + WINCONx_ENLOCAL_F | WINCONx_LOCALSEL_MASK, + WINCONx_ENLOCAL_F | WINCONx_LOCALSEL_F(plane->index)); + } else { + writel(dma_addr, ctx->addr + DECON_VIDW0xADD0B0(win)); + val = dma_addr + pitch * state->src.h; + writel(val, ctx->addr + DECON_VIDW0xADD1B0(win)); + if (!(ctx->out_type & IFTYPE_HDMI)) + val = BIT_VAL(pitch - state->crtc.w * cpp, 27, 14) + | BIT_VAL(state->crtc.w * cpp, 13, 0); + else + val = BIT_VAL(pitch - state->crtc.w * cpp, 29, 15) + | BIT_VAL(state->crtc.w * cpp, 14, 0); + writel(val, ctx->addr + DECON_VIDW0xADD2(win)); + } + /* window enable */ decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, ~0); }
+static void decon_disable_plane(struct exynos_drm_crtc *crtc, + struct exynos_drm_plane *plane) +{ + if (plane->ops && plane->ops->disable_plane) + plane->ops->disable_plane(plane); +} + static void decon_atomic_flush(struct exynos_drm_crtc *crtc) { struct decon_context *ctx = to_decon(crtc); @@ -448,7 +498,7 @@ static void decon_atomic_flush(struct exynos_drm_crtc *crtc) for (; win < WINDOWS_NR; ++win) { if (!readl(ctx->addr + DECON_WINCONx(win)) & WINCONx_ENWIN_F) break; - decon_set_bits(ctx, DECON_WINCONx(win), WINCONx_ENWIN_F, 0); + writel(0, ctx->addr + DECON_WINCONx(win)); }
spin_lock_irqsave(&ctx->vblank_lock, flags); @@ -590,8 +640,10 @@ static const struct exynos_drm_crtc_ops decon_crtc_ops = { .disable = decon_disable, .enable_vblank = decon_enable_vblank, .disable_vblank = decon_disable_vblank, + .atomic_check = decon_atomic_check, .atomic_begin = decon_atomic_begin, .update_plane = decon_update_plane, + .disable_plane = decon_disable_plane, .mode_valid = decon_mode_valid, .atomic_flush = decon_atomic_flush, }; diff --git a/drivers/gpu/drm/exynos/regs-decon5433.h b/drivers/gpu/drm/exynos/regs-decon5433.h index 63db6974bf14..21a1c0bdd10a 100644 --- a/drivers/gpu/drm/exynos/regs-decon5433.h +++ b/drivers/gpu/drm/exynos/regs-decon5433.h @@ -98,6 +98,9 @@ #define VIDOUT_COMMAND_IF (0x2 << 20)
/* WINCONx */ +#define WINCONx_LOCALSEL_F(n) ((n) << 21) +#define WINCONx_LOCALSEL_MASK (0x3 << 21) +#define WINCONx_ENLOCAL_F (0x1 << 20) #define WINCONx_HAWSWP_F (1 << 16) #define WINCONx_WSWP_F (1 << 15) #define WINCONx_BURSTLEN_MASK (0x3 << 10) @@ -184,6 +187,9 @@ #define VIDTCON2_LINEVAL(x) (((x) & 0xfff) << 16) #define VIDTCON2_HOZVAL(x) ((x) & 0xfff)
+/* DECON_UPDATE_SCHEME */ +#define UPDATE_SCHEME_OTF_PER_FRAME (1 << 31) + /* TRIGCON */ #define TRIGCON_TRIGEN_PER_F (1 << 31) #define TRIGCON_TRIGEN_F (1 << 30)
On 25/03/2019 08:13, Andrzej Hajda wrote:
GSCALERs in Exynos5433 have local path to DECON and DECON_TV. They can be used as extra planes with support for non-RGB formats and scaling. To enable it on DECON update_plane and disable_plane callback should be modified. Moreover DSD mux should be set accordingly, and finally atomic_check callback should be used to limit the number of active planes.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com
drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 80 +++++++++++++++---- drivers/gpu/drm/exynos/regs-decon5433.h | 6 ++ 2 files changed, 72 insertions(+), 14 deletions(-)
diff --git a/drivers/gpu/drm/ex
Hi guys!
I am working on DRM bindings conversion to DT schema format and I found this set only partially applied. I merged the DTS patches ("dsd" clock), but I think the driver and bindings were not picked up.
Nevertheless I am going to include the "dsd" clock in the new bindings, so the DTS passes DT schema checks. Let me know if other approach (revert of DTS change) should be taken.
Best regards, Krzysztof
Hi Krzysztof,
22. 2. 7. 01:51에 Krzysztof Kozlowski 이(가) 쓴 글:
On 25/03/2019 08:13, Andrzej Hajda wrote:
GSCALERs in Exynos5433 have local path to DECON and DECON_TV. They can be used as extra planes with support for non-RGB formats and scaling. To enable it on DECON update_plane and disable_plane callback should be modified. Moreover DSD mux should be set accordingly, and finally atomic_check callback should be used to limit the number of active planes.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com
drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 80 +++++++++++++++---- drivers/gpu/drm/exynos/regs-decon5433.h | 6 ++ 2 files changed, 72 insertions(+), 14 deletions(-)
diff --git a/drivers/gpu/drm/ex
Hi guys!
I am working on DRM bindings conversion to DT schema format and I found this set only partially applied. I merged the DTS patches ("dsd" clock), but I think the driver and bindings were not picked up.
Nevertheless I am going to include the "dsd" clock in the new bindings, so the DTS passes DT schema checks. Let me know if other approach (revert of DTS change) should be taken.
Sorry for late response.
As of now, "dsd" is a dead property not used anywhere. This patch series makes real user not to work correctly due to ABI change. How about reverting it until this patch series is merged after fixing the real user problem?
Thanks, Inki Dae
Best regards, Krzysztof
On 02/03/2022 02:00, Inki Dae wrote:
Hi Krzysztof,
- 01:51에 Krzysztof Kozlowski 이(가) 쓴 글:
On 25/03/2019 08:13, Andrzej Hajda wrote:
GSCALERs in Exynos5433 have local path to DECON and DECON_TV. They can be used as extra planes with support for non-RGB formats and scaling. To enable it on DECON update_plane and disable_plane callback should be modified. Moreover DSD mux should be set accordingly, and finally atomic_check callback should be used to limit the number of active planes.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com
drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 80 +++++++++++++++---- drivers/gpu/drm/exynos/regs-decon5433.h | 6 ++ 2 files changed, 72 insertions(+), 14 deletions(-)
diff --git a/drivers/gpu/drm/ex
Hi guys!
I am working on DRM bindings conversion to DT schema format and I found this set only partially applied. I merged the DTS patches ("dsd" clock), but I think the driver and bindings were not picked up.
Nevertheless I am going to include the "dsd" clock in the new bindings, so the DTS passes DT schema checks. Let me know if other approach (revert of DTS change) should be taken.
Sorry for late response.
As of now, "dsd" is a dead property not used anywhere. This patch series makes real user not to work correctly due to ABI change. How about reverting it until this patch series is merged after fixing the real user problem?
The Exynos5433 DECON bindings were already merged by Rob, so someone would need to send a revert. However this does not answer the actual question - whether the "dsd" clock is necessary, whether it is there (routed to DECON). If it is, it should stay in the bindings.
Best regards, Krzysztof
Hi Krzysztof,
On 03.03.2022 17:03, Krzysztof Kozlowski wrote:
On 02/03/2022 02:00, Inki Dae wrote:
- 01:51에 Krzysztof Kozlowski 이(가) 쓴 글:
On 25/03/2019 08:13, Andrzej Hajda wrote:
GSCALERs in Exynos5433 have local path to DECON and DECON_TV. They can be used as extra planes with support for non-RGB formats and scaling. To enable it on DECON update_plane and disable_plane callback should be modified. Moreover DSD mux should be set accordingly, and finally atomic_check callback should be used to limit the number of active planes.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com
drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 80 +++++++++++++++---- drivers/gpu/drm/exynos/regs-decon5433.h | 6 ++ 2 files changed, 72 insertions(+), 14 deletions(-)
diff --git a/drivers/gpu/drm/ex
Hi guys!
I am working on DRM bindings conversion to DT schema format and I found this set only partially applied. I merged the DTS patches ("dsd" clock), but I think the driver and bindings were not picked up.
Nevertheless I am going to include the "dsd" clock in the new bindings, so the DTS passes DT schema checks. Let me know if other approach (revert of DTS change) should be taken.
Sorry for late response.
As of now, "dsd" is a dead property not used anywhere. This patch series makes real user not to work correctly due to ABI change. How about reverting it until this patch series is merged after fixing the real user problem?
The Exynos5433 DECON bindings were already merged by Rob, so someone would need to send a revert. However this does not answer the actual question - whether the "dsd" clock is necessary, whether it is there (routed to DECON). If it is, it should stay in the bindings.
It is routed to DECON hardware and enabling it is needed to make the so called 'local path' (when DECON takes image data directly from the GSCALER hardware block instead of the memory buffer) working.
Best regards
On 03/03/2022 17:11, Marek Szyprowski wrote:
Hi Krzysztof,
On 03.03.2022 17:03, Krzysztof Kozlowski wrote:
On 02/03/2022 02:00, Inki Dae wrote:
- 01:51에 Krzysztof Kozlowski 이(가) 쓴 글:
On 25/03/2019 08:13, Andrzej Hajda wrote:
GSCALERs in Exynos5433 have local path to DECON and DECON_TV. They can be used as extra planes with support for non-RGB formats and scaling. To enable it on DECON update_plane and disable_plane callback should be modified. Moreover DSD mux should be set accordingly, and finally atomic_check callback should be used to limit the number of active planes.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com
drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 80 +++++++++++++++---- drivers/gpu/drm/exynos/regs-decon5433.h | 6 ++ 2 files changed, 72 insertions(+), 14 deletions(-)
diff --git a/drivers/gpu/drm/ex
Hi guys!
I am working on DRM bindings conversion to DT schema format and I found this set only partially applied. I merged the DTS patches ("dsd" clock), but I think the driver and bindings were not picked up.
Nevertheless I am going to include the "dsd" clock in the new bindings, so the DTS passes DT schema checks. Let me know if other approach (revert of DTS change) should be taken.
Sorry for late response.
As of now, "dsd" is a dead property not used anywhere. This patch series makes real user not to work correctly due to ABI change. How about reverting it until this patch series is merged after fixing the real user problem?
The Exynos5433 DECON bindings were already merged by Rob, so someone would need to send a revert. However this does not answer the actual question - whether the "dsd" clock is necessary, whether it is there (routed to DECON). If it is, it should stay in the bindings.
It is routed to DECON hardware and enabling it is needed to make the so called 'local path' (when DECON takes image data directly from the GSCALER hardware block instead of the memory buffer) working.
Awesome, thanks for confirmation! Bindings are good then.
Best regards, Krzysztof
DECON should wait for previous update before starting new one. Otherwise internal registers can be updated in non-atomic, error prone way. This patch fixes occasional occurrences of vblank timeouts on tm2 platform: [ 3167.968742] [CRTC:55:crtc-0] vblank wait timed out [ 3167.987440] WARNING: CPU: 1 PID: 194 at ../drivers/gpu/drm/drm_atomic_helper.c:1423 drm_atomic_helper_wait_for_vblanks.part.9+0x2c0/0x2c8 [ 3168.029990] Modules linked in: [ 3168.047240] CPU: 1 PID: 194 Comm: modetest Tainted: G W 5.0.0-rc1+ #694 [ 3168.069539] Hardware name: Samsung TM2 board (DT) ... [ 3168.453566] Call trace: [ 3168.469705] drm_atomic_helper_wait_for_vblanks.part.9+0x2c0/0x2c8 [ 3168.489983] drm_atomic_helper_commit_tail_rpm+0x60/0x78 [ 3168.509463] commit_tail+0x44/0x78 [ 3168.527053] drm_atomic_helper_commit+0xe8/0x160 [ 3168.546010] drm_atomic_commit+0x48/0x58 [ 3168.564304] drm_atomic_helper_update_plane+0x11c/0x140 [ 3168.584080] __setplane_atomic+0x130/0x150 [ 3168.602799] setplane_internal+0xb0/0x1a8 [ 3168.621493] drm_mode_setplane+0xc4/0x1b8 [ 3168.640219] drm_ioctl_kernel+0x94/0x110 [ 3168.658920] drm_ioctl+0x1c8/0x428 ...
Signed-off-by: Andrzej Hajda a.hajda@samsung.com --- drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 5 +++++ 1 file changed, 5 insertions(+)
diff --git a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c index b0332763594e..09f035f52444 100644 --- a/drivers/gpu/drm/exynos/exynos5433_drm_decon.c +++ b/drivers/gpu/drm/exynos/exynos5433_drm_decon.c @@ -406,6 +406,11 @@ static void decon_set_gscl_mode(struct decon_context *ctx) static void decon_atomic_begin(struct exynos_drm_crtc *crtc) { struct decon_context *ctx = to_decon(crtc); + u32 val; + + /* wait for finish previous updates */ + if (readl_poll_timeout(ctx->addr + DECON_UPDATE, val, !val, 1000, 20000) < 0) + dev_err(ctx->dev, "DECON_UPDATE timeout\n");
decon_shadow_protect(ctx, true); decon_set_gscl_mode(ctx);
GSCALER does not support BGRX8888, instead it supports XBGR8888.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com --- drivers/gpu/drm/exynos/exynos_drm_gsc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c index 28a738a68a82..c7a97d053ab1 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c @@ -502,7 +502,7 @@ static void gsc_src_set_fmt(struct gsc_context *ctx, u32 fmt, bool tiled) case DRM_FORMAT_ARGB8888: cfg |= GSC_IN_XRGB8888; break; - case DRM_FORMAT_BGRX8888: + case DRM_FORMAT_XBGR8888: cfg |= (GSC_IN_XRGB8888 | GSC_IN_RB_SWAP); break; case DRM_FORMAT_YUYV: @@ -689,7 +689,7 @@ static void gsc_dst_set_fmt(struct gsc_context *ctx, u32 fmt, bool tiled) case DRM_FORMAT_XRGB8888: cfg |= (GSC_OUT_XRGB8888 | GSC_OUT_GLOBAL_ALPHA(0xff)); break; - case DRM_FORMAT_BGRX8888: + case DRM_FORMAT_XBGR8888: cfg |= (GSC_OUT_XRGB8888 | GSC_OUT_RB_SWAP); break; case DRM_FORMAT_YUYV: @@ -1197,7 +1197,7 @@ static struct exynos_drm_ipp_funcs ipp_funcs = { };
static const unsigned int gsc_formats[] = { - DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888, DRM_FORMAT_BGRX8888, + DRM_FORMAT_ARGB8888, DRM_FORMAT_XRGB8888, DRM_FORMAT_XBGR8888, DRM_FORMAT_RGB565, DRM_FORMAT_NV12, DRM_FORMAT_NV16, DRM_FORMAT_NV21, DRM_FORMAT_NV61, DRM_FORMAT_UYVY, DRM_FORMAT_VYUY, DRM_FORMAT_YUYV, DRM_FORMAT_YVYU,
YVU420 requires swapping addresses of U and V planes.
Signed-off-by: Andrzej Hajda a.hajda@samsung.com --- drivers/gpu/drm/exynos/exynos_drm_gsc.c | 52 ++++++++++++++++++------- 1 file changed, 37 insertions(+), 15 deletions(-)
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c index c7a97d053ab1..f75739e8bc55 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c +++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c @@ -535,10 +535,8 @@ static void gsc_src_set_fmt(struct gsc_context *ctx, u32 fmt, bool tiled) cfg |= GSC_IN_YUV422_3P; break; case DRM_FORMAT_YUV420: - cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV420_3P); - break; case DRM_FORMAT_YVU420: - cfg |= (GSC_IN_CHROMA_ORDER_CRCB | GSC_IN_YUV420_3P); + cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV420_3P); break; case DRM_FORMAT_NV12: cfg |= (GSC_IN_CHROMA_ORDER_CBCR | GSC_IN_YUV420_2P); @@ -658,13 +656,32 @@ static void gsc_src_set_buf_seq(struct gsc_context *ctx, u32 buf_id, gsc_write(cfg, GSC_IN_BASE_ADDR_CR_MASK); }
+/* returns HW plane index based on pixel format */ +static int gsc_hw_plane_index(int index, u32 format) +{ + switch (format) { + case DRM_FORMAT_YVU420: + switch (index) { + case 0: return 0; + case 1: return 2; + case 2: return 1; + } + default: + return index; + } +} + static void gsc_src_set_addr(struct gsc_context *ctx, u32 buf_id, struct exynos_drm_ipp_buffer *buf) { + int idx; + /* address register set */ gsc_write(buf->dma_addr[0], GSC_IN_BASE_ADDR_Y(buf_id)); - gsc_write(buf->dma_addr[1], GSC_IN_BASE_ADDR_CB(buf_id)); - gsc_write(buf->dma_addr[2], GSC_IN_BASE_ADDR_CR(buf_id)); + idx = gsc_hw_plane_index(1, buf->format->format); + gsc_write(buf->dma_addr[idx], GSC_IN_BASE_ADDR_CB(buf_id)); + idx = gsc_hw_plane_index(2, buf->format->format); + gsc_write(buf->dma_addr[idx], GSC_IN_BASE_ADDR_CR(buf_id));
gsc_src_set_buf_seq(ctx, buf_id, true); } @@ -722,10 +739,8 @@ static void gsc_dst_set_fmt(struct gsc_context *ctx, u32 fmt, bool tiled) cfg |= GSC_OUT_YUV422_3P; break; case DRM_FORMAT_YUV420: - cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV420_3P); - break; case DRM_FORMAT_YVU420: - cfg |= (GSC_OUT_CHROMA_ORDER_CRCB | GSC_OUT_YUV420_3P); + cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV420_3P); break; case DRM_FORMAT_NV12: cfg |= (GSC_OUT_CHROMA_ORDER_CBCR | GSC_OUT_YUV420_2P); @@ -985,10 +1000,13 @@ static void gsc_dst_set_buf_seq(struct gsc_context *ctx, u32 buf_id, static void gsc_dst_set_addr(struct gsc_context *ctx, u32 buf_id, struct exynos_drm_ipp_buffer *buf) { - /* address register set */ + int i; + gsc_write(buf->dma_addr[0], GSC_OUT_BASE_ADDR_Y(buf_id)); - gsc_write(buf->dma_addr[1], GSC_OUT_BASE_ADDR_CB(buf_id)); - gsc_write(buf->dma_addr[2], GSC_OUT_BASE_ADDR_CR(buf_id)); + i = gsc_hw_plane_index(1, buf->format->format); + gsc_write(buf->dma_addr[i], GSC_OUT_BASE_ADDR_CB(buf_id)); + i = gsc_hw_plane_index(2, buf->format->format); + gsc_write(buf->dma_addr[i], GSC_OUT_BASE_ADDR_CR(buf_id));
gsc_dst_set_buf_seq(ctx, buf_id, true); } @@ -1238,10 +1256,14 @@ static void gsc_update_plane(struct exynos_drm_plane *plane) gsc_write(BIT(16) * cropped_w / scaled_w, GSC_MAIN_H_RATIO); gsc_write(BIT(16) * cropped_h / scaled_h, GSC_MAIN_V_RATIO); gsc_write(exynos_drm_fb_dma_addr(fb, 0), GSC_IN_BASE_ADDR_Y(0)); - if (fb->format->num_planes > 1) - gsc_write(exynos_drm_fb_dma_addr(fb, 1), GSC_IN_BASE_ADDR_CB(0)); - if (fb->format->num_planes > 2) - gsc_write(exynos_drm_fb_dma_addr(fb, 2), GSC_IN_BASE_ADDR_CR(0)); + if (fb->format->num_planes > 1) { + i = gsc_hw_plane_index(1, fb->format->format); + gsc_write(exynos_drm_fb_dma_addr(fb, i), GSC_IN_BASE_ADDR_CB(0)); + } + if (fb->format->num_planes > 2) { + i = gsc_hw_plane_index(2, fb->format->format); + gsc_write(exynos_drm_fb_dma_addr(fb, i), GSC_IN_BASE_ADDR_CR(0)); + } gsc_src_set_fmt(ctx, fb->format->format, fb->modifier); gsc_write(scaled_w * scaled_h, GSC_SMART_IF_PIXEL_NUM); gsc_write(GSC_ENABLE_SFR_UPDATE | GSC_ENABLE_ON, GSC_ENABLE);
Hi Andrzej,
19. 3. 25. 오후 4:13에 Andrzej Hajda 이(가) 쓴 글:
Hi Inki,
GSCALERs in Exynos SoCs support conversion between wide range of image formats, plus scaling and rotation. Driver already supports mem2mem mode - via ExynosDRM IPP framework. This patchset adds support for mem to display mode - framebuffers can be converted, scaled and send directly to Display Controller. From DRM framework's point of view every GSCALER exposes drm_plane which can be connected to display controller (display panel or TV). The feature is not well documented so the development was quite difficult - a process of trial and error, vendor code analysis, guessing from datasheets. Hopefully most of the issues were solved. I have developed and tested it on TM2 device with panel and TV paths.
The patchset contains three parts:
- Preparatory patches - mostly cleanup and refactoring of drm_crtc and drm_plane related structures, to allow usage of planes which are not physically bound to crtcs (01-13).
- Adding local path support to GSCALER and DECON (14-20).
- Few fixes of bugs existing already in the code but discovered due to added local path support (21-23).
The patchset is based on exynos_drm_next plus my patchset adding zpos to DECON and FIMD - 'drm/exynos: add support for dynamic zpos in DECON and FIMD' - it is required to allow set z-pos position of GSCALER planes.
As for this, we had a discussion before, https://patchwork.kernel.org/cover/10715521/
And the last comment I left was, "I know. Your patch will show that plane order is changed by changing mapping of plane from one window to another window regardless of overlay priority change support. I'm not clear but seems maybe we could do more something with your patch even though DECON/FIMD have limit. So I will enqueue your patch until real user is fixed."
Did you fix TDM module of Tizen which is a real user? Without any modification of the TDM module, the user doesn't work.
To simplify tests I have also created branch containing all required patches: Repo: https://git.tizen.org/cgit/platform/kernel/linux-exynos Branch: sandbox/ahajda/dev/exynos-drm-local-path
This is v2 version of the patchset. In this version I have moved code setting cursor plane in crtc to separate patch together with code disabling fast cursor updates - hardware does not support it. To keep bisectability DTS patches should be applied before subsequent ones. It is rebased on today's exynos-drm-next.
Please be aware that DTS patches has been already applied to samsung-soc tree, I left them here to simplify testing on exynos-drm-next, which is not in sync with samsung-soc, for this reason I have moved them on the beginning of the patchset.
Got it. I can test it by doing cherry-pick these two patches.
Thanks, Inki Dae
Regards Andrzej
Andrzej Hajda (24): arm64: dts: exynos: configure GSCALER related clocks arm64: dts: exynos: add DSD/GSD clocks to DECONs and GSCALERs drm/exynos: remove exynos_drm_plane.h header drm/exynos: remove spare macro drm/exynos: drop exynos_drm_plane_config structure drm/exynos: add exynos_drm_crtc_init function drm/exynos/decon5433: embed exynos_drm_crtc directly into context drm/exynos/decon7: embed exynos_drm_crtc directly into context drm/exynos/fimd: embed exynos_drm_crtc directly into context drm/exynos/mixer: embed exynos_drm_crtc directly into context drm/exynos/vidi: embed exynos_drm_crtc directly into context drm/exynos: remove standalone exynos_drm_crtc leftovers drm/exynos/vidi: remove encoder_to_vidi helper drm/exynos: unify plane type assignment drm/exynos: set primary plane in exynos_drm_crtc_init drm/exynos: set cursor plane in exynos_drm_crtc_init drm/exynos: add plane update/disable callbacks for planes drm/exynos: add GSCALER plane capability drm/exynos/gscaler: fix id assignement drm/exynos/gscaler: add local path support drm/exynos/decon5433: add local path support drm/exynos/decon5433: wait for finish previous update drm/exynos/gscaler: change supported color format BGRX8888 to XBGR8888 drm/exynos/gscaler: fix handling YVU420 pixel format
.../dts/exynos/exynos5433-tm2-common.dtsi | 6 + arch/arm64/boot/dts/exynos/exynos5433-tm2.dts | 6 +- arch/arm64/boot/dts/exynos/exynos5433.dtsi | 25 +- drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 162 ++++++++----- drivers/gpu/drm/exynos/exynos7_drm_decon.c | 66 +++-- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 46 ++-- drivers/gpu/drm/exynos/exynos_drm_crtc.h | 7 +- drivers/gpu/drm/exynos/exynos_drm_drv.c | 1 - drivers/gpu/drm/exynos/exynos_drm_drv.h | 50 ++-- drivers/gpu/drm/exynos/exynos_drm_fb.c | 10 +- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 85 +++---- drivers/gpu/drm/exynos/exynos_drm_gsc.c | 229 ++++++++++++++---- drivers/gpu/drm/exynos/exynos_drm_plane.c | 84 ++++--- drivers/gpu/drm/exynos/exynos_drm_plane.h | 14 -- drivers/gpu/drm/exynos/exynos_drm_vidi.c | 48 ++-- drivers/gpu/drm/exynos/exynos_mixer.c | 95 +++----- drivers/gpu/drm/exynos/regs-decon5433.h | 6 + drivers/gpu/drm/exynos/regs-gsc.h | 6 + 18 files changed, 538 insertions(+), 408 deletions(-) delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_plane.h
On 26.03.2019 09:45, Inki Dae wrote:
Hi Andrzej,
- 오후 4:13에 Andrzej Hajda 이(가) 쓴 글:
Hi Inki,
GSCALERs in Exynos SoCs support conversion between wide range of image formats, plus scaling and rotation. Driver already supports mem2mem mode - via ExynosDRM IPP framework. This patchset adds support for mem to display mode - framebuffers can be converted, scaled and send directly to Display Controller. From DRM framework's point of view every GSCALER exposes drm_plane which can be connected to display controller (display panel or TV). The feature is not well documented so the development was quite difficult - a process of trial and error, vendor code analysis, guessing from datasheets. Hopefully most of the issues were solved. I have developed and tested it on TM2 device with panel and TV paths.
The patchset contains three parts:
- Preparatory patches - mostly cleanup and refactoring of drm_crtc and drm_plane related structures, to allow usage of planes which are not physically bound to crtcs (01-13).
- Adding local path support to GSCALER and DECON (14-20).
- Few fixes of bugs existing already in the code but discovered due to added local path support (21-23).
The patchset is based on exynos_drm_next plus my patchset adding zpos to DECON and FIMD - 'drm/exynos: add support for dynamic zpos in DECON and FIMD' - it is required to allow set z-pos position of GSCALER planes.
As for this, we had a discussion before, https://patchwork.kernel.org/cover/10715521/
And the last comment I left was, "I know. Your patch will show that plane order is changed by changing mapping of plane from one window to another window regardless of overlay priority change support. I'm not clear but seems maybe we could do more something with your patch even though DECON/FIMD have limit. So I will enqueue your patch until real user is fixed."
Did you fix TDM module of Tizen which is a real user? Without any modification of the TDM module, the user doesn't work.
Last time I have tried to work with Tizen on tm2 the whole system was very unstable, the display was black even without my patches, so I gave up. If you want to fix TDM in Tizen anyway I can try it again, the only problem is that I am currently busy with other tasks, so it can take some time to look at Tizen again.
Regards
Andrzej
To simplify tests I have also created branch containing all required patches: Repo: https://git.tizen.org/cgit/platform/kernel/linux-exynos Branch: sandbox/ahajda/dev/exynos-drm-local-path
This is v2 version of the patchset. In this version I have moved code setting cursor plane in crtc to separate patch together with code disabling fast cursor updates - hardware does not support it. To keep bisectability DTS patches should be applied before subsequent ones. It is rebased on today's exynos-drm-next.
Please be aware that DTS patches has been already applied to samsung-soc tree, I left them here to simplify testing on exynos-drm-next, which is not in sync with samsung-soc, for this reason I have moved them on the beginning of the patchset.
Got it. I can test it by doing cherry-pick these two patches.
Thanks, Inki Dae
Regards Andrzej
Andrzej Hajda (24): arm64: dts: exynos: configure GSCALER related clocks arm64: dts: exynos: add DSD/GSD clocks to DECONs and GSCALERs drm/exynos: remove exynos_drm_plane.h header drm/exynos: remove spare macro drm/exynos: drop exynos_drm_plane_config structure drm/exynos: add exynos_drm_crtc_init function drm/exynos/decon5433: embed exynos_drm_crtc directly into context drm/exynos/decon7: embed exynos_drm_crtc directly into context drm/exynos/fimd: embed exynos_drm_crtc directly into context drm/exynos/mixer: embed exynos_drm_crtc directly into context drm/exynos/vidi: embed exynos_drm_crtc directly into context drm/exynos: remove standalone exynos_drm_crtc leftovers drm/exynos/vidi: remove encoder_to_vidi helper drm/exynos: unify plane type assignment drm/exynos: set primary plane in exynos_drm_crtc_init drm/exynos: set cursor plane in exynos_drm_crtc_init drm/exynos: add plane update/disable callbacks for planes drm/exynos: add GSCALER plane capability drm/exynos/gscaler: fix id assignement drm/exynos/gscaler: add local path support drm/exynos/decon5433: add local path support drm/exynos/decon5433: wait for finish previous update drm/exynos/gscaler: change supported color format BGRX8888 to XBGR8888 drm/exynos/gscaler: fix handling YVU420 pixel format
.../dts/exynos/exynos5433-tm2-common.dtsi | 6 + arch/arm64/boot/dts/exynos/exynos5433-tm2.dts | 6 +- arch/arm64/boot/dts/exynos/exynos5433.dtsi | 25 +- drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 162 ++++++++----- drivers/gpu/drm/exynos/exynos7_drm_decon.c | 66 +++-- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 46 ++-- drivers/gpu/drm/exynos/exynos_drm_crtc.h | 7 +- drivers/gpu/drm/exynos/exynos_drm_drv.c | 1 - drivers/gpu/drm/exynos/exynos_drm_drv.h | 50 ++-- drivers/gpu/drm/exynos/exynos_drm_fb.c | 10 +- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 85 +++---- drivers/gpu/drm/exynos/exynos_drm_gsc.c | 229 ++++++++++++++---- drivers/gpu/drm/exynos/exynos_drm_plane.c | 84 ++++--- drivers/gpu/drm/exynos/exynos_drm_plane.h | 14 -- drivers/gpu/drm/exynos/exynos_drm_vidi.c | 48 ++-- drivers/gpu/drm/exynos/exynos_mixer.c | 95 +++----- drivers/gpu/drm/exynos/regs-decon5433.h | 6 + drivers/gpu/drm/exynos/regs-gsc.h | 6 + 18 files changed, 538 insertions(+), 408 deletions(-) delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_plane.h
19. 3. 26. 오후 10:51에 Andrzej Hajda 이(가) 쓴 글:
On 26.03.2019 09:45, Inki Dae wrote:
Hi Andrzej,
- 오후 4:13에 Andrzej Hajda 이(가) 쓴 글:
Hi Inki,
GSCALERs in Exynos SoCs support conversion between wide range of image formats, plus scaling and rotation. Driver already supports mem2mem mode - via ExynosDRM IPP framework. This patchset adds support for mem to display mode - framebuffers can be converted, scaled and send directly to Display Controller. From DRM framework's point of view every GSCALER exposes drm_plane which can be connected to display controller (display panel or TV). The feature is not well documented so the development was quite difficult - a process of trial and error, vendor code analysis, guessing from datasheets. Hopefully most of the issues were solved. I have developed and tested it on TM2 device with panel and TV paths.
The patchset contains three parts:
- Preparatory patches - mostly cleanup and refactoring of drm_crtc and drm_plane related structures, to allow usage of planes which are not physically bound to crtcs (01-13).
- Adding local path support to GSCALER and DECON (14-20).
- Few fixes of bugs existing already in the code but discovered due to added local path support (21-23).
The patchset is based on exynos_drm_next plus my patchset adding zpos to DECON and FIMD - 'drm/exynos: add support for dynamic zpos in DECON and FIMD' - it is required to allow set z-pos position of GSCALER planes.
As for this, we had a discussion before, https://patchwork.kernel.org/cover/10715521/
And the last comment I left was, "I know. Your patch will show that plane order is changed by changing mapping of plane from one window to another window regardless of overlay priority change support. I'm not clear but seems maybe we could do more something with your patch even though DECON/FIMD have limit. So I will enqueue your patch until real user is fixed."
Did you fix TDM module of Tizen which is a real user? Without any modification of the TDM module, the user doesn't work.
Last time I have tried to work with Tizen on tm2 the whole system was very unstable, the display was black even without my patches, so I gave up. If you want to fix TDM in Tizen anyway I can try it again, the only problem is that I am currently busy with other tasks, so it can take some time to look at Tizen again.
I tested Tizen platform and it worked - I could see launcher UI on screen. The version I used was tizen-unified_20190322.1_mobile-wayland-armv7l-tm2.tar. Could you try it again?
Ps. I know you are busy with other works but DRM community wants to take care of all real users so we have to follow this. so new ABI or any changes cannot be upstreamed without real user who uses this.
Thanks, Inki Dae
Regards
Andrzej
To simplify tests I have also created branch containing all required patches: Repo: https://git.tizen.org/cgit/platform/kernel/linux-exynos Branch: sandbox/ahajda/dev/exynos-drm-local-path
This is v2 version of the patchset. In this version I have moved code setting cursor plane in crtc to separate patch together with code disabling fast cursor updates - hardware does not support it. To keep bisectability DTS patches should be applied before subsequent ones. It is rebased on today's exynos-drm-next.
Please be aware that DTS patches has been already applied to samsung-soc tree, I left them here to simplify testing on exynos-drm-next, which is not in sync with samsung-soc, for this reason I have moved them on the beginning of the patchset.
Got it. I can test it by doing cherry-pick these two patches.
Thanks, Inki Dae
Regards Andrzej
Andrzej Hajda (24): arm64: dts: exynos: configure GSCALER related clocks arm64: dts: exynos: add DSD/GSD clocks to DECONs and GSCALERs drm/exynos: remove exynos_drm_plane.h header drm/exynos: remove spare macro drm/exynos: drop exynos_drm_plane_config structure drm/exynos: add exynos_drm_crtc_init function drm/exynos/decon5433: embed exynos_drm_crtc directly into context drm/exynos/decon7: embed exynos_drm_crtc directly into context drm/exynos/fimd: embed exynos_drm_crtc directly into context drm/exynos/mixer: embed exynos_drm_crtc directly into context drm/exynos/vidi: embed exynos_drm_crtc directly into context drm/exynos: remove standalone exynos_drm_crtc leftovers drm/exynos/vidi: remove encoder_to_vidi helper drm/exynos: unify plane type assignment drm/exynos: set primary plane in exynos_drm_crtc_init drm/exynos: set cursor plane in exynos_drm_crtc_init drm/exynos: add plane update/disable callbacks for planes drm/exynos: add GSCALER plane capability drm/exynos/gscaler: fix id assignement drm/exynos/gscaler: add local path support drm/exynos/decon5433: add local path support drm/exynos/decon5433: wait for finish previous update drm/exynos/gscaler: change supported color format BGRX8888 to XBGR8888 drm/exynos/gscaler: fix handling YVU420 pixel format
.../dts/exynos/exynos5433-tm2-common.dtsi | 6 + arch/arm64/boot/dts/exynos/exynos5433-tm2.dts | 6 +- arch/arm64/boot/dts/exynos/exynos5433.dtsi | 25 +- drivers/gpu/drm/exynos/exynos5433_drm_decon.c | 162 ++++++++----- drivers/gpu/drm/exynos/exynos7_drm_decon.c | 66 +++-- drivers/gpu/drm/exynos/exynos_drm_crtc.c | 46 ++-- drivers/gpu/drm/exynos/exynos_drm_crtc.h | 7 +- drivers/gpu/drm/exynos/exynos_drm_drv.c | 1 - drivers/gpu/drm/exynos/exynos_drm_drv.h | 50 ++-- drivers/gpu/drm/exynos/exynos_drm_fb.c | 10 +- drivers/gpu/drm/exynos/exynos_drm_fimd.c | 85 +++---- drivers/gpu/drm/exynos/exynos_drm_gsc.c | 229 ++++++++++++++---- drivers/gpu/drm/exynos/exynos_drm_plane.c | 84 ++++--- drivers/gpu/drm/exynos/exynos_drm_plane.h | 14 -- drivers/gpu/drm/exynos/exynos_drm_vidi.c | 48 ++-- drivers/gpu/drm/exynos/exynos_mixer.c | 95 +++----- drivers/gpu/drm/exynos/regs-decon5433.h | 6 + drivers/gpu/drm/exynos/regs-gsc.h | 6 + 18 files changed, 538 insertions(+), 408 deletions(-) delete mode 100644 drivers/gpu/drm/exynos/exynos_drm_plane.h
dri-devel@lists.freedesktop.org