Loading drivers/gpu/drm/msm/dp/dp_mst_drm.c +188 −123 Original line number Diff line number Diff line Loading @@ -66,6 +66,7 @@ struct dp_drm_mst_fw_helper_ops { struct drm_dp_mst_port *port); void (*deallocate_vcpi)(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port); int (*get_avail_slots)(struct drm_dp_mst_topology_mgr *mgr); }; struct dp_mst_sim_port_data { Loading @@ -91,20 +92,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; Loading @@ -116,6 +115,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; Loading @@ -135,10 +141,55 @@ 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; 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, Loading Loading @@ -357,6 +408,11 @@ static int dp_mst_sim_topology_mgr_set_mst( return 0; } static int _dp_mst_get_avail_slots(struct drm_dp_mst_topology_mgr *mgr) { return to_dp_mst_topology_state(mgr->base.state)->avail_slots; } static void _dp_mst_get_vcpi_info( struct drm_dp_mst_topology_mgr *mgr, int vcpi, int *start_slot, int *num_slots) Loading Loading @@ -422,6 +478,7 @@ static const struct dp_drm_mst_fw_helper_ops drm_dp_mst_fw_helper_ops = { .atomic_release_vcpi_slots = drm_dp_atomic_release_vcpi_slots, .reset_vcpi_slots = drm_dp_mst_reset_vcpi_slots, .deallocate_vcpi = drm_dp_mst_deallocate_vcpi, .get_avail_slots = _dp_mst_get_avail_slots, }; static const struct dp_drm_mst_fw_helper_ops drm_dp_sim_mst_fw_helper_ops = { Loading @@ -439,6 +496,7 @@ static const struct dp_drm_mst_fw_helper_ops drm_dp_sim_mst_fw_helper_ops = { .atomic_release_vcpi_slots = drm_dp_atomic_release_vcpi_slots, .reset_vcpi_slots = drm_dp_mst_reset_vcpi_slots, .deallocate_vcpi = drm_dp_mst_deallocate_vcpi, .get_avail_slots = _dp_mst_get_avail_slots, }; /* DP MST Bridge OPs */ Loading Loading @@ -469,6 +527,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"); Loading @@ -479,13 +539,17 @@ static bool dp_mst_bridge_mode_fixup(struct drm_bridge *drm_bridge, } bridge = to_dp_mst_bridge(drm_bridge); if (!bridge->connector) { pr_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)) { pr_err("Invalid bridge state\n"); ret = false; goto end; } if (!bridge->dp_panel) { if (!bridge_state->dp_panel) { pr_err("Invalid dp_panel\n"); ret = false; goto end; Loading @@ -493,7 +557,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); Loading @@ -507,7 +571,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"); Loading @@ -523,7 +586,7 @@ static int _dp_mst_compute_config(struct drm_atomic_state *state, DP_MST_DEBUG("exit\n"); return rc; return slots; } static void _dp_mst_update_timeslots(struct dp_mst_private *mst, Loading Loading @@ -716,9 +779,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) { pr_err("Invalid connector\n"); return; Loading Loading @@ -868,17 +928,8 @@ static void dp_mst_bridge_post_disable(struct drm_bridge *drm_bridge) pr_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); Loading @@ -889,6 +940,7 @@ static void dp_mst_bridge_mode_set(struct drm_bridge *drm_bridge, 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"); Loading @@ -899,23 +951,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) { pr_err("Invalid connector\n"); return; } bridge->connector = bridge->old_connector; bridge->old_connector = NULL; } if (!bridge->dp_panel) { if (!bridge->old_dp_panel) { pr_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; Loading Loading @@ -947,6 +986,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; Loading Loading @@ -998,6 +1038,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(&bridge->obj, &state->base, &dp_mst_bridge_state_funcs); DP_MST_DEBUG("mst drm bridge init. bridge id:%d\n", i); /* Loading @@ -1012,6 +1062,7 @@ int dp_mst_drm_bridge_init(void *data, struct drm_encoder *encoder) bridge->encoder); if (bridge->fixed_connector == NULL) { pr_err("failed to create fixed connector\n"); kfree(state); rc = -ENOMEM; goto end; } Loading Loading @@ -1097,9 +1148,7 @@ 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; const u32 tot_slots = 63; if (!connector || !mode || !display) { pr_err("invalid input\n"); Loading @@ -1110,23 +1159,8 @@ 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; for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { if (mst->mst_bridge[i].encoder_active_sts && (mst->mst_bridge[i].connector != connector)) { active_enc_cnt++; slots_in_use += mst->mst_bridge[i].num_slots; } } mutex_unlock(&mst->mst_lock); if (active_enc_cnt < DP_STREAM_MAX) available_slots = tot_slots - slots_in_use; else { pr_debug("all mst streams are active\n"); return MODE_BAD; } available_slots = mst->mst_fw_cbs->get_avail_slots(&mst->mst_mgr); dp_display->convert_to_dp_mode(dp_display, c_conn->drv_panel, mode, &dp_mode); Loading Loading @@ -1199,21 +1233,34 @@ 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; } Loading @@ -1230,23 +1277,6 @@ dp_mst_atomic_best_encoder(struct drm_connector *connector, 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_connector_state *new_conn_state) { Loading @@ -1255,7 +1285,8 @@ static int dp_mst_connector_atomic_check(struct drm_connector *connector, struct drm_connector_state *old_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; Loading @@ -1263,18 +1294,9 @@ static int dp_mst_connector_atomic_check(struct drm_connector *connector, DP_MST_DEBUG("enter:\n"); /* * Skip atomic check during mst suspend, to avoid mismanagement of * available vcpi slots. */ if (mst->state == PM_SUSPEND) return rc; if (!new_conn_state) return rc; mutex_lock(&mst->mst_lock); state = new_conn_state->state; old_conn_state = drm_atomic_get_old_connector_state(state, connector); Loading @@ -1294,53 +1316,95 @@ 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) 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->num_slots; if (drm_atomic_crtc_needs_modeset(crtc_state) && slots > 0) { slots = bridge_state->num_slots; if (slots > 0) { rc = mst->mst_fw_cbs->atomic_release_vcpi_slots(state, &mst->mst_mgr, slots); if (rc) { pr_err("failed releasing %d vcpi slots rc:%d\n", pr_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: if (!new_conn_state->crtc) goto end; crtc_state = drm_atomic_get_new_crtc_state(state, new_conn_state->crtc); if (drm_atomic_crtc_needs_modeset(crtc_state)) { 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; } 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; } Loading Loading @@ -1504,20 +1568,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; } Loading Loading
drivers/gpu/drm/msm/dp/dp_mst_drm.c +188 −123 Original line number Diff line number Diff line Loading @@ -66,6 +66,7 @@ struct dp_drm_mst_fw_helper_ops { struct drm_dp_mst_port *port); void (*deallocate_vcpi)(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port); int (*get_avail_slots)(struct drm_dp_mst_topology_mgr *mgr); }; struct dp_mst_sim_port_data { Loading @@ -91,20 +92,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; Loading @@ -116,6 +115,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; Loading @@ -135,10 +141,55 @@ 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; 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, Loading Loading @@ -357,6 +408,11 @@ static int dp_mst_sim_topology_mgr_set_mst( return 0; } static int _dp_mst_get_avail_slots(struct drm_dp_mst_topology_mgr *mgr) { return to_dp_mst_topology_state(mgr->base.state)->avail_slots; } static void _dp_mst_get_vcpi_info( struct drm_dp_mst_topology_mgr *mgr, int vcpi, int *start_slot, int *num_slots) Loading Loading @@ -422,6 +478,7 @@ static const struct dp_drm_mst_fw_helper_ops drm_dp_mst_fw_helper_ops = { .atomic_release_vcpi_slots = drm_dp_atomic_release_vcpi_slots, .reset_vcpi_slots = drm_dp_mst_reset_vcpi_slots, .deallocate_vcpi = drm_dp_mst_deallocate_vcpi, .get_avail_slots = _dp_mst_get_avail_slots, }; static const struct dp_drm_mst_fw_helper_ops drm_dp_sim_mst_fw_helper_ops = { Loading @@ -439,6 +496,7 @@ static const struct dp_drm_mst_fw_helper_ops drm_dp_sim_mst_fw_helper_ops = { .atomic_release_vcpi_slots = drm_dp_atomic_release_vcpi_slots, .reset_vcpi_slots = drm_dp_mst_reset_vcpi_slots, .deallocate_vcpi = drm_dp_mst_deallocate_vcpi, .get_avail_slots = _dp_mst_get_avail_slots, }; /* DP MST Bridge OPs */ Loading Loading @@ -469,6 +527,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"); Loading @@ -479,13 +539,17 @@ static bool dp_mst_bridge_mode_fixup(struct drm_bridge *drm_bridge, } bridge = to_dp_mst_bridge(drm_bridge); if (!bridge->connector) { pr_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)) { pr_err("Invalid bridge state\n"); ret = false; goto end; } if (!bridge->dp_panel) { if (!bridge_state->dp_panel) { pr_err("Invalid dp_panel\n"); ret = false; goto end; Loading @@ -493,7 +557,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); Loading @@ -507,7 +571,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"); Loading @@ -523,7 +586,7 @@ static int _dp_mst_compute_config(struct drm_atomic_state *state, DP_MST_DEBUG("exit\n"); return rc; return slots; } static void _dp_mst_update_timeslots(struct dp_mst_private *mst, Loading Loading @@ -716,9 +779,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) { pr_err("Invalid connector\n"); return; Loading Loading @@ -868,17 +928,8 @@ static void dp_mst_bridge_post_disable(struct drm_bridge *drm_bridge) pr_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); Loading @@ -889,6 +940,7 @@ static void dp_mst_bridge_mode_set(struct drm_bridge *drm_bridge, 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"); Loading @@ -899,23 +951,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) { pr_err("Invalid connector\n"); return; } bridge->connector = bridge->old_connector; bridge->old_connector = NULL; } if (!bridge->dp_panel) { if (!bridge->old_dp_panel) { pr_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; Loading Loading @@ -947,6 +986,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; Loading Loading @@ -998,6 +1038,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(&bridge->obj, &state->base, &dp_mst_bridge_state_funcs); DP_MST_DEBUG("mst drm bridge init. bridge id:%d\n", i); /* Loading @@ -1012,6 +1062,7 @@ int dp_mst_drm_bridge_init(void *data, struct drm_encoder *encoder) bridge->encoder); if (bridge->fixed_connector == NULL) { pr_err("failed to create fixed connector\n"); kfree(state); rc = -ENOMEM; goto end; } Loading Loading @@ -1097,9 +1148,7 @@ 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; const u32 tot_slots = 63; if (!connector || !mode || !display) { pr_err("invalid input\n"); Loading @@ -1110,23 +1159,8 @@ 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; for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { if (mst->mst_bridge[i].encoder_active_sts && (mst->mst_bridge[i].connector != connector)) { active_enc_cnt++; slots_in_use += mst->mst_bridge[i].num_slots; } } mutex_unlock(&mst->mst_lock); if (active_enc_cnt < DP_STREAM_MAX) available_slots = tot_slots - slots_in_use; else { pr_debug("all mst streams are active\n"); return MODE_BAD; } available_slots = mst->mst_fw_cbs->get_avail_slots(&mst->mst_mgr); dp_display->convert_to_dp_mode(dp_display, c_conn->drv_panel, mode, &dp_mode); Loading Loading @@ -1199,21 +1233,34 @@ 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; } Loading @@ -1230,23 +1277,6 @@ dp_mst_atomic_best_encoder(struct drm_connector *connector, 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_connector_state *new_conn_state) { Loading @@ -1255,7 +1285,8 @@ static int dp_mst_connector_atomic_check(struct drm_connector *connector, struct drm_connector_state *old_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; Loading @@ -1263,18 +1294,9 @@ static int dp_mst_connector_atomic_check(struct drm_connector *connector, DP_MST_DEBUG("enter:\n"); /* * Skip atomic check during mst suspend, to avoid mismanagement of * available vcpi slots. */ if (mst->state == PM_SUSPEND) return rc; if (!new_conn_state) return rc; mutex_lock(&mst->mst_lock); state = new_conn_state->state; old_conn_state = drm_atomic_get_old_connector_state(state, connector); Loading @@ -1294,53 +1316,95 @@ 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) 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->num_slots; if (drm_atomic_crtc_needs_modeset(crtc_state) && slots > 0) { slots = bridge_state->num_slots; if (slots > 0) { rc = mst->mst_fw_cbs->atomic_release_vcpi_slots(state, &mst->mst_mgr, slots); if (rc) { pr_err("failed releasing %d vcpi slots rc:%d\n", pr_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: if (!new_conn_state->crtc) goto end; crtc_state = drm_atomic_get_new_crtc_state(state, new_conn_state->crtc); if (drm_atomic_crtc_needs_modeset(crtc_state)) { 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; } 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; } Loading Loading @@ -1504,20 +1568,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; } Loading