Skip to content

Commit

Permalink
clk: tegra: defer application of init table
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
nvswarren committed Apr 4, 2013
1 parent 82ce742 commit 441f199
Show file tree
Hide file tree
Showing 6 changed files with 29 additions and 2 deletions.
3 changes: 3 additions & 0 deletions arch/arm/mach-tegra/tegra.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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;
Expand Down
7 changes: 6 additions & 1 deletion drivers/clk/tegra/clk-tegra20.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
}
7 changes: 6 additions & 1 deletion drivers/clk/tegra/clk-tegra30.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
}
10 changes: 10 additions & 0 deletions drivers/clk/tegra/clk.c
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
3 changes: 3 additions & 0 deletions drivers/clk/tegra/clk.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
1 change: 1 addition & 0 deletions include/linux/clk/tegra.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_ */

0 comments on commit 441f199

Please sign in to comment.