Skip to content

Commit 097064b

Browse files
committed
Merge tag 'tegra-for-5.5-clk-v2' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux into clk-tegra
Pull Tegra clk driver updates from Thierry Reding: The bulk of these changes implement suspend/resume support for Tegra210. In addition, some of the SOR clocks on earlier Tegra generations are reimplemented to more closely match the implementation on later chips, which in turn makes it possible to handle HDMI and DP support in a more unified way. * tag 'tegra-for-5.5-clk-v2' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux: (21 commits) clk: tegra: Fix build error without CONFIG_PM_SLEEP clk: tegra: Add missing stubs for the case of !CONFIG_PM_SLEEP clk: tegra: Optimize PLLX restore on Tegra20/30 clk: tegra: Add suspend and resume support on Tegra210 clk: tegra: Share clk and rst register defines with Tegra clock driver clk: tegra: Use fence_udelay() during PLLU init clk: tegra: clk-dfll: Add suspend and resume support clk: tegra: clk-super: Add restore-context support clk: tegra: clk-super: Fix to enable PLLP branches to CPU clk: tegra: periph: Add restore_context support clk: tegra: Support for OSC context save and restore clk: tegra: pll: Save and restore pll context clk: tegra: pllout: Save and restore pllout context clk: tegra: divider: Save and restore divider rate clk: tegra: Reimplement SOR clocks on Tegra210 clk: tegra: Reimplement SOR clock on Tegra124 clk: tegra: Rename sor0_lvds to sor0_out clk: tegra: Move SOR0 implementation to Tegra124 clk: tegra: Remove last remains of TEGRA210_CLK_SOR1_SRC clk: tegra: Add Tegra20/30 EMC clock implementation ...
2 parents 55ae8a1 + 07b293c commit 097064b

24 files changed

+978
-188
lines changed

drivers/clk/tegra/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ obj-y += clk-tegra-fixed.o
1717
obj-y += clk-tegra-super-gen4.o
1818
obj-$(CONFIG_TEGRA_CLK_EMC) += clk-emc.o
1919
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clk-tegra20.o
20+
obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clk-tegra20-emc.o
2021
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += clk-tegra30.o
22+
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += clk-tegra20-emc.o
2123
obj-$(CONFIG_ARCH_TEGRA_114_SOC) += clk-tegra114.o
2224
obj-$(CONFIG_ARCH_TEGRA_124_SOC) += clk-tegra124.o
2325
obj-$(CONFIG_TEGRA_CLK_DFLL) += clk-tegra124-dfll-fcpu.o

drivers/clk/tegra/clk-dfll.c

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1487,6 +1487,7 @@ static int dfll_init(struct tegra_dfll *td)
14871487
td->last_unrounded_rate = 0;
14881488

14891489
pm_runtime_enable(td->dev);
1490+
pm_runtime_irq_safe(td->dev);
14901491
pm_runtime_get_sync(td->dev);
14911492

14921493
dfll_set_mode(td, DFLL_DISABLED);
@@ -1513,6 +1514,61 @@ static int dfll_init(struct tegra_dfll *td)
15131514
return ret;
15141515
}
15151516

1517+
/**
1518+
* tegra_dfll_suspend - check DFLL is disabled
1519+
* @dev: DFLL device *
1520+
*
1521+
* DFLL clock should be disabled by the CPUFreq driver. So, make
1522+
* sure it is disabled and disable all clocks needed by the DFLL.
1523+
*/
1524+
int tegra_dfll_suspend(struct device *dev)
1525+
{
1526+
struct tegra_dfll *td = dev_get_drvdata(dev);
1527+
1528+
if (dfll_is_running(td)) {
1529+
dev_err(td->dev, "DFLL still enabled while suspending\n");
1530+
return -EBUSY;
1531+
}
1532+
1533+
reset_control_assert(td->dvco_rst);
1534+
1535+
return 0;
1536+
}
1537+
EXPORT_SYMBOL(tegra_dfll_suspend);
1538+
1539+
/**
1540+
* tegra_dfll_resume - reinitialize DFLL on resume
1541+
* @dev: DFLL instance
1542+
*
1543+
* DFLL is disabled and reset during suspend and resume.
1544+
* So, reinitialize the DFLL IP block back for use.
1545+
* DFLL clock is enabled later in closed loop mode by CPUFreq
1546+
* driver before switching its clock source to DFLL output.
1547+
*/
1548+
int tegra_dfll_resume(struct device *dev)
1549+
{
1550+
struct tegra_dfll *td = dev_get_drvdata(dev);
1551+
1552+
reset_control_deassert(td->dvco_rst);
1553+
1554+
pm_runtime_get_sync(td->dev);
1555+
1556+
dfll_set_mode(td, DFLL_DISABLED);
1557+
dfll_set_default_params(td);
1558+
1559+
if (td->soc->init_clock_trimmers)
1560+
td->soc->init_clock_trimmers();
1561+
1562+
dfll_set_open_loop_config(td);
1563+
1564+
dfll_init_out_if(td);
1565+
1566+
pm_runtime_put_sync(td->dev);
1567+
1568+
return 0;
1569+
}
1570+
EXPORT_SYMBOL(tegra_dfll_resume);
1571+
15161572
/*
15171573
* DT data fetch
15181574
*/

drivers/clk/tegra/clk-dfll.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,7 @@ int tegra_dfll_register(struct platform_device *pdev,
4242
struct tegra_dfll_soc_data *tegra_dfll_unregister(struct platform_device *pdev);
4343
int tegra_dfll_runtime_suspend(struct device *dev);
4444
int tegra_dfll_runtime_resume(struct device *dev);
45+
int tegra_dfll_suspend(struct device *dev);
46+
int tegra_dfll_resume(struct device *dev);
4547

4648
#endif /* __DRIVERS_CLK_TEGRA_CLK_DFLL_H */

drivers/clk/tegra/clk-divider.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,21 @@ static int clk_frac_div_set_rate(struct clk_hw *hw, unsigned long rate,
109109
return 0;
110110
}
111111

112+
static void clk_divider_restore_context(struct clk_hw *hw)
113+
{
114+
struct clk_hw *parent = clk_hw_get_parent(hw);
115+
unsigned long parent_rate = clk_hw_get_rate(parent);
116+
unsigned long rate = clk_hw_get_rate(hw);
117+
118+
if (clk_frac_div_set_rate(hw, rate, parent_rate) < 0)
119+
WARN_ON(1);
120+
}
121+
112122
const struct clk_ops tegra_clk_frac_div_ops = {
113123
.recalc_rate = clk_frac_div_recalc_rate,
114124
.set_rate = clk_frac_div_set_rate,
115125
.round_rate = clk_frac_div_round_rate,
126+
.restore_context = clk_divider_restore_context,
116127
};
117128

118129
struct clk *tegra_clk_register_divider(const char *name,

drivers/clk/tegra/clk-id.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -236,9 +236,9 @@ enum clk_id {
236236
tegra_clk_soc_therm,
237237
tegra_clk_soc_therm_8,
238238
tegra_clk_sor0,
239-
tegra_clk_sor0_lvds,
239+
tegra_clk_sor0_out,
240240
tegra_clk_sor1,
241-
tegra_clk_sor1_src,
241+
tegra_clk_sor1_out,
242242
tegra_clk_spdif,
243243
tegra_clk_spdif_2x,
244244
tegra_clk_spdif_in,

drivers/clk/tegra/clk-periph.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
44
*/
55

6+
#include <linux/clk.h>
67
#include <linux/clk-provider.h>
78
#include <linux/export.h>
89
#include <linux/slab.h>
@@ -99,6 +100,23 @@ static void clk_periph_disable(struct clk_hw *hw)
99100
gate_ops->disable(gate_hw);
100101
}
101102

103+
static void clk_periph_restore_context(struct clk_hw *hw)
104+
{
105+
struct tegra_clk_periph *periph = to_clk_periph(hw);
106+
const struct clk_ops *div_ops = periph->div_ops;
107+
struct clk_hw *div_hw = &periph->divider.hw;
108+
int parent_id;
109+
110+
parent_id = clk_hw_get_parent_index(hw);
111+
if (WARN_ON(parent_id < 0))
112+
return;
113+
114+
if (!(periph->gate.flags & TEGRA_PERIPH_NO_DIV))
115+
div_ops->restore_context(div_hw);
116+
117+
clk_periph_set_parent(hw, parent_id);
118+
}
119+
102120
const struct clk_ops tegra_clk_periph_ops = {
103121
.get_parent = clk_periph_get_parent,
104122
.set_parent = clk_periph_set_parent,
@@ -108,6 +126,7 @@ const struct clk_ops tegra_clk_periph_ops = {
108126
.is_enabled = clk_periph_is_enabled,
109127
.enable = clk_periph_enable,
110128
.disable = clk_periph_disable,
129+
.restore_context = clk_periph_restore_context,
111130
};
112131

113132
static const struct clk_ops tegra_clk_periph_nodiv_ops = {
@@ -116,6 +135,7 @@ static const struct clk_ops tegra_clk_periph_nodiv_ops = {
116135
.is_enabled = clk_periph_is_enabled,
117136
.enable = clk_periph_enable,
118137
.disable = clk_periph_disable,
138+
.restore_context = clk_periph_restore_context,
119139
};
120140

121141
static const struct clk_ops tegra_clk_periph_no_gate_ops = {
@@ -124,6 +144,7 @@ static const struct clk_ops tegra_clk_periph_no_gate_ops = {
124144
.recalc_rate = clk_periph_recalc_rate,
125145
.round_rate = clk_periph_round_rate,
126146
.set_rate = clk_periph_set_rate,
147+
.restore_context = clk_periph_restore_context,
127148
};
128149

129150
static struct clk *_tegra_clk_register_periph(const char *name,

drivers/clk/tegra/clk-pll-out.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,19 @@ static void clk_pll_out_disable(struct clk_hw *hw)
6969
spin_unlock_irqrestore(pll_out->lock, flags);
7070
}
7171

72+
static void tegra_clk_pll_out_restore_context(struct clk_hw *hw)
73+
{
74+
if (!__clk_get_enable_count(hw->clk))
75+
clk_pll_out_disable(hw);
76+
else
77+
clk_pll_out_enable(hw);
78+
}
79+
7280
const struct clk_ops tegra_clk_pll_out_ops = {
7381
.is_enabled = clk_pll_out_is_enabled,
7482
.enable = clk_pll_out_enable,
7583
.disable = clk_pll_out_disable,
84+
.restore_context = tegra_clk_pll_out_restore_context,
7685
};
7786

7887
struct clk *tegra_clk_register_pll_out(const char *name,

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);

drivers/clk/tegra/clk-sdmmc-mux.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,21 @@ static void clk_sdmmc_mux_disable(struct clk_hw *hw)
194194
gate_ops->disable(gate_hw);
195195
}
196196

197+
static void clk_sdmmc_mux_restore_context(struct clk_hw *hw)
198+
{
199+
struct clk_hw *parent = clk_hw_get_parent(hw);
200+
unsigned long parent_rate = clk_hw_get_rate(parent);
201+
unsigned long rate = clk_hw_get_rate(hw);
202+
int parent_id;
203+
204+
parent_id = clk_hw_get_parent_index(hw);
205+
if (WARN_ON(parent_id < 0))
206+
return;
207+
208+
clk_sdmmc_mux_set_parent(hw, parent_id);
209+
clk_sdmmc_mux_set_rate(hw, rate, parent_rate);
210+
}
211+
197212
static const struct clk_ops tegra_clk_sdmmc_mux_ops = {
198213
.get_parent = clk_sdmmc_mux_get_parent,
199214
.set_parent = clk_sdmmc_mux_set_parent,
@@ -203,6 +218,7 @@ static const struct clk_ops tegra_clk_sdmmc_mux_ops = {
203218
.is_enabled = clk_sdmmc_mux_is_enabled,
204219
.enable = clk_sdmmc_mux_enable,
205220
.disable = clk_sdmmc_mux_disable,
221+
.restore_context = clk_sdmmc_mux_restore_context,
206222
};
207223

208224
struct clk *tegra_clk_register_sdmmc_mux_div(const char *name,

0 commit comments

Comments
 (0)