diff --git a/msm/sde/sde_kms.c b/msm/sde/sde_kms.c index 2797a0be4f..3928eb76d8 100644 --- a/msm/sde/sde_kms.c +++ b/msm/sde/sde_kms.c @@ -2641,7 +2641,6 @@ static int sde_kms_pm_suspend(struct device *dev) sde_kms = to_sde_kms(ddev_to_msm_kms(ddev)); SDE_EVT32(0); - pm_runtime_put_noidle(dev); /* disable hot-plug polling */ drm_kms_helper_poll_disable(ddev); @@ -2750,6 +2749,15 @@ unlock: } drm_modeset_drop_locks(&ctx); drm_modeset_acquire_fini(&ctx); + + /* + * pm runtime driver avoids multiple runtime_suspend API call by + * checking runtime_status. However, this call helps when there is a + * race condition between pm_suspend call and doze_suspend/power_off + * commit. It removes the extra vote from suspend and adds it back + * later to allow power collapse during pm_suspend call + */ + pm_runtime_put_sync(dev); pm_runtime_get_noresume(dev); return ret; diff --git a/msm/sde_rsc.c b/msm/sde_rsc.c index ed380bcbf9..f60b7e4fe4 100644 --- a/msm/sde_rsc.c +++ b/msm/sde_rsc.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include @@ -399,6 +398,86 @@ static u32 sde_rsc_timer_calculate(struct sde_rsc_priv *rsc, return ret; } +static int sde_rsc_resource_disable(struct sde_rsc_priv *rsc) +{ + struct dss_module_power *mp; + u32 reg_bus_hdl; + + if (!rsc) { + pr_err("invalid drv data\n"); + return -EINVAL; + } + + if (atomic_read(&rsc->resource_refcount) == 0) { + pr_err("%pS: invalid rsc resource disable call\n", + __builtin_return_address(0)); + return -EINVAL; + } + + if (atomic_dec_return(&rsc->resource_refcount) != 0) + return 0; + + mp = &rsc->phandle.mp; + msm_dss_enable_clk(mp->clk_config, mp->num_clk, false); + reg_bus_hdl = rsc->phandle.reg_bus_hdl; + if (reg_bus_hdl) + msm_bus_scale_client_update_request(reg_bus_hdl, + VOTE_INDEX_DISABLE); + msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, false); + + return 0; +} + +static int sde_rsc_resource_enable(struct sde_rsc_priv *rsc) +{ + struct dss_module_power *mp; + int rc = 0; + u32 reg_bus_hdl; + + if (!rsc) { + pr_err("invalid drv data\n"); + return -EINVAL; + } + + if (atomic_inc_return(&rsc->resource_refcount) != 1) + return 0; + + mp = &rsc->phandle.mp; + rc = msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, true); + if (rc) { + pr_err("failed to enable vregs rc=%d\n", rc); + goto end; + } + + reg_bus_hdl = rsc->phandle.reg_bus_hdl; + if (reg_bus_hdl) { + rc = msm_bus_scale_client_update_request(reg_bus_hdl, + VOTE_INDEX_LOW); + if (rc) { + pr_err("failed to set reg bus vote rc=%d\n", rc); + goto reg_bus_hdl_err; + } + } + + rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, true); + if (rc) { + pr_err("clock enable failed rc:%d\n", rc); + goto clk_err; + } + + return rc; + +clk_err: + if (reg_bus_hdl) + msm_bus_scale_client_update_request(reg_bus_hdl, + VOTE_INDEX_DISABLE); +reg_bus_hdl_err: + msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, false); +end: + atomic_dec(&rsc->resource_refcount); + return rc; +} + static int sde_rsc_switch_to_cmd(struct sde_rsc_priv *rsc, struct sde_rsc_cmd_config *config, struct sde_rsc_client *caller_client, @@ -824,7 +903,7 @@ int sde_rsc_client_state_update(struct sde_rsc_client *caller_client, caller_client->name, state); if (rsc->current_state == SDE_RSC_IDLE_STATE) - pm_runtime_get_sync(rsc->dev); + sde_rsc_resource_enable(rsc); switch (state) { case SDE_RSC_IDLE_STATE: @@ -882,7 +961,7 @@ int sde_rsc_client_state_update(struct sde_rsc_client *caller_client, clk_disable: if (rsc->current_state == SDE_RSC_IDLE_STATE) - pm_runtime_put_sync(rsc->dev); + sde_rsc_resource_disable(rsc); end: mutex_unlock(&rsc->client_lock); return rc; @@ -959,7 +1038,7 @@ int sde_rsc_client_trigger_vote(struct sde_rsc_client *caller_client, rsc->bw_config.ib_vote[i] = rsc->bw_config.new_ib_vote[i]; } - rc = pm_runtime_get_sync(rsc->dev); + rc = sde_rsc_resource_enable(rsc); if (rc < 0) goto clk_enable_fail; @@ -990,7 +1069,7 @@ int sde_rsc_client_trigger_vote(struct sde_rsc_client *caller_client, rsc->hw_ops.tcs_use_ok(rsc); end: - pm_runtime_put_sync(rsc->dev); + sde_rsc_resource_disable(rsc); clk_enable_fail: mutex_unlock(&rsc->client_lock); @@ -1299,7 +1378,7 @@ static void sde_rsc_deinit(struct platform_device *pdev, if (!rsc) return; - pm_runtime_put_sync(rsc->dev); + sde_rsc_resource_disable(rsc); if (rsc->sw_fs_enabled) regulator_disable(rsc->fs); if (rsc->fs) @@ -1314,82 +1393,6 @@ static void sde_rsc_deinit(struct platform_device *pdev, kfree(rsc); } -#ifdef CONFIG_PM -static int sde_rsc_runtime_suspend(struct device *dev) -{ - struct sde_rsc_priv *rsc = dev_get_drvdata(dev); - struct dss_module_power *mp; - u32 reg_bus_hdl; - - if (!rsc) { - pr_err("invalid drv data\n"); - return -EINVAL; - } - - mp = &rsc->phandle.mp; - msm_dss_enable_clk(mp->clk_config, mp->num_clk, false); - reg_bus_hdl = rsc->phandle.reg_bus_hdl; - if (reg_bus_hdl) - msm_bus_scale_client_update_request(reg_bus_hdl, - VOTE_INDEX_DISABLE); - msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, false); - - return 0; -} - -static int sde_rsc_runtime_resume(struct device *dev) -{ - struct sde_rsc_priv *rsc = dev_get_drvdata(dev); - struct dss_module_power *mp; - int rc = 0; - u32 reg_bus_hdl; - - if (!rsc) { - pr_err("invalid drv data\n"); - return -EINVAL; - } - - mp = &rsc->phandle.mp; - rc = msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, true); - if (rc) { - pr_err("failed to enable vregs rc=%d\n", rc); - goto end; - } - - reg_bus_hdl = rsc->phandle.reg_bus_hdl; - if (reg_bus_hdl) { - rc = msm_bus_scale_client_update_request(reg_bus_hdl, - VOTE_INDEX_LOW); - if (rc) { - pr_err("failed to set reg bus vote rc=%d\n", rc); - goto reg_bus_hdl_err; - } - } - - rc = msm_dss_enable_clk(mp->clk_config, mp->num_clk, true); - if (rc) { - pr_err("clock enable failed rc:%d\n", rc); - goto clk_err; - } - - return rc; - -clk_err: - if (reg_bus_hdl) - msm_bus_scale_client_update_request(reg_bus_hdl, - VOTE_INDEX_DISABLE); -reg_bus_hdl_err: - msm_dss_enable_vreg(mp->vreg_config, mp->num_vreg, false); -end: - return rc; -} -#endif - -static const struct dev_pm_ops sde_rsc_pm_ops = { - SET_RUNTIME_PM_OPS(sde_rsc_runtime_suspend, - sde_rsc_runtime_resume, NULL) -}; - /** * sde_rsc_bind - bind rsc device with controlling device * @dev: Pointer to base of platform device @@ -1556,8 +1559,7 @@ static int sde_rsc_probe(struct platform_device *pdev) rsc->sw_fs_enabled = true; - pm_runtime_enable(rsc->dev); - ret = pm_runtime_get_sync(rsc->dev); + ret = sde_rsc_resource_enable(rsc); if (ret < 0) { pr_err("failed to enable sde rsc power resources rc:%d\n", ret); goto sde_rsc_fail; @@ -1566,12 +1568,13 @@ static int sde_rsc_probe(struct platform_device *pdev) if (sde_rsc_timer_calculate(rsc, NULL, SDE_RSC_IDLE_STATE)) goto sde_rsc_fail; - pm_runtime_put_sync(rsc->dev); + sde_rsc_resource_disable(rsc); INIT_LIST_HEAD(&rsc->client_list); INIT_LIST_HEAD(&rsc->event_list); mutex_init(&rsc->client_lock); init_waitqueue_head(&rsc->rsc_vsync_waitq); + atomic_set(&rsc->resource_refcount, 0); pr_info("sde rsc index:%d probed successfully\n", SDE_RSC_INDEX + counter); @@ -1644,7 +1647,6 @@ static struct platform_driver sde_rsc_platform_driver = { .name = "sde_rsc", .of_match_table = dt_match, .suppress_bind_attrs = true, - .pm = &sde_rsc_pm_ops, }, }; diff --git a/msm/sde_rsc_priv.h b/msm/sde_rsc_priv.h index b1261e1888..5f63061f4a 100644 --- a/msm/sde_rsc_priv.h +++ b/msm/sde_rsc_priv.h @@ -185,6 +185,7 @@ struct sde_rsc_bw_config { * rsc_vsync_waitq: Queue to wait for the vsync. * bw_config: check sde_rsc_bw_config structure description. * dev: rsc device node + * resource_refcount: Track rsc resource refcount */ struct sde_rsc_priv { u32 version; @@ -225,6 +226,7 @@ struct sde_rsc_priv { struct sde_rsc_bw_config bw_config; struct device *dev; + atomic_t resource_refcount; }; /**