Skip to content

Commit bc0b3a6

Browse files
Sowjanya Komatinenithierryreding
authored andcommitted
clk: tegra: pll: Save and restore pll context
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 resume, pll context is restored based on cached rate and state. Acked-by: Thierry Reding <[email protected]> Signed-off-by: Sowjanya Komatineni <[email protected]> Signed-off-by: Thierry Reding <[email protected]>
1 parent fa62228 commit bc0b3a6

File tree

1 file changed

+54
-32
lines changed

1 file changed

+54
-32
lines changed

drivers/clk/tegra/clk-pll.c

Lines changed: 54 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1008,13 +1008,35 @@ static unsigned long clk_plle_recalc_rate(struct clk_hw *hw,
10081008
return rate;
10091009
}
10101010

1011+
static void tegra_clk_pll_restore_context(struct clk_hw *hw)
1012+
{
1013+
struct tegra_clk_pll *pll = to_clk_pll(hw);
1014+
struct clk_hw *parent = clk_hw_get_parent(hw);
1015+
unsigned long parent_rate = clk_hw_get_rate(parent);
1016+
unsigned long rate = clk_hw_get_rate(hw);
1017+
1018+
if (clk_pll_is_enabled(hw))
1019+
return;
1020+
1021+
if (pll->params->set_defaults)
1022+
pll->params->set_defaults(pll);
1023+
1024+
clk_pll_set_rate(hw, rate, parent_rate);
1025+
1026+
if (!__clk_get_enable_count(hw->clk))
1027+
clk_pll_disable(hw);
1028+
else
1029+
clk_pll_enable(hw);
1030+
}
1031+
10111032
const struct clk_ops tegra_clk_pll_ops = {
10121033
.is_enabled = clk_pll_is_enabled,
10131034
.enable = clk_pll_enable,
10141035
.disable = clk_pll_disable,
10151036
.recalc_rate = clk_pll_recalc_rate,
10161037
.round_rate = clk_pll_round_rate,
10171038
.set_rate = clk_pll_set_rate,
1039+
.restore_context = tegra_clk_pll_restore_context,
10181040
};
10191041

10201042
const struct clk_ops tegra_clk_plle_ops = {
@@ -1802,6 +1824,27 @@ static int clk_pllu_tegra114_enable(struct clk_hw *hw)
18021824

18031825
return ret;
18041826
}
1827+
1828+
static void _clk_plle_tegra_init_parent(struct tegra_clk_pll *pll)
1829+
{
1830+
u32 val, val_aux;
1831+
1832+
/* ensure parent is set to pll_ref */
1833+
val = pll_readl_base(pll);
1834+
val_aux = pll_readl(pll->params->aux_reg, pll);
1835+
1836+
if (val & PLL_BASE_ENABLE) {
1837+
if ((val_aux & PLLE_AUX_PLLRE_SEL) ||
1838+
(val_aux & PLLE_AUX_PLLP_SEL))
1839+
WARN(1, "pll_e enabled with unsupported parent %s\n",
1840+
(val_aux & PLLE_AUX_PLLP_SEL) ? "pllp_out0" :
1841+
"pll_re_vco");
1842+
} else {
1843+
val_aux &= ~(PLLE_AUX_PLLRE_SEL | PLLE_AUX_PLLP_SEL);
1844+
pll_writel(val_aux, pll->params->aux_reg, pll);
1845+
fence_udelay(1, pll->clk_base);
1846+
}
1847+
}
18051848
#endif
18061849

18071850
static struct tegra_clk_pll *_tegra_init_pll(void __iomem *clk_base,
@@ -2214,27 +2257,12 @@ struct clk *tegra_clk_register_plle_tegra114(const char *name,
22142257
{
22152258
struct tegra_clk_pll *pll;
22162259
struct clk *clk;
2217-
u32 val, val_aux;
22182260

22192261
pll = _tegra_init_pll(clk_base, NULL, pll_params, lock);
22202262
if (IS_ERR(pll))
22212263
return ERR_CAST(pll);
22222264

2223-
/* ensure parent is set to pll_re_vco */
2224-
2225-
val = pll_readl_base(pll);
2226-
val_aux = pll_readl(pll_params->aux_reg, pll);
2227-
2228-
if (val & PLL_BASE_ENABLE) {
2229-
if ((val_aux & PLLE_AUX_PLLRE_SEL) ||
2230-
(val_aux & PLLE_AUX_PLLP_SEL))
2231-
WARN(1, "pll_e enabled with unsupported parent %s\n",
2232-
(val_aux & PLLE_AUX_PLLP_SEL) ? "pllp_out0" :
2233-
"pll_re_vco");
2234-
} else {
2235-
val_aux &= ~(PLLE_AUX_PLLRE_SEL | PLLE_AUX_PLLP_SEL);
2236-
pll_writel(val_aux, pll_params->aux_reg, pll);
2237-
}
2265+
_clk_plle_tegra_init_parent(pll);
22382266

22392267
clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
22402268
&tegra_clk_plle_tegra114_ops);
@@ -2276,6 +2304,7 @@ static const struct clk_ops tegra_clk_pllss_ops = {
22762304
.recalc_rate = clk_pll_recalc_rate,
22772305
.round_rate = clk_pll_ramp_round_rate,
22782306
.set_rate = clk_pllxc_set_rate,
2307+
.restore_context = tegra_clk_pll_restore_context,
22792308
};
22802309

22812310
struct clk *tegra_clk_register_pllss(const char *name, const char *parent_name,
@@ -2520,11 +2549,19 @@ static void clk_plle_tegra210_disable(struct clk_hw *hw)
25202549
spin_unlock_irqrestore(pll->lock, flags);
25212550
}
25222551

2552+
static void tegra_clk_plle_t210_restore_context(struct clk_hw *hw)
2553+
{
2554+
struct tegra_clk_pll *pll = to_clk_pll(hw);
2555+
2556+
_clk_plle_tegra_init_parent(pll);
2557+
}
2558+
25232559
static const struct clk_ops tegra_clk_plle_tegra210_ops = {
25242560
.is_enabled = clk_plle_tegra210_is_enabled,
25252561
.enable = clk_plle_tegra210_enable,
25262562
.disable = clk_plle_tegra210_disable,
25272563
.recalc_rate = clk_pll_recalc_rate,
2564+
.restore_context = tegra_clk_plle_t210_restore_context,
25282565
};
25292566

25302567
struct clk *tegra_clk_register_plle_tegra210(const char *name,
@@ -2535,27 +2572,12 @@ struct clk *tegra_clk_register_plle_tegra210(const char *name,
25352572
{
25362573
struct tegra_clk_pll *pll;
25372574
struct clk *clk;
2538-
u32 val, val_aux;
25392575

25402576
pll = _tegra_init_pll(clk_base, NULL, pll_params, lock);
25412577
if (IS_ERR(pll))
25422578
return ERR_CAST(pll);
25432579

2544-
/* ensure parent is set to pll_re_vco */
2545-
2546-
val = pll_readl_base(pll);
2547-
val_aux = pll_readl(pll_params->aux_reg, pll);
2548-
2549-
if (val & PLLE_BASE_ENABLE) {
2550-
if ((val_aux & PLLE_AUX_PLLRE_SEL) ||
2551-
(val_aux & PLLE_AUX_PLLP_SEL))
2552-
WARN(1, "pll_e enabled with unsupported parent %s\n",
2553-
(val_aux & PLLE_AUX_PLLP_SEL) ? "pllp_out0" :
2554-
"pll_re_vco");
2555-
} else {
2556-
val_aux &= ~(PLLE_AUX_PLLRE_SEL | PLLE_AUX_PLLP_SEL);
2557-
pll_writel(val_aux, pll_params->aux_reg, pll);
2558-
}
2580+
_clk_plle_tegra_init_parent(pll);
25592581

25602582
clk = _tegra_clk_register_pll(pll, name, parent_name, flags,
25612583
&tegra_clk_plle_tegra210_ops);

0 commit comments

Comments
 (0)