Message ID | 1565308020-31952-6-git-send-email-skomatineni@nvidia.com |
---|---|
State | New |
Headers | show |
Series | SC7 entry and exit support for Tegra210 | expand |
09.08.2019 2:46, Sowjanya Komatineni пишет: > This patch implements save and restore of PLL context. > > During system suspend, core power goes off and looses the settings > of the Tegra CAR controller registers. > > So during suspend entry pll context is stored and on resume it is > restored back along with its state. > > Acked-by: Thierry Reding <treding@nvidia.com> > Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com> > --- > drivers/clk/tegra/clk-pll.c | 88 ++++++++++++++++++++++++++++----------------- > drivers/clk/tegra/clk.h | 2 ++ > 2 files changed, 58 insertions(+), 32 deletions(-) > > diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c > index 1583f5fc992f..e52add2bbdbb 100644 > --- a/drivers/clk/tegra/clk-pll.c > +++ b/drivers/clk/tegra/clk-pll.c > @@ -1008,6 +1008,28 @@ static unsigned long clk_plle_recalc_rate(struct clk_hw *hw, > return rate; > } > > +static void tegra_clk_pll_restore_context(struct clk_hw *hw) > +{ > + struct tegra_clk_pll *pll = to_clk_pll(hw); > + struct clk_hw *parent = clk_hw_get_parent(hw); > + unsigned long parent_rate = clk_hw_get_rate(parent); > + unsigned long rate = clk_hw_get_rate(hw); > + u32 val; > + > + if (clk_pll_is_enabled(hw)) > + return; > + > + if (pll->params->set_defaults) > + pll->params->set_defaults(pll); > + > + clk_pll_set_rate(hw, rate, parent_rate); > + > + if (!__clk_get_enable_count(hw->clk)) What about orphaned clocks? Is enable_count > 0 for them? > + clk_pll_disable(hw); > + else > + clk_pll_enable(hw); > +} [snip]
09.08.2019 2:46, Sowjanya Komatineni пишет: > This patch implements save and restore of PLL context. > > During system suspend, core power goes off and looses the settings > of the Tegra CAR controller registers. > > So during suspend entry pll context is stored and on resume it is > restored back along with its state. > > Acked-by: Thierry Reding <treding@nvidia.com> > Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com> > --- > drivers/clk/tegra/clk-pll.c | 88 ++++++++++++++++++++++++++++----------------- > drivers/clk/tegra/clk.h | 2 ++ > 2 files changed, 58 insertions(+), 32 deletions(-) > > diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c > index 1583f5fc992f..e52add2bbdbb 100644 > --- a/drivers/clk/tegra/clk-pll.c > +++ b/drivers/clk/tegra/clk-pll.c > @@ -1008,6 +1008,28 @@ static unsigned long clk_plle_recalc_rate(struct clk_hw *hw, > return rate; > } > > +static void tegra_clk_pll_restore_context(struct clk_hw *hw) > +{ > + struct tegra_clk_pll *pll = to_clk_pll(hw); > + struct clk_hw *parent = clk_hw_get_parent(hw); > + unsigned long parent_rate = clk_hw_get_rate(parent); > + unsigned long rate = clk_hw_get_rate(hw); > + u32 val; > + > + if (clk_pll_is_enabled(hw)) > + return; > + > + if (pll->params->set_defaults) > + pll->params->set_defaults(pll); > + > + clk_pll_set_rate(hw, rate, parent_rate); > + > + if (!__clk_get_enable_count(hw->clk)) > + clk_pll_disable(hw); > + else > + clk_pll_enable(hw); > +} drivers/clk/tegra/clk-pll.c: In function ‘tegra_clk_pll_restore_context’: drivers/clk/tegra/clk-pll.c:1024:6: warning: unused variable ‘val’ [-Wunused-variable] 1024 | u32 val;
On 8/9/19 4:33 AM, Dmitry Osipenko wrote: > 09.08.2019 2:46, Sowjanya Komatineni пишет: >> This patch implements save and restore of PLL context. >> >> During system suspend, core power goes off and looses the settings >> of the Tegra CAR controller registers. >> >> So during suspend entry pll context is stored and on resume it is >> restored back along with its state. >> >> Acked-by: Thierry Reding <treding@nvidia.com> >> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com> >> --- >> drivers/clk/tegra/clk-pll.c | 88 ++++++++++++++++++++++++++++----------------- >> drivers/clk/tegra/clk.h | 2 ++ >> 2 files changed, 58 insertions(+), 32 deletions(-) >> >> diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c >> index 1583f5fc992f..e52add2bbdbb 100644 >> --- a/drivers/clk/tegra/clk-pll.c >> +++ b/drivers/clk/tegra/clk-pll.c >> @@ -1008,6 +1008,28 @@ static unsigned long clk_plle_recalc_rate(struct clk_hw *hw, >> return rate; >> } >> >> +static void tegra_clk_pll_restore_context(struct clk_hw *hw) >> +{ >> + struct tegra_clk_pll *pll = to_clk_pll(hw); >> + struct clk_hw *parent = clk_hw_get_parent(hw); >> + unsigned long parent_rate = clk_hw_get_rate(parent); >> + unsigned long rate = clk_hw_get_rate(hw); >> + u32 val; >> + >> + if (clk_pll_is_enabled(hw)) >> + return; >> + >> + if (pll->params->set_defaults) >> + pll->params->set_defaults(pll); >> + >> + clk_pll_set_rate(hw, rate, parent_rate); >> + >> + if (!__clk_get_enable_count(hw->clk)) > What about orphaned clocks? Is enable_count > 0 for them? There are no orphaned pll clocks. >> + clk_pll_disable(hw); >> + else >> + clk_pll_enable(hw); >> +} > [snip]
09.08.2019 20:39, Sowjanya Komatineni пишет: > > On 8/9/19 4:33 AM, Dmitry Osipenko wrote: >> 09.08.2019 2:46, Sowjanya Komatineni пишет: >>> This patch implements save and restore of PLL context. >>> >>> During system suspend, core power goes off and looses the settings >>> of the Tegra CAR controller registers. >>> >>> So during suspend entry pll context is stored and on resume it is >>> restored back along with its state. >>> >>> Acked-by: Thierry Reding <treding@nvidia.com> >>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com> >>> --- >>> drivers/clk/tegra/clk-pll.c | 88 ++++++++++++++++++++++++++++----------------- >>> drivers/clk/tegra/clk.h | 2 ++ >>> 2 files changed, 58 insertions(+), 32 deletions(-) >>> >>> diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c >>> index 1583f5fc992f..e52add2bbdbb 100644 >>> --- a/drivers/clk/tegra/clk-pll.c >>> +++ b/drivers/clk/tegra/clk-pll.c >>> @@ -1008,6 +1008,28 @@ static unsigned long clk_plle_recalc_rate(struct clk_hw *hw, >>> return rate; >>> } >>> +static void tegra_clk_pll_restore_context(struct clk_hw *hw) >>> +{ >>> + struct tegra_clk_pll *pll = to_clk_pll(hw); >>> + struct clk_hw *parent = clk_hw_get_parent(hw); >>> + unsigned long parent_rate = clk_hw_get_rate(parent); >>> + unsigned long rate = clk_hw_get_rate(hw); >>> + u32 val; >>> + >>> + if (clk_pll_is_enabled(hw)) >>> + return; >>> + >>> + if (pll->params->set_defaults) >>> + pll->params->set_defaults(pll); >>> + >>> + clk_pll_set_rate(hw, rate, parent_rate); >>> + >>> + if (!__clk_get_enable_count(hw->clk)) >> What about orphaned clocks? Is enable_count > 0 for them? > There are no orphaned pll clocks. Sorry, I meant the "clk_ignore_unused".
On 8/9/19 10:50 AM, Dmitry Osipenko wrote: > 09.08.2019 20:39, Sowjanya Komatineni пишет: >> On 8/9/19 4:33 AM, Dmitry Osipenko wrote: >>> 09.08.2019 2:46, Sowjanya Komatineni пишет: >>>> This patch implements save and restore of PLL context. >>>> >>>> During system suspend, core power goes off and looses the settings >>>> of the Tegra CAR controller registers. >>>> >>>> So during suspend entry pll context is stored and on resume it is >>>> restored back along with its state. >>>> >>>> Acked-by: Thierry Reding <treding@nvidia.com> >>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com> >>>> --- >>>> drivers/clk/tegra/clk-pll.c | 88 ++++++++++++++++++++++++++++----------------- >>>> drivers/clk/tegra/clk.h | 2 ++ >>>> 2 files changed, 58 insertions(+), 32 deletions(-) >>>> >>>> diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c >>>> index 1583f5fc992f..e52add2bbdbb 100644 >>>> --- a/drivers/clk/tegra/clk-pll.c >>>> +++ b/drivers/clk/tegra/clk-pll.c >>>> @@ -1008,6 +1008,28 @@ static unsigned long clk_plle_recalc_rate(struct clk_hw *hw, >>>> return rate; >>>> } >>>> +static void tegra_clk_pll_restore_context(struct clk_hw *hw) >>>> +{ >>>> + struct tegra_clk_pll *pll = to_clk_pll(hw); >>>> + struct clk_hw *parent = clk_hw_get_parent(hw); >>>> + unsigned long parent_rate = clk_hw_get_rate(parent); >>>> + unsigned long rate = clk_hw_get_rate(hw); >>>> + u32 val; >>>> + >>>> + if (clk_pll_is_enabled(hw)) >>>> + return; >>>> + >>>> + if (pll->params->set_defaults) >>>> + pll->params->set_defaults(pll); >>>> + >>>> + clk_pll_set_rate(hw, rate, parent_rate); >>>> + >>>> + if (!__clk_get_enable_count(hw->clk)) >>> What about orphaned clocks? Is enable_count > 0 for them? >> There are no orphaned pll clocks. > Sorry, I meant the "clk_ignore_unused". clocks with CLK_IGNORE_UNUSED are taken care by clk driver. clk_disable_unused checks for clocks with this flag and if they are not enabled it will enable them. So by the time suspend happens enable_count is > 0
09.08.2019 21:50, Sowjanya Komatineni пишет: > > On 8/9/19 10:50 AM, Dmitry Osipenko wrote: >> 09.08.2019 20:39, Sowjanya Komatineni пишет: >>> On 8/9/19 4:33 AM, Dmitry Osipenko wrote: >>>> 09.08.2019 2:46, Sowjanya Komatineni пишет: >>>>> This patch implements save and restore of PLL context. >>>>> >>>>> During system suspend, core power goes off and looses the settings >>>>> of the Tegra CAR controller registers. >>>>> >>>>> So during suspend entry pll context is stored and on resume it is >>>>> restored back along with its state. >>>>> >>>>> Acked-by: Thierry Reding <treding@nvidia.com> >>>>> Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com> >>>>> --- >>>>> drivers/clk/tegra/clk-pll.c | 88 ++++++++++++++++++++++++++++----------------- >>>>> drivers/clk/tegra/clk.h | 2 ++ >>>>> 2 files changed, 58 insertions(+), 32 deletions(-) >>>>> >>>>> diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c >>>>> index 1583f5fc992f..e52add2bbdbb 100644 >>>>> --- a/drivers/clk/tegra/clk-pll.c >>>>> +++ b/drivers/clk/tegra/clk-pll.c >>>>> @@ -1008,6 +1008,28 @@ static unsigned long clk_plle_recalc_rate(struct clk_hw *hw, >>>>> return rate; >>>>> } >>>>> +static void tegra_clk_pll_restore_context(struct clk_hw *hw) >>>>> +{ >>>>> + struct tegra_clk_pll *pll = to_clk_pll(hw); >>>>> + struct clk_hw *parent = clk_hw_get_parent(hw); >>>>> + unsigned long parent_rate = clk_hw_get_rate(parent); >>>>> + unsigned long rate = clk_hw_get_rate(hw); >>>>> + u32 val; >>>>> + >>>>> + if (clk_pll_is_enabled(hw)) >>>>> + return; >>>>> + >>>>> + if (pll->params->set_defaults) >>>>> + pll->params->set_defaults(pll); >>>>> + >>>>> + clk_pll_set_rate(hw, rate, parent_rate); >>>>> + >>>>> + if (!__clk_get_enable_count(hw->clk)) >>>> What about orphaned clocks? Is enable_count > 0 for them? >>> There are no orphaned pll clocks. >> Sorry, I meant the "clk_ignore_unused". > > clocks with CLK_IGNORE_UNUSED are taken care by clk driver. > > clk_disable_unused checks for clocks with this flag and if they are not enabled it will > enable them. > > So by the time suspend happens enable_count is > 0 Okay.
diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c index 1583f5fc992f..e52add2bbdbb 100644 --- a/drivers/clk/tegra/clk-pll.c +++ b/drivers/clk/tegra/clk-pll.c @@ -1008,6 +1008,28 @@ static unsigned long clk_plle_recalc_rate(struct clk_hw *hw, return rate; } +static void tegra_clk_pll_restore_context(struct clk_hw *hw) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + struct clk_hw *parent = clk_hw_get_parent(hw); + unsigned long parent_rate = clk_hw_get_rate(parent); + unsigned long rate = clk_hw_get_rate(hw); + u32 val; + + if (clk_pll_is_enabled(hw)) + return; + + if (pll->params->set_defaults) + pll->params->set_defaults(pll); + + clk_pll_set_rate(hw, rate, parent_rate); + + if (!__clk_get_enable_count(hw->clk)) + clk_pll_disable(hw); + else + clk_pll_enable(hw); +} + const struct clk_ops tegra_clk_pll_ops = { .is_enabled = clk_pll_is_enabled, .enable = clk_pll_enable, @@ -1015,6 +1037,7 @@ const struct clk_ops tegra_clk_pll_ops = { .recalc_rate = clk_pll_recalc_rate, .round_rate = clk_pll_round_rate, .set_rate = clk_pll_set_rate, + .restore_context = tegra_clk_pll_restore_context, }; const struct clk_ops tegra_clk_plle_ops = { @@ -1802,6 +1825,27 @@ static int clk_pllu_tegra114_enable(struct clk_hw *hw) return ret; } + +static void _clk_plle_tegra_init_parent(struct tegra_clk_pll *pll) +{ + u32 val, val_aux; + + /* ensure parent is set to pll_ref */ + val = pll_readl_base(pll); + val_aux = pll_readl(pll->params->aux_reg, pll); + + if (val & PLL_BASE_ENABLE) { + if ((val_aux & PLLE_AUX_PLLRE_SEL) || + (val_aux & PLLE_AUX_PLLP_SEL)) + WARN(1, "pll_e enabled with unsupported parent %s\n", + (val_aux & PLLE_AUX_PLLP_SEL) ? "pllp_out0" : + "pll_re_vco"); + } else { + val_aux &= ~(PLLE_AUX_PLLRE_SEL | PLLE_AUX_PLLP_SEL); + pll_writel(val_aux, pll->params->aux_reg, pll); + fence_udelay(1, pll->clk_base); + } +} #endif static struct tegra_clk_pll *_tegra_init_pll(void __iomem *clk_base, @@ -2214,27 +2258,12 @@ struct clk *tegra_clk_register_plle_tegra114(const char *name, { struct tegra_clk_pll *pll; struct clk *clk; - u32 val, val_aux; pll = _tegra_init_pll(clk_base, NULL, pll_params, lock); if (IS_ERR(pll)) return ERR_CAST(pll); - /* ensure parent is set to pll_re_vco */ - - val = pll_readl_base(pll); - val_aux = pll_readl(pll_params->aux_reg, pll); - - if (val & PLL_BASE_ENABLE) { - if ((val_aux & PLLE_AUX_PLLRE_SEL) || - (val_aux & PLLE_AUX_PLLP_SEL)) - WARN(1, "pll_e enabled with unsupported parent %s\n", - (val_aux & PLLE_AUX_PLLP_SEL) ? "pllp_out0" : - "pll_re_vco"); - } else { - val_aux &= ~(PLLE_AUX_PLLRE_SEL | PLLE_AUX_PLLP_SEL); - pll_writel(val_aux, pll_params->aux_reg, pll); - } + _clk_plle_tegra_init_parent(pll); clk = _tegra_clk_register_pll(pll, name, parent_name, flags, &tegra_clk_plle_tegra114_ops); @@ -2276,6 +2305,7 @@ static const struct clk_ops tegra_clk_pllss_ops = { .recalc_rate = clk_pll_recalc_rate, .round_rate = clk_pll_ramp_round_rate, .set_rate = clk_pllxc_set_rate, + .restore_context = tegra_clk_pll_restore_context, }; struct clk *tegra_clk_register_pllss(const char *name, const char *parent_name, @@ -2375,6 +2405,7 @@ struct clk *tegra_clk_register_pllre_tegra210(const char *name, pll_params->vco_min = pll_params->adjust_vco(pll_params, parent_rate); + pll_params->flags |= TEGRA_PLLRE; pll = _tegra_init_pll(clk_base, pmc, pll_params, lock); if (IS_ERR(pll)) return ERR_CAST(pll); @@ -2520,11 +2551,19 @@ static void clk_plle_tegra210_disable(struct clk_hw *hw) spin_unlock_irqrestore(pll->lock, flags); } +static void tegra_clk_plle_t210_restore_context(struct clk_hw *hw) +{ + struct tegra_clk_pll *pll = to_clk_pll(hw); + + _clk_plle_tegra_init_parent(pll); +} + static const struct clk_ops tegra_clk_plle_tegra210_ops = { .is_enabled = clk_plle_tegra210_is_enabled, .enable = clk_plle_tegra210_enable, .disable = clk_plle_tegra210_disable, .recalc_rate = clk_pll_recalc_rate, + .restore_context = tegra_clk_plle_t210_restore_context, }; struct clk *tegra_clk_register_plle_tegra210(const char *name, @@ -2535,27 +2574,12 @@ struct clk *tegra_clk_register_plle_tegra210(const char *name, { struct tegra_clk_pll *pll; struct clk *clk; - u32 val, val_aux; pll = _tegra_init_pll(clk_base, NULL, pll_params, lock); if (IS_ERR(pll)) return ERR_CAST(pll); - /* ensure parent is set to pll_re_vco */ - - val = pll_readl_base(pll); - val_aux = pll_readl(pll_params->aux_reg, pll); - - if (val & PLLE_BASE_ENABLE) { - if ((val_aux & PLLE_AUX_PLLRE_SEL) || - (val_aux & PLLE_AUX_PLLP_SEL)) - WARN(1, "pll_e enabled with unsupported parent %s\n", - (val_aux & PLLE_AUX_PLLP_SEL) ? "pllp_out0" : - "pll_re_vco"); - } else { - val_aux &= ~(PLLE_AUX_PLLRE_SEL | PLLE_AUX_PLLP_SEL); - pll_writel(val_aux, pll_params->aux_reg, pll); - } + _clk_plle_tegra_init_parent(pll); clk = _tegra_clk_register_pll(pll, name, parent_name, flags, &tegra_clk_plle_tegra210_ops); diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h index a464524fbc90..dc546292e030 100644 --- a/drivers/clk/tegra/clk.h +++ b/drivers/clk/tegra/clk.h @@ -233,6 +233,7 @@ struct tegra_clk_pll; * TEGRA_PLLMB - PLLMB has should be treated similar to PLLM. This * flag indicated that it is PLLMB. * TEGRA_PLL_VCO_OUT - Used to indicate that the PLL has a VCO output + * TEGRA_PLLRE - Used to indicate that it is PLLRE */ struct tegra_clk_pll_params { unsigned long input_min; @@ -299,6 +300,7 @@ struct tegra_clk_pll_params { #define TEGRA_MDIV_NEW BIT(11) #define TEGRA_PLLMB BIT(12) #define TEGRA_PLL_VCO_OUT BIT(13) +#define TEGRA_PLLRE BIT(14) /** * struct tegra_clk_pll - Tegra PLL clock