[RFC/WIP] drm/rockchip: Support CRTC gamma LUT

Ezequiel Garcia ezequiel at collabora.com
Tue Jun 18 13:36:01 UTC 2019


On Thu, 2019-06-13 at 15:36 -0400, Ilia Mirkin wrote:
> Note that userspace may provide any size of gamma lut. Have a look at
> i915/intel_color.c:intel_color_check which filters out only the
> allowed sizes. Consider having a special allowance for 256-sized LUTs
> since that's what most legacy userspace will set, and it seems like a
> waste to create a 10-bit LUT for RGBA8 color.
> 

Right. I will add a check for the gamma lut size.

Unfortunately, this hardware seems to only support 10-bit, 1024-sized LUTs.

The spec does mention a support 8-bit, 256-entries, but it's not at all
clear how configure that.

Thanks for the feedback,
Ezequiel

>   -ilia
> 
> On Thu, Jun 13, 2019 at 3:23 PM Ezequiel Garcia <ezequiel at collabora.com> wrote:
> > Add CRTC gamma LUT configuration on RK3288 and RK3399.
> > 
> > Signed-off-by: Ezequiel Garcia <ezequiel at collabora.com>
> > ---
> > This patch seems to work well on RK3288, but produces
> > a distorted output on RK3399. I was hoping
> > someone could have any idea, so we can support both
> > platforms.
> > 
> >  drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 87 +++++++++++++++++++++
> >  drivers/gpu/drm/rockchip/rockchip_drm_vop.h |  2 +
> >  drivers/gpu/drm/rockchip/rockchip_vop_reg.c |  4 +
> >  drivers/gpu/drm/rockchip/rockchip_vop_reg.h |  1 +
> >  4 files changed, 94 insertions(+)
> > 
> > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
> > index 12ed5265a90b..8381679c1045 100644
> > --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
> > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
> > @@ -38,6 +38,8 @@
> >  #include "rockchip_drm_vop.h"
> >  #include "rockchip_rgb.h"
> > 
> > +#define VOP_GAMMA_LUT_SIZE 1024
> > +
> >  #define VOP_WIN_SET(vop, win, name, v) \
> >                 vop_reg_set(vop, &win->phy->name, win->base, ~0, v, #name)
> >  #define VOP_SCL_SET(vop, win, name, v) \
> > @@ -137,6 +139,7 @@ struct vop {
> > 
> >         uint32_t *regsbak;
> >         void __iomem *regs;
> > +       void __iomem *lut_regs;
> > 
> >         /* physical map length of vop register */
> >         uint32_t len;
> > @@ -1153,6 +1156,46 @@ static void vop_wait_for_irq_handler(struct vop *vop)
> >         synchronize_irq(vop->irq);
> >  }
> > 
> > +static bool vop_dsp_lut_is_enable(struct vop *vop)
> > +{
> > +       return vop_read_reg(vop, 0, &vop->data->common->dsp_lut_en);
> > +}
> > +
> > +static void vop_crtc_gamma_set(struct vop *vop, struct drm_crtc *crtc,
> > +                              struct drm_crtc_state *state)
> > +{
> > +       struct drm_color_lut *lut;
> > +       int i, idle, ret;
> > +
> > +       if (!state->gamma_lut)
> > +               return;
> > +       lut = state->gamma_lut->data;
> > +
> > +       spin_lock(&vop->reg_lock);
> > +       VOP_REG_SET(vop, common, dsp_lut_en, 0);
> > +       vop_cfg_done(vop);
> > +       spin_unlock(&vop->reg_lock);
> > +
> > +       ret = readx_poll_timeout(vop_dsp_lut_is_enable, vop,
> > +                          idle, !idle, 5, 10 * 30000);
> > +       if (ret)
> > +               return;
> > +
> > +       spin_lock(&vop->reg_lock);
> > +       for (i = 0; i < crtc->gamma_size; i++) {
> > +               u32 word;
> > +
> > +               word = (drm_color_lut_extract(lut[i].red, 10) << 20) |
> > +                      (drm_color_lut_extract(lut[i].green, 10) << 10) |
> > +                       drm_color_lut_extract(lut[i].blue, 10);
> > +               writel(word, vop->lut_regs + i * 4);
> > +       }
> > +
> > +       VOP_REG_SET(vop, common, dsp_lut_en, 1);
> > +       vop_cfg_done(vop);
> > +       spin_unlock(&vop->reg_lock);
> > +}
> > +
> >  static void vop_crtc_atomic_flush(struct drm_crtc *crtc,
> >                                   struct drm_crtc_state *old_crtc_state)
> >  {
> > @@ -1201,6 +1244,9 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc,
> >                 drm_flip_work_queue(&vop->fb_unref_work, old_plane_state->fb);
> >                 set_bit(VOP_PENDING_FB_UNREF, &vop->pending);
> >         }
> > +
> > +       if (vop->lut_regs && crtc->state->color_mgmt_changed)
> > +               vop_crtc_gamma_set(vop, crtc, crtc->state);
> >  }
> > 
> >  static const struct drm_crtc_helper_funcs vop_crtc_helper_funcs = {
> > @@ -1323,6 +1369,7 @@ static const struct drm_crtc_funcs vop_crtc_funcs = {
> >         .disable_vblank = vop_crtc_disable_vblank,
> >         .set_crc_source = vop_crtc_set_crc_source,
> >         .verify_crc_source = vop_crtc_verify_crc_source,
> > +       .gamma_set = drm_atomic_helper_legacy_gamma_set,
> >  };
> > 
> >  static void vop_fb_unref_worker(struct drm_flip_work *work, void *val)
> > @@ -1480,6 +1527,8 @@ static int vop_create_crtc(struct vop *vop)
> >                 goto err_cleanup_planes;
> > 
> >         drm_crtc_helper_add(crtc, &vop_crtc_helper_funcs);
> > +       drm_mode_crtc_set_gamma_size(crtc, VOP_GAMMA_LUT_SIZE);
> > +       drm_crtc_enable_color_mgmt(crtc, 0, false, VOP_GAMMA_LUT_SIZE);
> > 
> >         /*
> >          * Create drm_planes for overlay windows with possible_crtcs restricted
> > @@ -1744,6 +1793,41 @@ int rockchip_drm_wait_vact_end(struct drm_crtc *crtc, unsigned int mstimeout)
> >  }
> >  EXPORT_SYMBOL(rockchip_drm_wait_vact_end);
> > 
> > +static int vop_gamma_lut_request(struct device *dev,
> > +                                struct resource *res, struct vop *vop)
> > +{
> > +       resource_size_t offset = vop->data->gamma_lut_addr_off;
> > +       resource_size_t size = VOP_GAMMA_LUT_SIZE * 4;
> > +
> > +       /*
> > +        * Some SoCs (e.g. RK3288) have the gamma LUT address after
> > +        * the MMU registers, which means we can't request and ioremap
> > +        * the entire register set. Other (e.g. RK3399) have gamma LUT
> > +        * address before MMU.
> > +        *
> > +        * Therefore, we need to request and ioremap those that haven't
> > +        * been already.
> > +        */
> > +       if (vop->len >= (offset + size)) {
> > +               vop->lut_regs = vop->regs + offset;
> > +               return 0;
> > +       }
> > +
> > +       if (!devm_request_mem_region(dev, res->start + offset,
> > +                                    size, dev_name(dev))) {
> > +               dev_warn(dev, "can't request gamma lut region\n");
> > +               return -EBUSY;
> > +       }
> > +
> > +       vop->lut_regs = devm_ioremap(dev, res->start + offset, size);
> > +       if (!vop->lut_regs) {
> > +               dev_err(dev, "can't ioremap gamma lut address\n");
> > +               devm_release_mem_region(dev, res->start + offset, size);
> > +               return -ENOMEM;
> > +       }
> > +       return 0;
> > +}
> > +
> >  static int vop_bind(struct device *dev, struct device *master, void *data)
> >  {
> >         struct platform_device *pdev = to_platform_device(dev);
> > @@ -1776,6 +1860,9 @@ static int vop_bind(struct device *dev, struct device *master, void *data)
> >         if (IS_ERR(vop->regs))
> >                 return PTR_ERR(vop->regs);
> > 
> > +       if (vop->data->gamma_lut_addr_off)
> > +               vop_gamma_lut_request(dev, res, vop);
> > +
> >         vop->regsbak = devm_kzalloc(dev, vop->len, GFP_KERNEL);
> >         if (!vop->regsbak)
> >                 return -ENOMEM;
> > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
> > index 2149a889c29d..12d5bde0d0bc 100644
> > --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
> > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
> > @@ -67,6 +67,7 @@ struct vop_common {
> >         struct vop_reg dither_down_mode;
> >         struct vop_reg dither_down_en;
> >         struct vop_reg dither_up;
> > +       struct vop_reg dsp_lut_en;
> >         struct vop_reg gate_en;
> >         struct vop_reg mmu_en;
> >         struct vop_reg out_mode;
> > @@ -170,6 +171,7 @@ struct vop_data {
> >         const struct vop_win_yuv2yuv_data *win_yuv2yuv;
> >         const struct vop_win_data *win;
> >         unsigned int win_size;
> > +       off_t gamma_lut_addr_off;
> > 
> >  #define VOP_FEATURE_OUTPUT_RGB10       BIT(0)
> >  #define VOP_FEATURE_INTERNAL_RGB       BIT(1)
> > diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
> > index 7b9c74750f6d..63fbb384893b 100644
> > --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
> > +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
> > @@ -593,6 +593,7 @@ static const struct vop_common rk3288_common = {
> >         .dither_down_en = VOP_REG(RK3288_DSP_CTRL1, 0x1, 2),
> >         .pre_dither_down = VOP_REG(RK3288_DSP_CTRL1, 0x1, 1),
> >         .dither_up = VOP_REG(RK3288_DSP_CTRL1, 0x1, 6),
> > +       .dsp_lut_en = VOP_REG(RK3288_DSP_CTRL1, 0x1, 0),
> >         .data_blank = VOP_REG(RK3288_DSP_CTRL0, 0x1, 19),
> >         .dsp_blank = VOP_REG(RK3288_DSP_CTRL0, 0x3, 18),
> >         .out_mode = VOP_REG(RK3288_DSP_CTRL0, 0xf, 0),
> > @@ -641,6 +642,7 @@ static const struct vop_data rk3288_vop = {
> >         .output = &rk3288_output,
> >         .win = rk3288_vop_win_data,
> >         .win_size = ARRAY_SIZE(rk3288_vop_win_data),
> > +       .gamma_lut_addr_off = RK3288_GAMMA_LUT_ADDR,
> >  };
> > 
> >  static const int rk3368_vop_intrs[] = {
> > @@ -811,6 +813,7 @@ static const struct vop_data rk3399_vop_big = {
> >         .win = rk3368_vop_win_data,
> >         .win_size = ARRAY_SIZE(rk3368_vop_win_data),
> >         .win_yuv2yuv = rk3399_vop_big_win_yuv2yuv_data,
> > +       .gamma_lut_addr_off = RK3399_GAMMA_LUT_ADDR,
> >  };
> > 
> >  static const struct vop_win_data rk3399_vop_lit_win_data[] = {
> > @@ -836,6 +839,7 @@ static const struct vop_data rk3399_vop_lit = {
> >         .win = rk3399_vop_lit_win_data,
> >         .win_size = ARRAY_SIZE(rk3399_vop_lit_win_data),
> >         .win_yuv2yuv = rk3399_vop_lit_win_yuv2yuv_data,
> > +       .gamma_lut_addr_off = RK3399_GAMMA_LUT_ADDR,
> >  };
> > 
> >  static const struct vop_win_data rk3228_vop_win_data[] = {
> > diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h
> > index 6e9fa5815d4d..490318382f74 100644
> > --- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.h
> > +++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.h
> > @@ -113,6 +113,7 @@
> >  #define RK3288_DSP_VACT_ST_END                 0x0194
> >  #define RK3288_DSP_VS_ST_END_F1                        0x0198
> >  #define RK3288_DSP_VACT_ST_END_F1              0x019c
> > +#define RK3288_GAMMA_LUT_ADDR                  0x1000
> >  /* register definition end */
> > 
> >  /* rk3368 register definition */
> > --
> > 2.20.1
> > 
> > _______________________________________________
> > dri-devel mailing list
> > dri-devel at lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/dri-devel




More information about the dri-devel mailing list