clk: tegra: defer application of init table
authorStephen Warren <swarren@nvidia.com>
Mon, 25 Mar 2013 19:22:24 +0000 (13:22 -0600)
committerStephen Warren <swarren@nvidia.com>
Thu, 4 Apr 2013 22:09:05 +0000 (16:09 -0600)
The Tegra clock driver is initialized during the ARM machine descriptor's
.init_irq() hook. It can't be initialized earlier, since dynamic memory
usage is required. It can't be initialized later, since the .init_timer()
hook needs the clocks initialized. However, at this time, udelay()
doesn't work.

The Tegra clock initialization table may enable some PLLs. Enabling a PLL
may require usage of udelay(). Hence, this can't happen right when the
clock driver is initialized.

To solve this, separate the clock driver initialization from the clock
table processing, so they can execute at separate times.

Signed-off-by: Stephen Warren <swarren@nvidia.com>
arch/arm/mach-tegra/tegra.c
drivers/clk/tegra/clk-tegra20.c
drivers/clk/tegra/clk-tegra30.c
drivers/clk/tegra/clk.c
drivers/clk/tegra/clk.h
include/linux/clk/tegra.h

index 84deeab23ee7e6d7209d7389ce76a4cbd42cb70a..61749e2d811112d67642db8d9eeecb151e0b127b 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/slab.h>
 #include <linux/sys_soc.h>
 #include <linux/usb/tegra_usb_phy.h>
+#include <linux/clk/tegra.h>
 
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -87,6 +88,8 @@ static void __init tegra_dt_init(void)
        struct soc_device *soc_dev;
        struct device *parent = NULL;
 
+       tegra_clocks_apply_init_table();
+
        soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
        if (!soc_dev_attr)
                goto out;
index a7dc0a937361c7d56d741ab11788988f61232ba3..a15fb28197b5760c1a98a25f5c0c3f464e3f5f65 100644 (file)
@@ -1252,6 +1252,11 @@ static __initdata struct tegra_clk_init_table init_table[] = {
        {clk_max, clk_max, 0, 0}, /* This MUST be the last entry */
 };
 
+static void __init tegra20_clock_apply_init_table(void)
+{
+       tegra_init_from_table(init_table, clks, clk_max);
+}
+
 /*
  * Some clocks may be used by different drivers depending on the board
  * configuration.  List those here to register them twice in the clock lookup
@@ -1318,7 +1323,7 @@ void __init tegra20_clock_init(struct device_node *np)
        clk_data.clk_num = ARRAY_SIZE(clks);
        of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
 
-       tegra_init_from_table(init_table, clks, clk_max);
+       tegra_clk_apply_init_table = tegra20_clock_apply_init_table;
 
        tegra_cpu_car_ops = &tegra20_cpu_car_ops;
 }
index 181a6eef5ce80bd88f3b7342e8037db8117f11fa..e0ee93c2db6c0270c8240999f4eba74440bbb1af 100644 (file)
@@ -1916,6 +1916,11 @@ static __initdata struct tegra_clk_init_table init_table[] = {
        {clk_max, clk_max, 0, 0}, /* This MUST be the last entry. */
 };
 
+static void __init tegra30_clock_apply_init_table(void)
+{
+       tegra_init_from_table(init_table, clks, clk_max);
+}
+
 /*
  * Some clocks may be used by different drivers depending on the board
  * configuration.  List those here to register them twice in the clock lookup
@@ -1989,7 +1994,7 @@ void __init tegra30_clock_init(struct device_node *np)
        clk_data.clk_num = ARRAY_SIZE(clks);
        of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
 
-       tegra_init_from_table(init_table, clks, clk_max);
+       tegra_clk_apply_init_table = tegra30_clock_apply_init_table;
 
        tegra_cpu_car_ops = &tegra30_cpu_car_ops;
 }
index a603b9af0ad38cda8ca3ee590174909dcaea2994..4a61d15425dc0cf781a515f67ef3e4021e456946 100644 (file)
@@ -83,3 +83,13 @@ void __init tegra_clocks_init(void)
 {
        of_clk_init(tegra_dt_clk_match);
 }
+
+tegra_clk_apply_init_table_func tegra_clk_apply_init_table;
+
+void __init tegra_clocks_apply_init_table(void)
+{
+       if (!tegra_clk_apply_init_table)
+               return;
+
+       tegra_clk_apply_init_table();
+}
index a09d7dcaf183da6778a0e8499feece6a925615dd..3c566e2d518ab24505ada2aebebe3a263e7d8e8c 100644 (file)
@@ -510,4 +510,7 @@ void tegra30_clock_init(struct device_node *np);
 static inline void tegra30_clock_init(struct device_node *np) {}
 #endif /* CONFIG_ARCH_TEGRA_3x_SOC */
 
+typedef void (*tegra_clk_apply_init_table_func)(void);
+extern tegra_clk_apply_init_table_func tegra_clk_apply_init_table;
+
 #endif /* TEGRA_CLK_H */
index 404d6f940872b0da7373f6ee13172ab089fdf97b..642789baec741cf6574d661587091c75d864b946 100644 (file)
@@ -123,5 +123,6 @@ static inline void tegra_cpu_clock_resume(void)
 void tegra_periph_reset_deassert(struct clk *c);
 void tegra_periph_reset_assert(struct clk *c);
 void tegra_clocks_init(void);
+void tegra_clocks_apply_init_table(void);
 
 #endif /* __LINUX_CLK_TEGRA_H_ */