Gamma correction is optional and can be used to adjust the color output values to match the gamut of a particular TFT LCD panel Errata: Gamma_R, Gamma_G and Gamma_B registers are little-endian registers while the rest of the address-space in 2D-ACE is big-endian. Workaround: Split the DCU regs into "regs", "palette", "gamma" and "cursor". Create a second regmap for gamma memory space using little endian. Suggested-by: Stefan Agner <stefan@xxxxxxxx> Signed-off-by: Meng Yi <meng.yi@xxxxxxx> --- Changes since V1: -created a second regmap for gamma -updated the DCU DT binding -removed Kconfig for gamma and enable gamma when valid data filled. --- .../devicetree/bindings/display/fsl,dcu.txt | 15 +++++++++- drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c | 32 ++++++++++++++++++++ drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c | 35 +++++++++++++++++++++- drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h | 7 +++++ 4 files changed, 87 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/display/fsl,dcu.txt b/Documentation/devicetree/bindings/display/fsl,dcu.txt index 63ec2a6..e3cf2de 100644 --- a/Documentation/devicetree/bindings/display/fsl,dcu.txt +++ b/Documentation/devicetree/bindings/display/fsl,dcu.txt @@ -6,6 +6,15 @@ Required properties: * "fsl,vf610-dcu". - reg: Address and length of the register set for dcu. + Parameter Address Range + + Register address space 0x0000 – 0x1FFF + Palette/Tile address space 0x2000 – 0x3FFF + Gamma_R address space 0x4000 – 0x43FF + Gamma_G address space 0x4400 – 0x47FF + Gamma_B address space 0x4800 – 0x4BFF + Cursor address space 0x4C00 – 0x4FFF + - clocks: Handle to "dcu" and "pix" clock (in the order below) This can be the same clock (e.g. LS1021a) See ../clocks/clock-bindings.txt for details. @@ -20,7 +29,11 @@ Optional properties: Examples: dcu: dcu@2ce0000 { compatible = "fsl,ls1021a-dcu"; - reg = <0x0 0x2ce0000 0x0 0x10000>; + reg = <0x0 0x2ce0000 0x0 0x2000>, + <0x0 0x2ce2000 0x0 0x2000>, + <0x0 0x2ce4000 0x0 0xc00>, + <0x0 0x2ce4c00 0x0 0x400>; + reg-names = "regs", "palette", "gamma", "cursor"; clocks = <&platform_clk 0>, <&platform_clk 0>; clock-names = "dcu", "pix"; big-endian; diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c index 3371635..4ff969b 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_crtc.c @@ -22,6 +22,30 @@ #include "fsl_dcu_drm_drv.h" #include "fsl_dcu_drm_plane.h" +static void fsl_crtc_gamma_set(struct drm_crtc *crtc, struct drm_color_lut *lut, + uint32_t size) +{ + struct fsl_dcu_drm_device *fsl_dev = crtc->dev->dev_private; + unsigned int i; + + if (crtc->state->gamma_lut->data) { + for (i = 0; i < size; i++) { + regmap_write(fsl_dev->regmap_gamma, FSL_GAMMA_R + 4 * i, + lut[i].red); + regmap_write(fsl_dev->regmap_gamma, FSL_GAMMA_G + 4 * i, + lut[i].green); + regmap_write(fsl_dev->regmap_gamma, FSL_GAMMA_B + 4 * i, + lut[i].blue); + } + + regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE, + DCU_MODE_EN_GAMMA_MASK, + DCU_MODE_GAMMA_ENABLE); + } else + regmap_update_bits(fsl_dev->regmap, DCU_DCU_MODE, + DCU_MODE_EN_GAMMA_MASK, 0); +} + static void fsl_dcu_drm_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_crtc_state *old_crtc_state) { @@ -37,6 +61,10 @@ static void fsl_dcu_drm_crtc_atomic_flush(struct drm_crtc *crtc, drm_crtc_send_vblank_event(crtc, event); spin_unlock_irq(&crtc->dev->event_lock); } + + if (crtc->state->color_mgmt_changed && crtc->state->gamma_lut) + fsl_crtc_gamma_set(crtc, (struct drm_color_lut *) + crtc->state->gamma_lut->data, 256); } static void fsl_dcu_drm_disable_crtc(struct drm_crtc *crtc) @@ -135,6 +163,7 @@ static const struct drm_crtc_funcs fsl_dcu_drm_crtc_funcs = { .page_flip = drm_atomic_helper_page_flip, .reset = drm_atomic_helper_crtc_reset, .set_config = drm_atomic_helper_set_config, + .gamma_set = drm_atomic_helper_legacy_gamma_set, }; int fsl_dcu_drm_crtc_create(struct fsl_dcu_drm_device *fsl_dev) @@ -158,5 +187,8 @@ int fsl_dcu_drm_crtc_create(struct fsl_dcu_drm_device *fsl_dev) drm_crtc_helper_add(crtc, &fsl_dcu_drm_crtc_helper_funcs); + drm_crtc_enable_color_mgmt(crtc, 0, false, 256); + drm_mode_crtc_set_gamma_size(crtc, 256); + return 0; } diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c index 092aaec..e662890 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.c @@ -48,6 +48,20 @@ static const struct regmap_config fsl_dcu_regmap_config = { .volatile_reg = fsl_dcu_drm_is_volatile_reg, }; +/* + * force using little endian here since ls1021a's gamma regs are little + * endian while the other regs are big endian, and all vf610s's regs + * are little endian + */ +static const struct regmap_config fsl_dcu_regmap_gamma_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, + .val_format_endian = REGMAP_ENDIAN_LITTLE, + + .volatile_reg = fsl_dcu_drm_is_volatile_reg, +}; + static int fsl_dcu_drm_irq_init(struct drm_device *dev) { struct fsl_dcu_drm_device *fsl_dev = dev->dev_private; @@ -327,7 +341,7 @@ static int fsl_dcu_drm_probe(struct platform_device *pdev) struct drm_device *drm; struct device *dev = &pdev->dev; struct resource *res; - void __iomem *base; + void __iomem *base, *base_gamma; struct drm_driver *driver = &fsl_dcu_drm_driver; struct clk *pix_clk_in; char pix_clk_name[32]; @@ -370,6 +384,25 @@ static int fsl_dcu_drm_probe(struct platform_device *pdev) return PTR_ERR(fsl_dev->regmap); } + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gamma"); + if (!res) { + dev_err(dev, "could not get gamma memory resource\n"); + return -ENODEV; + } + + base_gamma = devm_ioremap_resource(dev, res); + if (IS_ERR(base_gamma)) { + ret = PTR_ERR(base_gamma); + return ret; + } + + fsl_dev->regmap_gamma = devm_regmap_init_mmio(dev, base_gamma, + &fsl_dcu_regmap_gamma_config); + if (IS_ERR(fsl_dev->regmap_gamma)) { + dev_err(dev, "regmap_gamma init failed\n"); + return PTR_ERR(fsl_dev->regmap_gamma); + } + fsl_dev->clk = devm_clk_get(dev, "dcu"); if (IS_ERR(fsl_dev->clk)) { dev_err(dev, "failed to get dcu clock\n"); diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h index 3b371fe7..2610b6c 100644 --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_drv.h @@ -25,6 +25,8 @@ #define DCU_MODE_NORMAL 1 #define DCU_MODE_TEST 2 #define DCU_MODE_COLORBAR 3 +#define DCU_MODE_EN_GAMMA_MASK 0x04 +#define DCU_MODE_GAMMA_ENABLE BIT(2) #define DCU_BGND 0x0014 #define DCU_BGND_R(x) ((x) << 16) @@ -165,6 +167,10 @@ #define VF610_LAYER_REG_NUM 9 #define LS1021A_LAYER_REG_NUM 10 +#define FSL_GAMMA_R 0x000 +#define FSL_GAMMA_G 0x400 +#define FSL_GAMMA_B 0x800 + struct clk; struct device; struct drm_device; @@ -182,6 +188,7 @@ struct fsl_dcu_drm_device { struct device *dev; struct device_node *np; struct regmap *regmap; + struct regmap *regmap_gamma; int irq; struct clk *clk; struct clk *pix_clk; -- 2.1.0.27.g96db324 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel