@@ -3626,9 +3626,17 @@ static int amdgpu_dm_connector_init(struct amdgpu_display_manager *dm,
drm_connector_register(&aconnector->base);
- if (connector_type == DRM_MODE_CONNECTOR_DisplayPort
- || connector_type == DRM_MODE_CONNECTOR_eDP)
- amdgpu_dm_initialize_dp_connector(dm, aconnector);
+ if (connector_type == DRM_MODE_CONNECTOR_DisplayPort ||
+ connector_type == DRM_MODE_CONNECTOR_eDP) {
+ res = amdgpu_dm_initialize_dp_connector(dm, aconnector);
+ if (res) {
+ drm_connector_unregister(&aconnector->base);
+ drm_connector_cleanup(&aconnector->base);
+ aconnector->connector_id = -1;
+
+ goto out_free;
+ }
+ }
#if defined(CONFIG_BACKLIGHT_CLASS_DEVICE) ||\
defined(CONFIG_BACKLIGHT_CLASS_DEVICE_MODULE)
@@ -475,22 +475,49 @@ static const struct drm_dp_mst_topology_cbs dm_mst_cbs = {
.register_connector = dm_dp_mst_register_connector
};
-void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm,
- struct amdgpu_dm_connector *aconnector)
+static const struct drm_private_state_funcs dm_mst_state_funcs = {
+ .atomic_duplicate_state = drm_atomic_dp_mst_duplicate_topology_state,
+ .atomic_destroy_state = drm_atomic_dp_mst_destroy_topology_state,
+};
+
+int amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm,
+ struct amdgpu_dm_connector *aconnector)
{
+ struct drm_dp_mst_topology_state *state =
+ kzalloc(sizeof(*state), GFP_KERNEL);
+ int ret = 0;
+
+ if (!state)
+ return -ENOMEM;
+
aconnector->dm_dp_aux.aux.name = "dmdc";
aconnector->dm_dp_aux.aux.dev = dm->adev->dev;
aconnector->dm_dp_aux.aux.transfer = dm_dp_aux_transfer;
aconnector->dm_dp_aux.ddc_service = aconnector->dc_link->ddc;
- drm_dp_aux_register(&aconnector->dm_dp_aux.aux);
+ ret = drm_dp_aux_register(&aconnector->dm_dp_aux.aux);
+ if (ret)
+ goto err_aux;
+
aconnector->mst_mgr.cbs = &dm_mst_cbs;
- drm_dp_mst_topology_mgr_init(
+ aconnector->mst_mgr.funcs = &dm_mst_state_funcs;
+ ret = drm_dp_mst_topology_mgr_init(
&aconnector->mst_mgr,
+ state,
dm->adev->ddev,
&aconnector->dm_dp_aux.aux,
16,
4,
aconnector->connector_id);
+ if (ret)
+ goto err_mst;
+
+ return 0;
+
+err_mst:
+ drm_dp_aux_unregister(&aconnector->dm_dp_aux.aux);
+err_aux:
+ kfree(state);
+ return ret;
}
@@ -29,8 +29,8 @@
struct amdgpu_display_manager;
struct amdgpu_dm_connector;
-void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm,
- struct amdgpu_dm_connector *aconnector);
+int amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm,
+ struct amdgpu_dm_connector *aconnector);
void dm_dp_mst_dc_sink_create(struct drm_connector *connector);
#endif
@@ -3100,33 +3100,89 @@ static void drm_dp_destroy_connector_work(struct work_struct *work)
(*mgr->cbs->hotplug)(mgr);
}
-static struct drm_private_state *
-drm_dp_mst_duplicate_state(struct drm_private_obj *obj)
+/**
+ * drm_atomic_dp_mst_duplicate_topology_state - default
+ * drm_dp_mst_topology_state duplicate handler
+ *
+ * For drivers which don't yet subclass drm_dp_mst_topology_state
+ *
+ * RETURNS: the duplicated state on success, or an error code embedded into a
+ * pointer value otherwise.
+ */
+struct drm_private_state *
+drm_atomic_dp_mst_duplicate_topology_state(struct drm_private_obj *obj)
{
+ struct drm_dp_mst_topology_mgr *mgr = to_dp_mst_topology_mgr(obj);
struct drm_dp_mst_topology_state *state;
+ int ret;
state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL);
if (!state)
return NULL;
- __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base);
+ ret = __drm_atomic_dp_mst_duplicate_topology_state(mgr, state);
+ if (ret) {
+ kfree(state);
+ return NULL;
+ }
return &state->base;
}
+EXPORT_SYMBOL(drm_atomic_dp_mst_duplicate_topology_state);
-static void drm_dp_mst_destroy_state(struct drm_private_obj *obj,
- struct drm_private_state *state)
+/**
+ * __drm_atomic_dp_mst_duplicate_topology_state - default
+ * drm_dp_mst_topology_state duplicate hook
+ *
+ * Copies atomic state from an MST topology's current state. This is useful
+ * for drivers that subclass the MST topology state.
+ *
+ * RETURNS: 0 on success, negative error code on failure.
+ */
+int
+__drm_atomic_dp_mst_duplicate_topology_state(struct drm_dp_mst_topology_mgr *mgr,
+ struct drm_dp_mst_topology_state *state)
+{
+ struct drm_private_obj *obj = &mgr->base;
+
+ memcpy(state, obj->state, sizeof(*state));
+
+ __drm_atomic_helper_private_obj_duplicate_state(&mgr->base,
+ &state->base);
+ return 0;
+}
+EXPORT_SYMBOL(__drm_atomic_dp_mst_duplicate_topology_state);
+
+/**
+ * drm_atomic_dp_mst_destroy_topology_state - default
+ * drm_dp_mst_topology_state destroy handler
+ *
+ * For drivers which don't yet subclass drm_dp_mst_topology_state.
+ */
+void
+drm_atomic_dp_mst_destroy_topology_state(struct drm_private_obj *obj,
+ struct drm_private_state *state)
{
struct drm_dp_mst_topology_state *mst_state =
to_dp_mst_topology_state(state);
+ __drm_atomic_dp_mst_destroy_topology_state(mst_state);
+
kfree(mst_state);
}
+EXPORT_SYMBOL(drm_atomic_dp_mst_destroy_topology_state);
-static const struct drm_private_state_funcs mst_state_funcs = {
- .atomic_duplicate_state = drm_dp_mst_duplicate_state,
- .atomic_destroy_state = drm_dp_mst_destroy_state,
-};
+/**
+ * __drm_atomic_dp_mst_destroy_topology_state - default
+ * drm_dp_mst_topology_state destroy hook
+ *
+ * Frees the resources associated with the given drm_dp_mst_topology_state.
+ * This is useful for drivers that subclass the MST topology state.
+ */
+void
+__drm_atomic_dp_mst_destroy_topology_state(struct drm_dp_mst_topology_state *state) {
+}
+EXPORT_SYMBOL(__drm_atomic_dp_mst_destroy_topology_state);
/**
* drm_atomic_dp_mst_get_topology_state: get MST topology state
@@ -3157,21 +3213,25 @@ EXPORT_SYMBOL(drm_atomic_dp_mst_get_topology_state);
/**
* drm_dp_mst_topology_mgr_init - initialise a topology manager
* @mgr: manager struct to initialise
+ * @state: atomic topology state to init, allocated by the driver
* @dev: device providing this structure - for i2c addition.
* @aux: DP helper aux channel to talk to this device
* @max_dpcd_transaction_bytes: hw specific DPCD transaction limit
* @max_payloads: maximum number of payloads this GPU can source
* @conn_base_id: the connector object ID the MST device is connected to.
*
+ * Note that this function doesn't take care of allocating the atomic MST
+ * state, this must be handled by the caller before calling
+ * drm_dp_mst_topology_mgr_init().
+ *
* Return 0 for success, or negative error code on failure
*/
int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr,
+ struct drm_dp_mst_topology_state *state,
struct drm_device *dev, struct drm_dp_aux *aux,
int max_dpcd_transaction_bytes,
int max_payloads, int conn_base_id)
{
- struct drm_dp_mst_topology_state *mst_state;
-
mutex_init(&mgr->lock);
mutex_init(&mgr->qlock);
mutex_init(&mgr->payload_lock);
@@ -3200,18 +3260,14 @@ 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");
- mst_state = kzalloc(sizeof(*mst_state), GFP_KERNEL);
- if (mst_state == NULL)
- return -ENOMEM;
-
- mst_state->mgr = mgr;
+ state->mgr = mgr;
/* max. time slots - one slot for MTP header */
- mst_state->avail_slots = 63;
+ state->avail_slots = 63;
drm_atomic_private_obj_init(&mgr->base,
- &mst_state->base,
- &mst_state_funcs);
+ &state->base,
+ mgr->funcs);
return 0;
}
@@ -587,19 +587,30 @@ intel_dp_create_fake_mst_encoders(struct intel_digital_port *intel_dig_port)
return true;
}
+static const struct drm_private_state_funcs mst_state_funcs = {
+ .atomic_destroy_state = drm_atomic_dp_mst_destroy_topology_state,
+ .atomic_duplicate_state = drm_atomic_dp_mst_duplicate_topology_state,
+};
+
int
intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_base_id)
{
struct intel_dp *intel_dp = &intel_dig_port->dp;
+ struct drm_dp_mst_topology_state *mst_state;
struct drm_device *dev = intel_dig_port->base.base.dev;
int ret;
+ mst_state = kzalloc(sizeof(*mst_state), GFP_KERNEL);
+ if (!mst_state)
+ return -ENOMEM;
+
intel_dp->can_mst = true;
intel_dp->mst_mgr.cbs = &mst_cbs;
+ intel_dp->mst_mgr.funcs = &mst_state_funcs;
/* create encoders */
intel_dp_create_fake_mst_encoders(intel_dig_port);
- ret = drm_dp_mst_topology_mgr_init(&intel_dp->mst_mgr, dev,
+ ret = drm_dp_mst_topology_mgr_init(&intel_dp->mst_mgr, mst_state, dev,
&intel_dp->aux, 16, 3, conn_base_id);
if (ret) {
intel_dp->can_mst = false;
@@ -3310,6 +3310,12 @@ nv50_mstm = {
.hotplug = nv50_mstm_hotplug,
};
+static const struct drm_private_state_funcs
+nv50_mst_state_funcs = {
+ .atomic_duplicate_state = drm_atomic_dp_mst_duplicate_topology_state,
+ .atomic_destroy_state = drm_atomic_dp_mst_destroy_topology_state,
+};
+
void
nv50_mstm_service(struct nv50_mstm *mstm)
{
@@ -3438,6 +3444,7 @@ nv50_mstm_new(struct nouveau_encoder *outp, struct drm_dp_aux *aux, int aux_max,
{
const int max_payloads = hweight8(outp->dcb->heads);
struct drm_device *dev = outp->base.base.dev;
+ struct drm_dp_mst_topology_state *state;
struct nv50_mstm *mstm;
int ret, i;
u8 dpcd;
@@ -3454,10 +3461,16 @@ nv50_mstm_new(struct nouveau_encoder *outp, struct drm_dp_aux *aux, int aux_max,
if (!(mstm = *pmstm = kzalloc(sizeof(*mstm), GFP_KERNEL)))
return -ENOMEM;
+ if (!(state = kzalloc(sizeof(*state), GFP_KERNEL))) {
+ kfree(mstm);
+ return -ENOMEM;
+ }
mstm->outp = outp;
mstm->mgr.cbs = &nv50_mstm;
+ mstm->mgr.funcs = &nv50_mst_state_funcs;
- ret = drm_dp_mst_topology_mgr_init(&mstm->mgr, dev, aux, aux_max,
+ ret = drm_dp_mst_topology_mgr_init(&mstm->mgr, state, dev,
+ aux, aux_max,
max_payloads, conn_base_id);
if (ret)
return ret;
@@ -335,6 +335,11 @@ static const struct drm_dp_mst_topology_cbs mst_cbs = {
.hotplug = radeon_dp_mst_hotplug,
};
+static const struct drm_private_state_funcs mst_state_funcs = {
+ .atomic_duplicate_state = drm_atomic_dp_mst_duplicate_topology_state,
+ .atomic_destroy_state = drm_atomic_dp_mst_destroy_topology_state,
+};
+
static struct
radeon_connector *radeon_mst_find_connector(struct drm_encoder *encoder)
{
@@ -657,12 +662,18 @@ int
radeon_dp_mst_init(struct radeon_connector *radeon_connector)
{
struct drm_device *dev = radeon_connector->base.dev;
+ struct drm_dp_mst_topology_state *state =
+ kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return -ENOMEM;
if (!radeon_connector->ddc_bus->has_aux)
return 0;
radeon_connector->mst_mgr.cbs = &mst_cbs;
- return drm_dp_mst_topology_mgr_init(&radeon_connector->mst_mgr, dev,
+ radeon_connector->mst_mgr.funcs = &mst_state_funcs;
+ return drm_dp_mst_topology_mgr_init(&radeon_connector->mst_mgr,
+ state, dev,
&radeon_connector->ddc_bus->aux, 16, 6,
radeon_connector->base.base.id);
}
@@ -565,6 +565,7 @@ struct drm_dp_mst_topology_mgr {
};
int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr,
+ struct drm_dp_mst_topology_state *state,
struct drm_device *dev, struct drm_dp_aux *aux,
int max_dpcd_transaction_bytes,
int max_payloads, int conn_base_id);
@@ -620,6 +621,13 @@ int drm_dp_mst_topology_mgr_resume(struct drm_dp_mst_topology_mgr *mgr);
struct drm_dp_mst_topology_state *drm_atomic_dp_mst_get_topology_state(struct drm_atomic_state *state,
struct drm_dp_mst_topology_mgr *mgr);
+struct drm_private_state *drm_atomic_dp_mst_duplicate_topology_state(struct drm_private_obj *obj);
+int __drm_atomic_dp_mst_duplicate_topology_state(struct drm_dp_mst_topology_mgr *mgr,
+ struct drm_dp_mst_topology_state *state);
+void drm_atomic_dp_mst_destroy_topology_state(struct drm_private_obj *obj,
+ struct drm_private_state *state);
+void __drm_atomic_dp_mst_destroy_topology_state(struct drm_dp_mst_topology_state *state);
+
int drm_dp_atomic_find_vcpi_slots(struct drm_atomic_state *state,
struct drm_dp_mst_topology_mgr *mgr,
struct drm_dp_mst_port *port, int pbn);
This is useful for drivers (which will probably be all of them soon) which need to track state that is exclusive to the topology, and not a specific connector on said topology. This includes things such as the link rate and lane count that are shared by all of the connectors on the topology. Signed-off-by: Lyude Paul <lyude@redhat.com> Cc: Manasi Navare <manasi.d.navare@intel.com> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> --- drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 14 +++- .../amd/display/amdgpu_dm/amdgpu_dm_mst_types.c | 35 +++++++- .../amd/display/amdgpu_dm/amdgpu_dm_mst_types.h | 4 +- drivers/gpu/drm/drm_dp_mst_topology.c | 94 +++++++++++++++++----- drivers/gpu/drm/i915/intel_dp_mst.c | 13 ++- drivers/gpu/drm/nouveau/nv50_display.c | 15 +++- drivers/gpu/drm/radeon/radeon_dp_mst.c | 13 ++- include/drm/drm_dp_mst_helper.h | 8 ++ 8 files changed, 165 insertions(+), 31 deletions(-)