@@ -37,6 +37,17 @@ static struct vc4_ctm_state *to_vc4_ctm_state(struct drm_private_state *priv)
3737 return container_of (priv , struct vc4_ctm_state , base );
3838}
3939
40+ struct vc4_hvs_state {
41+ struct drm_private_state base ;
42+ unsigned int unassigned_channels ;
43+ };
44+
45+ static struct vc4_hvs_state *
46+ to_vc4_hvs_state (struct drm_private_state * priv )
47+ {
48+ return container_of (priv , struct vc4_hvs_state , base );
49+ }
50+
4051struct vc4_load_tracker_state {
4152 struct drm_private_state base ;
4253 u64 hvs_load ;
@@ -171,6 +182,19 @@ vc4_ctm_commit(struct vc4_dev *vc4, struct drm_atomic_state *state)
171182 VC4_SET_FIELD (ctm_state -> fifo , SCALER_OLEDOFFS_DISPFIFO ));
172183}
173184
185+ static struct vc4_hvs_state *
186+ vc4_hvs_get_global_state (struct drm_atomic_state * state )
187+ {
188+ struct vc4_dev * vc4 = to_vc4_dev (state -> dev );
189+ struct drm_private_state * priv_state ;
190+
191+ priv_state = drm_atomic_get_private_obj_state (state , & vc4 -> hvs_channels );
192+ if (IS_ERR (priv_state ))
193+ return ERR_CAST (priv_state );
194+
195+ return to_vc4_hvs_state (priv_state );
196+ }
197+
174198static void vc4_hvs_pv_muxing_commit (struct vc4_dev * vc4 ,
175199 struct drm_atomic_state * state )
176200{
@@ -662,6 +686,59 @@ static int vc4_load_tracker_obj_init(struct vc4_dev *vc4)
662686 return drmm_add_action_or_reset (& vc4 -> base , vc4_load_tracker_obj_fini , NULL );
663687}
664688
689+ static struct drm_private_state *
690+ vc4_hvs_channels_duplicate_state (struct drm_private_obj * obj )
691+ {
692+ struct vc4_hvs_state * old_state = to_vc4_hvs_state (obj -> state );
693+ struct vc4_hvs_state * state ;
694+
695+ state = kzalloc (sizeof (* state ), GFP_KERNEL );
696+ if (!state )
697+ return NULL ;
698+
699+ __drm_atomic_helper_private_obj_duplicate_state (obj , & state -> base );
700+
701+ state -> unassigned_channels = old_state -> unassigned_channels ;
702+
703+ return & state -> base ;
704+ }
705+
706+ static void vc4_hvs_channels_destroy_state (struct drm_private_obj * obj ,
707+ struct drm_private_state * state )
708+ {
709+ struct vc4_hvs_state * hvs_state = to_vc4_hvs_state (state );
710+
711+ kfree (hvs_state );
712+ }
713+
714+ static const struct drm_private_state_funcs vc4_hvs_state_funcs = {
715+ .atomic_duplicate_state = vc4_hvs_channels_duplicate_state ,
716+ .atomic_destroy_state = vc4_hvs_channels_destroy_state ,
717+ };
718+
719+ static void vc4_hvs_channels_obj_fini (struct drm_device * dev , void * unused )
720+ {
721+ struct vc4_dev * vc4 = to_vc4_dev (dev );
722+
723+ drm_atomic_private_obj_fini (& vc4 -> hvs_channels );
724+ }
725+
726+ static int vc4_hvs_channels_obj_init (struct vc4_dev * vc4 )
727+ {
728+ struct vc4_hvs_state * state ;
729+
730+ state = kzalloc (sizeof (* state ), GFP_KERNEL );
731+ if (!state )
732+ return - ENOMEM ;
733+
734+ state -> unassigned_channels = GENMASK (HVS_NUM_CHANNELS - 1 , 0 );
735+ drm_atomic_private_obj_init (& vc4 -> base , & vc4 -> hvs_channels ,
736+ & state -> base ,
737+ & vc4_hvs_state_funcs );
738+
739+ return drmm_add_action_or_reset (& vc4 -> base , vc4_hvs_channels_obj_fini , NULL );
740+ }
741+
665742/*
666743 * The BCM2711 HVS has up to 7 outputs connected to the pixelvalves and
667744 * the TXP (and therefore all the CRTCs found on that platform).
@@ -678,6 +755,14 @@ static int vc4_load_tracker_obj_init(struct vc4_dev *vc4)
678755 * need to consider all the running CRTCs in the DRM device to assign
679756 * a FIFO, not just the one in the state.
680757 *
758+ * - To fix the above, we can't use drm_atomic_get_crtc_state on all
759+ * enabled CRTCs to pull their CRTC state into the global state, since
760+ * a page flip would start considering their vblank to complete. Since
761+ * we don't have a guarantee that they are actually active, that
762+ * vblank might never happen, and shouldn't even be considered if we
763+ * want to do a page flip on a single CRTC. That can be tested by
764+ * doing a modetest -v first on HDMI1 and then on HDMI0.
765+ *
681766 * - Since we need the pixelvalve to be disabled and enabled back when
682767 * the FIFO is changed, we should keep the FIFO assigned for as long
683768 * as the CRTC is enabled, only considering it free again once that
@@ -687,46 +772,33 @@ static int vc4_load_tracker_obj_init(struct vc4_dev *vc4)
687772static int vc4_pv_muxing_atomic_check (struct drm_device * dev ,
688773 struct drm_atomic_state * state )
689774{
690- unsigned long unassigned_channels = GENMASK ( HVS_NUM_CHANNELS - 1 , 0 ) ;
775+ struct vc4_hvs_state * hvs_new_state ;
691776 struct drm_crtc_state * old_crtc_state , * new_crtc_state ;
692777 struct drm_crtc * crtc ;
693778 unsigned int i ;
694779
695- /*
696- * Since the HVS FIFOs are shared across all the pixelvalves and
697- * the TXP (and thus all the CRTCs), we need to pull the current
698- * state of all the enabled CRTCs so that an update to a single
699- * CRTC still keeps the previous FIFOs enabled and assigned to
700- * the same CRTCs, instead of evaluating only the CRTC being
701- * modified.
702- */
703- list_for_each_entry (crtc , & dev -> mode_config .crtc_list , head ) {
704- struct drm_crtc_state * crtc_state ;
705-
706- if (!crtc -> state -> enable )
707- continue ;
708-
709- crtc_state = drm_atomic_get_crtc_state (state , crtc );
710- if (IS_ERR (crtc_state ))
711- return PTR_ERR (crtc_state );
712- }
780+ hvs_new_state = vc4_hvs_get_global_state (state );
781+ if (!hvs_new_state )
782+ return - EINVAL ;
713783
714784 for_each_oldnew_crtc_in_state (state , crtc , old_crtc_state , new_crtc_state , i ) {
785+ struct vc4_crtc_state * old_vc4_crtc_state =
786+ to_vc4_crtc_state (old_crtc_state );
715787 struct vc4_crtc_state * new_vc4_crtc_state =
716788 to_vc4_crtc_state (new_crtc_state );
717789 struct vc4_crtc * vc4_crtc = to_vc4_crtc (crtc );
718790 unsigned int matching_channels ;
719791
720- if (old_crtc_state -> enable && !new_crtc_state -> enable )
792+ if (old_crtc_state -> enable && !new_crtc_state -> enable ) {
793+ hvs_new_state -> unassigned_channels |= BIT (old_vc4_crtc_state -> assigned_channel );
721794 new_vc4_crtc_state -> assigned_channel = VC4_HVS_CHANNEL_DISABLED ;
795+ }
722796
723797 if (!new_crtc_state -> enable )
724798 continue ;
725799
726- if (new_vc4_crtc_state -> assigned_channel != VC4_HVS_CHANNEL_DISABLED ) {
727- unassigned_channels &= ~BIT (new_vc4_crtc_state -> assigned_channel );
800+ if (new_vc4_crtc_state -> assigned_channel != VC4_HVS_CHANNEL_DISABLED )
728801 continue ;
729- }
730802
731803 /*
732804 * The problem we have to solve here is that we have
@@ -752,12 +824,12 @@ static int vc4_pv_muxing_atomic_check(struct drm_device *dev,
752824 * the future, we will need to have something smarter,
753825 * but it works so far.
754826 */
755- matching_channels = unassigned_channels & vc4_crtc -> data -> hvs_available_channels ;
827+ matching_channels = hvs_new_state -> unassigned_channels & vc4_crtc -> data -> hvs_available_channels ;
756828 if (matching_channels ) {
757829 unsigned int channel = ffs (matching_channels ) - 1 ;
758830
759831 new_vc4_crtc_state -> assigned_channel = channel ;
760- unassigned_channels &= ~BIT (channel );
832+ hvs_new_state -> unassigned_channels &= ~BIT (channel );
761833 } else {
762834 return - EINVAL ;
763835 }
@@ -841,6 +913,10 @@ int vc4_kms_load(struct drm_device *dev)
841913 if (ret )
842914 return ret ;
843915
916+ ret = vc4_hvs_channels_obj_init (vc4 );
917+ if (ret )
918+ return ret ;
919+
844920 drm_mode_config_reset (dev );
845921
846922 drm_kms_helper_poll_init (dev );
0 commit comments