diff options
author | Prashant Gaikwad <pgaikwad@nvidia.com> | 2011-11-15 19:59:47 +0530 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2012-03-22 23:48:56 -0700 |
commit | 7e275c0f7eea78e0cdca33cbbdcef408c72b19a6 (patch) | |
tree | 506381cfe1088a5596fb587265b66bd00fd5064d /arch/arm/mach-tegra/tegra2_clocks.c | |
parent | c067e82ac7cdd6668f47798128b82445b73d7e42 (diff) |
ARM: tegra: clock: Enable EMC scaling for AP25
Workaround added to enable EMC scaling for AP25.
PLL switching support added for 300MHz EMC scaling step.
Bug 892505
Reviewed-on: http://git-master/r/#change,41718
Reviewed-on: http://git-master/r/#change,41720
Reviewed-on: http://git-master/r/#change,60861
Change-Id: I885b8dc4e3b6124ebed572c06cea773de6c83471
Reviewed-on: http://git-master/r/64465
Reviewed-by: Rohan Somvanshi <rsomvanshi@nvidia.com>
Tested-by: Rohan Somvanshi <rsomvanshi@nvidia.com>
Rebase-Id: Rb8e58cfa7fe1106978030c8aea292e95a7a5da2b
Diffstat (limited to 'arch/arm/mach-tegra/tegra2_clocks.c')
-rw-r--r-- | arch/arm/mach-tegra/tegra2_clocks.c | 63 |
1 files changed, 59 insertions, 4 deletions
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c index a8abd9177c90..eded56abb6b5 100644 --- a/arch/arm/mach-tegra/tegra2_clocks.c +++ b/arch/arm/mach-tegra/tegra2_clocks.c @@ -154,6 +154,10 @@ #define PMC_BLINK_TIMER_DATA_OFF_SHIFT 16 #define PMC_BLINK_TIMER_DATA_OFF_MASK 0xffff +#define AP25_EMC_BRIDGE_RATE 380000000 +#define AP25_EMC_INTERMEDIATE_RATE 760000000 +#define AP25_EMC_SCALING_STEP 600000000 + static void __iomem *reg_clk_base = IO_ADDRESS(TEGRA_CLK_RESET_BASE); static void __iomem *reg_pmc_base = IO_ADDRESS(TEGRA_PMC_BASE); static void __iomem *misc_gp_hidrev_base = IO_ADDRESS(TEGRA_APB_MISC_BASE); @@ -1269,14 +1273,35 @@ static long tegra2_emc_clk_round_rate(struct clk *c, unsigned long rate) if (new_rate < 0) return c->max_rate; - BUG_ON(new_rate != tegra2_periph_clk_round_rate(c, new_rate)); - return new_rate; } static int tegra2_emc_clk_set_rate(struct clk *c, unsigned long rate) { int ret; + int divider; + struct clk *p = NULL; + unsigned long inp_rate; + unsigned long new_rate; + const struct clk_mux_sel *sel; + + for (sel = c->inputs; sel->input != NULL; sel++) { + inp_rate = clk_get_rate(sel->input); + + divider = clk_div71_get_divider(inp_rate, rate); + if (divider < 0) + return divider; + + new_rate = DIV_ROUND_UP(inp_rate * 2, divider + 2); + if ((abs(rate - new_rate)) < 2000) { + p = sel->input; + break; + } + } + + BUG_ON(!p); + BUG_ON(divider & 0x1); + /* * The Tegra2 memory controller has an interlock with the clock * block that allows memory shadowed registers to be updated, @@ -1287,6 +1312,13 @@ static int tegra2_emc_clk_set_rate(struct clk *c, unsigned long rate) if (ret < 0) return ret; + if (c->parent != p) { + BUG_ON(divider != 0); + ret = clk_set_parent_locked(c, p); + udelay(1); + return ret; + } + ret = tegra2_periph_clk_set_rate(c, rate); udelay(1); @@ -1477,15 +1509,38 @@ static struct clk_ops tegra_cdev_clk_ops = { static int tegra2_clk_shared_bus_update(struct clk *bus) { struct clk *c; + unsigned long old_rate; unsigned long rate = bus->min_rate; + int sku_id = tegra_sku_id(); - list_for_each_entry(c, &bus->shared_bus_list, u.shared_bus_user.node) + list_for_each_entry(c, &bus->shared_bus_list, + u.shared_bus_user.node) { if (c->u.shared_bus_user.enabled) rate = max(c->u.shared_bus_user.rate, rate); + } + + old_rate = clk_get_rate_locked(bus); - if (rate == clk_get_rate_locked(bus)) + if (rate == old_rate) return 0; + /* WAR: For AP25 EMC scaling */ + if ((sku_id == 0x17) && (bus->flags & PERIPH_EMC_ENB)) { + if (old_rate == AP25_EMC_SCALING_STEP && + rate != AP25_EMC_INTERMEDIATE_RATE) + clk_set_rate_locked(bus, AP25_EMC_INTERMEDIATE_RATE); + + if (((old_rate > AP25_EMC_BRIDGE_RATE) && + (rate < AP25_EMC_BRIDGE_RATE)) || + ((old_rate < AP25_EMC_BRIDGE_RATE) && + (rate > AP25_EMC_BRIDGE_RATE))) + clk_set_rate_locked(bus, AP25_EMC_BRIDGE_RATE); + + if (rate == AP25_EMC_SCALING_STEP && + old_rate != AP25_EMC_INTERMEDIATE_RATE) + clk_set_rate_locked(bus, AP25_EMC_INTERMEDIATE_RATE); + } + return clk_set_rate_locked(bus, rate); }; |