Loading msm/dp/dp_mst_drm.c +191 −115 Original line number Original line Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only /* /* * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ */ /* /* Loading Loading @@ -110,20 +110,18 @@ struct dp_mst_sim_mode { struct dp_mst_bridge { struct dp_mst_bridge { struct drm_bridge base; struct drm_bridge base; struct drm_private_obj obj; u32 id; u32 id; bool in_use; bool in_use; struct dp_display *display; struct dp_display *display; struct drm_encoder *encoder; struct drm_encoder *encoder; bool encoder_active_sts; struct drm_display_mode drm_mode; struct drm_display_mode drm_mode; struct dp_display_mode dp_mode; struct dp_display_mode dp_mode; struct drm_connector *connector; struct drm_connector *connector; struct drm_connector *old_connector; void *dp_panel; void *dp_panel; void *old_dp_panel; int vcpi; int vcpi; int pbn; int pbn; Loading @@ -135,6 +133,13 @@ struct dp_mst_bridge { struct drm_connector *fixed_connector; 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 { struct dp_mst_private { bool mst_initialized; bool mst_initialized; struct dp_mst_caps caps; struct dp_mst_caps caps; Loading @@ -154,10 +159,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(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_private dp_mst; struct dp_mst_encoder_info_cache dp_mst_enc_cache; 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) static void dp_mst_sim_destroy_port(struct kref *ref) { { struct drm_dp_mst_port *port = container_of(ref, struct drm_dp_mst_port *port = container_of(ref, Loading Loading @@ -609,6 +659,8 @@ static bool dp_mst_bridge_mode_fixup(struct drm_bridge *drm_bridge, struct dp_display_mode dp_mode; struct dp_display_mode dp_mode; struct dp_mst_bridge *bridge; struct dp_mst_bridge *bridge; struct dp_display *dp; struct dp_display *dp; struct drm_crtc_state *crtc_state; struct dp_mst_bridge_state *bridge_state; DP_MST_DEBUG("enter\n"); DP_MST_DEBUG("enter\n"); Loading @@ -619,13 +671,17 @@ static bool dp_mst_bridge_mode_fixup(struct drm_bridge *drm_bridge, } } bridge = to_dp_mst_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; ret = false; goto end; goto end; } } if (!bridge->dp_panel) { if (!bridge_state->dp_panel) { DP_ERR("Invalid dp_panel\n"); DP_ERR("Invalid dp_panel\n"); ret = false; ret = false; goto end; goto end; Loading @@ -633,7 +689,7 @@ static bool dp_mst_bridge_mode_fixup(struct drm_bridge *drm_bridge, dp = bridge->display; 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); convert_to_drm_mode(&dp_mode, adjusted_mode); DP_MST_DEBUG("mst bridge [%d] mode:%s fixup\n", bridge->id, mode->name); DP_MST_DEBUG("mst bridge [%d] mode:%s fixup\n", bridge->id, mode->name); Loading @@ -647,7 +703,6 @@ static int _dp_mst_compute_config(struct drm_atomic_state *state, { { int slots = 0, pbn; int slots = 0, pbn; struct sde_connector *c_conn = to_sde_connector(connector); struct sde_connector *c_conn = to_sde_connector(connector); int rc = 0; DP_MST_DEBUG("enter\n"); DP_MST_DEBUG("enter\n"); Loading @@ -663,7 +718,7 @@ static int _dp_mst_compute_config(struct drm_atomic_state *state, DP_MST_DEBUG("exit\n"); DP_MST_DEBUG("exit\n"); return rc; return slots; } } static void _dp_mst_update_timeslots(struct dp_mst_private *mst, static void _dp_mst_update_timeslots(struct dp_mst_private *mst, Loading Loading @@ -856,9 +911,6 @@ static void dp_mst_bridge_pre_enable(struct drm_bridge *drm_bridge) bridge = to_dp_mst_bridge(drm_bridge); bridge = to_dp_mst_bridge(drm_bridge); dp = bridge->display; dp = bridge->display; bridge->old_connector = NULL; bridge->old_dp_panel = NULL; if (!bridge->connector) { if (!bridge->connector) { DP_ERR("Invalid connector\n"); DP_ERR("Invalid connector\n"); return; return; Loading Loading @@ -1008,17 +1060,8 @@ static void dp_mst_bridge_post_disable(struct drm_bridge *drm_bridge) DP_INFO("[%d] DP display unprepare failed, rc=%d\n", DP_INFO("[%d] DP display unprepare failed, rc=%d\n", bridge->id, rc); bridge->id, rc); /* maintain the connector to encoder link during suspend/resume */ bridge->connector = NULL; if (mst->state != PM_SUSPEND) { bridge->dp_panel = NULL; /* 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; } DP_MST_INFO_LOG("mst bridge [%d] post disable complete\n", DP_MST_INFO_LOG("mst bridge [%d] post disable complete\n", bridge->id); bridge->id); Loading @@ -1029,6 +1072,7 @@ static void dp_mst_bridge_mode_set(struct drm_bridge *drm_bridge, struct drm_display_mode *adjusted_mode) struct drm_display_mode *adjusted_mode) { { struct dp_mst_bridge *bridge; struct dp_mst_bridge *bridge; struct dp_mst_bridge_state *dp_bridge_state; struct dp_display *dp; struct dp_display *dp; DP_MST_DEBUG("enter\n"); DP_MST_DEBUG("enter\n"); Loading @@ -1039,23 +1083,10 @@ static void dp_mst_bridge_mode_set(struct drm_bridge *drm_bridge, } } bridge = to_dp_mst_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) { dp_bridge_state = to_dp_mst_bridge_state(bridge); if (!bridge->old_dp_panel) { bridge->connector = dp_bridge_state->connector; DP_ERR("Invalid dp_panel\n"); bridge->dp_panel = dp_bridge_state->dp_panel; return; } bridge->dp_panel = bridge->old_dp_panel; bridge->old_dp_panel = NULL; } dp = bridge->display; dp = bridge->display; Loading Loading @@ -1087,6 +1118,7 @@ int dp_mst_drm_bridge_init(void *data, struct drm_encoder *encoder) { { int rc = 0; int rc = 0; struct dp_mst_bridge *bridge = NULL; struct dp_mst_bridge *bridge = NULL; struct dp_mst_bridge_state *state; struct drm_device *dev; struct drm_device *dev; struct dp_display *display = data; struct dp_display *display = data; struct msm_drm_private *priv = NULL; struct msm_drm_private *priv = NULL; Loading Loading @@ -1138,6 +1170,16 @@ int dp_mst_drm_bridge_init(void *data, struct drm_encoder *encoder) encoder->bridge = &bridge->base; encoder->bridge = &bridge->base; priv->bridges[priv->num_bridges++] = &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); DP_MST_DEBUG("mst drm bridge init. bridge id:%d\n", i); /* /* Loading @@ -1152,6 +1194,7 @@ int dp_mst_drm_bridge_init(void *data, struct drm_encoder *encoder) bridge->encoder); bridge->encoder); if (bridge->fixed_connector == NULL) { if (bridge->fixed_connector == NULL) { DP_ERR("failed to create fixed connector\n"); DP_ERR("failed to create fixed connector\n"); kfree(state); rc = -ENOMEM; rc = -ENOMEM; goto end; goto end; } } Loading Loading @@ -1237,8 +1280,9 @@ enum drm_mode_status dp_mst_connector_mode_valid( struct drm_dp_mst_port *mst_port; struct drm_dp_mst_port *mst_port; struct dp_display_mode dp_mode; struct dp_display_mode dp_mode; uint16_t available_pbn, required_pbn; uint16_t available_pbn, required_pbn; int i, slots_in_use = 0, active_enc_cnt = 0; int available_slots, required_slots; 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; const u32 tot_slots = 63; if (!connector || !mode || !display) { if (!connector || !mode || !display) { Loading @@ -1250,21 +1294,21 @@ enum drm_mode_status dp_mst_connector_mode_valid( c_conn = to_sde_connector(connector); c_conn = to_sde_connector(connector); mst_port = c_conn->mst_port; mst_port = c_conn->mst_port; mutex_lock(&mst->mst_lock); /* dp bridge state is protected by drm_mode_config.connection_mutex */ available_pbn = mst_port->available_pbn; for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { if (mst->mst_bridge[i].encoder_active_sts && dp_bridge_state = to_dp_mst_bridge_state(&mst->mst_bridge[i]); (mst->mst_bridge[i].connector != connector)) { if (dp_bridge_state->connector && dp_bridge_state->connector != connector) { active_enc_cnt++; 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; available_slots = tot_slots - slots_in_use; else { } else { DP_DEBUG("all mst streams are active\n"); pr_debug("all mst streams are active\n"); return MODE_BAD; return MODE_BAD; } } Loading Loading @@ -1340,24 +1384,38 @@ dp_mst_atomic_best_encoder(struct drm_connector *connector, struct dp_mst_private *mst = dp_display->dp_mst_prv_info; struct dp_mst_private *mst = dp_display->dp_mst_prv_info; struct sde_connector *conn = to_sde_connector(connector); struct sde_connector *conn = to_sde_connector(connector); struct drm_encoder *enc = NULL; struct drm_encoder *enc = NULL; struct dp_mst_bridge_state *bridge_state; u32 i; u32 i; if (state->best_encoder) return state->best_encoder; for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { 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; enc = mst->mst_bridge[i].encoder; goto end; goto end; } } } } for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { if (!mst->mst_bridge[i].encoder_active_sts && if (mst->mst_bridge[i].fixed_connector) !mst->mst_bridge[i].fixed_connector) { continue; mst->mst_bridge[i].encoder_active_sts = true; mst->mst_bridge[i].connector = connector; bridge_state = dp_mst_get_bridge_atomic_state( mst->mst_bridge[i].dp_panel = conn->drv_panel; 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; enc = mst->mst_bridge[i].encoder; break; break; } } } } end: end: Loading @@ -1371,23 +1429,6 @@ dp_mst_atomic_best_encoder(struct drm_connector *connector, return enc; 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, static int dp_mst_connector_atomic_check(struct drm_connector *connector, void *display, struct drm_connector_state *new_conn_state) void *display, struct drm_connector_state *new_conn_state) { { Loading @@ -1396,7 +1437,8 @@ static int dp_mst_connector_atomic_check(struct drm_connector *connector, struct drm_connector_state *old_conn_state; struct drm_connector_state *old_conn_state; struct drm_crtc *old_crtc; struct drm_crtc *old_crtc; struct drm_crtc_state *crtc_state; 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_display *dp_display = display; struct dp_mst_private *mst = dp_display->dp_mst_prv_info; struct dp_mst_private *mst = dp_display->dp_mst_prv_info; struct sde_connector *c_conn; struct sde_connector *c_conn; Loading @@ -1404,18 +1446,9 @@ static int dp_mst_connector_atomic_check(struct drm_connector *connector, DP_MST_DEBUG("enter:\n"); 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) if (!new_conn_state) return rc; return rc; mutex_lock(&mst->mst_lock); state = new_conn_state->state; state = new_conn_state->state; old_conn_state = drm_atomic_get_old_connector_state(state, connector); old_conn_state = drm_atomic_get_old_connector_state(state, connector); Loading @@ -1435,22 +1468,47 @@ static int dp_mst_connector_atomic_check(struct drm_connector *connector, bridge->num_slots); bridge->num_slots); } } bridge = _dp_mst_get_bridge_from_encoder(dp_display, if (drm_atomic_crtc_needs_modeset(crtc_state)) { old_conn_state->best_encoder); if (WARN_ON(!old_conn_state->best_encoder)) { if (!bridge) rc = -EINVAL; goto end; goto end; } bridge = to_dp_mst_bridge( old_conn_state->best_encoder->bridge); slots = bridge->num_slots; bridge_state = dp_mst_get_bridge_atomic_state(state, bridge); if (drm_atomic_crtc_needs_modeset(crtc_state) && slots > 0) { 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, rc = mst->mst_fw_cbs->atomic_release_vcpi_slots(state, &mst->mst_mgr, slots); &mst->mst_mgr, slots); if (rc) { if (rc) { DP_ERR("failed releasing %d vcpi slots rc:%d\n", pr_err("failed releasing %d vcpi slots %d\n", slots, rc); slots, rc); goto end; 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: mode_set: if (!new_conn_state->crtc) if (!new_conn_state->crtc) goto end; goto end; Loading @@ -1460,28 +1518,45 @@ static int dp_mst_connector_atomic_check(struct drm_connector *connector, if (drm_atomic_crtc_needs_modeset(crtc_state) && crtc_state->active) { if (drm_atomic_crtc_needs_modeset(crtc_state) && crtc_state->active) { c_conn = to_sde_connector(connector); 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, dp_display->convert_to_dp_mode(dp_display, c_conn->drv_panel, &crtc_state->mode, &dp_mode); &crtc_state->mode, &dp_mode); slots = _dp_mst_compute_config(state, mst, connector, &dp_mode); slots = _dp_mst_compute_config(state, mst, connector, &dp_mode); if (slots < 0) { if (slots < 0) { rc = slots; 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; goto end; bridge->connector = NULL; bridge->dp_panel = NULL; bridge->encoder_active_sts = false; } } bridge_state->num_slots = slots; } } end: end: mutex_unlock(&mst->mst_lock); DP_MST_DEBUG("mst connector:%d atomic check ret %d\n", DP_MST_DEBUG("mst connector:%d atomic check\n", connector->base.id); connector->base.id, rc); return rc; return rc; } } Loading Loading @@ -1645,20 +1720,21 @@ dp_mst_fixed_atomic_best_encoder(struct drm_connector *connector, struct dp_mst_private *mst = dp_display->dp_mst_prv_info; struct dp_mst_private *mst = dp_display->dp_mst_prv_info; struct sde_connector *conn = to_sde_connector(connector); struct sde_connector *conn = to_sde_connector(connector); struct drm_encoder *enc = NULL; struct drm_encoder *enc = NULL; struct dp_mst_bridge_state *bridge_state; u32 i; u32 i; for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { if (state->best_encoder) if (mst->mst_bridge[i].connector == connector) { return state->best_encoder; enc = mst->mst_bridge[i].encoder; goto end; } } for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { if (mst->mst_bridge[i].fixed_connector == connector) { if (mst->mst_bridge[i].fixed_connector == connector) { mst->mst_bridge[i].encoder_active_sts = true; bridge_state = dp_mst_get_bridge_atomic_state( mst->mst_bridge[i].connector = connector; state->state, &mst->mst_bridge[i]); mst->mst_bridge[i].dp_panel = conn->drv_panel; if (IS_ERR(bridge_state)) goto end; bridge_state->connector = connector; bridge_state->dp_panel = conn->drv_panel; enc = mst->mst_bridge[i].encoder; enc = mst->mst_bridge[i].encoder; break; break; } } Loading Loading
msm/dp/dp_mst_drm.c +191 −115 Original line number Original line Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only // SPDX-License-Identifier: GPL-2.0-only /* /* * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved. */ */ /* /* Loading Loading @@ -110,20 +110,18 @@ struct dp_mst_sim_mode { struct dp_mst_bridge { struct dp_mst_bridge { struct drm_bridge base; struct drm_bridge base; struct drm_private_obj obj; u32 id; u32 id; bool in_use; bool in_use; struct dp_display *display; struct dp_display *display; struct drm_encoder *encoder; struct drm_encoder *encoder; bool encoder_active_sts; struct drm_display_mode drm_mode; struct drm_display_mode drm_mode; struct dp_display_mode dp_mode; struct dp_display_mode dp_mode; struct drm_connector *connector; struct drm_connector *connector; struct drm_connector *old_connector; void *dp_panel; void *dp_panel; void *old_dp_panel; int vcpi; int vcpi; int pbn; int pbn; Loading @@ -135,6 +133,13 @@ struct dp_mst_bridge { struct drm_connector *fixed_connector; 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 { struct dp_mst_private { bool mst_initialized; bool mst_initialized; struct dp_mst_caps caps; struct dp_mst_caps caps; Loading @@ -154,10 +159,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(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_private dp_mst; struct dp_mst_encoder_info_cache dp_mst_enc_cache; 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) static void dp_mst_sim_destroy_port(struct kref *ref) { { struct drm_dp_mst_port *port = container_of(ref, struct drm_dp_mst_port *port = container_of(ref, Loading Loading @@ -609,6 +659,8 @@ static bool dp_mst_bridge_mode_fixup(struct drm_bridge *drm_bridge, struct dp_display_mode dp_mode; struct dp_display_mode dp_mode; struct dp_mst_bridge *bridge; struct dp_mst_bridge *bridge; struct dp_display *dp; struct dp_display *dp; struct drm_crtc_state *crtc_state; struct dp_mst_bridge_state *bridge_state; DP_MST_DEBUG("enter\n"); DP_MST_DEBUG("enter\n"); Loading @@ -619,13 +671,17 @@ static bool dp_mst_bridge_mode_fixup(struct drm_bridge *drm_bridge, } } bridge = to_dp_mst_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; ret = false; goto end; goto end; } } if (!bridge->dp_panel) { if (!bridge_state->dp_panel) { DP_ERR("Invalid dp_panel\n"); DP_ERR("Invalid dp_panel\n"); ret = false; ret = false; goto end; goto end; Loading @@ -633,7 +689,7 @@ static bool dp_mst_bridge_mode_fixup(struct drm_bridge *drm_bridge, dp = bridge->display; 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); convert_to_drm_mode(&dp_mode, adjusted_mode); DP_MST_DEBUG("mst bridge [%d] mode:%s fixup\n", bridge->id, mode->name); DP_MST_DEBUG("mst bridge [%d] mode:%s fixup\n", bridge->id, mode->name); Loading @@ -647,7 +703,6 @@ static int _dp_mst_compute_config(struct drm_atomic_state *state, { { int slots = 0, pbn; int slots = 0, pbn; struct sde_connector *c_conn = to_sde_connector(connector); struct sde_connector *c_conn = to_sde_connector(connector); int rc = 0; DP_MST_DEBUG("enter\n"); DP_MST_DEBUG("enter\n"); Loading @@ -663,7 +718,7 @@ static int _dp_mst_compute_config(struct drm_atomic_state *state, DP_MST_DEBUG("exit\n"); DP_MST_DEBUG("exit\n"); return rc; return slots; } } static void _dp_mst_update_timeslots(struct dp_mst_private *mst, static void _dp_mst_update_timeslots(struct dp_mst_private *mst, Loading Loading @@ -856,9 +911,6 @@ static void dp_mst_bridge_pre_enable(struct drm_bridge *drm_bridge) bridge = to_dp_mst_bridge(drm_bridge); bridge = to_dp_mst_bridge(drm_bridge); dp = bridge->display; dp = bridge->display; bridge->old_connector = NULL; bridge->old_dp_panel = NULL; if (!bridge->connector) { if (!bridge->connector) { DP_ERR("Invalid connector\n"); DP_ERR("Invalid connector\n"); return; return; Loading Loading @@ -1008,17 +1060,8 @@ static void dp_mst_bridge_post_disable(struct drm_bridge *drm_bridge) DP_INFO("[%d] DP display unprepare failed, rc=%d\n", DP_INFO("[%d] DP display unprepare failed, rc=%d\n", bridge->id, rc); bridge->id, rc); /* maintain the connector to encoder link during suspend/resume */ bridge->connector = NULL; if (mst->state != PM_SUSPEND) { bridge->dp_panel = NULL; /* 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; } DP_MST_INFO_LOG("mst bridge [%d] post disable complete\n", DP_MST_INFO_LOG("mst bridge [%d] post disable complete\n", bridge->id); bridge->id); Loading @@ -1029,6 +1072,7 @@ static void dp_mst_bridge_mode_set(struct drm_bridge *drm_bridge, struct drm_display_mode *adjusted_mode) struct drm_display_mode *adjusted_mode) { { struct dp_mst_bridge *bridge; struct dp_mst_bridge *bridge; struct dp_mst_bridge_state *dp_bridge_state; struct dp_display *dp; struct dp_display *dp; DP_MST_DEBUG("enter\n"); DP_MST_DEBUG("enter\n"); Loading @@ -1039,23 +1083,10 @@ static void dp_mst_bridge_mode_set(struct drm_bridge *drm_bridge, } } bridge = to_dp_mst_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) { dp_bridge_state = to_dp_mst_bridge_state(bridge); if (!bridge->old_dp_panel) { bridge->connector = dp_bridge_state->connector; DP_ERR("Invalid dp_panel\n"); bridge->dp_panel = dp_bridge_state->dp_panel; return; } bridge->dp_panel = bridge->old_dp_panel; bridge->old_dp_panel = NULL; } dp = bridge->display; dp = bridge->display; Loading Loading @@ -1087,6 +1118,7 @@ int dp_mst_drm_bridge_init(void *data, struct drm_encoder *encoder) { { int rc = 0; int rc = 0; struct dp_mst_bridge *bridge = NULL; struct dp_mst_bridge *bridge = NULL; struct dp_mst_bridge_state *state; struct drm_device *dev; struct drm_device *dev; struct dp_display *display = data; struct dp_display *display = data; struct msm_drm_private *priv = NULL; struct msm_drm_private *priv = NULL; Loading Loading @@ -1138,6 +1170,16 @@ int dp_mst_drm_bridge_init(void *data, struct drm_encoder *encoder) encoder->bridge = &bridge->base; encoder->bridge = &bridge->base; priv->bridges[priv->num_bridges++] = &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); DP_MST_DEBUG("mst drm bridge init. bridge id:%d\n", i); /* /* Loading @@ -1152,6 +1194,7 @@ int dp_mst_drm_bridge_init(void *data, struct drm_encoder *encoder) bridge->encoder); bridge->encoder); if (bridge->fixed_connector == NULL) { if (bridge->fixed_connector == NULL) { DP_ERR("failed to create fixed connector\n"); DP_ERR("failed to create fixed connector\n"); kfree(state); rc = -ENOMEM; rc = -ENOMEM; goto end; goto end; } } Loading Loading @@ -1237,8 +1280,9 @@ enum drm_mode_status dp_mst_connector_mode_valid( struct drm_dp_mst_port *mst_port; struct drm_dp_mst_port *mst_port; struct dp_display_mode dp_mode; struct dp_display_mode dp_mode; uint16_t available_pbn, required_pbn; uint16_t available_pbn, required_pbn; int i, slots_in_use = 0, active_enc_cnt = 0; int available_slots, required_slots; 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; const u32 tot_slots = 63; if (!connector || !mode || !display) { if (!connector || !mode || !display) { Loading @@ -1250,21 +1294,21 @@ enum drm_mode_status dp_mst_connector_mode_valid( c_conn = to_sde_connector(connector); c_conn = to_sde_connector(connector); mst_port = c_conn->mst_port; mst_port = c_conn->mst_port; mutex_lock(&mst->mst_lock); /* dp bridge state is protected by drm_mode_config.connection_mutex */ available_pbn = mst_port->available_pbn; for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { if (mst->mst_bridge[i].encoder_active_sts && dp_bridge_state = to_dp_mst_bridge_state(&mst->mst_bridge[i]); (mst->mst_bridge[i].connector != connector)) { if (dp_bridge_state->connector && dp_bridge_state->connector != connector) { active_enc_cnt++; 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; available_slots = tot_slots - slots_in_use; else { } else { DP_DEBUG("all mst streams are active\n"); pr_debug("all mst streams are active\n"); return MODE_BAD; return MODE_BAD; } } Loading Loading @@ -1340,24 +1384,38 @@ dp_mst_atomic_best_encoder(struct drm_connector *connector, struct dp_mst_private *mst = dp_display->dp_mst_prv_info; struct dp_mst_private *mst = dp_display->dp_mst_prv_info; struct sde_connector *conn = to_sde_connector(connector); struct sde_connector *conn = to_sde_connector(connector); struct drm_encoder *enc = NULL; struct drm_encoder *enc = NULL; struct dp_mst_bridge_state *bridge_state; u32 i; u32 i; if (state->best_encoder) return state->best_encoder; for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { 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; enc = mst->mst_bridge[i].encoder; goto end; goto end; } } } } for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { if (!mst->mst_bridge[i].encoder_active_sts && if (mst->mst_bridge[i].fixed_connector) !mst->mst_bridge[i].fixed_connector) { continue; mst->mst_bridge[i].encoder_active_sts = true; mst->mst_bridge[i].connector = connector; bridge_state = dp_mst_get_bridge_atomic_state( mst->mst_bridge[i].dp_panel = conn->drv_panel; 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; enc = mst->mst_bridge[i].encoder; break; break; } } } } end: end: Loading @@ -1371,23 +1429,6 @@ dp_mst_atomic_best_encoder(struct drm_connector *connector, return enc; 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, static int dp_mst_connector_atomic_check(struct drm_connector *connector, void *display, struct drm_connector_state *new_conn_state) void *display, struct drm_connector_state *new_conn_state) { { Loading @@ -1396,7 +1437,8 @@ static int dp_mst_connector_atomic_check(struct drm_connector *connector, struct drm_connector_state *old_conn_state; struct drm_connector_state *old_conn_state; struct drm_crtc *old_crtc; struct drm_crtc *old_crtc; struct drm_crtc_state *crtc_state; 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_display *dp_display = display; struct dp_mst_private *mst = dp_display->dp_mst_prv_info; struct dp_mst_private *mst = dp_display->dp_mst_prv_info; struct sde_connector *c_conn; struct sde_connector *c_conn; Loading @@ -1404,18 +1446,9 @@ static int dp_mst_connector_atomic_check(struct drm_connector *connector, DP_MST_DEBUG("enter:\n"); 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) if (!new_conn_state) return rc; return rc; mutex_lock(&mst->mst_lock); state = new_conn_state->state; state = new_conn_state->state; old_conn_state = drm_atomic_get_old_connector_state(state, connector); old_conn_state = drm_atomic_get_old_connector_state(state, connector); Loading @@ -1435,22 +1468,47 @@ static int dp_mst_connector_atomic_check(struct drm_connector *connector, bridge->num_slots); bridge->num_slots); } } bridge = _dp_mst_get_bridge_from_encoder(dp_display, if (drm_atomic_crtc_needs_modeset(crtc_state)) { old_conn_state->best_encoder); if (WARN_ON(!old_conn_state->best_encoder)) { if (!bridge) rc = -EINVAL; goto end; goto end; } bridge = to_dp_mst_bridge( old_conn_state->best_encoder->bridge); slots = bridge->num_slots; bridge_state = dp_mst_get_bridge_atomic_state(state, bridge); if (drm_atomic_crtc_needs_modeset(crtc_state) && slots > 0) { 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, rc = mst->mst_fw_cbs->atomic_release_vcpi_slots(state, &mst->mst_mgr, slots); &mst->mst_mgr, slots); if (rc) { if (rc) { DP_ERR("failed releasing %d vcpi slots rc:%d\n", pr_err("failed releasing %d vcpi slots %d\n", slots, rc); slots, rc); goto end; 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: mode_set: if (!new_conn_state->crtc) if (!new_conn_state->crtc) goto end; goto end; Loading @@ -1460,28 +1518,45 @@ static int dp_mst_connector_atomic_check(struct drm_connector *connector, if (drm_atomic_crtc_needs_modeset(crtc_state) && crtc_state->active) { if (drm_atomic_crtc_needs_modeset(crtc_state) && crtc_state->active) { c_conn = to_sde_connector(connector); 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, dp_display->convert_to_dp_mode(dp_display, c_conn->drv_panel, &crtc_state->mode, &dp_mode); &crtc_state->mode, &dp_mode); slots = _dp_mst_compute_config(state, mst, connector, &dp_mode); slots = _dp_mst_compute_config(state, mst, connector, &dp_mode); if (slots < 0) { if (slots < 0) { rc = slots; 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; goto end; bridge->connector = NULL; bridge->dp_panel = NULL; bridge->encoder_active_sts = false; } } bridge_state->num_slots = slots; } } end: end: mutex_unlock(&mst->mst_lock); DP_MST_DEBUG("mst connector:%d atomic check ret %d\n", DP_MST_DEBUG("mst connector:%d atomic check\n", connector->base.id); connector->base.id, rc); return rc; return rc; } } Loading Loading @@ -1645,20 +1720,21 @@ dp_mst_fixed_atomic_best_encoder(struct drm_connector *connector, struct dp_mst_private *mst = dp_display->dp_mst_prv_info; struct dp_mst_private *mst = dp_display->dp_mst_prv_info; struct sde_connector *conn = to_sde_connector(connector); struct sde_connector *conn = to_sde_connector(connector); struct drm_encoder *enc = NULL; struct drm_encoder *enc = NULL; struct dp_mst_bridge_state *bridge_state; u32 i; u32 i; for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { if (state->best_encoder) if (mst->mst_bridge[i].connector == connector) { return state->best_encoder; enc = mst->mst_bridge[i].encoder; goto end; } } for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) { if (mst->mst_bridge[i].fixed_connector == connector) { if (mst->mst_bridge[i].fixed_connector == connector) { mst->mst_bridge[i].encoder_active_sts = true; bridge_state = dp_mst_get_bridge_atomic_state( mst->mst_bridge[i].connector = connector; state->state, &mst->mst_bridge[i]); mst->mst_bridge[i].dp_panel = conn->drv_panel; if (IS_ERR(bridge_state)) goto end; bridge_state->connector = connector; bridge_state->dp_panel = conn->drv_panel; enc = mst->mst_bridge[i].encoder; enc = mst->mst_bridge[i].encoder; break; break; } } Loading