msm: sde: Fix SDE rotator clock disable sequence
It is necessary to follow a certain order when disabling the rotator clock. Not doing so might lead to clock actually not turning off and cause power leakage. CRs-Fixed: 1081010 Change-Id: I16e500aa87813cd3a1e18f134ea1ed145b9e1ef8 Signed-off-by: Benjamin Chan <bkchan@codeaurora.org>
This commit is contained in:
parent
46aa49c118
commit
c6f19b4fa5
3 changed files with 111 additions and 71 deletions
|
@ -266,7 +266,7 @@ static int sde_rotator_update_clk(struct sde_rot_mgr *mgr)
|
||||||
|
|
||||||
SDEROT_DBG("core_clk %lu\n", total_clk_rate);
|
SDEROT_DBG("core_clk %lu\n", total_clk_rate);
|
||||||
ATRACE_INT("core_clk", total_clk_rate);
|
ATRACE_INT("core_clk", total_clk_rate);
|
||||||
sde_rotator_set_clk_rate(mgr, total_clk_rate, mgr->core_clk_idx);
|
sde_rotator_set_clk_rate(mgr, total_clk_rate, SDE_ROTATOR_CLK_ROT_CORE);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -300,11 +300,34 @@ static void sde_rotator_footswitch_ctrl(struct sde_rot_mgr *mgr, bool on)
|
||||||
mgr->regulator_enable = on;
|
mgr->regulator_enable = on;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sde_rotator_clk_ctrl(struct sde_rot_mgr *mgr, int enable)
|
static int sde_rotator_enable_clk(struct sde_rot_mgr *mgr, int clk_idx)
|
||||||
{
|
{
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
int i, changed = 0;
|
|
||||||
|
clk = sde_rotator_get_clk(mgr, clk_idx);
|
||||||
|
if (clk) {
|
||||||
|
ret = clk_prepare_enable(clk);
|
||||||
|
if (ret)
|
||||||
|
SDEROT_ERR("enable failed clk_idx %d\n", clk_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sde_rotator_disable_clk(struct sde_rot_mgr *mgr, int clk_idx)
|
||||||
|
{
|
||||||
|
struct clk *clk;
|
||||||
|
|
||||||
|
clk = sde_rotator_get_clk(mgr, clk_idx);
|
||||||
|
if (clk)
|
||||||
|
clk_disable_unprepare(clk);
|
||||||
|
}
|
||||||
|
|
||||||
|
int sde_rotator_clk_ctrl(struct sde_rot_mgr *mgr, int enable)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
int changed = 0;
|
||||||
|
|
||||||
if (enable) {
|
if (enable) {
|
||||||
if (mgr->rot_enable_clk_cnt == 0)
|
if (mgr->rot_enable_clk_cnt == 0)
|
||||||
|
@ -323,32 +346,41 @@ int sde_rotator_clk_ctrl(struct sde_rot_mgr *mgr, int enable)
|
||||||
if (changed) {
|
if (changed) {
|
||||||
SDEROT_EVTLOG(enable);
|
SDEROT_EVTLOG(enable);
|
||||||
SDEROT_DBG("Rotator clk %s\n", enable ? "enable" : "disable");
|
SDEROT_DBG("Rotator clk %s\n", enable ? "enable" : "disable");
|
||||||
for (i = 0; i < mgr->num_rot_clk; i++) {
|
|
||||||
clk = mgr->rot_clk[i].clk;
|
|
||||||
|
|
||||||
if (!clk)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (enable) {
|
if (enable) {
|
||||||
ret = clk_prepare_enable(clk);
|
ret = sde_rotator_enable_clk(mgr,
|
||||||
if (ret) {
|
SDE_ROTATOR_CLK_MNOC_AHB);
|
||||||
SDEROT_ERR(
|
if (ret)
|
||||||
"enable failed clk_idx %d\n",
|
goto error_mnoc_ahb;
|
||||||
i);
|
ret = sde_rotator_enable_clk(mgr,
|
||||||
goto error;
|
SDE_ROTATOR_CLK_MDSS_AHB);
|
||||||
}
|
if (ret)
|
||||||
} else {
|
goto error_mdss_ahb;
|
||||||
clk_disable_unprepare(clk);
|
ret = sde_rotator_enable_clk(mgr,
|
||||||
}
|
SDE_ROTATOR_CLK_MDSS_AXI);
|
||||||
}
|
if (ret)
|
||||||
|
goto error_mdss_axi;
|
||||||
|
ret = sde_rotator_enable_clk(mgr,
|
||||||
|
SDE_ROTATOR_CLK_ROT_CORE);
|
||||||
|
if (ret)
|
||||||
|
goto error_rot_core;
|
||||||
|
ret = sde_rotator_enable_clk(mgr,
|
||||||
|
SDE_ROTATOR_CLK_MDSS_ROT);
|
||||||
|
if (ret)
|
||||||
|
goto error_mdss_rot;
|
||||||
|
|
||||||
if (enable) {
|
|
||||||
/* Active+Sleep */
|
/* Active+Sleep */
|
||||||
msm_bus_scale_client_update_context(
|
msm_bus_scale_client_update_context(
|
||||||
mgr->data_bus.bus_hdl, false,
|
mgr->data_bus.bus_hdl, false,
|
||||||
mgr->data_bus.curr_bw_uc_idx);
|
mgr->data_bus.curr_bw_uc_idx);
|
||||||
trace_rot_bw_ao_as_context(0);
|
trace_rot_bw_ao_as_context(0);
|
||||||
} else {
|
} else {
|
||||||
|
sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_MDSS_ROT);
|
||||||
|
sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_ROT_CORE);
|
||||||
|
sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_MDSS_AXI);
|
||||||
|
sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_MDSS_AHB);
|
||||||
|
sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_MNOC_AHB);
|
||||||
|
|
||||||
/* Active Only */
|
/* Active Only */
|
||||||
msm_bus_scale_client_update_context(
|
msm_bus_scale_client_update_context(
|
||||||
mgr->data_bus.bus_hdl, true,
|
mgr->data_bus.bus_hdl, true,
|
||||||
|
@ -358,9 +390,15 @@ int sde_rotator_clk_ctrl(struct sde_rot_mgr *mgr, int enable)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
error:
|
error_mdss_rot:
|
||||||
for (i--; i >= 0; i--)
|
sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_ROT_CORE);
|
||||||
clk_disable_unprepare(mgr->rot_clk[i].clk);
|
error_rot_core:
|
||||||
|
sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_MDSS_AXI);
|
||||||
|
error_mdss_axi:
|
||||||
|
sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_MDSS_AHB);
|
||||||
|
error_mdss_ahb:
|
||||||
|
sde_rotator_disable_clk(mgr, SDE_ROTATOR_CLK_MNOC_AHB);
|
||||||
|
error_mnoc_ahb:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2101,7 +2139,6 @@ static ssize_t sde_rotator_show_state(struct device *dev,
|
||||||
SPRINT("footswitch_cnt=%d\n", mgr->res_ref_cnt);
|
SPRINT("footswitch_cnt=%d\n", mgr->res_ref_cnt);
|
||||||
SPRINT("regulator_enable=%d\n", mgr->regulator_enable);
|
SPRINT("regulator_enable=%d\n", mgr->regulator_enable);
|
||||||
SPRINT("enable_clk_cnt=%d\n", mgr->rot_enable_clk_cnt);
|
SPRINT("enable_clk_cnt=%d\n", mgr->rot_enable_clk_cnt);
|
||||||
SPRINT("core_clk_idx=%d\n", mgr->core_clk_idx);
|
|
||||||
for (i = 0; i < mgr->num_rot_clk; i++)
|
for (i = 0; i < mgr->num_rot_clk; i++)
|
||||||
if (mgr->rot_clk[i].clk)
|
if (mgr->rot_clk[i].clk)
|
||||||
SPRINT("%s=%lu\n", mgr->rot_clk[i].clk_name,
|
SPRINT("%s=%lu\n", mgr->rot_clk[i].clk_name,
|
||||||
|
@ -2301,17 +2338,39 @@ static int sde_rotator_bus_scale_register(struct sde_rot_mgr *mgr)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int sde_rotator_search_dt_clk(struct platform_device *pdev,
|
||||||
|
struct sde_rot_mgr *mgr, char *clk_name, int clk_idx)
|
||||||
|
{
|
||||||
|
struct clk *tmp;
|
||||||
|
|
||||||
|
if (clk_idx >= SDE_ROTATOR_CLK_MAX) {
|
||||||
|
SDEROT_ERR("invalid clk index %d\n", clk_idx);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
tmp = devm_clk_get(&pdev->dev, clk_name);
|
||||||
|
if (IS_ERR(tmp)) {
|
||||||
|
SDEROT_ERR("unable to get clk: %s\n", clk_name);
|
||||||
|
return PTR_ERR(tmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
strlcpy(mgr->rot_clk[clk_idx].clk_name, clk_name,
|
||||||
|
sizeof(mgr->rot_clk[clk_idx].clk_name));
|
||||||
|
|
||||||
|
mgr->rot_clk[clk_idx].clk = tmp;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int sde_rotator_parse_dt_clk(struct platform_device *pdev,
|
static int sde_rotator_parse_dt_clk(struct platform_device *pdev,
|
||||||
struct sde_rot_mgr *mgr)
|
struct sde_rot_mgr *mgr)
|
||||||
{
|
{
|
||||||
u32 i = 0, rc = 0;
|
u32 rc = 0;
|
||||||
const char *clock_name;
|
|
||||||
int num_clk;
|
int num_clk;
|
||||||
|
|
||||||
num_clk = of_property_count_strings(pdev->dev.of_node,
|
num_clk = of_property_count_strings(pdev->dev.of_node,
|
||||||
"clock-names");
|
"clock-names");
|
||||||
if (num_clk <= 0) {
|
if ((num_clk <= 0) || (num_clk > SDE_ROTATOR_CLK_MAX)) {
|
||||||
SDEROT_ERR("clocks are not defined\n");
|
SDEROT_ERR("Number of clocks are out of range: %d\n", num_clk);
|
||||||
goto clk_err;
|
goto clk_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2325,19 +2384,17 @@ static int sde_rotator_parse_dt_clk(struct platform_device *pdev,
|
||||||
goto clk_err;
|
goto clk_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < mgr->num_rot_clk; i++) {
|
if (sde_rotator_search_dt_clk(pdev, mgr, "mnoc_clk",
|
||||||
u32 clock_rate = 0;
|
SDE_ROTATOR_CLK_MNOC_AHB) ||
|
||||||
|
sde_rotator_search_dt_clk(pdev, mgr, "iface_clk",
|
||||||
of_property_read_string_index(pdev->dev.of_node, "clock-names",
|
SDE_ROTATOR_CLK_MDSS_AHB) ||
|
||||||
i, &clock_name);
|
sde_rotator_search_dt_clk(pdev, mgr, "axi_clk",
|
||||||
strlcpy(mgr->rot_clk[i].clk_name, clock_name,
|
SDE_ROTATOR_CLK_MDSS_AXI) ||
|
||||||
sizeof(mgr->rot_clk[i].clk_name));
|
sde_rotator_search_dt_clk(pdev, mgr, "rot_core_clk",
|
||||||
|
SDE_ROTATOR_CLK_ROT_CORE) ||
|
||||||
of_property_read_u32_index(pdev->dev.of_node, "clock-rate",
|
sde_rotator_search_dt_clk(pdev, mgr, "rot_clk",
|
||||||
i, &clock_rate);
|
SDE_ROTATOR_CLK_MDSS_ROT))
|
||||||
mgr->rot_clk[i].rate = clock_rate;
|
rc = -EINVAL;
|
||||||
}
|
|
||||||
|
|
||||||
clk_err:
|
clk_err:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
@ -2345,10 +2402,7 @@ clk_err:
|
||||||
static int sde_rotator_register_clk(struct platform_device *pdev,
|
static int sde_rotator_register_clk(struct platform_device *pdev,
|
||||||
struct sde_rot_mgr *mgr)
|
struct sde_rot_mgr *mgr)
|
||||||
{
|
{
|
||||||
int i, ret;
|
int ret;
|
||||||
struct clk *clk;
|
|
||||||
struct sde_rot_clk *rot_clk;
|
|
||||||
int core_clk_idx = -1;
|
|
||||||
|
|
||||||
ret = sde_rotator_parse_dt_clk(pdev, mgr);
|
ret = sde_rotator_parse_dt_clk(pdev, mgr);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
@ -2356,28 +2410,6 @@ static int sde_rotator_register_clk(struct platform_device *pdev,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < mgr->num_rot_clk; i++) {
|
|
||||||
rot_clk = &mgr->rot_clk[i];
|
|
||||||
|
|
||||||
clk = devm_clk_get(&pdev->dev, rot_clk->clk_name);
|
|
||||||
if (IS_ERR(clk)) {
|
|
||||||
SDEROT_ERR("unable to get clk: %s\n",
|
|
||||||
rot_clk->clk_name);
|
|
||||||
return PTR_ERR(clk);
|
|
||||||
}
|
|
||||||
rot_clk->clk = clk;
|
|
||||||
|
|
||||||
if (strcmp(rot_clk->clk_name, "rot_core_clk") == 0)
|
|
||||||
core_clk_idx = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (core_clk_idx < 0) {
|
|
||||||
SDEROT_ERR("undefined core clk\n");
|
|
||||||
return -ENXIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
mgr->core_clk_idx = core_clk_idx;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,6 +92,15 @@ enum sde_rotator_ts {
|
||||||
SDE_ROTATOR_TS_MAX
|
SDE_ROTATOR_TS_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum sde_rotator_clk_type {
|
||||||
|
SDE_ROTATOR_CLK_MDSS_AHB,
|
||||||
|
SDE_ROTATOR_CLK_MDSS_AXI,
|
||||||
|
SDE_ROTATOR_CLK_ROT_CORE,
|
||||||
|
SDE_ROTATOR_CLK_MDSS_ROT,
|
||||||
|
SDE_ROTATOR_CLK_MNOC_AHB,
|
||||||
|
SDE_ROTATOR_CLK_MAX
|
||||||
|
};
|
||||||
|
|
||||||
struct sde_rotation_item {
|
struct sde_rotation_item {
|
||||||
/* rotation request flag */
|
/* rotation request flag */
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
|
@ -275,7 +284,6 @@ struct sde_rot_mgr {
|
||||||
int rot_enable_clk_cnt;
|
int rot_enable_clk_cnt;
|
||||||
struct sde_rot_clk *rot_clk;
|
struct sde_rot_clk *rot_clk;
|
||||||
int num_rot_clk;
|
int num_rot_clk;
|
||||||
int core_clk_idx;
|
|
||||||
u32 rdot_limit;
|
u32 rdot_limit;
|
||||||
u32 wrot_limit;
|
u32 wrot_limit;
|
||||||
|
|
||||||
|
|
|
@ -2337,9 +2337,9 @@ int sde_rotator_r3_init(struct sde_rot_mgr *mgr)
|
||||||
goto error_hw_rev_init;
|
goto error_hw_rev_init;
|
||||||
|
|
||||||
/* set rotator CBCR to shutoff memory/periphery on clock off.*/
|
/* set rotator CBCR to shutoff memory/periphery on clock off.*/
|
||||||
clk_set_flags(mgr->rot_clk[mgr->core_clk_idx].clk,
|
clk_set_flags(mgr->rot_clk[SDE_ROTATOR_CLK_ROT_CORE].clk,
|
||||||
CLKFLAG_NORETAIN_MEM);
|
CLKFLAG_NORETAIN_MEM);
|
||||||
clk_set_flags(mgr->rot_clk[mgr->core_clk_idx].clk,
|
clk_set_flags(mgr->rot_clk[SDE_ROTATOR_CLK_ROT_CORE].clk,
|
||||||
CLKFLAG_NORETAIN_PERIPH);
|
CLKFLAG_NORETAIN_PERIPH);
|
||||||
|
|
||||||
mdata->sde_rot_hw = rot;
|
mdata->sde_rot_hw = rot;
|
||||||
|
|
Loading…
Add table
Reference in a new issue