Commit 0464ed1a authored by Maxime Ripard's avatar Maxime Ripard

drm/probe-helper: Create a HPD IRQ event helper for a single connector

The drm_helper_hpd_irq_event() function is iterating over all the
connectors when an hotplug event is detected.

During that iteration, it will call each connector detect function and
figure out if its status changed.

Finally, if any connector changed, it will notify the user-space and the
clients that something changed on the DRM device.

This is supposed to be used for drivers that don't have a hotplug
interrupt for individual connectors. However, drivers that can use an
interrupt for a single connector are left in the dust and can either
reimplement the logic used during the iteration for each connector or
use that helper and iterate over all connectors all the time.

Since both are suboptimal, let's create a helper that will only perform
the status detection on a single connector.
Signed-off-by: default avatarMaxime Ripard <maxime@cerno.tech>
Reviewed-by: default avatarSam Ravnborg <sam@ravnborg.org>
Link: https://patchwork.freedesktop.org/patch/msgid/20210914101724.266570-2-maxime@cerno.tech
parent 7dad41aa
......@@ -795,6 +795,86 @@ void drm_kms_helper_poll_fini(struct drm_device *dev)
}
EXPORT_SYMBOL(drm_kms_helper_poll_fini);
static bool check_connector_changed(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
enum drm_connector_status old_status;
u64 old_epoch_counter;
/* Only handle HPD capable connectors. */
drm_WARN_ON(dev, !(connector->polled & DRM_CONNECTOR_POLL_HPD));
drm_WARN_ON(dev, !mutex_is_locked(&dev->mode_config.mutex));
old_status = connector->status;
old_epoch_counter = connector->epoch_counter;
connector->status = drm_helper_probe_detect(connector, NULL, false);
if (old_epoch_counter == connector->epoch_counter) {
drm_dbg_kms(dev, "[CONNECTOR:%d:%s] Same epoch counter %llu\n",
connector->base.id,
connector->name,
connector->epoch_counter);
return false;
}
drm_dbg_kms(dev, "[CONNECTOR:%d:%s] status updated from %s to %s\n",
connector->base.id,
connector->name,
drm_get_connector_status_name(old_status),
drm_get_connector_status_name(connector->status));
drm_dbg_kms(dev, "[CONNECTOR:%d:%s] Changed epoch counter %llu => %llu\n",
connector->base.id,
connector->name,
old_epoch_counter,
connector->epoch_counter);
return true;
}
/**
* drm_connector_helper_hpd_irq_event - hotplug processing
* @connector: drm_connector
*
* Drivers can use this helper function to run a detect cycle on a connector
* which has the DRM_CONNECTOR_POLL_HPD flag set in its &polled member.
*
* This helper function is useful for drivers which can track hotplug
* interrupts for a single connector. Drivers that want to send a
* hotplug event for all connectors or can't track hotplug interrupts
* per connector need to use drm_helper_hpd_irq_event().
*
* This function must be called from process context with no mode
* setting locks held.
*
* Note that a connector can be both polled and probed from the hotplug
* handler, in case the hotplug interrupt is known to be unreliable.
*
* Returns:
* A boolean indicating whether the connector status changed or not
*/
bool drm_connector_helper_hpd_irq_event(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
bool changed;
mutex_lock(&dev->mode_config.mutex);
changed = check_connector_changed(connector);
mutex_unlock(&dev->mode_config.mutex);
if (changed) {
drm_kms_helper_hotplug_event(dev);
drm_dbg_kms(dev, "[CONNECTOR:%d:%s] Sent hotplug event\n",
connector->base.id,
connector->name);
}
return changed;
}
EXPORT_SYMBOL(drm_connector_helper_hpd_irq_event);
/**
* drm_helper_hpd_irq_event - hotplug processing
* @dev: drm_device
......@@ -808,9 +888,10 @@ EXPORT_SYMBOL(drm_kms_helper_poll_fini);
* interrupts for each connector.
*
* Drivers which support hotplug interrupts for each connector individually and
* which have a more fine-grained detect logic should bypass this code and
* directly call drm_kms_helper_hotplug_event() in case the connector state
* changed.
* which have a more fine-grained detect logic can use
* drm_connector_helper_hpd_irq_event(). Alternatively, they should bypass this
* code and directly call drm_kms_helper_hotplug_event() in case the connector
* state changed.
*
* This function must be called from process context with no mode
* setting locks held.
......@@ -825,9 +906,7 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev)
{
struct drm_connector *connector;
struct drm_connector_list_iter conn_iter;
enum drm_connector_status old_status;
bool changed = false;
u64 old_epoch_counter;
if (!dev->mode_config.poll_enabled)
return false;
......@@ -839,33 +918,8 @@ bool drm_helper_hpd_irq_event(struct drm_device *dev)
if (!(connector->polled & DRM_CONNECTOR_POLL_HPD))
continue;
old_status = connector->status;
old_epoch_counter = connector->epoch_counter;
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] Old epoch counter %llu\n", connector->base.id,
connector->name,
old_epoch_counter);
connector->status = drm_helper_probe_detect(connector, NULL, false);
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n",
connector->base.id,
connector->name,
drm_get_connector_status_name(old_status),
drm_get_connector_status_name(connector->status));
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] New epoch counter %llu\n",
connector->base.id,
connector->name,
connector->epoch_counter);
/*
* Check if epoch counter had changed, meaning that we need
* to send a uevent.
*/
if (old_epoch_counter != connector->epoch_counter)
if (check_connector_changed(connector))
changed = true;
}
drm_connector_list_iter_end(&conn_iter);
mutex_unlock(&dev->mode_config.mutex);
......
......@@ -18,6 +18,7 @@ int drm_helper_probe_detect(struct drm_connector *connector,
void drm_kms_helper_poll_init(struct drm_device *dev);
void drm_kms_helper_poll_fini(struct drm_device *dev);
bool drm_helper_hpd_irq_event(struct drm_device *dev);
bool drm_connector_helper_hpd_irq_event(struct drm_connector *connector);
void drm_kms_helper_hotplug_event(struct drm_device *dev);
void drm_kms_helper_poll_disable(struct drm_device *dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment