Re: [PATCH 2/3] drm/rockchip: Add optional support for CRTC gamma LUT
Hi Jacopo, Thanks for the review. On Fri, 2019-06-21 at 10:22 +0200, Jacopo Mondi wrote: > Hi Ezequiel, >just a few minor comments. Thanks for this new iteration. > > On Tue, Jun 18, 2019 at 06:34:05PM -0300, Ezequiel Garcia wrote: > > Add an optional CRTC gamma LUT support, and enable it on RK3288. > > This is currently enabled via a separate address resource, > > which needs to be specified in the devicetree. > > > > The address resource is required because on some SoCs, such as > > RK3288, the LUT address is after the MMU address, and the latter > > is supported by a different driver. This prevents the DRM driver > > from requesting an entire register space. > > > > The current implementation works for RGB 10-bit tables, as that > > is what seems to work on RK3288. > > > > Signed-off-by: Ezequiel Garcia > > --- > > Changes from RFC: > > * Request (an optional) address resource for the LUT. > > * Drop support for RK3399, which doesn't seem to work > > out of the box and needs more research. > > * Support pass-thru setting when GAMMA_LUT is NULL. > > * Add a check for the gamma size, as suggested by Ilia. > > * Move gamma setting to atomic_commit_tail, as pointed > > out by Jacopo/Laurent, is the correct way. > > --- > > drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 3 + > > drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 106 > > drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 7 ++ > > drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 2 + > > 4 files changed, 118 insertions(+) > > > > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c > > b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c > > index 1c69066b6894..bf9ad6240971 100644 > > --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c > > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c > > @@ -16,6 +16,7 @@ > > #include "rockchip_drm_fb.h" > > #include "rockchip_drm_gem.h" > > #include "rockchip_drm_psr.h" > > +#include "rockchip_drm_vop.h" > > > > static int rockchip_drm_fb_dirty(struct drm_framebuffer *fb, > > struct drm_file *file, > > @@ -128,6 +129,8 @@ rockchip_atomic_helper_commit_tail_rpm(struct > > drm_atomic_state *old_state) > > > > drm_atomic_helper_commit_modeset_disables(dev, old_state); > > > > + rockchip_drm_vop_gamma_set(old_state); > > + > > drm_atomic_helper_commit_modeset_enables(dev, old_state); > > > > drm_atomic_helper_commit_planes(dev, old_state, > > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > > b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > > index 12ed5265a90b..5b6edbe2673f 100644 > > --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > > @@ -137,6 +137,7 @@ struct vop { > > > > uint32_t *regsbak; > > void __iomem *regs; > > + void __iomem *lut_regs; > > > > /* physical map length of vop register */ > > uint32_t len; > > @@ -1153,6 +1154,94 @@ 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_write_gamma_lut(struct vop *vop, struct drm_crtc > > *crtc) > > +{ > > + struct drm_color_lut *lut = crtc->state->gamma_lut->data; > > + int i; > > unsigned i > Sure, my bad. > > + > > + for (i = 0; i < crtc->gamma_size; i++) { > > + u32 word; > > here and below you could declare and initialize in one line. Matter of > tastes, up to you. > > > + > > + 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); > > + } > > +} > > + > > +static void vop_crtc_gamma_set(struct vop *vop, struct drm_crtc *crtc, > > + struct drm_crtc_state *old_state) > > +{ > > + int idle, ret, i; > > idle and i could be unsigned > Ditto. > > + > > + 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, 30 * 1000); > > + if (ret) > > + return; > > + > > + spin_lock(&vop->reg_lock); > > + > > + if (crtc->state->gamma_lut) { > > + if (!old_state->gamma_lut || (crtc->state->gamma_lut->base.id != > > + old_state->gamma_lut->base.id)) > > + vop_crtc_write_gamma_lut(vop, crtc); > > + } else { > > i could also be declared here... > > > + for (i = 0; i < crtc->gamma_size; i++) { > > + u32 word; > > + > > + word = (i << 20) | (i << 10) | i; > > + writel(word, vop->lut_regs + i * 4); > >
Re: [PATCH 2/3] drm/rockchip: Add optional support for CRTC gamma LUT
On Thu, 2019-06-20 at 10:25 -0700, Doug Anderson wrote: > Hi, > > On Tue, Jun 18, 2019 at 2:43 PM Ezequiel Garcia > wrote: > > +static void vop_crtc_gamma_set(struct vop *vop, struct drm_crtc *crtc, > > + struct drm_crtc_state *old_state) > > +{ > > + int idle, ret, i; > > + > > + 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, 30 * 1000); > > + if (ret) > > Worth an error message? > Sure. > > > @@ -1205,6 +1294,7 @@ static void vop_crtc_atomic_flush(struct drm_crtc > > *crtc, > > > > static const struct drm_crtc_helper_funcs vop_crtc_helper_funcs = { > > .mode_fixup = vop_crtc_mode_fixup, > > + .atomic_check = vop_crtc_atomic_check, > > At first I was worried that there was a bug here since in the context > of dw_hdmi (an encoder) adding ".atomic_check" caused ".mode_fixup" to > stop getting called as per mode_fixup() in > "drivers/gpu/drm/drm_atomic_helper.c". > > ...but it seems like it's OK for CRTCs, so I think we're fine. > > > > @@ -1323,6 +1413,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, > > Are there any issues in adding this ".gamma_set" property even though > we may or may not actually have the ability to set the gamma > (depending on whether or not the LUT register range was provided in > the device tree)? I am a DRM noob but > drm_atomic_helper_legacy_gamma_set() is not a trivial little function > and now we'll be running it in some cases where we don't actually have > gamma. > > I also notice that there's at least one bit of code that seems to > check if ".gamma_set" is NULL. ...and if it is, it'll return -ENOSYS > right away. Do we still properly return -ENOSYS on devices that don't > have the register range? > > It seems like the absolute safest would be to have two copies of this > struct: one used for VOPs that have the range and one for VOPs that > don't. > > ...but possibly I'm just paranoid and as I've said I'm a clueless > noob. If someone says it's fine to always provide the .gamma_set > property that's fine too. > Provided we do the suggestion below (setting gamma_size and enabling color management) when lut_regs is set, then I think we are fine. Before this change: * GAMMA_LUT property doesn't exist, and so can't be set. * DRM_IOCTL_MODE_SETGAMMA (legacy) return ENOSYS. After this change, on platforms that doesn't support this: * GAMMA_LUT property doesn't exist, and so can't be set. * DRM_IOCTL_MODE_SETGAMMA (legacy) return EINVAL. The only difference is the ENOSYS/EINVAL errno, which I doubt will regress anything. I don't think this difference deserves assigning (the legacy) .gamma_set hook conditionally, which would make the implementation too ugly. > > > static void vop_fb_unref_worker(struct drm_flip_work *work, void *val) > > @@ -1480,6 +1571,10 @@ static int vop_create_crtc(struct vop *vop) > > goto err_cleanup_planes; > > > > drm_crtc_helper_add(crtc, &vop_crtc_helper_funcs); > > + if (vop_data->lut_size) { > > + drm_mode_crtc_set_gamma_size(crtc, vop_data->lut_size); > > + drm_crtc_enable_color_mgmt(crtc, 0, false, > > vop_data->lut_size); > > Should we only do the above calls if we successfully mapped the resources? > Yes, totally. See above. > > > @@ -1776,6 +1871,17 @@ static int vop_bind(struct device *dev, struct > > device *master, void *data) > > if (IS_ERR(vop->regs)) > > return PTR_ERR(vop->regs); > > > > + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lut"); > > As per comments in the bindings, shouldn't use the name "lut" but > should just pick resource #1. Yes. Thanks a lot for the review, Ezequiel ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH 2/3] drm/rockchip: Add optional support for CRTC gamma LUT
Hi Ezequiel, just a few minor comments. Thanks for this new iteration. On Tue, Jun 18, 2019 at 06:34:05PM -0300, Ezequiel Garcia wrote: > Add an optional CRTC gamma LUT support, and enable it on RK3288. > This is currently enabled via a separate address resource, > which needs to be specified in the devicetree. > > The address resource is required because on some SoCs, such as > RK3288, the LUT address is after the MMU address, and the latter > is supported by a different driver. This prevents the DRM driver > from requesting an entire register space. > > The current implementation works for RGB 10-bit tables, as that > is what seems to work on RK3288. > > Signed-off-by: Ezequiel Garcia > --- > Changes from RFC: > * Request (an optional) address resource for the LUT. > * Drop support for RK3399, which doesn't seem to work > out of the box and needs more research. > * Support pass-thru setting when GAMMA_LUT is NULL. > * Add a check for the gamma size, as suggested by Ilia. > * Move gamma setting to atomic_commit_tail, as pointed > out by Jacopo/Laurent, is the correct way. > --- > drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 3 + > drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 106 > drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 7 ++ > drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 2 + > 4 files changed, 118 insertions(+) > > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c > b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c > index 1c69066b6894..bf9ad6240971 100644 > --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c > @@ -16,6 +16,7 @@ > #include "rockchip_drm_fb.h" > #include "rockchip_drm_gem.h" > #include "rockchip_drm_psr.h" > +#include "rockchip_drm_vop.h" > > static int rockchip_drm_fb_dirty(struct drm_framebuffer *fb, >struct drm_file *file, > @@ -128,6 +129,8 @@ rockchip_atomic_helper_commit_tail_rpm(struct > drm_atomic_state *old_state) > > drm_atomic_helper_commit_modeset_disables(dev, old_state); > > + rockchip_drm_vop_gamma_set(old_state); > + > drm_atomic_helper_commit_modeset_enables(dev, old_state); > > drm_atomic_helper_commit_planes(dev, old_state, > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > index 12ed5265a90b..5b6edbe2673f 100644 > --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > @@ -137,6 +137,7 @@ struct vop { > > uint32_t *regsbak; > void __iomem *regs; > + void __iomem *lut_regs; > > /* physical map length of vop register */ > uint32_t len; > @@ -1153,6 +1154,94 @@ 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_write_gamma_lut(struct vop *vop, struct drm_crtc *crtc) > +{ > + struct drm_color_lut *lut = crtc->state->gamma_lut->data; > + int i; unsigned i > + > + for (i = 0; i < crtc->gamma_size; i++) { > + u32 word; here and below you could declare and initialize in one line. Matter of tastes, up to you. > + > + 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); > + } > +} > + > +static void vop_crtc_gamma_set(struct vop *vop, struct drm_crtc *crtc, > +struct drm_crtc_state *old_state) > +{ > + int idle, ret, i; idle and i could be unsigned > + > + 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, 30 * 1000); > + if (ret) > + return; > + > + spin_lock(&vop->reg_lock); > + > + if (crtc->state->gamma_lut) { > + if (!old_state->gamma_lut || (crtc->state->gamma_lut->base.id != > + old_state->gamma_lut->base.id)) > + vop_crtc_write_gamma_lut(vop, crtc); > + } else { i could also be declared here... > + for (i = 0; i < crtc->gamma_size; i++) { > + u32 word; > + > + word = (i << 20) | (i << 10) | i; > + writel(word, vop->lut_regs + i * 4); > + } I might be confused, but are you here configuring a linear LUT table? Isn't this equivalent to have it disabled? > + } > + > + VOP_REG_SET(vop, common, dsp_lut_en, 1); > + vop_cfg_done(vop); > + spin_unlock(&vop->reg_lock); > +} > + > +static int vop_crtc_atomic_check(struct drm_crtc
Re: [PATCH 2/3] drm/rockchip: Add optional support for CRTC gamma LUT
Hi, On Tue, Jun 18, 2019 at 2:43 PM Ezequiel Garcia wrote: > > +static void vop_crtc_gamma_set(struct vop *vop, struct drm_crtc *crtc, > + struct drm_crtc_state *old_state) > +{ > + int idle, ret, i; > + > + 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, 30 * 1000); > + if (ret) Worth an error message? > @@ -1205,6 +1294,7 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc, > > static const struct drm_crtc_helper_funcs vop_crtc_helper_funcs = { > .mode_fixup = vop_crtc_mode_fixup, > + .atomic_check = vop_crtc_atomic_check, At first I was worried that there was a bug here since in the context of dw_hdmi (an encoder) adding ".atomic_check" caused ".mode_fixup" to stop getting called as per mode_fixup() in "drivers/gpu/drm/drm_atomic_helper.c". ...but it seems like it's OK for CRTCs, so I think we're fine. > @@ -1323,6 +1413,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, Are there any issues in adding this ".gamma_set" property even though we may or may not actually have the ability to set the gamma (depending on whether or not the LUT register range was provided in the device tree)? I am a DRM noob but drm_atomic_helper_legacy_gamma_set() is not a trivial little function and now we'll be running it in some cases where we don't actually have gamma. I also notice that there's at least one bit of code that seems to check if ".gamma_set" is NULL. ...and if it is, it'll return -ENOSYS right away. Do we still properly return -ENOSYS on devices that don't have the register range? It seems like the absolute safest would be to have two copies of this struct: one used for VOPs that have the range and one for VOPs that don't. ...but possibly I'm just paranoid and as I've said I'm a clueless noob. If someone says it's fine to always provide the .gamma_set property that's fine too. > static void vop_fb_unref_worker(struct drm_flip_work *work, void *val) > @@ -1480,6 +1571,10 @@ static int vop_create_crtc(struct vop *vop) > goto err_cleanup_planes; > > drm_crtc_helper_add(crtc, &vop_crtc_helper_funcs); > + if (vop_data->lut_size) { > + drm_mode_crtc_set_gamma_size(crtc, vop_data->lut_size); > + drm_crtc_enable_color_mgmt(crtc, 0, false, > vop_data->lut_size); Should we only do the above calls if we successfully mapped the resources? > @@ -1776,6 +1871,17 @@ static int vop_bind(struct device *dev, struct device > *master, void *data) > if (IS_ERR(vop->regs)) > return PTR_ERR(vop->regs); > > + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lut"); As per comments in the bindings, shouldn't use the name "lut" but should just pick resource #1. ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH 2/3] drm/rockchip: Add optional support for CRTC gamma LUT
On Wed, 2019-06-19 at 00:18 +0200, Heiko Stübner wrote: > Am Mittwoch, 19. Juni 2019, 00:09:57 CEST schrieb Ezequiel Garcia: > > On Tue, 2019-06-18 at 17:47 -0400, Ilia Mirkin wrote: > > > On Tue, Jun 18, 2019 at 5:43 PM Ezequiel Garcia > > > wrote: > > > > Add an optional CRTC gamma LUT support, and enable it on RK3288. > > > > This is currently enabled via a separate address resource, > > > > which needs to be specified in the devicetree. > > > > > > > > The address resource is required because on some SoCs, such as > > > > RK3288, the LUT address is after the MMU address, and the latter > > > > is supported by a different driver. This prevents the DRM driver > > > > from requesting an entire register space. > > > > > > > > The current implementation works for RGB 10-bit tables, as that > > > > is what seems to work on RK3288. > > > > > > > > Signed-off-by: Ezequiel Garcia > > > > --- > > > > Changes from RFC: > > > > * Request (an optional) address resource for the LUT. > > > > * Drop support for RK3399, which doesn't seem to work > > > > out of the box and needs more research. > > > > * Support pass-thru setting when GAMMA_LUT is NULL. > > > > * Add a check for the gamma size, as suggested by Ilia. > > > > * Move gamma setting to atomic_commit_tail, as pointed > > > > out by Jacopo/Laurent, is the correct way. > > > > --- > > > > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > > > > b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > > > > index 12ed5265a90b..5b6edbe2673f 100644 > > > > --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > > > > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > > > > +static void vop_crtc_gamma_set(struct vop *vop, struct drm_crtc *crtc, > > > > + struct drm_crtc_state *old_state) > > > > +{ > > > > + int idle, ret, i; > > > > + > > > > + 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, 30 * 1000); > > > > + if (ret) > > > > + return; > > > > + > > > > + spin_lock(&vop->reg_lock); > > > > + > > > > + if (crtc->state->gamma_lut) { > > > > + if (!old_state->gamma_lut || > > > > (crtc->state->gamma_lut->base.id != > > > > + > > > > old_state->gamma_lut->base.id)) > > > > + vop_crtc_write_gamma_lut(vop, crtc); > > > > + } else { > > > > + for (i = 0; i < crtc->gamma_size; i++) { > > > > + u32 word; > > > > + > > > > + word = (i << 20) | (i << 10) | i; > > > > + writel(word, vop->lut_regs + i * 4); > > > > + } > > > > > > Note - I'm not in any way familiar with the hardware, so take with a > > > grain of salt -- > > > > > > Could you just leave dsp_lut_en turned off in this case? > > > > > > > That was the first thing I tried :-) > > > > It seems dsp_lut_en is not to enable the CRTC gamma LUT stage, > > but to enable writing the gamma LUT to the internal RAM. > > I guess that warants a code comment stating this, so we don't end > up with well-meant cleanup patches in the future :-) . > Sure, makes sense. Any other feedback aside from this? Thanks, Ezequiel
Re: [PATCH 2/3] drm/rockchip: Add optional support for CRTC gamma LUT
Am Mittwoch, 19. Juni 2019, 00:09:57 CEST schrieb Ezequiel Garcia: > On Tue, 2019-06-18 at 17:47 -0400, Ilia Mirkin wrote: > > On Tue, Jun 18, 2019 at 5:43 PM Ezequiel Garcia > > wrote: > > > Add an optional CRTC gamma LUT support, and enable it on RK3288. > > > This is currently enabled via a separate address resource, > > > which needs to be specified in the devicetree. > > > > > > The address resource is required because on some SoCs, such as > > > RK3288, the LUT address is after the MMU address, and the latter > > > is supported by a different driver. This prevents the DRM driver > > > from requesting an entire register space. > > > > > > The current implementation works for RGB 10-bit tables, as that > > > is what seems to work on RK3288. > > > > > > Signed-off-by: Ezequiel Garcia > > > --- > > > Changes from RFC: > > > * Request (an optional) address resource for the LUT. > > > * Drop support for RK3399, which doesn't seem to work > > > out of the box and needs more research. > > > * Support pass-thru setting when GAMMA_LUT is NULL. > > > * Add a check for the gamma size, as suggested by Ilia. > > > * Move gamma setting to atomic_commit_tail, as pointed > > > out by Jacopo/Laurent, is the correct way. > > > --- > > > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > > > b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > > > index 12ed5265a90b..5b6edbe2673f 100644 > > > --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > > > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > > > +static void vop_crtc_gamma_set(struct vop *vop, struct drm_crtc *crtc, > > > + struct drm_crtc_state *old_state) > > > +{ > > > + int idle, ret, i; > > > + > > > + 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, 30 * 1000); > > > + if (ret) > > > + return; > > > + > > > + spin_lock(&vop->reg_lock); > > > + > > > + if (crtc->state->gamma_lut) { > > > + if (!old_state->gamma_lut || > > > (crtc->state->gamma_lut->base.id != > > > + > > > old_state->gamma_lut->base.id)) > > > + vop_crtc_write_gamma_lut(vop, crtc); > > > + } else { > > > + for (i = 0; i < crtc->gamma_size; i++) { > > > + u32 word; > > > + > > > + word = (i << 20) | (i << 10) | i; > > > + writel(word, vop->lut_regs + i * 4); > > > + } > > > > Note - I'm not in any way familiar with the hardware, so take with a > > grain of salt -- > > > > Could you just leave dsp_lut_en turned off in this case? > > > > That was the first thing I tried :-) > > It seems dsp_lut_en is not to enable the CRTC gamma LUT stage, > but to enable writing the gamma LUT to the internal RAM. I guess that warants a code comment stating this, so we don't end up with well-meant cleanup patches in the future :-) . > > And the specs list no register to enable/disable the gamma LUT. > > Thanks! > Eze > >
Re: [PATCH 2/3] drm/rockchip: Add optional support for CRTC gamma LUT
On Tue, 2019-06-18 at 17:47 -0400, Ilia Mirkin wrote: > On Tue, Jun 18, 2019 at 5:43 PM Ezequiel Garcia > wrote: > > Add an optional CRTC gamma LUT support, and enable it on RK3288. > > This is currently enabled via a separate address resource, > > which needs to be specified in the devicetree. > > > > The address resource is required because on some SoCs, such as > > RK3288, the LUT address is after the MMU address, and the latter > > is supported by a different driver. This prevents the DRM driver > > from requesting an entire register space. > > > > The current implementation works for RGB 10-bit tables, as that > > is what seems to work on RK3288. > > > > Signed-off-by: Ezequiel Garcia > > --- > > Changes from RFC: > > * Request (an optional) address resource for the LUT. > > * Drop support for RK3399, which doesn't seem to work > > out of the box and needs more research. > > * Support pass-thru setting when GAMMA_LUT is NULL. > > * Add a check for the gamma size, as suggested by Ilia. > > * Move gamma setting to atomic_commit_tail, as pointed > > out by Jacopo/Laurent, is the correct way. > > --- > > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > > b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > > index 12ed5265a90b..5b6edbe2673f 100644 > > --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > > +static void vop_crtc_gamma_set(struct vop *vop, struct drm_crtc *crtc, > > + struct drm_crtc_state *old_state) > > +{ > > + int idle, ret, i; > > + > > + 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, 30 * 1000); > > + if (ret) > > + return; > > + > > + spin_lock(&vop->reg_lock); > > + > > + if (crtc->state->gamma_lut) { > > + if (!old_state->gamma_lut || > > (crtc->state->gamma_lut->base.id != > > + > > old_state->gamma_lut->base.id)) > > + vop_crtc_write_gamma_lut(vop, crtc); > > + } else { > > + for (i = 0; i < crtc->gamma_size; i++) { > > + u32 word; > > + > > + word = (i << 20) | (i << 10) | i; > > + writel(word, vop->lut_regs + i * 4); > > + } > > Note - I'm not in any way familiar with the hardware, so take with a > grain of salt -- > > Could you just leave dsp_lut_en turned off in this case? > That was the first thing I tried :-) It seems dsp_lut_en is not to enable the CRTC gamma LUT stage, but to enable writing the gamma LUT to the internal RAM. And the specs list no register to enable/disable the gamma LUT. Thanks! Eze ___ dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
Re: [PATCH 2/3] drm/rockchip: Add optional support for CRTC gamma LUT
On Tue, Jun 18, 2019 at 5:43 PM Ezequiel Garcia wrote: > > Add an optional CRTC gamma LUT support, and enable it on RK3288. > This is currently enabled via a separate address resource, > which needs to be specified in the devicetree. > > The address resource is required because on some SoCs, such as > RK3288, the LUT address is after the MMU address, and the latter > is supported by a different driver. This prevents the DRM driver > from requesting an entire register space. > > The current implementation works for RGB 10-bit tables, as that > is what seems to work on RK3288. > > Signed-off-by: Ezequiel Garcia > --- > Changes from RFC: > * Request (an optional) address resource for the LUT. > * Drop support for RK3399, which doesn't seem to work > out of the box and needs more research. > * Support pass-thru setting when GAMMA_LUT is NULL. > * Add a check for the gamma size, as suggested by Ilia. > * Move gamma setting to atomic_commit_tail, as pointed > out by Jacopo/Laurent, is the correct way. > --- > diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > index 12ed5265a90b..5b6edbe2673f 100644 > --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c > +static void vop_crtc_gamma_set(struct vop *vop, struct drm_crtc *crtc, > + struct drm_crtc_state *old_state) > +{ > + int idle, ret, i; > + > + 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, 30 * 1000); > + if (ret) > + return; > + > + spin_lock(&vop->reg_lock); > + > + if (crtc->state->gamma_lut) { > + if (!old_state->gamma_lut || (crtc->state->gamma_lut->base.id > != > + old_state->gamma_lut->base.id)) > + vop_crtc_write_gamma_lut(vop, crtc); > + } else { > + for (i = 0; i < crtc->gamma_size; i++) { > + u32 word; > + > + word = (i << 20) | (i << 10) | i; > + writel(word, vop->lut_regs + i * 4); > + } Note - I'm not in any way familiar with the hardware, so take with a grain of salt -- Could you just leave dsp_lut_en turned off in this case? Cheers, -ilia > + } > + > + VOP_REG_SET(vop, common, dsp_lut_en, 1); > + vop_cfg_done(vop); > + spin_unlock(&vop->reg_lock); > +}
[PATCH 2/3] drm/rockchip: Add optional support for CRTC gamma LUT
Add an optional CRTC gamma LUT support, and enable it on RK3288. This is currently enabled via a separate address resource, which needs to be specified in the devicetree. The address resource is required because on some SoCs, such as RK3288, the LUT address is after the MMU address, and the latter is supported by a different driver. This prevents the DRM driver from requesting an entire register space. The current implementation works for RGB 10-bit tables, as that is what seems to work on RK3288. Signed-off-by: Ezequiel Garcia --- Changes from RFC: * Request (an optional) address resource for the LUT. * Drop support for RK3399, which doesn't seem to work out of the box and needs more research. * Support pass-thru setting when GAMMA_LUT is NULL. * Add a check for the gamma size, as suggested by Ilia. * Move gamma setting to atomic_commit_tail, as pointed out by Jacopo/Laurent, is the correct way. --- drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 3 + drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 106 drivers/gpu/drm/rockchip/rockchip_drm_vop.h | 7 ++ drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 2 + 4 files changed, 118 insertions(+) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c index 1c69066b6894..bf9ad6240971 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c @@ -16,6 +16,7 @@ #include "rockchip_drm_fb.h" #include "rockchip_drm_gem.h" #include "rockchip_drm_psr.h" +#include "rockchip_drm_vop.h" static int rockchip_drm_fb_dirty(struct drm_framebuffer *fb, struct drm_file *file, @@ -128,6 +129,8 @@ rockchip_atomic_helper_commit_tail_rpm(struct drm_atomic_state *old_state) drm_atomic_helper_commit_modeset_disables(dev, old_state); + rockchip_drm_vop_gamma_set(old_state); + drm_atomic_helper_commit_modeset_enables(dev, old_state); drm_atomic_helper_commit_planes(dev, old_state, diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index 12ed5265a90b..5b6edbe2673f 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -137,6 +137,7 @@ struct vop { uint32_t *regsbak; void __iomem *regs; + void __iomem *lut_regs; /* physical map length of vop register */ uint32_t len; @@ -1153,6 +1154,94 @@ 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_write_gamma_lut(struct vop *vop, struct drm_crtc *crtc) +{ + struct drm_color_lut *lut = crtc->state->gamma_lut->data; + int i; + + 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); + } +} + +static void vop_crtc_gamma_set(struct vop *vop, struct drm_crtc *crtc, + struct drm_crtc_state *old_state) +{ + int idle, ret, i; + + 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, 30 * 1000); + if (ret) + return; + + spin_lock(&vop->reg_lock); + + if (crtc->state->gamma_lut) { + if (!old_state->gamma_lut || (crtc->state->gamma_lut->base.id != + old_state->gamma_lut->base.id)) + vop_crtc_write_gamma_lut(vop, crtc); + } else { + for (i = 0; i < crtc->gamma_size; i++) { + u32 word; + + word = (i << 20) | (i << 10) | i; + 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 int vop_crtc_atomic_check(struct drm_crtc *crtc, + struct drm_crtc_state *crtc_state) +{ + struct vop *vop = to_vop(crtc); + + if (vop->lut_regs && crtc_state->color_mgmt_changed && + crtc_state->gamma_lut) { + int len; + + len = drm_color_lut_size(crtc_state->gamma_lut); + if (len != crtc->gamma_size) { + DRM_DEBUG_KMS("Invalid LUT size; got %d, expected %d\n", + len, crtc->gamma_size); + return -EINVAL; + } +