Commit 63cc5a4d authored by Thierry Reding's avatar Thierry Reding

clk: tegra: Model oscillator as clock

Currently the Tegra clock driver simplifies the clock tree somewhat by
taking advantage of the fact that clk_m runs at the same frequency as
the oscillator. While that's true on all currently supported SoCs, it
does not apply to Tegra210 anymore. On Tegra210 clk_m is typically
divided down from the oscillator frequency. To support that setup, add
a separate clock for the oscillator that both clk_m and pll_ref derive
from.

Modify the tegra_osc_clk_init() function to take an additional divider
parameter for clk_m. Existing SoCs always pass in 1, whereas Tegra210
will read the divider from a register in the clock & reset controller.
Signed-off-by: default avatarThierry Reding <treding@nvidia.com>
parent 699b477a
...@@ -30,13 +30,12 @@ ...@@ -30,13 +30,12 @@
#define OSC_CTRL_OSC_FREQ_SHIFT 28 #define OSC_CTRL_OSC_FREQ_SHIFT 28
#define OSC_CTRL_PLL_REF_DIV_SHIFT 26 #define OSC_CTRL_PLL_REF_DIV_SHIFT 26
int __init tegra_osc_clk_init(void __iomem *clk_base, int __init tegra_osc_clk_init(void __iomem *clk_base, struct tegra_clk *clks,
struct tegra_clk *tegra_clks, unsigned long *input_freqs, unsigned int num,
unsigned long *input_freqs, int num, unsigned int clk_m_div, unsigned long *osc_freq,
unsigned long *osc_freq,
unsigned long *pll_ref_freq) unsigned long *pll_ref_freq)
{ {
struct clk *clk; struct clk *clk, *osc;
struct clk **dt_clk; struct clk **dt_clk;
u32 val, pll_ref_div; u32 val, pll_ref_div;
unsigned osc_idx; unsigned osc_idx;
...@@ -54,22 +53,25 @@ int __init tegra_osc_clk_init(void __iomem *clk_base, ...@@ -54,22 +53,25 @@ int __init tegra_osc_clk_init(void __iomem *clk_base,
return -EINVAL; return -EINVAL;
} }
dt_clk = tegra_lookup_dt_id(tegra_clk_clk_m, tegra_clks); osc = clk_register_fixed_rate(NULL, "osc", NULL, CLK_IS_ROOT,
*osc_freq);
dt_clk = tegra_lookup_dt_id(tegra_clk_clk_m, clks);
if (!dt_clk) if (!dt_clk)
return 0; return 0;
clk = clk_register_fixed_rate(NULL, "clk_m", NULL, CLK_IS_ROOT, clk = clk_register_fixed_factor(NULL, "clk_m", "osc",
*osc_freq); 0, 1, clk_m_div);
*dt_clk = clk; *dt_clk = clk;
/* pll_ref */ /* pll_ref */
val = (val >> OSC_CTRL_PLL_REF_DIV_SHIFT) & 3; val = (val >> OSC_CTRL_PLL_REF_DIV_SHIFT) & 3;
pll_ref_div = 1 << val; pll_ref_div = 1 << val;
dt_clk = tegra_lookup_dt_id(tegra_clk_pll_ref, tegra_clks); dt_clk = tegra_lookup_dt_id(tegra_clk_pll_ref, clks);
if (!dt_clk) if (!dt_clk)
return 0; return 0;
clk = clk_register_fixed_factor(NULL, "pll_ref", "clk_m", clk = clk_register_fixed_factor(NULL, "pll_ref", "osc",
0, 1, pll_ref_div); 0, 1, pll_ref_div);
*dt_clk = clk; *dt_clk = clk;
......
...@@ -1480,7 +1480,8 @@ static void __init tegra124_132_clock_init_pre(struct device_node *np) ...@@ -1480,7 +1480,8 @@ static void __init tegra124_132_clock_init_pre(struct device_node *np)
return; return;
if (tegra_osc_clk_init(clk_base, tegra124_clks, tegra124_input_freq, if (tegra_osc_clk_init(clk_base, tegra124_clks, tegra124_input_freq,
ARRAY_SIZE(tegra124_input_freq), &osc_freq, &pll_ref_freq) < 0) ARRAY_SIZE(tegra124_input_freq), 1, &osc_freq,
&pll_ref_freq) < 0)
return; return;
tegra_fixed_clk_init(tegra124_clks); tegra_fixed_clk_init(tegra124_clks);
......
...@@ -1434,7 +1434,8 @@ static void __init tegra30_clock_init(struct device_node *np) ...@@ -1434,7 +1434,8 @@ static void __init tegra30_clock_init(struct device_node *np)
return; return;
if (tegra_osc_clk_init(clk_base, tegra30_clks, tegra30_input_freq, if (tegra_osc_clk_init(clk_base, tegra30_clks, tegra30_input_freq,
ARRAY_SIZE(tegra30_input_freq), &input_freq, NULL) < 0) ARRAY_SIZE(tegra30_input_freq), 1, &input_freq,
NULL) < 0)
return; return;
......
...@@ -615,9 +615,9 @@ void tegra_periph_clk_init(void __iomem *clk_base, void __iomem *pmc_base, ...@@ -615,9 +615,9 @@ void tegra_periph_clk_init(void __iomem *clk_base, void __iomem *pmc_base,
void tegra_pmc_clk_init(void __iomem *pmc_base, struct tegra_clk *tegra_clks); void tegra_pmc_clk_init(void __iomem *pmc_base, struct tegra_clk *tegra_clks);
void tegra_fixed_clk_init(struct tegra_clk *tegra_clks); void tegra_fixed_clk_init(struct tegra_clk *tegra_clks);
int tegra_osc_clk_init(void __iomem *clk_base, struct tegra_clk *tegra_clks, int tegra_osc_clk_init(void __iomem *clk_base, struct tegra_clk *clks,
unsigned long *input_freqs, int num, unsigned long *input_freqs, unsigned int num,
unsigned long *osc_freq, unsigned int clk_m_div, unsigned long *osc_freq,
unsigned long *pll_ref_freq); unsigned long *pll_ref_freq);
void tegra_super_clk_gen4_init(void __iomem *clk_base, void tegra_super_clk_gen4_init(void __iomem *clk_base,
void __iomem *pmc_base, struct tegra_clk *tegra_clks, void __iomem *pmc_base, struct tegra_clk *tegra_clks,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment