mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	drm: Add an HPD poll helper to reschedule the poll work
Add a helper to reschedule drm_mode_config::output_poll_work after
polling has been enabled for a connector (and needing a reschedule,
since previously polling was disabled for all connectors and hence
output_poll_work was not running).
This is needed by the next patch fixing HPD polling on i915.
CC: stable@vger.kernel.org # 6.4+
Cc: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Cc: dri-devel@lists.freedesktop.org
Reviewed-by: Jouni Högander <jouni.hogander@intel.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20230822113015.41224-1-imre.deak@intel.com
(cherry picked from commit fe2352fd64)
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
			
			
This commit is contained in:
		
							parent
							
								
									e0d25c591a
								
							
						
					
					
						commit
						a94e7ccfc4
					
				
					 2 changed files with 47 additions and 22 deletions
				
			
		| 
						 | 
					@ -262,6 +262,26 @@ static bool drm_kms_helper_enable_hpd(struct drm_device *dev)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define DRM_OUTPUT_POLL_PERIOD (10*HZ)
 | 
					#define DRM_OUTPUT_POLL_PERIOD (10*HZ)
 | 
				
			||||||
 | 
					static void reschedule_output_poll_work(struct drm_device *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned long delay = DRM_OUTPUT_POLL_PERIOD;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (dev->mode_config.delayed_event)
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * FIXME:
 | 
				
			||||||
 | 
							 *
 | 
				
			||||||
 | 
							 * Use short (1s) delay to handle the initial delayed event.
 | 
				
			||||||
 | 
							 * This delay should not be needed, but Optimus/nouveau will
 | 
				
			||||||
 | 
							 * fail in a mysterious way if the delayed event is handled as
 | 
				
			||||||
 | 
							 * soon as possible like it is done in
 | 
				
			||||||
 | 
							 * drm_helper_probe_single_connector_modes() in case the poll
 | 
				
			||||||
 | 
							 * was enabled before.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							delay = HZ;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						schedule_delayed_work(&dev->mode_config.output_poll_work, delay);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * drm_kms_helper_poll_enable - re-enable output polling.
 | 
					 * drm_kms_helper_poll_enable - re-enable output polling.
 | 
				
			||||||
 * @dev: drm_device
 | 
					 * @dev: drm_device
 | 
				
			||||||
| 
						 | 
					@ -279,37 +299,41 @@ static bool drm_kms_helper_enable_hpd(struct drm_device *dev)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void drm_kms_helper_poll_enable(struct drm_device *dev)
 | 
					void drm_kms_helper_poll_enable(struct drm_device *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	bool poll = false;
 | 
					 | 
				
			||||||
	unsigned long delay = DRM_OUTPUT_POLL_PERIOD;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!dev->mode_config.poll_enabled || !drm_kms_helper_poll ||
 | 
						if (!dev->mode_config.poll_enabled || !drm_kms_helper_poll ||
 | 
				
			||||||
	    dev->mode_config.poll_running)
 | 
						    dev->mode_config.poll_running)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	poll = drm_kms_helper_enable_hpd(dev);
 | 
						if (drm_kms_helper_enable_hpd(dev) ||
 | 
				
			||||||
 | 
						    dev->mode_config.delayed_event)
 | 
				
			||||||
	if (dev->mode_config.delayed_event) {
 | 
							reschedule_output_poll_work(dev);
 | 
				
			||||||
		/*
 | 
					 | 
				
			||||||
		 * FIXME:
 | 
					 | 
				
			||||||
		 *
 | 
					 | 
				
			||||||
		 * Use short (1s) delay to handle the initial delayed event.
 | 
					 | 
				
			||||||
		 * This delay should not be needed, but Optimus/nouveau will
 | 
					 | 
				
			||||||
		 * fail in a mysterious way if the delayed event is handled as
 | 
					 | 
				
			||||||
		 * soon as possible like it is done in
 | 
					 | 
				
			||||||
		 * drm_helper_probe_single_connector_modes() in case the poll
 | 
					 | 
				
			||||||
		 * was enabled before.
 | 
					 | 
				
			||||||
		 */
 | 
					 | 
				
			||||||
		poll = true;
 | 
					 | 
				
			||||||
		delay = HZ;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (poll)
 | 
					 | 
				
			||||||
		schedule_delayed_work(&dev->mode_config.output_poll_work, delay);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	dev->mode_config.poll_running = true;
 | 
						dev->mode_config.poll_running = true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL(drm_kms_helper_poll_enable);
 | 
					EXPORT_SYMBOL(drm_kms_helper_poll_enable);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * drm_kms_helper_poll_reschedule - reschedule the output polling work
 | 
				
			||||||
 | 
					 * @dev: drm_device
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This function reschedules the output polling work, after polling for a
 | 
				
			||||||
 | 
					 * connector has been enabled.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Drivers must call this helper after enabling polling for a connector by
 | 
				
			||||||
 | 
					 * setting %DRM_CONNECTOR_POLL_CONNECT / %DRM_CONNECTOR_POLL_DISCONNECT flags
 | 
				
			||||||
 | 
					 * in drm_connector::polled. Note that after disabling polling by clearing these
 | 
				
			||||||
 | 
					 * flags for a connector will stop the output polling work automatically if
 | 
				
			||||||
 | 
					 * the polling is disabled for all other connectors as well.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The function can be called only after polling has been enabled by calling
 | 
				
			||||||
 | 
					 * drm_kms_helper_poll_init() / drm_kms_helper_poll_enable().
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void drm_kms_helper_poll_reschedule(struct drm_device *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (dev->mode_config.poll_running)
 | 
				
			||||||
 | 
							reschedule_output_poll_work(dev);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					EXPORT_SYMBOL(drm_kms_helper_poll_reschedule);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static enum drm_connector_status
 | 
					static enum drm_connector_status
 | 
				
			||||||
drm_helper_probe_detect_ctx(struct drm_connector *connector, bool force)
 | 
					drm_helper_probe_detect_ctx(struct drm_connector *connector, bool force)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,6 +25,7 @@ void drm_kms_helper_connector_hotplug_event(struct drm_connector *connector);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void drm_kms_helper_poll_disable(struct drm_device *dev);
 | 
					void drm_kms_helper_poll_disable(struct drm_device *dev);
 | 
				
			||||||
void drm_kms_helper_poll_enable(struct drm_device *dev);
 | 
					void drm_kms_helper_poll_enable(struct drm_device *dev);
 | 
				
			||||||
 | 
					void drm_kms_helper_poll_reschedule(struct drm_device *dev);
 | 
				
			||||||
bool drm_kms_helper_is_poll_worker(void);
 | 
					bool drm_kms_helper_is_poll_worker(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum drm_mode_status drm_crtc_helper_mode_valid_fixed(struct drm_crtc *crtc,
 | 
					enum drm_mode_status drm_crtc_helper_mode_valid_fixed(struct drm_crtc *crtc,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue