diff --git a/msm/dp/dp_display.c b/msm/dp/dp_display.c index 2520501423..141bf9bac7 100644 --- a/msm/dp/dp_display.c +++ b/msm/dp/dp_display.c @@ -202,6 +202,7 @@ struct dp_display_private { struct work_struct connect_work; struct work_struct attention_work; struct mutex session_lock; + struct mutex accounting_lock; bool hdcp_delayed_off; bool no_aux_switch; @@ -209,6 +210,7 @@ struct dp_display_private { struct dp_mst mst; u32 tot_dsc_blks_in_use; + u32 tot_lm_blks_in_use; bool process_hpd_connect; struct dev_pm_qos_request pm_qos_req[NR_CPUS]; @@ -1483,6 +1485,25 @@ static int dp_display_usbpd_configure_cb(struct device *dev) return 0; } +static void dp_display_clear_reservation(struct dp_display *dp, struct dp_panel *panel) +{ + struct dp_display_private *dp_display; + + if (!dp || !panel) { + DP_ERR("invalid params\n"); + return; + } + + dp_display = container_of(dp, struct dp_display_private, dp_display); + + mutex_lock(&dp_display->accounting_lock); + + dp_display->tot_lm_blks_in_use -= panel->max_lm; + panel->max_lm = 0; + + mutex_unlock(&dp_display->accounting_lock); +} + static void dp_display_clear_dsc_resources(struct dp_display_private *dp, struct dp_panel *panel) { @@ -1562,6 +1583,7 @@ static void dp_display_clean(struct dp_display_private *dp) dp_display_stream_pre_disable(dp, dp_panel); dp_display_stream_disable(dp, dp_panel); + dp_display_clear_reservation(&dp->dp_display, dp_panel); dp_panel->deinit(dp_panel, 0); } @@ -1589,6 +1611,8 @@ static int dp_display_handle_disconnect(struct dp_display_private *dp) dp_display_host_unready(dp); + dp->tot_lm_blks_in_use = 0; + mutex_unlock(&dp->session_lock); SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state); @@ -2002,6 +2026,7 @@ static int dp_init_sub_modules(struct dp_display_private *dp) }; mutex_init(&dp->session_lock); + mutex_init(&dp->accounting_lock); dp->parser = dp_parser_get(dp->pdev); if (IS_ERR(dp->parser)) { @@ -2172,6 +2197,7 @@ static int dp_init_sub_modules(struct dp_display_private *dp) dp->cached_connector_status = connector_status_disconnected; dp->tot_dsc_blks_in_use = 0; + dp->tot_lm_blks_in_use = 0; dp->debug->hdcp_disabled = hdcp_disabled; dp_display_update_hdcp_status(dp, true); @@ -2809,6 +2835,8 @@ static int dp_display_unprepare(struct dp_display *dp_display, void *panel) /* log this as it results from user action of cable dis-connection */ DP_INFO("[OK]\n"); end: + dp->tot_lm_blks_in_use -= dp_panel->max_lm; + dp_panel->max_lm = 0; dp_panel->deinit(dp_panel, flags); mutex_unlock(&dp->session_lock); SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_EXIT, dp->state); @@ -2867,11 +2895,14 @@ static int dp_display_validate_topology(struct dp_display_private *dp, u32 num_lm = 0, num_dsc = 0, num_3dmux = 0; bool dsc_capable = dp_mode->capabilities & DP_PANEL_CAPS_DSC; u32 fps = dp_mode->timing.refresh_rate; + int avail_lm = 0; + + mutex_lock(&dp->accounting_lock); rc = msm_get_mixer_count(priv, mode, avail_res, &num_lm); if (rc) { DP_ERR("error getting mixer count. rc:%d\n", rc); - return rc; + goto end; } /* Merge using DSC, if enabled */ @@ -2879,7 +2910,7 @@ static int dp_display_validate_topology(struct dp_display_private *dp, rc = msm_get_dsc_count(priv, mode->hdisplay, &num_dsc); if (rc) { DP_ERR("error getting dsc count. rc:%d\n", rc); - return rc; + goto end; } num_dsc = max(num_lm, num_dsc); @@ -2889,7 +2920,8 @@ static int dp_display_validate_topology(struct dp_display_private *dp, avail_res->num_lm); /* Clear DSC caps and retry */ dp_mode->capabilities &= ~DP_PANEL_CAPS_DSC; - return -EAGAIN; + rc = -EAGAIN; + goto end; } else { /* Only DSCMERGE is supported on DP */ num_lm = num_dsc; @@ -2900,24 +2932,36 @@ static int dp_display_validate_topology(struct dp_display_private *dp, num_3dmux = 1; } - if (num_lm > avail_res->num_lm) { + avail_lm = avail_res->num_lm + avail_res->num_lm_in_use - dp->tot_lm_blks_in_use; + if ((num_lm > dp_panel->max_lm) && (num_lm > avail_lm)) { DP_DEBUG("mode %sx%d is invalid, not enough lm %d %d\n", - mode->name, fps, num_lm, num_lm, avail_res->num_lm); - return -EPERM; + mode->name, fps, num_lm, avail_res->num_lm); + rc = -EPERM; + goto end; } else if (!num_dsc && (num_lm == dual && !num_3dmux)) { DP_DEBUG("mode %sx%d is invalid, not enough 3dmux %d %d\n", mode->name, fps, num_3dmux, avail_res->num_3dmux); - return -EPERM; + rc = -EPERM; + goto end; } else if (num_lm == quad && num_dsc != quad) { DP_DEBUG("mode %sx%d is invalid, unsupported DP topology lm:%d dsc:%d\n", mode->name, fps, num_lm, num_dsc); - return -EPERM; + rc = -EPERM; + goto end; } DP_DEBUG_V("mode %sx%d is valid, supported DP topology lm:%d dsc:%d 3dmux:%d\n", mode->name, fps, num_lm, num_dsc, num_3dmux); - return 0; + dp->tot_lm_blks_in_use -= dp_panel->max_lm; + dp_panel->max_lm = num_lm > avail_res->num_lm_in_use ? max(dp_panel->max_lm, num_lm) : 0; + dp->tot_lm_blks_in_use += dp_panel->max_lm; + + rc = 0; + +end: + mutex_unlock(&dp->accounting_lock); + return rc; } static enum drm_mode_status dp_display_validate_mode( @@ -2973,6 +3017,8 @@ static enum drm_mode_status dp_display_validate_mode( mode_status = MODE_OK; end: + if (mode_status != MODE_OK) + dp_display_clear_reservation(dp_display, dp_panel); mutex_unlock(&dp->session_lock); DP_DEBUG_V("[%s] mode is %s\n", mode->name, @@ -3645,6 +3691,7 @@ static int dp_display_probe(struct platform_device *pdev) g_dp_display->set_colorspace = dp_display_setup_colospace; g_dp_display->get_available_dp_resources = dp_display_get_available_dp_resources; + g_dp_display->clear_reservation = dp_display_clear_reservation; rc = component_add(&pdev->dev, &dp_display_comp_ops); if (rc) { diff --git a/msm/dp/dp_display.h b/msm/dp/dp_display.h index 45f5fec043..11a0bb870f 100644 --- a/msm/dp/dp_display.h +++ b/msm/dp/dp_display.h @@ -105,6 +105,7 @@ struct dp_display { int (*get_available_dp_resources)(struct dp_display *dp_display, const struct msm_resource_caps_info *avail_res, struct msm_resource_caps_info *max_dp_avail_res); + void (*clear_reservation)(struct dp_display *dp, struct dp_panel *panel); }; void *get_ipc_log_context(void); diff --git a/msm/dp/dp_drm.c b/msm/dp/dp_drm.c index 4a65073152..5180209202 100644 --- a/msm/dp/dp_drm.c +++ b/msm/dp/dp_drm.c @@ -257,6 +257,8 @@ static void dp_bridge_mode_set(struct drm_bridge *drm_bridge, dp->convert_to_dp_mode(dp, bridge->dp_panel, adjusted_mode, &bridge->dp_mode); + + dp->clear_reservation(dp, bridge->dp_panel); } static bool dp_bridge_mode_fixup(struct drm_bridge *drm_bridge, @@ -290,6 +292,7 @@ static bool dp_bridge_mode_fixup(struct drm_bridge *drm_bridge, dp = bridge->display; dp->convert_to_dp_mode(dp, bridge->dp_panel, mode, &dp_mode); + dp->clear_reservation(dp, bridge->dp_panel); convert_to_drm_mode(&dp_mode, adjusted_mode); end: return ret; diff --git a/msm/dp/dp_mst_drm.c b/msm/dp/dp_mst_drm.c index 5e72dcb7c1..477b5f5d54 100644 --- a/msm/dp/dp_mst_drm.c +++ b/msm/dp/dp_mst_drm.c @@ -345,6 +345,7 @@ static bool dp_mst_bridge_mode_fixup(struct drm_bridge *drm_bridge, dp = bridge->display; dp->convert_to_dp_mode(dp, bridge_state->dp_panel, mode, &dp_mode); + dp->clear_reservation(dp, bridge_state->dp_panel); convert_to_drm_mode(&dp_mode, adjusted_mode); DP_MST_DEBUG("mst bridge [%d] mode:%s fixup\n", bridge->id, mode->name); @@ -775,6 +776,7 @@ static void dp_mst_bridge_mode_set(struct drm_bridge *drm_bridge, memcpy(&bridge->drm_mode, adjusted_mode, sizeof(bridge->drm_mode)); dp->convert_to_dp_mode(dp, bridge->dp_panel, adjusted_mode, &bridge->dp_mode); + dp->clear_reservation(dp, dp_bridge_state->dp_panel); DP_MST_INFO("mst bridge:%d conn:%d mode set complete %s\n", bridge->id, DP_MST_CONN_ID(bridge), mode->name); diff --git a/msm/dp/dp_panel.h b/msm/dp/dp_panel.h index 3e71882001..92b0743bbf 100644 --- a/msm/dp/dp_panel.h +++ b/msm/dp/dp_panel.h @@ -137,6 +137,7 @@ struct dp_panel { u32 pbn; u32 dsc_blks_in_use; + u32 max_lm; /* DRM connector assosiated with this panel */ struct drm_connector *connector; diff --git a/msm/msm_drv.h b/msm/msm_drv.h index f97e997688..39f35fa078 100644 --- a/msm/msm_drv.h +++ b/msm/msm_drv.h @@ -828,6 +828,7 @@ struct msm_mode_info { /** * struct msm_resource_caps_info - defines hw resources + * @num_lm_in_use number of layer mixers allocated to a specified encoder * @num_lm number of layer mixers available * @num_dsc number of dsc available * @num_vdc number of vdc available @@ -836,6 +837,7 @@ struct msm_mode_info { * @max_mixer_width: max width supported by layer mixer */ struct msm_resource_caps_info { + uint32_t num_lm_in_use; uint32_t num_lm; uint32_t num_dsc; uint32_t num_vdc; diff --git a/msm/sde/sde_rm.c b/msm/sde/sde_rm.c index 8f8a4c575a..fc2e20486b 100644 --- a/msm/sde/sde_rm.c +++ b/msm/sde/sde_rm.c @@ -286,27 +286,33 @@ void sde_rm_get_resource_info(struct sde_rm *rm, { struct sde_rm_hw_blk *blk; enum sde_hw_blk_type type; - struct sde_rm_rsvp rsvp; const struct sde_lm_cfg *lm_cfg; bool is_built_in, is_pref; u32 lm_pref = (BIT(SDE_DISP_PRIMARY_PREF) | BIT(SDE_DISP_SECONDARY_PREF)); + mutex_lock(&rm->rm_lock); + /* Get all currently available resources */ memcpy(avail_res, &rm->avail_res, sizeof(rm->avail_res)); + /** + * When the encoder is null, assume display is external in order to return the count of + * availalbe non-preferred LMs + */ if (!drm_enc) - return; - - is_built_in = sde_encoder_is_built_in_display(drm_enc); - - rsvp.enc_id = drm_enc->base.id; + is_built_in = false; + else + is_built_in = sde_encoder_is_built_in_display(drm_enc); for (type = 0; type < SDE_HW_BLK_MAX; type++) { list_for_each_entry(blk, &rm->hw_blks[type], list) { /* Add back resources allocated to the given encoder */ - if (blk->rsvp && blk->rsvp->enc_id == rsvp.enc_id) + if (blk->rsvp && drm_enc && blk->rsvp->enc_id == drm_enc->base.id) { _sde_rm_inc_resource_info(rm, avail_res, blk); + if (type == SDE_HW_BLK_LM) + avail_res->num_lm_in_use++; + } /** * Remove unallocated preferred lms that cannot reserved @@ -316,11 +322,13 @@ void sde_rm_get_resource_info(struct sde_rm *rm, lm_cfg = to_sde_hw_mixer(blk->hw)->cap; is_pref = lm_cfg->features & lm_pref; - if (!blk->rsvp && !is_built_in && is_pref) + if (!blk->rsvp && !blk->rsvp_nxt && !is_built_in && is_pref) _sde_rm_dec_resource_info(rm, avail_res, blk); } } } + + mutex_unlock(&rm->rm_lock); } static void _sde_rm_print_rsvps(