summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/drm_dp_mst_topology.c75
1 files changed, 75 insertions, 0 deletions
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
index d3fc7e4e85b7..0ad0baae5c7e 100644
--- a/drivers/gpu/drm/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -2936,6 +2936,69 @@ static void drm_dp_destroy_connector_work(struct work_struct *work)
(*mgr->cbs->hotplug)(mgr);
}
+void *drm_dp_mst_duplicate_state(struct drm_atomic_state *state, void *obj)
+{
+ struct drm_dp_mst_topology_mgr *mgr = obj;
+ struct drm_dp_mst_topology_state *new_mst_state;
+
+ if (WARN_ON(!mgr->state))
+ return NULL;
+
+ new_mst_state = kmemdup(mgr->state, sizeof(*new_mst_state), GFP_KERNEL);
+ if (new_mst_state)
+ new_mst_state->state = state;
+ return new_mst_state;
+}
+
+void drm_dp_mst_swap_state(void *obj, void **obj_state_ptr)
+{
+ struct drm_dp_mst_topology_mgr *mgr = obj;
+ struct drm_dp_mst_topology_state **topology_state_ptr;
+
+ topology_state_ptr = (struct drm_dp_mst_topology_state **)obj_state_ptr;
+
+ mgr->state->state = (*topology_state_ptr)->state;
+ swap(*topology_state_ptr, mgr->state);
+ mgr->state->state = NULL;
+}
+
+void drm_dp_mst_destroy_state(void *obj_state)
+{
+ kfree(obj_state);
+}
+
+static const struct drm_private_state_funcs mst_state_funcs = {
+ .duplicate_state = drm_dp_mst_duplicate_state,
+ .swap_state = drm_dp_mst_swap_state,
+ .destroy_state = drm_dp_mst_destroy_state,
+};
+
+/**
+ * drm_atomic_get_mst_topology_state: get MST topology state
+ *
+ * @state: global atomic state
+ * @mgr: MST topology manager, also the private object in this case
+ *
+ * This function wraps drm_atomic_get_priv_obj_state() passing in the MST atomic
+ * state vtable so that the private object state returned is that of a MST
+ * topology object. Also, drm_atomic_get_private_obj_state() expects the caller
+ * to care of the locking, so warn if don't hold the connection_mutex.
+ *
+ * RETURNS:
+ *
+ * The MST topology state or error pointer.
+ */
+struct drm_dp_mst_topology_state *drm_atomic_get_mst_topology_state(struct drm_atomic_state *state,
+ struct drm_dp_mst_topology_mgr *mgr)
+{
+ struct drm_device *dev = mgr->dev;
+
+ WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
+ return drm_atomic_get_private_obj_state(state, mgr,
+ &mst_state_funcs);
+}
+EXPORT_SYMBOL(drm_atomic_get_mst_topology_state);
+
/**
* drm_dp_mst_topology_mgr_init - initialise a topology manager
* @mgr: manager struct to initialise
@@ -2980,6 +3043,15 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr,
if (test_calc_pbn_mode() < 0)
DRM_ERROR("MST PBN self-test failed\n");
+ mgr->state = kzalloc(sizeof(*mgr->state), GFP_KERNEL);
+ if (mgr->state == NULL)
+ return -ENOMEM;
+ mgr->state->mgr = mgr;
+
+ /* max. time slots - one slot for MTP header */
+ mgr->state->avail_slots = 63;
+ mgr->funcs = &mst_state_funcs;
+
return 0;
}
EXPORT_SYMBOL(drm_dp_mst_topology_mgr_init);
@@ -3000,6 +3072,9 @@ void drm_dp_mst_topology_mgr_destroy(struct drm_dp_mst_topology_mgr *mgr)
mutex_unlock(&mgr->payload_lock);
mgr->dev = NULL;
mgr->aux = NULL;
+ kfree(mgr->state);
+ mgr->state = NULL;
+ mgr->funcs = NULL;
}
EXPORT_SYMBOL(drm_dp_mst_topology_mgr_destroy);