diff --git a/msm/dp/dp_mst_drm.c b/msm/dp/dp_mst_drm.c index d9ada01306..1cb8c0fff6 100644 --- a/msm/dp/dp_mst_drm.c +++ b/msm/dp/dp_mst_drm.c @@ -110,20 +110,18 @@ struct dp_mst_sim_mode { struct dp_mst_bridge { struct drm_bridge base; + struct drm_private_obj obj; u32 id; bool in_use; struct dp_display *display; struct drm_encoder *encoder; - bool encoder_active_sts; struct drm_display_mode drm_mode; struct dp_display_mode dp_mode; struct drm_connector *connector; - struct drm_connector *old_connector; void *dp_panel; - void *old_dp_panel; int vcpi; int pbn; @@ -135,6 +133,13 @@ struct dp_mst_bridge { struct drm_connector *fixed_connector; }; +struct dp_mst_bridge_state { + struct drm_private_state base; + struct drm_connector *connector; + void *dp_panel; + int num_slots; +}; + struct dp_mst_private { bool mst_initialized; struct dp_mst_caps caps; @@ -154,6 +159,12 @@ struct dp_mst_encoder_info_cache { }; #define to_dp_mst_bridge(x) container_of((x), struct dp_mst_bridge, base) +#define to_dp_mst_bridge_priv(x) \ + container_of((x), struct dp_mst_bridge, obj) +#define to_dp_mst_bridge_priv_state(x) \ + container_of((x), struct dp_mst_bridge_state, base) +#define to_dp_mst_bridge_state(x) \ + to_dp_mst_bridge_priv_state((x)->obj.state) struct dp_mst_private dp_mst; struct dp_mst_encoder_info_cache dp_mst_enc_cache; @@ -174,6 +185,45 @@ static void dp_mst_hotplug(struct drm_dp_mst_topology_mgr *mgr) DP_MST_INFO_LOG("mst hot plug event\n"); } +static struct drm_private_state *dp_mst_duplicate_bridge_state( + struct drm_private_obj *obj) +{ + struct dp_mst_bridge_state *state; + + state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL); + if (!state) + return NULL; + + __drm_atomic_helper_private_obj_duplicate_state(obj, &state->base); + + return &state->base; +} + +static void dp_mst_destroy_bridge_state(struct drm_private_obj *obj, + struct drm_private_state *state) +{ + struct dp_mst_bridge_state *priv_state = + to_dp_mst_bridge_priv_state(state); + + kfree(priv_state); +} + +static const struct drm_private_state_funcs dp_mst_bridge_state_funcs = { + .atomic_duplicate_state = dp_mst_duplicate_bridge_state, + .atomic_destroy_state = dp_mst_destroy_bridge_state, +}; + +static struct dp_mst_bridge_state *dp_mst_get_bridge_atomic_state( + struct drm_atomic_state *state, struct dp_mst_bridge *bridge) +{ + struct drm_device *dev = bridge->base.dev; + + WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex)); + + return to_dp_mst_bridge_priv_state( + drm_atomic_get_private_obj_state(state, &bridge->obj)); +} + static void dp_mst_sim_destroy_port(struct kref *ref) { struct drm_dp_mst_port *port = container_of(ref, @@ -657,6 +707,8 @@ static bool dp_mst_bridge_mode_fixup(struct drm_bridge *drm_bridge, struct dp_display_mode dp_mode; struct dp_mst_bridge *bridge; struct dp_display *dp; + struct drm_crtc_state *crtc_state; + struct dp_mst_bridge_state *bridge_state; DP_MST_DEBUG("enter\n"); SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY); @@ -668,13 +720,17 @@ static bool dp_mst_bridge_mode_fixup(struct drm_bridge *drm_bridge, } bridge = to_dp_mst_bridge(drm_bridge); - if (!bridge->connector) { - DP_ERR("Invalid connector\n"); + + crtc_state = container_of(mode, struct drm_crtc_state, mode); + bridge_state = dp_mst_get_bridge_atomic_state(crtc_state->state, + bridge); + if (IS_ERR(bridge_state)) { + DP_ERR("invalid bridge state\n"); ret = false; goto end; } - if (!bridge->dp_panel) { + if (!bridge_state->dp_panel) { DP_ERR("Invalid dp_panel\n"); ret = false; goto end; @@ -682,7 +738,7 @@ static bool dp_mst_bridge_mode_fixup(struct drm_bridge *drm_bridge, dp = bridge->display; - dp->convert_to_dp_mode(dp, bridge->dp_panel, mode, &dp_mode); + dp->convert_to_dp_mode(dp, bridge_state->dp_panel, mode, &dp_mode); convert_to_drm_mode(&dp_mode, adjusted_mode); DP_MST_DEBUG("mst bridge [%d] mode:%s fixup\n", bridge->id, mode->name); @@ -696,7 +752,6 @@ static int _dp_mst_compute_config(struct drm_atomic_state *state, { int slots = 0, pbn; struct sde_connector *c_conn = to_sde_connector(connector); - int rc = 0; DP_MST_DEBUG("enter\n"); SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY); @@ -714,7 +769,7 @@ static int _dp_mst_compute_config(struct drm_atomic_state *state, DP_MST_DEBUG("exit\n"); SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT); - return rc; + return slots; } static void _dp_mst_update_timeslots(struct dp_mst_private *mst, @@ -938,9 +993,6 @@ static void dp_mst_bridge_pre_enable(struct drm_bridge *drm_bridge) bridge = to_dp_mst_bridge(drm_bridge); dp = bridge->display; - bridge->old_connector = NULL; - bridge->old_dp_panel = NULL; - if (!bridge->connector) { DP_ERR("Invalid connector\n"); return; @@ -1099,17 +1151,8 @@ static void dp_mst_bridge_post_disable(struct drm_bridge *drm_bridge) DP_INFO("[%d] DP display unprepare failed, rc=%d\n", bridge->id, rc); - /* maintain the connector to encoder link during suspend/resume */ - if (mst->state != PM_SUSPEND) { - /* Disconnect the connector and panel info from bridge */ - mst->mst_bridge[bridge->id].old_connector = - mst->mst_bridge[bridge->id].connector; - mst->mst_bridge[bridge->id].old_dp_panel = - mst->mst_bridge[bridge->id].dp_panel; - mst->mst_bridge[bridge->id].connector = NULL; - mst->mst_bridge[bridge->id].dp_panel = NULL; - mst->mst_bridge[bridge->id].encoder_active_sts = false; - } + bridge->connector = NULL; + bridge->dp_panel = NULL; DP_MST_INFO_LOG("mst bridge [%d] post disable complete\n", bridge->id); @@ -1120,6 +1163,7 @@ static void dp_mst_bridge_mode_set(struct drm_bridge *drm_bridge, const struct drm_display_mode *adjusted_mode) { struct dp_mst_bridge *bridge; + struct dp_mst_bridge_state *dp_bridge_state; struct dp_display *dp; DP_MST_DEBUG("enter\n"); @@ -1131,23 +1175,10 @@ static void dp_mst_bridge_mode_set(struct drm_bridge *drm_bridge, } bridge = to_dp_mst_bridge(drm_bridge); - if (!bridge->connector) { - if (!bridge->old_connector) { - DP_ERR("Invalid connector\n"); - return; - } - bridge->connector = bridge->old_connector; - bridge->old_connector = NULL; - } - if (!bridge->dp_panel) { - if (!bridge->old_dp_panel) { - DP_ERR("Invalid dp_panel\n"); - return; - } - bridge->dp_panel = bridge->old_dp_panel; - bridge->old_dp_panel = NULL; - } + dp_bridge_state = to_dp_mst_bridge_state(bridge); + bridge->connector = dp_bridge_state->connector; + bridge->dp_panel = dp_bridge_state->dp_panel; dp = bridge->display; @@ -1179,6 +1210,7 @@ int dp_mst_drm_bridge_init(void *data, struct drm_encoder *encoder) { int rc = 0; struct dp_mst_bridge *bridge = NULL; + struct dp_mst_bridge_state *state; struct drm_device *dev; struct dp_display *display = data; struct msm_drm_private *priv = NULL; @@ -1230,6 +1262,16 @@ int dp_mst_drm_bridge_init(void *data, struct drm_encoder *encoder) encoder->bridge = &bridge->base; priv->bridges[priv->num_bridges++] = &bridge->base; + state = kzalloc(sizeof(*state), GFP_KERNEL); + if (state == NULL) { + rc = -ENOMEM; + goto end; + } + + drm_atomic_private_obj_init(dev, &bridge->obj, + &state->base, + &dp_mst_bridge_state_funcs); + DP_MST_DEBUG("mst drm bridge init. bridge id:%d\n", i); /* @@ -1244,6 +1286,7 @@ int dp_mst_drm_bridge_init(void *data, struct drm_encoder *encoder) bridge->encoder); if (bridge->fixed_connector == NULL) { DP_ERR("failed to create fixed connector\n"); + kfree(state); rc = -ENOMEM; goto end; } @@ -1333,8 +1376,9 @@ enum drm_mode_status dp_mst_connector_mode_valid( struct drm_dp_mst_port *mst_port; struct dp_display_mode dp_mode; uint16_t available_pbn, required_pbn; - int i, slots_in_use = 0, active_enc_cnt = 0; int available_slots, required_slots; + struct dp_mst_bridge_state *dp_bridge_state; + int i, slots_in_use = 0, active_enc_cnt = 0; const u32 tot_slots = 63; if (!connector || !mode || !display) { @@ -1346,20 +1390,20 @@ enum drm_mode_status dp_mst_connector_mode_valid( c_conn = to_sde_connector(connector); mst_port = c_conn->mst_port; - mutex_lock(&mst->mst_lock); - available_pbn = mst_port->available_pbn; + /* dp bridge state is protected by drm_mode_config.connection_mutex */ for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { - if (mst->mst_bridge[i].encoder_active_sts && - (mst->mst_bridge[i].connector != connector)) { + dp_bridge_state = to_dp_mst_bridge_state(&mst->mst_bridge[i]); + if (dp_bridge_state->connector && + dp_bridge_state->connector != connector) { active_enc_cnt++; - slots_in_use += mst->mst_bridge[i].num_slots; + slots_in_use += dp_bridge_state->num_slots; } } - mutex_unlock(&mst->mst_lock); - if (active_enc_cnt < DP_STREAM_MAX) + if (active_enc_cnt < DP_STREAM_MAX) { + available_pbn = mst_port->available_pbn; available_slots = tot_slots - slots_in_use; - else { + } else { DP_DEBUG("all mst streams are active\n"); return MODE_BAD; } @@ -1440,24 +1484,38 @@ dp_mst_atomic_best_encoder(struct drm_connector *connector, struct dp_mst_private *mst = dp_display->dp_mst_prv_info; struct sde_connector *conn = to_sde_connector(connector); struct drm_encoder *enc = NULL; + struct dp_mst_bridge_state *bridge_state; u32 i; + if (state->best_encoder) + return state->best_encoder; + for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { - if (mst->mst_bridge[i].connector == connector) { + bridge_state = dp_mst_get_bridge_atomic_state( + state->state, &mst->mst_bridge[i]); + if (IS_ERR(bridge_state)) + goto end; + + if (bridge_state->connector == connector) { enc = mst->mst_bridge[i].encoder; goto end; } } for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { - if (!mst->mst_bridge[i].encoder_active_sts && - !mst->mst_bridge[i].fixed_connector) { - mst->mst_bridge[i].encoder_active_sts = true; - mst->mst_bridge[i].connector = connector; - mst->mst_bridge[i].dp_panel = conn->drv_panel; + if (mst->mst_bridge[i].fixed_connector) + continue; + + bridge_state = dp_mst_get_bridge_atomic_state( + state->state, &mst->mst_bridge[i]); + + if (!bridge_state->connector) { + bridge_state->connector = connector; + bridge_state->dp_panel = conn->drv_panel; enc = mst->mst_bridge[i].encoder; break; } + } end: @@ -1471,23 +1529,6 @@ end: return enc; } -static struct dp_mst_bridge *_dp_mst_get_bridge_from_encoder( - struct dp_display *dp_display, - struct drm_encoder *encoder) -{ - struct dp_mst_private *mst = dp_display->dp_mst_prv_info; - int i; - - for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { - if (mst->mst_bridge[i].encoder == encoder) - return &mst->mst_bridge[i]; - } - - DP_MST_DEBUG("mst bridge detect for encoder failed\n"); - - return NULL; -} - static int dp_mst_connector_atomic_check(struct drm_connector *connector, void *display, struct drm_atomic_state *state) { @@ -1496,7 +1537,8 @@ static int dp_mst_connector_atomic_check(struct drm_connector *connector, struct drm_connector_state *new_conn_state; struct drm_crtc *old_crtc; struct drm_crtc_state *crtc_state; - struct dp_mst_bridge *bridge = NULL; + struct dp_mst_bridge *bridge; + struct dp_mst_bridge_state *bridge_state; struct dp_display *dp_display = display; struct dp_mst_private *mst = dp_display->dp_mst_prv_info; struct sde_connector *c_conn = to_sde_connector(connector); @@ -1505,13 +1547,6 @@ static int dp_mst_connector_atomic_check(struct drm_connector *connector, DP_MST_DEBUG("enter:\n"); SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY); - /* - * Skip atomic check during mst suspend, to avoid mismanagement of - * available vcpi slots. - */ - if (mst->state == PM_SUSPEND) - return rc; - if (!state) return rc; @@ -1519,8 +1554,6 @@ static int dp_mst_connector_atomic_check(struct drm_connector *connector, if (!new_conn_state) return rc; - mutex_lock(&mst->mst_lock); - old_conn_state = drm_atomic_get_old_connector_state(state, connector); if (!old_conn_state) goto mode_set; @@ -1538,20 +1571,45 @@ static int dp_mst_connector_atomic_check(struct drm_connector *connector, bridge->num_slots); } - bridge = _dp_mst_get_bridge_from_encoder(dp_display, - old_conn_state->best_encoder); - if (!bridge) - goto end; - - slots = bridge->num_slots; - if (drm_atomic_crtc_needs_modeset(crtc_state) && slots > 0) { - rc = mst->mst_fw_cbs->atomic_release_vcpi_slots(state, - &mst->mst_mgr, c_conn->mst_port); - if (rc) { - DP_ERR("failed releasing %d vcpi slots rc:%d\n", - slots, rc); + if (drm_atomic_crtc_needs_modeset(crtc_state)) { + if (WARN_ON(!old_conn_state->best_encoder)) { + rc = -EINVAL; goto end; } + + bridge = to_dp_mst_bridge( + old_conn_state->best_encoder->bridge); + + bridge_state = dp_mst_get_bridge_atomic_state(state, bridge); + if (IS_ERR(bridge_state)) { + rc = PTR_ERR(bridge_state); + goto end; + } + + if (WARN_ON(bridge_state->connector != connector)) { + rc = -EINVAL; + goto end; + } + + slots = bridge_state->num_slots; + if (slots > 0) { + rc = mst->mst_fw_cbs->atomic_release_vcpi_slots(state, + &mst->mst_mgr, c_conn->mst_port); + if (rc) { + DP_ERR("failed releasing %d vcpi slots %d\n", + slots, rc); + goto end; + } + } + + bridge_state->num_slots = 0; + + if (!new_conn_state->crtc && mst->state != PM_SUSPEND) { + bridge_state->connector = NULL; + bridge_state->dp_panel = NULL; + + DP_MST_DEBUG("clear best encoder: %d\n", bridge->id); + } } mode_set: @@ -1561,28 +1619,47 @@ mode_set: crtc_state = drm_atomic_get_new_crtc_state(state, new_conn_state->crtc); if (drm_atomic_crtc_needs_modeset(crtc_state) && crtc_state->active) { + c_conn = to_sde_connector(connector); + + if (WARN_ON(!new_conn_state->best_encoder)) { + rc = -EINVAL; + goto end; + } + + bridge = to_dp_mst_bridge( + new_conn_state->best_encoder->bridge); + + bridge_state = dp_mst_get_bridge_atomic_state(state, bridge); + if (IS_ERR(bridge_state)) { + rc = PTR_ERR(bridge_state); + goto end; + } + + if (WARN_ON(bridge_state->connector != connector)) { + rc = -EINVAL; + goto end; + } + + if (WARN_ON(bridge_state->num_slots)) { + rc = -EINVAL; + goto end; + } + dp_display->convert_to_dp_mode(dp_display, c_conn->drv_panel, &crtc_state->mode, &dp_mode); slots = _dp_mst_compute_config(state, mst, connector, &dp_mode); if (slots < 0) { rc = slots; - - /* Disconnect the conn and panel info from bridge */ - bridge = _dp_mst_get_bridge_from_encoder(dp_display, - new_conn_state->best_encoder); - if (!bridge) - goto end; - - bridge->connector = NULL; - bridge->dp_panel = NULL; - bridge->encoder_active_sts = false; + goto end; } + + bridge_state->num_slots = slots; } end: - mutex_unlock(&mst->mst_lock); - DP_MST_DEBUG("mst connector:%d atomic check\n", connector->base.id); + DP_MST_DEBUG("mst connector:%d atomic check ret %d\n", + connector->base.id, rc); return rc; } @@ -1758,20 +1835,21 @@ dp_mst_fixed_atomic_best_encoder(struct drm_connector *connector, struct dp_mst_private *mst = dp_display->dp_mst_prv_info; struct sde_connector *conn = to_sde_connector(connector); struct drm_encoder *enc = NULL; + struct dp_mst_bridge_state *bridge_state; u32 i; - for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { - if (mst->mst_bridge[i].connector == connector) { - enc = mst->mst_bridge[i].encoder; - goto end; - } - } + if (state->best_encoder) + return state->best_encoder; for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { if (mst->mst_bridge[i].fixed_connector == connector) { - mst->mst_bridge[i].encoder_active_sts = true; - mst->mst_bridge[i].connector = connector; - mst->mst_bridge[i].dp_panel = conn->drv_panel; + bridge_state = dp_mst_get_bridge_atomic_state( + state->state, &mst->mst_bridge[i]); + if (IS_ERR(bridge_state)) + goto end; + + bridge_state->connector = connector; + bridge_state->dp_panel = conn->drv_panel; enc = mst->mst_bridge[i].encoder; break; }