[PATCH v3] rockchip/drm: vop2: add support for gamma LUT

Piotr Zalewski pZ010001011111 at proton.me
Sat Jul 27 17:44:39 UTC 2024


On Friday, July 26th, 2024 at 1:31 PM, Daniel Stone <daniel at fooishbar.org> wrote:

> Hi Piotr,

Hi Daniel, sorry for delayed response.

>
> > static void vop2_dither_setup(struct drm_crtc *crtc, u32 *dsp_ctrl)
> > @@ -2152,6 +2127,9 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc,
> >
> > vop2_post_config(crtc);
> >
> > + if (crtc->state->gamma_lut)
> > + vop2_crtc_gamma_set(vop2, crtc, old_state, &dsp_ctrl);
>
>
> I think this call should be unconditional, so that we correctly
> program LUT_DIS if there is no LUT set up during enable.
>

Noted

> > @@ -2599,8 +2575,17 @@ static void vop2_crtc_atomic_begin(struct drm_crtc *crtc,
> > vop2_setup_alpha(vp);
> > vop2_setup_dly_for_windows(vop2);
> >
> > - if (crtc_state->color_mgmt_changed && !crtc_state->active_changed)
> > - vop2_crtc_gamma_set(vop2, crtc, old_crtc_state);
> > + if (crtc_state->color_mgmt_changed && !crtc_state->active_changed) {
> > + u32 dsp_ctrl = vop2_vp_read(vp, RK3568_VP_DSP_CTRL);;
> > +
> > + vop2_lock(vop2);
> > +
> > + vop2_crtc_gamma_set(vop2, crtc, old_crtc_state, &dsp_ctrl);
> > +
> > + vop2_vp_write(vp, RK3568_VP_DSP_CTRL, dsp_ctrl);
> > + vop2_cfg_done(vp);
> > + vop2_unlock(vop2);
> > + }
>
>
> Calling lock/set/write/done/unlock here seems like an anti-pattern;
> the cfg_done is already written in atomic_flush, so at least that part
> is not necessary.

Right sorry for sending such code. I wanted to demonstrate the idea.

> On platforms like RK3588, it looks like the new LUT can just be
> written directly from atomic_begin without needing to program
> DSP_CTRL, take locks, or synchronise against anything, so that should
> be an easy straight-line path.
>
> On platforms like RK3568, it would probably be better to set
> mode_changed when the colour management configuration changes. That
> will give you a good point to synchronise the cross-VOP dependencies
> (i.e. claim or release the shared LUT when it is being
> enabled/disabled), and also a hint to userspace that it is not going
> to be a seamless transition as the LUT is disabled, programmed, then
> re-enabled.
>
> I think this would end up in a net reduction of LoC as well as a net
> reduction of code weirdness.

Okay so if I understood you correctly you suggest setting mode_changed in 
order to trigger full modeset (check->begin->flush->enable) to cleanly 
handle the RK356x case and for RK3588 just write the LUT in begin and 
don't do anything more.

I tried to do this but couldn't get the thing to work. It seems like 
setting the mode_changed manually in atomic_check, messes something up 
with the CRTC states. Namely, the retrieved new state in subsequent 
atomic_begin call isn't the same state (as a result, flags 
color_mgmt_changed and mode_changed are both false when they are checked 
in atomic_begin which stops further gamma LUT reconfiguration). Below is 
how I reworked this (included only parts which changed).

As already mentioned, in atomic check the mode_changed flag is set, then in 
atomic begin gamma LUT is disabled and DSP_LUT_EN bit unset (or gamma LUT 
is written directly based on if it's RK356x or not). Then in atomic_flush 
video port is selected and gamma LUT is written. Gamma LUT is enabled in 
atomic_enable.

Perhaps I'm missing something important, if so please hint what exactly. 

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
index 9873172e3fd3..9c5ee2d85a58 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c
@@ -2051,6 +2092,13 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc,
 
 	clk_set_rate(vp->dclk, clock);
 
+	/**
+	 * Enable gamma LUT in atomic enable
+	 */
+	if (crtc_state->gamma_lut && (vop2->data->soc_id == 3566 ||
+				      vop2->data->soc_id == 3568))
+		dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_LUT_EN;
+
 	vop2_post_config(crtc);
 
 	vop2_cfg_done(vp);
@@ -2062,6 +2110,39 @@ static void vop2_crtc_atomic_enable(struct drm_crtc *crtc,
 	vop2_unlock(vop2);
 }
 
+static int vop2_crtc_atomic_check_gamma(struct vop2_video_port *vp,
+					struct drm_crtc *crtc,
+					struct drm_crtc_state *crtc_state)
+{
+	struct vop2 *vop2 = vp->vop2;
+	unsigned int len;
+
+	if (!vp->vop2->lut_regs || !crtc_state->color_mgmt_changed ||
+	    !crtc_state->gamma_lut)
+		return 0;
+
+	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;
+	}
+
+	if (!crtc_state->mode_changed && (vop2->data->soc_id == 3566 ||
+					  vop2->data->soc_id == 3568)) {
+		int ret;
+
+		crtc_state->mode_changed = true;
+
+		ret = drm_atomic_helper_check_modeset(crtc->dev,
+				crtc_state->state);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
 static int vop2_crtc_atomic_check(struct drm_crtc *crtc,
 				  struct drm_atomic_state *state)
 {
@@ -2069,6 +2150,11 @@ static int vop2_crtc_atomic_check(struct drm_crtc *crtc,
 	struct drm_plane *plane;
 	int nplanes = 0;
 	struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+	int ret;
+
+	ret = vop2_crtc_atomic_check_gamma(vp, crtc, crtc_state);
+	if (ret)
+		return ret;
 
 	drm_atomic_crtc_state_for_each_plane(plane, crtc_state)
 		nplanes++;
@@ -2456,9 +2542,36 @@ static void vop2_setup_dly_for_windows(struct vop2 *vop2)
 	vop2_writel(vop2, RK3568_SMART_DLY_NUM, sdly);
 }
 
+static void vop2_crtc_atomic_begin_gamma(struct vop2 *vop2,
+					struct drm_crtc *crtc) {
+	struct vop2_video_port *vp = to_vop2_video_port(crtc);
+	int ret;
+	u32 dsp_ctrl;
+
+	vop2_lock(vop2);
+	/**
+	 * Gamma lut always has to be disabled in both cases. When gamma
+	 * lut is enabled it needs to be disabled before writing (Applies
+	 * only to RK356x SoCs).
+	 */
+	vop2_vp_dsp_lut_disable(vp);
+
+	vop2_cfg_done(vp);
+	vop2_unlock(vop2);
+
+	ret = readx_poll_timeout(vop2_vp_dsp_lut_is_enabled, vp, dsp_ctrl,
+			!dsp_ctrl, 5, 30 * 1000);
+	if (ret) {
+		DRM_DEV_ERROR(vop2->dev,
+			"display LUT RAM enable timeout!\n");
+	}
+}
+
 static void vop2_crtc_atomic_begin(struct drm_crtc *crtc,
 				   struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *crtc_state =
+		drm_atomic_get_new_crtc_state(state, crtc);
 	struct vop2_video_port *vp = to_vop2_video_port(crtc);
 	struct vop2 *vop2 = vp->vop2;
 	struct drm_plane *plane;
@@ -2482,13 +2595,50 @@ static void vop2_crtc_atomic_begin(struct drm_crtc *crtc,
 	vop2_setup_layer_mixer(vp);
 	vop2_setup_alpha(vp);
 	vop2_setup_dly_for_windows(vop2);
+
+	if (crtc_state->color_mgmt_changed && !crtc_state->active_changed) {
+		/**
+		 * When the SoC is RK356x gamma lut change always triggers
+		 * mode_changed - proceed with gamma lut disable
+		 */
+		if (crtc_state->mode_changed &&
+		    (vop2->data->soc_id == 3566 ||
+		     vop2->data->soc_id == 3568))
+			vop2_crtc_atomic_begin_gamma(vop2, crtc);
+		/**
+		 * When the Soc isn't RK356x (eg. RK3588) gamma lut can be
+		 * written directly
+		 */
+		else if (crtc_state->gamma_lut)
+			vop2_crtc_write_gamma_lut(vop2, crtc);
+	}
+}
+
+static void vop2_crtc_atomic_flush_gamma(struct vop2 *vop2, struct vop2_video_port *vp, struct drm_crtc *crtc)
+{
+	if (vop2->data->soc_id == 3566 || vop2->data->soc_id == 3568) {
+		vop2_lock(vop2);
+
+		vop2_crtc_write_gamma_lut(vop2, crtc);
+		vop2_writel(vp->vop2, RK3568_LUT_PORT_SEL, vp->id);
+
+		vop2_unlock(vop2);
+	}
 }
 
 static void vop2_crtc_atomic_flush(struct drm_crtc *crtc,
 				   struct drm_atomic_state *state)
 {
+	struct drm_crtc_state *crtc_state =
+		drm_atomic_get_new_crtc_state(state, crtc);
 	struct vop2_video_port *vp = to_vop2_video_port(crtc);
 
+	/**
+	 * Write gamma LUT in atomic flush
+	 */
+	if (crtc_state->mode_changed && crtc_state->gamma_lut)
+		vop2_crtc_atomic_flush_gamma(vp->vop2, vp, crtc);
+
 	vop2_post_config(crtc);
 
 	vop2_cfg_done(vp);



More information about the dri-devel mailing list