Loading drivers/gpu/drm/msm/sde/sde_connector.c +79 −0 Original line number Diff line number Diff line Loading @@ -115,6 +115,83 @@ static int sde_backlight_setup(struct sde_connector *c_conn) 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) { Loading Loading @@ -616,6 +693,8 @@ struct drm_connector *sde_connector_init(struct drm_device *dev, 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; Loading drivers/gpu/drm/msm/sde/sde_connector.h +78 −0 Original line number Diff line number Diff line Loading @@ -120,6 +120,16 @@ struct sde_connector_ops { */ int (*get_info)(struct msm_display_info *info, void *display); /** * enable_event - notify display of event registration/unregistration * @connector: Pointer to drm connector structure * @event_idx: SDE connector event index * @enable: Whether the event is being enabled/disabled * @display: Pointer to private display structure */ void (*enable_event)(struct drm_connector *connector, uint32_t event_idx, bool enable, void *display); int (*set_backlight)(void *display, u32 bl_lvl); /** Loading @@ -130,6 +140,28 @@ struct sde_connector_ops { int (*soft_reset)(void *display); }; /** * enum sde_connector_events - list of recognized connector events */ enum sde_connector_events { SDE_CONN_EVENT_VID_DONE, /* video mode frame done */ SDE_CONN_EVENT_CMD_DONE, /* command mode frame done */ SDE_CONN_EVENT_COUNT, }; /** * struct sde_connector_evt - local event registration entry structure * @cb_func: Pointer to desired callback function * @usr: User pointer to pass to callback on event trigger */ struct sde_connector_evt { 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 - local sde connector structure * @base: Base drm connector structure Loading @@ -146,6 +178,8 @@ struct sde_connector_ops { * @property_data: Array of private data for generic property handling * @blob_caps: Pointer to blob structure for 'capabilities' property * @fb_kmap: true if kernel mapping of framebuffer is requested * @event_table: Array of registered events * @event_lock: Lock object for event_table */ struct sde_connector { struct drm_connector base; Loading @@ -168,6 +202,8 @@ struct sde_connector { struct drm_property_blob *blob_caps; bool fb_kmap; struct sde_connector_evt event_table[SDE_CONN_EVENT_COUNT]; spinlock_t event_lock; }; /** Loading Loading @@ -312,5 +348,47 @@ void sde_connector_complete_commit(struct drm_connector *connector); int sde_connector_get_info(struct drm_connector *connector, struct msm_display_info *info); /** * sde_connector_trigger_event - indicate that an event has occurred * Any callbacks that have been registered against this event will * be called from the same thread context. * @connector: Pointer to drm connector structure * @event_idx: Index of event to trigger * @instance_idx: Event-specific "instance index" to pass to callback * @data0: Event-specific "data" to pass to callback * @data1: Event-specific "data" to pass to callback * @data2: Event-specific "data" to pass to callback * @data3: Event-specific "data" to pass to callback * Returns: Zero on success */ 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); /** * sde_connector_register_event - register a callback function for an event * @connector: Pointer to drm connector structure * @event_idx: Index of event to register * @cb_func: Pointer to desired callback function * @usr: User pointer to pass to callback on event trigger * Returns: Zero on success */ 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); /** * sde_connector_unregister_event - unregister all callbacks for an event * @connector: Pointer to drm connector structure * @event_idx: Index of event to register */ void sde_connector_unregister_event(struct drm_connector *connector, uint32_t event_idx); #endif /* _SDE_CONNECTOR_H_ */ drivers/gpu/drm/msm/sde/sde_crtc.c +116 −1 Original line number Diff line number Diff line Loading @@ -58,6 +58,18 @@ static inline struct sde_kms *_sde_crtc_get_kms(struct drm_crtc *crtc) return to_sde_kms(priv->kms); } static void _sde_crtc_deinit_events(struct sde_crtc *sde_crtc) { if (!sde_crtc) return; if (sde_crtc->event_thread) { kthread_flush_worker(&sde_crtc->event_worker); kthread_stop(sde_crtc->event_thread); sde_crtc->event_thread = NULL; } } static void sde_crtc_destroy(struct drm_crtc *crtc) { struct sde_crtc *sde_crtc = to_sde_crtc(crtc); Loading @@ -74,6 +86,7 @@ static void sde_crtc_destroy(struct drm_crtc *crtc) mutex_destroy(&sde_crtc->crtc_lock); sde_fence_deinit(&sde_crtc->output_fence); _sde_crtc_deinit_events(sde_crtc); drm_crtc_cleanup(crtc); kfree(sde_crtc); Loading Loading @@ -1967,6 +1980,100 @@ static const struct drm_crtc_helper_funcs sde_crtc_helper_funcs = { .atomic_flush = sde_crtc_atomic_flush, }; static void _sde_crtc_event_cb(struct kthread_work *work) { struct sde_crtc_event *event; struct sde_crtc *sde_crtc; unsigned long irq_flags; if (!work) { SDE_ERROR("invalid work item\n"); return; } event = container_of(work, struct sde_crtc_event, kt_work); if (event->cb_func) event->cb_func(event->usr); /* set sde_crtc to NULL for static work structures */ sde_crtc = event->sde_crtc; if (!sde_crtc) return; spin_lock_irqsave(&sde_crtc->event_lock, irq_flags); list_add_tail(&event->list, &sde_crtc->event_free_list); spin_unlock_irqrestore(&sde_crtc->event_lock, irq_flags); } int sde_crtc_event_queue(struct drm_crtc *crtc, void (*func)(void *usr), void *usr) { unsigned long irq_flags; struct sde_crtc *sde_crtc; struct sde_crtc_event *event = NULL; if (!crtc || !func) return -EINVAL; sde_crtc = to_sde_crtc(crtc); /* * Obtain an event struct from the private cache. This event * queue may be called from ISR contexts, so use a private * cache to avoid calling any memory allocation functions. */ spin_lock_irqsave(&sde_crtc->event_lock, irq_flags); if (!list_empty(&sde_crtc->event_free_list)) { event = list_first_entry(&sde_crtc->event_free_list, struct sde_crtc_event, list); list_del_init(&event->list); } spin_unlock_irqrestore(&sde_crtc->event_lock, irq_flags); if (!event) return -ENOMEM; /* populate event node */ event->sde_crtc = sde_crtc; event->cb_func = func; event->usr = usr; /* queue new event request */ kthread_init_work(&event->kt_work, _sde_crtc_event_cb); kthread_queue_work(&sde_crtc->event_worker, &event->kt_work); return 0; } static int _sde_crtc_init_events(struct sde_crtc *sde_crtc) { int i, rc = 0; if (!sde_crtc) { SDE_ERROR("invalid crtc\n"); return -EINVAL; } spin_lock_init(&sde_crtc->event_lock); INIT_LIST_HEAD(&sde_crtc->event_free_list); for (i = 0; i < SDE_CRTC_MAX_EVENT_COUNT; ++i) list_add_tail(&sde_crtc->event_cache[i].list, &sde_crtc->event_free_list); kthread_init_worker(&sde_crtc->event_worker); sde_crtc->event_thread = kthread_run(kthread_worker_fn, &sde_crtc->event_worker, "crtc_event:%d", sde_crtc->base.base.id); if (IS_ERR_OR_NULL(sde_crtc->event_thread)) { SDE_ERROR("failed to create event thread\n"); rc = PTR_ERR(sde_crtc->event_thread); sde_crtc->event_thread = NULL; } return rc; } /* initialize crtc */ struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_plane *plane) { Loading @@ -1974,7 +2081,7 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_plane *plane) struct sde_crtc *sde_crtc = NULL; struct msm_drm_private *priv = NULL; struct sde_kms *kms = NULL; int i; int i, rc; priv = dev->dev_private; kms = to_sde_kms(priv->kms); Loading Loading @@ -2008,6 +2115,14 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_plane *plane) /* save user friendly CRTC name for later */ snprintf(sde_crtc->name, SDE_CRTC_NAME_SIZE, "crtc%u", crtc->base.id); /* initialize event handling */ rc = _sde_crtc_init_events(sde_crtc); if (rc) { drm_crtc_cleanup(crtc); kfree(sde_crtc); return ERR_PTR(rc); } /* initialize output fence support */ mutex_init(&sde_crtc->crtc_lock); sde_fence_init(&sde_crtc->output_fence, sde_crtc->name, crtc->base.id); Loading drivers/gpu/drm/msm/sde/sde_crtc.h +45 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #ifndef _SDE_CRTC_H_ #define _SDE_CRTC_H_ #include <linux/kthread.h> #include "drm_crtc.h" #include "msm_prop.h" #include "sde_fence.h" Loading Loading @@ -78,6 +79,28 @@ struct sde_crtc_frame_event { u32 event; }; /** * struct sde_crtc_event - event callback tracking structure * @list: Linked list tracking node * @kt_work: Kthread worker structure * @sde_crtc: Pointer to associated sde_crtc structure * @cb_func: Pointer to callback function * @usr: Pointer to user data to be provided to the callback */ struct sde_crtc_event { struct list_head list; struct kthread_work kt_work; void *sde_crtc; void (*cb_func)(void *usr); void *usr; }; /* * Maximum number of free event structures to cache */ #define SDE_CRTC_MAX_EVENT_COUNT 16 /** * struct sde_crtc - virtualized CRTC data structure * @base : Base drm crtc structure Loading Loading @@ -105,6 +128,11 @@ struct sde_crtc_frame_event { * @frame_events : static allocation of in-flight frame events * @frame_event_list : available frame event list * @spin_lock : spin lock for frame event, transaction status, etc... * @event_thread : Pointer to event handler thread * @event_worker : Event worker queue * @event_cache : Local cache of event worker structures * @event_free_list : List of available event structures * @event_lock : Spinlock around event handling code */ struct sde_crtc { struct drm_crtc base; Loading Loading @@ -142,6 +170,13 @@ struct sde_crtc { struct sde_crtc_frame_event frame_events[SDE_CRTC_FRAME_EVENT_SIZE]; struct list_head frame_event_list; spinlock_t spin_lock; /* for handling internal event thread */ struct task_struct *event_thread; struct kthread_worker event_worker; struct sde_crtc_event event_cache[SDE_CRTC_MAX_EVENT_COUNT]; struct list_head event_free_list; spinlock_t event_lock; }; #define to_sde_crtc(x) container_of(x, struct sde_crtc, base) Loading Loading @@ -308,4 +343,14 @@ static inline bool sde_crtc_is_enabled(struct drm_crtc *crtc) return crtc ? crtc->enabled : false; } /** * sde_crtc_event_queue - request event callback * @crtc: Pointer to drm crtc structure * @func: Pointer to callback function * @usr: Pointer to user data to be passed to callback * Returns: Zero on success */ int sde_crtc_event_queue(struct drm_crtc *crtc, void (*func)(void *usr), void *usr); #endif /* _SDE_CRTC_H_ */ Loading
drivers/gpu/drm/msm/sde/sde_connector.c +79 −0 Original line number Diff line number Diff line Loading @@ -115,6 +115,83 @@ static int sde_backlight_setup(struct sde_connector *c_conn) 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) { Loading Loading @@ -616,6 +693,8 @@ struct drm_connector *sde_connector_init(struct drm_device *dev, 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; Loading
drivers/gpu/drm/msm/sde/sde_connector.h +78 −0 Original line number Diff line number Diff line Loading @@ -120,6 +120,16 @@ struct sde_connector_ops { */ int (*get_info)(struct msm_display_info *info, void *display); /** * enable_event - notify display of event registration/unregistration * @connector: Pointer to drm connector structure * @event_idx: SDE connector event index * @enable: Whether the event is being enabled/disabled * @display: Pointer to private display structure */ void (*enable_event)(struct drm_connector *connector, uint32_t event_idx, bool enable, void *display); int (*set_backlight)(void *display, u32 bl_lvl); /** Loading @@ -130,6 +140,28 @@ struct sde_connector_ops { int (*soft_reset)(void *display); }; /** * enum sde_connector_events - list of recognized connector events */ enum sde_connector_events { SDE_CONN_EVENT_VID_DONE, /* video mode frame done */ SDE_CONN_EVENT_CMD_DONE, /* command mode frame done */ SDE_CONN_EVENT_COUNT, }; /** * struct sde_connector_evt - local event registration entry structure * @cb_func: Pointer to desired callback function * @usr: User pointer to pass to callback on event trigger */ struct sde_connector_evt { 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 - local sde connector structure * @base: Base drm connector structure Loading @@ -146,6 +178,8 @@ struct sde_connector_ops { * @property_data: Array of private data for generic property handling * @blob_caps: Pointer to blob structure for 'capabilities' property * @fb_kmap: true if kernel mapping of framebuffer is requested * @event_table: Array of registered events * @event_lock: Lock object for event_table */ struct sde_connector { struct drm_connector base; Loading @@ -168,6 +202,8 @@ struct sde_connector { struct drm_property_blob *blob_caps; bool fb_kmap; struct sde_connector_evt event_table[SDE_CONN_EVENT_COUNT]; spinlock_t event_lock; }; /** Loading Loading @@ -312,5 +348,47 @@ void sde_connector_complete_commit(struct drm_connector *connector); int sde_connector_get_info(struct drm_connector *connector, struct msm_display_info *info); /** * sde_connector_trigger_event - indicate that an event has occurred * Any callbacks that have been registered against this event will * be called from the same thread context. * @connector: Pointer to drm connector structure * @event_idx: Index of event to trigger * @instance_idx: Event-specific "instance index" to pass to callback * @data0: Event-specific "data" to pass to callback * @data1: Event-specific "data" to pass to callback * @data2: Event-specific "data" to pass to callback * @data3: Event-specific "data" to pass to callback * Returns: Zero on success */ 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); /** * sde_connector_register_event - register a callback function for an event * @connector: Pointer to drm connector structure * @event_idx: Index of event to register * @cb_func: Pointer to desired callback function * @usr: User pointer to pass to callback on event trigger * Returns: Zero on success */ 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); /** * sde_connector_unregister_event - unregister all callbacks for an event * @connector: Pointer to drm connector structure * @event_idx: Index of event to register */ void sde_connector_unregister_event(struct drm_connector *connector, uint32_t event_idx); #endif /* _SDE_CONNECTOR_H_ */
drivers/gpu/drm/msm/sde/sde_crtc.c +116 −1 Original line number Diff line number Diff line Loading @@ -58,6 +58,18 @@ static inline struct sde_kms *_sde_crtc_get_kms(struct drm_crtc *crtc) return to_sde_kms(priv->kms); } static void _sde_crtc_deinit_events(struct sde_crtc *sde_crtc) { if (!sde_crtc) return; if (sde_crtc->event_thread) { kthread_flush_worker(&sde_crtc->event_worker); kthread_stop(sde_crtc->event_thread); sde_crtc->event_thread = NULL; } } static void sde_crtc_destroy(struct drm_crtc *crtc) { struct sde_crtc *sde_crtc = to_sde_crtc(crtc); Loading @@ -74,6 +86,7 @@ static void sde_crtc_destroy(struct drm_crtc *crtc) mutex_destroy(&sde_crtc->crtc_lock); sde_fence_deinit(&sde_crtc->output_fence); _sde_crtc_deinit_events(sde_crtc); drm_crtc_cleanup(crtc); kfree(sde_crtc); Loading Loading @@ -1967,6 +1980,100 @@ static const struct drm_crtc_helper_funcs sde_crtc_helper_funcs = { .atomic_flush = sde_crtc_atomic_flush, }; static void _sde_crtc_event_cb(struct kthread_work *work) { struct sde_crtc_event *event; struct sde_crtc *sde_crtc; unsigned long irq_flags; if (!work) { SDE_ERROR("invalid work item\n"); return; } event = container_of(work, struct sde_crtc_event, kt_work); if (event->cb_func) event->cb_func(event->usr); /* set sde_crtc to NULL for static work structures */ sde_crtc = event->sde_crtc; if (!sde_crtc) return; spin_lock_irqsave(&sde_crtc->event_lock, irq_flags); list_add_tail(&event->list, &sde_crtc->event_free_list); spin_unlock_irqrestore(&sde_crtc->event_lock, irq_flags); } int sde_crtc_event_queue(struct drm_crtc *crtc, void (*func)(void *usr), void *usr) { unsigned long irq_flags; struct sde_crtc *sde_crtc; struct sde_crtc_event *event = NULL; if (!crtc || !func) return -EINVAL; sde_crtc = to_sde_crtc(crtc); /* * Obtain an event struct from the private cache. This event * queue may be called from ISR contexts, so use a private * cache to avoid calling any memory allocation functions. */ spin_lock_irqsave(&sde_crtc->event_lock, irq_flags); if (!list_empty(&sde_crtc->event_free_list)) { event = list_first_entry(&sde_crtc->event_free_list, struct sde_crtc_event, list); list_del_init(&event->list); } spin_unlock_irqrestore(&sde_crtc->event_lock, irq_flags); if (!event) return -ENOMEM; /* populate event node */ event->sde_crtc = sde_crtc; event->cb_func = func; event->usr = usr; /* queue new event request */ kthread_init_work(&event->kt_work, _sde_crtc_event_cb); kthread_queue_work(&sde_crtc->event_worker, &event->kt_work); return 0; } static int _sde_crtc_init_events(struct sde_crtc *sde_crtc) { int i, rc = 0; if (!sde_crtc) { SDE_ERROR("invalid crtc\n"); return -EINVAL; } spin_lock_init(&sde_crtc->event_lock); INIT_LIST_HEAD(&sde_crtc->event_free_list); for (i = 0; i < SDE_CRTC_MAX_EVENT_COUNT; ++i) list_add_tail(&sde_crtc->event_cache[i].list, &sde_crtc->event_free_list); kthread_init_worker(&sde_crtc->event_worker); sde_crtc->event_thread = kthread_run(kthread_worker_fn, &sde_crtc->event_worker, "crtc_event:%d", sde_crtc->base.base.id); if (IS_ERR_OR_NULL(sde_crtc->event_thread)) { SDE_ERROR("failed to create event thread\n"); rc = PTR_ERR(sde_crtc->event_thread); sde_crtc->event_thread = NULL; } return rc; } /* initialize crtc */ struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_plane *plane) { Loading @@ -1974,7 +2081,7 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_plane *plane) struct sde_crtc *sde_crtc = NULL; struct msm_drm_private *priv = NULL; struct sde_kms *kms = NULL; int i; int i, rc; priv = dev->dev_private; kms = to_sde_kms(priv->kms); Loading Loading @@ -2008,6 +2115,14 @@ struct drm_crtc *sde_crtc_init(struct drm_device *dev, struct drm_plane *plane) /* save user friendly CRTC name for later */ snprintf(sde_crtc->name, SDE_CRTC_NAME_SIZE, "crtc%u", crtc->base.id); /* initialize event handling */ rc = _sde_crtc_init_events(sde_crtc); if (rc) { drm_crtc_cleanup(crtc); kfree(sde_crtc); return ERR_PTR(rc); } /* initialize output fence support */ mutex_init(&sde_crtc->crtc_lock); sde_fence_init(&sde_crtc->output_fence, sde_crtc->name, crtc->base.id); Loading
drivers/gpu/drm/msm/sde/sde_crtc.h +45 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #ifndef _SDE_CRTC_H_ #define _SDE_CRTC_H_ #include <linux/kthread.h> #include "drm_crtc.h" #include "msm_prop.h" #include "sde_fence.h" Loading Loading @@ -78,6 +79,28 @@ struct sde_crtc_frame_event { u32 event; }; /** * struct sde_crtc_event - event callback tracking structure * @list: Linked list tracking node * @kt_work: Kthread worker structure * @sde_crtc: Pointer to associated sde_crtc structure * @cb_func: Pointer to callback function * @usr: Pointer to user data to be provided to the callback */ struct sde_crtc_event { struct list_head list; struct kthread_work kt_work; void *sde_crtc; void (*cb_func)(void *usr); void *usr; }; /* * Maximum number of free event structures to cache */ #define SDE_CRTC_MAX_EVENT_COUNT 16 /** * struct sde_crtc - virtualized CRTC data structure * @base : Base drm crtc structure Loading Loading @@ -105,6 +128,11 @@ struct sde_crtc_frame_event { * @frame_events : static allocation of in-flight frame events * @frame_event_list : available frame event list * @spin_lock : spin lock for frame event, transaction status, etc... * @event_thread : Pointer to event handler thread * @event_worker : Event worker queue * @event_cache : Local cache of event worker structures * @event_free_list : List of available event structures * @event_lock : Spinlock around event handling code */ struct sde_crtc { struct drm_crtc base; Loading Loading @@ -142,6 +170,13 @@ struct sde_crtc { struct sde_crtc_frame_event frame_events[SDE_CRTC_FRAME_EVENT_SIZE]; struct list_head frame_event_list; spinlock_t spin_lock; /* for handling internal event thread */ struct task_struct *event_thread; struct kthread_worker event_worker; struct sde_crtc_event event_cache[SDE_CRTC_MAX_EVENT_COUNT]; struct list_head event_free_list; spinlock_t event_lock; }; #define to_sde_crtc(x) container_of(x, struct sde_crtc, base) Loading Loading @@ -308,4 +343,14 @@ static inline bool sde_crtc_is_enabled(struct drm_crtc *crtc) return crtc ? crtc->enabled : false; } /** * sde_crtc_event_queue - request event callback * @crtc: Pointer to drm crtc structure * @func: Pointer to callback function * @usr: Pointer to user data to be passed to callback * Returns: Zero on success */ int sde_crtc_event_queue(struct drm_crtc *crtc, void (*func)(void *usr), void *usr); #endif /* _SDE_CRTC_H_ */