Hi Am 05.11.20 um 14:56 schrieb Maxime Ripard:
The current HVS muxing code will consider the CRTCs in a given state to setup their muxing in the HVS, and disable the other CRTCs muxes. However, it's valid to only update a single CRTC with a state, and in this situation we would mux out a CRTC that was enabled but left untouched by the new state. Fix this by setting a flag on the CRTC state when the muxing has been changed, and only change the muxing configuration when that flag is there. Fixes: 87ebcd42fb7b ("drm/vc4: crtc: Assign output to channel automatically") Reviewed-by: Hoegeun Kwon <hoegeun.kwon@xxxxxxxxxxx> Tested-by: Hoegeun Kwon <hoegeun.kwon@xxxxxxxxxxx> Signed-off-by: Maxime Ripard <maxime@xxxxxxxxxx> --- drivers/gpu/drm/vc4/vc4_drv.h | 1 + drivers/gpu/drm/vc4/vc4_kms.c | 82 ++++++++++++++++++++--------------- 2 files changed, 48 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index 014113823647..325b53ff11b3 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -524,6 +524,7 @@ struct vc4_crtc_state { struct drm_mm_node mm; bool feed_txp; bool txp_armed; + bool needs_muxing;
Maybe rather 'update_muxing'.More generally, I'd separate fields that contain actual CRTC state, such assigned_channel, from those that only contain transitional state during update-commit, such as needs_muxing.
unsigned int assigned_channel;struct {diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c index 0a231ae500e5..7ef164afa9e2 100644 --- a/drivers/gpu/drm/vc4/vc4_kms.c +++ b/drivers/gpu/drm/vc4/vc4_kms.c @@ -226,10 +226,7 @@ static void vc5_hvs_pv_muxing_commit(struct vc4_dev *vc4, { struct drm_crtc_state *crtc_state; struct drm_crtc *crtc; - unsigned char dsp2_mux = 0; - unsigned char dsp3_mux = 3; - unsigned char dsp4_mux = 3; - unsigned char dsp5_mux = 3; + unsigned char mux; unsigned int i; u32 reg;@@ -237,50 +234,59 @@ static void vc5_hvs_pv_muxing_commit(struct vc4_dev *vc4,struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state); struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);- if (!crtc_state->active)+ if (!vc4_state->needs_muxing) continue;switch (vc4_crtc->data->hvs_output) {case 2: - dsp2_mux = (vc4_state->assigned_channel == 2) ? 0 : 1; + mux = (vc4_state->assigned_channel == 2) ? 0 : 1; + reg = HVS_READ(SCALER_DISPECTRL); + HVS_WRITE(SCALER_DISPECTRL, + (reg & ~SCALER_DISPECTRL_DSP2_MUX_MASK) | + VC4_SET_FIELD(mux, SCALER_DISPECTRL_DSP2_MUX)); break;case 3:- dsp3_mux = vc4_state->assigned_channel; + if (vc4_state->assigned_channel == VC4_HVS_CHANNEL_DISABLED) + mux = 3; + else + mux = vc4_state->assigned_channel; + + reg = HVS_READ(SCALER_DISPCTRL); + HVS_WRITE(SCALER_DISPCTRL, + (reg & ~SCALER_DISPCTRL_DSP3_MUX_MASK) | + VC4_SET_FIELD(mux, SCALER_DISPCTRL_DSP3_MUX)); break;case 4:- dsp4_mux = vc4_state->assigned_channel; + if (vc4_state->assigned_channel == VC4_HVS_CHANNEL_DISABLED) + mux = 3; + else + mux = vc4_state->assigned_channel; + + reg = HVS_READ(SCALER_DISPEOLN); + HVS_WRITE(SCALER_DISPEOLN, + (reg & ~SCALER_DISPEOLN_DSP4_MUX_MASK) | + VC4_SET_FIELD(mux, SCALER_DISPEOLN_DSP4_MUX)); + break;case 5:- dsp5_mux = vc4_state->assigned_channel; + if (vc4_state->assigned_channel == VC4_HVS_CHANNEL_DISABLED) + mux = 3; + else + mux = vc4_state->assigned_channel; + + reg = HVS_READ(SCALER_DISPDITHER); + HVS_WRITE(SCALER_DISPDITHER, + (reg & ~SCALER_DISPDITHER_DSP5_MUX_MASK) | + VC4_SET_FIELD(mux, SCALER_DISPDITHER_DSP5_MUX)); break;default:break; } } - - reg = HVS_READ(SCALER_DISPECTRL); - HVS_WRITE(SCALER_DISPECTRL, - (reg & ~SCALER_DISPECTRL_DSP2_MUX_MASK) | - VC4_SET_FIELD(dsp2_mux, SCALER_DISPECTRL_DSP2_MUX)); - - reg = HVS_READ(SCALER_DISPCTRL); - HVS_WRITE(SCALER_DISPCTRL, - (reg & ~SCALER_DISPCTRL_DSP3_MUX_MASK) | - VC4_SET_FIELD(dsp3_mux, SCALER_DISPCTRL_DSP3_MUX)); - - reg = HVS_READ(SCALER_DISPEOLN); - HVS_WRITE(SCALER_DISPEOLN, - (reg & ~SCALER_DISPEOLN_DSP4_MUX_MASK) | - VC4_SET_FIELD(dsp4_mux, SCALER_DISPEOLN_DSP4_MUX)); - - reg = HVS_READ(SCALER_DISPDITHER); - HVS_WRITE(SCALER_DISPDITHER, - (reg & ~SCALER_DISPDITHER_DSP5_MUX_MASK) | - VC4_SET_FIELD(dsp5_mux, SCALER_DISPDITHER_DSP5_MUX)); }static void@@ -787,17 +793,23 @@ static int vc4_pv_muxing_atomic_check(struct drm_device *dev, struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc); unsigned int matching_channels;+ /* Nothing to do here, let's skip it */+ if ((old_crtc_state->enable && new_crtc_state->enable) || + (!old_crtc_state->enable && !new_crtc_state->enable)) {
'if (old_crtc_state->enable == new_crtc_state->enable)' ?
+ new_vc4_crtc_state->needs_muxing = false;
Shouldn't this be cleared after duplicating the crtc state? No need to clear it then.
+ continue; + } + + /* Muxing will need to be modified, mark it as such */ + new_vc4_crtc_state->needs_muxing = true; + + /* If we're disabling our CRTC, we put back our channel */ if (old_crtc_state->enable && !new_crtc_state->enable) {
You've already checked that enable is different, so you can leave out the test on old_crtc_state->enable
With my suggestions considered Acked-by: Thomas Zimmermann <tzimmermann@xxxxxxx>
hvs_state->unassigned_channels |= BIT(old_vc4_crtc_state->assigned_channel); new_vc4_crtc_state->assigned_channel = VC4_HVS_CHANNEL_DISABLED; + continue; }- if (!new_crtc_state->enable)- continue; - - if (new_vc4_crtc_state->assigned_channel != VC4_HVS_CHANNEL_DISABLED) - continue; - /* * The problem we have to solve here is that we have * up to 7 encoders, connected to up to 6 CRTCs.
-- Thomas Zimmermann Graphics Driver Developer SUSE Software Solutions Germany GmbH Maxfeldstr. 5, 90409 Nürnberg, Germany (HRB 36809, AG Nürnberg) Geschäftsführer: Felix Imendörffer
Attachment:
OpenPGP_0x680DC11D530B7A23.asc
Description: application/pgp-keys
Attachment:
OpenPGP_signature
Description: OpenPGP digital signature