Skip to content

Commit 2820526

Browse files
committed
drm/vc4: kms: Don't disable the muxing of an active CRTC
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: 87ebcd4 ("drm/vc4: crtc: Assign output to channel automatically") Signed-off-by: Maxime Ripard <maxime@cerno.tech> Tested-by: Hoegeun Kwon <hoegeun.kwon@samsung.com> Reviewed-by: Hoegeun Kwon <hoegeun.kwon@samsung.com> Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de> Link: https://patchwork.freedesktop.org/patch/msgid/20201120144245.398711-3-maxime@cerno.tech
1 parent f2df84e commit 2820526

2 files changed

Lines changed: 48 additions & 36 deletions

File tree

drivers/gpu/drm/vc4/vc4_drv.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,9 @@ struct vc4_crtc_state {
532532
unsigned int top;
533533
unsigned int bottom;
534534
} margins;
535+
536+
/* Transitional state below, only valid during atomic commits */
537+
bool update_muxing;
535538
};
536539

537540
#define VC4_HVS_CHANNEL_DISABLED ((unsigned int)-1)

drivers/gpu/drm/vc4/vc4_kms.c

Lines changed: 45 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -239,61 +239,67 @@ static void vc5_hvs_pv_muxing_commit(struct vc4_dev *vc4,
239239
{
240240
struct drm_crtc_state *crtc_state;
241241
struct drm_crtc *crtc;
242-
unsigned char dsp2_mux = 0;
243-
unsigned char dsp3_mux = 3;
244-
unsigned char dsp4_mux = 3;
245-
unsigned char dsp5_mux = 3;
242+
unsigned char mux;
246243
unsigned int i;
247244
u32 reg;
248245

249246
for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
250247
struct vc4_crtc_state *vc4_state = to_vc4_crtc_state(crtc_state);
251248
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
252249

253-
if (!crtc_state->active)
250+
if (!vc4_state->update_muxing)
254251
continue;
255252

256253
switch (vc4_crtc->data->hvs_output) {
257254
case 2:
258-
dsp2_mux = (vc4_state->assigned_channel == 2) ? 0 : 1;
255+
mux = (vc4_state->assigned_channel == 2) ? 0 : 1;
256+
reg = HVS_READ(SCALER_DISPECTRL);
257+
HVS_WRITE(SCALER_DISPECTRL,
258+
(reg & ~SCALER_DISPECTRL_DSP2_MUX_MASK) |
259+
VC4_SET_FIELD(mux, SCALER_DISPECTRL_DSP2_MUX));
259260
break;
260261

261262
case 3:
262-
dsp3_mux = vc4_state->assigned_channel;
263+
if (vc4_state->assigned_channel == VC4_HVS_CHANNEL_DISABLED)
264+
mux = 3;
265+
else
266+
mux = vc4_state->assigned_channel;
267+
268+
reg = HVS_READ(SCALER_DISPCTRL);
269+
HVS_WRITE(SCALER_DISPCTRL,
270+
(reg & ~SCALER_DISPCTRL_DSP3_MUX_MASK) |
271+
VC4_SET_FIELD(mux, SCALER_DISPCTRL_DSP3_MUX));
263272
break;
264273

265274
case 4:
266-
dsp4_mux = vc4_state->assigned_channel;
275+
if (vc4_state->assigned_channel == VC4_HVS_CHANNEL_DISABLED)
276+
mux = 3;
277+
else
278+
mux = vc4_state->assigned_channel;
279+
280+
reg = HVS_READ(SCALER_DISPEOLN);
281+
HVS_WRITE(SCALER_DISPEOLN,
282+
(reg & ~SCALER_DISPEOLN_DSP4_MUX_MASK) |
283+
VC4_SET_FIELD(mux, SCALER_DISPEOLN_DSP4_MUX));
284+
267285
break;
268286

269287
case 5:
270-
dsp5_mux = vc4_state->assigned_channel;
288+
if (vc4_state->assigned_channel == VC4_HVS_CHANNEL_DISABLED)
289+
mux = 3;
290+
else
291+
mux = vc4_state->assigned_channel;
292+
293+
reg = HVS_READ(SCALER_DISPDITHER);
294+
HVS_WRITE(SCALER_DISPDITHER,
295+
(reg & ~SCALER_DISPDITHER_DSP5_MUX_MASK) |
296+
VC4_SET_FIELD(mux, SCALER_DISPDITHER_DSP5_MUX));
271297
break;
272298

273299
default:
274300
break;
275301
}
276302
}
277-
278-
reg = HVS_READ(SCALER_DISPECTRL);
279-
HVS_WRITE(SCALER_DISPECTRL,
280-
(reg & ~SCALER_DISPECTRL_DSP2_MUX_MASK) |
281-
VC4_SET_FIELD(dsp2_mux, SCALER_DISPECTRL_DSP2_MUX));
282-
283-
reg = HVS_READ(SCALER_DISPCTRL);
284-
HVS_WRITE(SCALER_DISPCTRL,
285-
(reg & ~SCALER_DISPCTRL_DSP3_MUX_MASK) |
286-
VC4_SET_FIELD(dsp3_mux, SCALER_DISPCTRL_DSP3_MUX));
287-
288-
reg = HVS_READ(SCALER_DISPEOLN);
289-
HVS_WRITE(SCALER_DISPEOLN,
290-
(reg & ~SCALER_DISPEOLN_DSP4_MUX_MASK) |
291-
VC4_SET_FIELD(dsp4_mux, SCALER_DISPEOLN_DSP4_MUX));
292-
293-
reg = HVS_READ(SCALER_DISPDITHER);
294-
HVS_WRITE(SCALER_DISPDITHER,
295-
(reg & ~SCALER_DISPDITHER_DSP5_MUX_MASK) |
296-
VC4_SET_FIELD(dsp5_mux, SCALER_DISPDITHER_DSP5_MUX));
297303
}
298304

299305
static void
@@ -789,16 +795,19 @@ static int vc4_pv_muxing_atomic_check(struct drm_device *dev,
789795
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
790796
unsigned int matching_channels;
791797

792-
if (old_crtc_state->enable && !new_crtc_state->enable) {
793-
hvs_new_state->unassigned_channels |= BIT(old_vc4_crtc_state->assigned_channel);
794-
new_vc4_crtc_state->assigned_channel = VC4_HVS_CHANNEL_DISABLED;
795-
}
796-
797-
if (!new_crtc_state->enable)
798+
/* Nothing to do here, let's skip it */
799+
if (old_crtc_state->enable == new_crtc_state->enable)
798800
continue;
799801

800-
if (new_vc4_crtc_state->assigned_channel != VC4_HVS_CHANNEL_DISABLED)
802+
/* Muxing will need to be modified, mark it as such */
803+
new_vc4_crtc_state->update_muxing = true;
804+
805+
/* If we're disabling our CRTC, we put back our channel */
806+
if (!new_crtc_state->enable) {
807+
hvs_new_state->unassigned_channels |= BIT(old_vc4_crtc_state->assigned_channel);
808+
new_vc4_crtc_state->assigned_channel = VC4_HVS_CHANNEL_DISABLED;
801809
continue;
810+
}
802811

803812
/*
804813
* The problem we have to solve here is that we have

0 commit comments

Comments
 (0)