Skip to content

Commit 8ba0b6d

Browse files
committed
drm/vc4: crtc: Keep the previously assigned HVS FIFO
The HVS FIFOs are currently assigned each time we have an atomic_check for all the enabled CRTCs. However, if we are running multiple outputs in parallel and we happen to disable the first (by index) CRTC, we end up changing the assigned FIFO of the second CRTC without disabling and reenabling the pixelvalve which ends up in a stall and eventually a VBLANK timeout. In order to fix this, we can create a special value for our assigned channel to mark it as disabled, and if our CRTC already had an assigned channel in its previous state, we keep on using it. Fixes: 87ebcd4 ("drm/vc4: crtc: Assign output to channel automatically") Signed-off-by: Maxime Ripard <[email protected]> Tested-by: Dave Stevenson <[email protected]> Reviewed-by: Dave Stevenson <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent 427c4a0 commit 8ba0b6d

File tree

3 files changed

+19
-6
lines changed

3 files changed

+19
-6
lines changed

drivers/gpu/drm/vc4/vc4_crtc.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -863,6 +863,7 @@ void vc4_crtc_reset(struct drm_crtc *crtc)
863863
return;
864864
}
865865

866+
vc4_crtc_state->assigned_channel = VC4_HVS_CHANNEL_DISABLED;
866867
__drm_atomic_helper_crtc_reset(crtc, &vc4_crtc_state->base);
867868
}
868869

drivers/gpu/drm/vc4/vc4_drv.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,8 @@ struct vc4_crtc_state {
532532
} margins;
533533
};
534534

535+
#define VC4_HVS_CHANNEL_DISABLED ((unsigned int)-1)
536+
535537
static inline struct vc4_crtc_state *
536538
to_vc4_crtc_state(struct drm_crtc_state *crtc_state)
537539
{

drivers/gpu/drm/vc4/vc4_kms.c

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -616,7 +616,7 @@ static int
616616
vc4_atomic_check(struct drm_device *dev, struct drm_atomic_state *state)
617617
{
618618
unsigned long unassigned_channels = GENMASK(NUM_CHANNELS - 1, 0);
619-
struct drm_crtc_state *crtc_state;
619+
struct drm_crtc_state *old_crtc_state, *new_crtc_state;
620620
struct drm_crtc *crtc;
621621
int i, ret;
622622

@@ -629,6 +629,8 @@ vc4_atomic_check(struct drm_device *dev, struct drm_atomic_state *state)
629629
* modified.
630630
*/
631631
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
632+
struct drm_crtc_state *crtc_state;
633+
632634
if (!crtc->state->enable)
633635
continue;
634636

@@ -637,14 +639,22 @@ vc4_atomic_check(struct drm_device *dev, struct drm_atomic_state *state)
637639
return PTR_ERR(crtc_state);
638640
}
639641

640-
for_each_new_crtc_in_state(state, crtc, crtc_state, i) {
641-
struct vc4_crtc_state *vc4_crtc_state =
642-
to_vc4_crtc_state(crtc_state);
642+
for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
643+
struct vc4_crtc_state *new_vc4_crtc_state =
644+
to_vc4_crtc_state(new_crtc_state);
643645
struct vc4_crtc *vc4_crtc = to_vc4_crtc(crtc);
644646
unsigned int matching_channels;
645647

646-
if (!crtc_state->enable)
648+
if (old_crtc_state->enable && !new_crtc_state->enable)
649+
new_vc4_crtc_state->assigned_channel = VC4_HVS_CHANNEL_DISABLED;
650+
651+
if (!new_crtc_state->enable)
652+
continue;
653+
654+
if (new_vc4_crtc_state->assigned_channel != VC4_HVS_CHANNEL_DISABLED) {
655+
unassigned_channels &= ~BIT(new_vc4_crtc_state->assigned_channel);
647656
continue;
657+
}
648658

649659
/*
650660
* The problem we have to solve here is that we have
@@ -674,7 +684,7 @@ vc4_atomic_check(struct drm_device *dev, struct drm_atomic_state *state)
674684
if (matching_channels) {
675685
unsigned int channel = ffs(matching_channels) - 1;
676686

677-
vc4_crtc_state->assigned_channel = channel;
687+
new_vc4_crtc_state->assigned_channel = channel;
678688
unassigned_channels &= ~BIT(channel);
679689
} else {
680690
return -EINVAL;

0 commit comments

Comments
 (0)