drm/msm/sde: support connector/crtc events
This patch adds support for internal driver events:
- direct callbacks may be registered against the sde connector,
and triggered via a new "trigger event" sde connector function;
this is suitable for simple event handlers that may be run
from within an ISR context
- delayed event handling may be posted against CRTCs, allowing
for event processing to occur within a worker thread rather
than the originating context (e.g., ISR handlers)
CRs-Fixed: 2005395
Change-Id: Idb0439892dfbda72d3c0ada882915492e3836ad8
Signed-off-by: Clarence Ip <cip@codeaurora.org>
diff --git a/drivers/gpu/drm/msm/sde/sde_connector.c b/drivers/gpu/drm/msm/sde/sde_connector.c
index 0e5342f..92b7e5d 100644
--- a/drivers/gpu/drm/msm/sde/sde_connector.c
+++ b/drivers/gpu/drm/msm/sde/sde_connector.c
@@ -115,6 +115,83 @@
return 0;
}
+int sde_connector_trigger_event(void *drm_connector,
+ uint32_t event_idx, uint32_t instance_idx,
+ uint32_t data0, uint32_t data1,
+ uint32_t data2, uint32_t data3)
+{
+ struct sde_connector *c_conn;
+ unsigned long irq_flags;
+ void (*cb_func)(uint32_t event_idx,
+ uint32_t instance_idx, void *usr,
+ uint32_t data0, uint32_t data1,
+ uint32_t data2, uint32_t data3);
+ void *usr;
+ int rc = 0;
+
+ /*
+ * This function may potentially be called from an ISR context, so
+ * avoid excessive logging/etc.
+ */
+ if (!drm_connector)
+ return -EINVAL;
+ else if (event_idx >= SDE_CONN_EVENT_COUNT)
+ return -EINVAL;
+ c_conn = to_sde_connector(drm_connector);
+
+ spin_lock_irqsave(&c_conn->event_lock, irq_flags);
+ cb_func = c_conn->event_table[event_idx].cb_func;
+ usr = c_conn->event_table[event_idx].usr;
+ spin_unlock_irqrestore(&c_conn->event_lock, irq_flags);
+
+ if (cb_func)
+ cb_func(event_idx, instance_idx, usr,
+ data0, data1, data2, data3);
+ else
+ rc = -EAGAIN;
+
+ return rc;
+}
+
+int sde_connector_register_event(struct drm_connector *connector,
+ uint32_t event_idx,
+ void (*cb_func)(uint32_t event_idx,
+ uint32_t instance_idx, void *usr,
+ uint32_t data0, uint32_t data1,
+ uint32_t data2, uint32_t data3),
+ void *usr)
+{
+ struct sde_connector *c_conn;
+ unsigned long irq_flags;
+
+ if (!connector) {
+ SDE_ERROR("invalid connector\n");
+ return -EINVAL;
+ } else if (event_idx >= SDE_CONN_EVENT_COUNT) {
+ SDE_ERROR("conn%d, invalid event %d\n",
+ connector->base.id, event_idx);
+ return -EINVAL;
+ }
+ c_conn = to_sde_connector(connector);
+
+ spin_lock_irqsave(&c_conn->event_lock, irq_flags);
+ c_conn->event_table[event_idx].cb_func = cb_func;
+ c_conn->event_table[event_idx].usr = usr;
+ spin_unlock_irqrestore(&c_conn->event_lock, irq_flags);
+
+ /* optionally notify display of event registration */
+ if (c_conn->ops.enable_event && c_conn->display)
+ c_conn->ops.enable_event(connector, event_idx,
+ cb_func != NULL, c_conn->display);
+ return 0;
+}
+
+void sde_connector_unregister_event(struct drm_connector *connector,
+ uint32_t event_idx)
+{
+ (void)sde_connector_register_event(connector, event_idx, 0, 0);
+}
+
int sde_connector_get_info(struct drm_connector *connector,
struct msm_display_info *info)
{
@@ -616,6 +693,8 @@
if (rc)
goto error_free_conn;
+ spin_lock_init(&c_conn->event_lock);
+
c_conn->connector_type = connector_type;
c_conn->encoder = encoder;
c_conn->panel = panel;