ARM: tegra: clock: Set safe rate for peripheral clocks
Alex Frid [Thu, 23 May 2013 04:01:17 +0000 (21:01 -0700)]
Initialize peripheral clocks for modules left under reset by bootloader
to safe oscillator frequency (clocks for modules taken out of reset
by bootloader must be at safe rate already).

Change-Id: I2ee0f1d24522570c3326107ad9b18760e7abb12d
Signed-off-by: Alex Frid <afrid@nvidia.com>
Reviewed-on: http://git-master/r/280085
Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>
(cherry picked from commit 618cbe6dbe4f9177493b2291f26262d17651bb7b)
Signed-off-by: Ajay Nandakumar <anandakumarm@nvidia.com>

arch/arm/mach-tegra/clock.c
arch/arm/mach-tegra/clock.h
arch/arm/mach-tegra/tegra11_clocks.c
arch/arm/mach-tegra/tegra12_clocks.c
arch/arm/mach-tegra/tegra14_clocks.c

index a3857d5..94e0939 100644 (file)
@@ -910,6 +910,27 @@ void __init tegra_clk_preset_emc_monitor(unsigned long rate)
        }
 }
 
+/*
+ * Set osc (safe) rate. Called only for peripherals left after boot under reset
+ * (peripherals that are taken out of reset by boot-loader must be at safe rate
+ * already - that will be checked by tegra_clk_verify_rates()).
+ */
+void __init tegra_periph_clk_safe_rate_init(struct clk *c)
+{
+       int ret;
+       unsigned long rate = tegra_clk_measure_input_freq();
+
+       if (clk_get_rate(c->parent) <= rate)
+               return;
+
+       if (c->ops && c->ops->set_rate && (c->flags & PERIPH_DIV)) {
+               ret = c->ops->set_rate(c, rate);
+               if (ret)
+                       pr_err("%s: failed to init %s rate %lu\n",
+                              __func__, c->name, rate);
+       }
+}
+
 static void __init tegra_clk_verify_rates(void)
 {
        struct clk *c;
index 45a9a56..bda9b38 100644 (file)
@@ -87,6 +87,8 @@ struct clk;
 
 #define SHARED_BUS_RETENTION   (1 << 0)
 
+#define PERIPH_DIV             (DIV_U71 | DIV_U151 | DIV_U16)
+
 #ifdef CONFIG_COMMON_CLK
 struct clk_tegra;
 #define to_clk_tegra(_hw) container_of(_hw, struct clk_tegra, hw)
@@ -358,6 +360,7 @@ struct tegra_clk_init_table {
 #ifndef CONFIG_COMMON_CLK
 void tegra_init_max_rate(struct clk *c, unsigned long max_rate);
 void tegra_clk_preset_emc_monitor(unsigned long rate);
+void tegra_periph_clk_safe_rate_init(struct clk *c);
 void tegra_clk_verify_parents(void);
 void clk_init(struct clk *clk);
 unsigned long tegra_clk_measure_input_freq(void);
index ed674ca..a849d50 100644 (file)
@@ -3932,6 +3932,13 @@ static void tegra11_periph_clk_init(struct clk *c)
                c->parent = c->inputs[0].input;
        }
 
+       /* if peripheral is left under reset - enforce safe rate */
+       if (!(c->flags & PERIPH_NO_RESET) &&
+           (clk_readl(PERIPH_CLK_TO_RST_REG(c)) & PERIPH_CLK_TO_BIT(c))) {
+               tegra_periph_clk_safe_rate_init(c);
+                val = clk_readl(c->reg);
+       }
+
        if (c->flags & DIV_U71) {
                u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK;
                if (c->flags & DIV_U71_IDLE) {
index 7116884..7e211fd 100644 (file)
@@ -4294,6 +4294,13 @@ static void tegra12_periph_clk_init(struct clk *c)
                c->parent = c->inputs[0].input;
        }
 
+       /* if peripheral is left under reset - enforce safe rate */
+       if (!(c->flags & PERIPH_NO_RESET) &&
+           (clk_readl(PERIPH_CLK_TO_RST_REG(c)) & PERIPH_CLK_TO_BIT(c))) {
+               tegra_periph_clk_safe_rate_init(c);
+                val = clk_readl(c->reg);
+       }
+
        if (c->flags & DIV_U71) {
                u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK;
                if (c->flags & DIV_U71_IDLE) {
index ec08193..07e766a 100644 (file)
@@ -3540,6 +3540,13 @@ static void tegra14_periph_clk_init(struct clk *c)
                c->parent = c->inputs[0].input;
        }
 
+       /* if peripheral is left under reset - enforce safe rate */
+       if (!(c->flags & PERIPH_NO_RESET) &&
+           (clk_readl(PERIPH_CLK_TO_RST_REG(c)) & PERIPH_CLK_TO_BIT(c))) {
+               tegra_periph_clk_safe_rate_init(c);
+                val = clk_readl(c->reg);
+       }
+
        if (c->flags & DIV_U71) {
                u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK;
                if (c->flags & DIV_U71_IDLE) {