diff options
author | Colin Cross <ccross@android.com> | 2010-06-08 03:49:46 (GMT) |
---|---|---|
committer | Colin Cross <ccross@android.com> | 2010-10-22 01:12:19 (GMT) |
commit | 71fc84cc35ee05913306bfe6e2454cdfc5bf7081 (patch) | |
tree | 0847b21ba9208dbfc5773c0fada2528da537add6 /arch/arm/mach-tegra/tegra2_clocks.c | |
parent | 73625e3e2e2bc36198f5b43e0f32d9dfb8e3b77c (diff) | |
download | linux-fsl-qoriq-71fc84cc35ee05913306bfe6e2454cdfc5bf7081.tar.xz |
[ARM] tegra: clock: Add dvfs support, bug fixes, and cleanups
- Add drivers to clock lookup table
- Add new pll_m entries
- Support I2C U16 divider
- Fix rate reporting on 32.768kHz clock
- Call propagate rate only if set_rate succeeds
- Add support for audio_sync clock
- Add 24MHz to PLLA frequency list
- Correct i2s1/2/spdifout mux
- Add suspend support
- Fix enable/disable parent clocks in set_parent
- Add max_rate parameter to all clocks
- DVFS support
- Add virtual cpu clock with dvfs
- Support clk_round_rate
- Fix requesting very high periph frequencies
- Add quirks for PLLU:
PLLU is slightly different from the rest of the PLLs. The
lock enable bit is at bit 22 instead of 18 in the MISC
register, and the post divider field is a single bit with
reversed values from other PLLs.
- Simplify recalculating clock rates
- Fix UART divider flags
- Remove unused clock ops
Signed-off-by: Colin Cross <ccross@android.com>
Diffstat (limited to 'arch/arm/mach-tegra/tegra2_clocks.c')
-rw-r--r-- | arch/arm/mach-tegra/tegra2_clocks.c | 778 |
1 files changed, 607 insertions, 171 deletions
diff --git a/arch/arm/mach-tegra/tegra2_clocks.c b/arch/arm/mach-tegra/tegra2_clocks.c index 4261632..cf1c9d0 100644 --- a/arch/arm/mach-tegra/tegra2_clocks.c +++ b/arch/arm/mach-tegra/tegra2_clocks.c @@ -30,14 +30,21 @@ #include <mach/iomap.h> #include "clock.h" +#include "fuse.h" +#include "tegra2_dvfs.h" #define RST_DEVICES 0x004 #define RST_DEVICES_SET 0x300 #define RST_DEVICES_CLR 0x304 +#define RST_DEVICES_NUM 3 #define CLK_OUT_ENB 0x010 #define CLK_OUT_ENB_SET 0x320 #define CLK_OUT_ENB_CLR 0x324 +#define CLK_OUT_ENB_NUM 3 + +#define CLK_MASK_ARM 0x44 +#define MISC_CLK_ENB 0x48 #define OSC_CTRL 0x50 #define OSC_CTRL_OSC_FREQ_MASK (3<<30) @@ -45,6 +52,7 @@ #define OSC_CTRL_OSC_FREQ_19_2MHZ (1<<30) #define OSC_CTRL_OSC_FREQ_12MHZ (2<<30) #define OSC_CTRL_OSC_FREQ_26MHZ (3<<30) +#define OSC_CTRL_MASK 0x3f2 #define OSC_FREQ_DET 0x58 #define OSC_FREQ_DET_TRIG (1<<31) @@ -53,10 +61,17 @@ #define OSC_FREQ_DET_BUSY (1<<31) #define OSC_FREQ_DET_CNT_MASK 0xFFFF +#define PERIPH_CLK_SOURCE_I2S1 0x100 +#define PERIPH_CLK_SOURCE_EMC 0x19c +#define PERIPH_CLK_SOURCE_OSC 0x1fc +#define PERIPH_CLK_SOURCE_NUM \ + ((PERIPH_CLK_SOURCE_OSC - PERIPH_CLK_SOURCE_I2S1) / 4) + #define PERIPH_CLK_SOURCE_MASK (3<<30) #define PERIPH_CLK_SOURCE_SHIFT 30 #define PERIPH_CLK_SOURCE_ENABLE (1<<28) -#define PERIPH_CLK_SOURCE_DIV_MASK 0xFF +#define PERIPH_CLK_SOURCE_DIVU71_MASK 0xFF +#define PERIPH_CLK_SOURCE_DIVU16_MASK 0xFFFF #define PERIPH_CLK_SOURCE_DIV_SHIFT 0 #define PLL_BASE 0x0 @@ -79,8 +94,9 @@ #define PLL_OUT_RESET_DISABLE (1<<0) #define PLL_MISC(c) (((c)->flags & PLL_ALT_MISC_REG) ? 0x4 : 0xc) +#define PLL_MISC_LOCK_ENABLE(c) (((c)->flags & PLLU) ? (1<<22) : (1<<18)) + #define PLL_MISC_DCCON_SHIFT 20 -#define PLL_MISC_LOCK_ENABLE (1<<18) #define PLL_MISC_CPCON_SHIFT 8 #define PLL_MISC_CPCON_MASK (0xF<<PLL_MISC_CPCON_SHIFT) #define PLL_MISC_LFCON_SHIFT 4 @@ -88,6 +104,8 @@ #define PLL_MISC_VCOCON_SHIFT 0 #define PLL_MISC_VCOCON_MASK (0xF<<PLL_MISC_VCOCON_SHIFT) +#define PLLU_BASE_POST_DIV (1<<20) + #define PLLD_MISC_CLKENABLE (1<<30) #define PLLD_MISC_DIV_RST (1<<23) #define PLLD_MISC_DCCON_SHIFT 12 @@ -143,30 +161,37 @@ unsigned long clk_measure_input_freq(void) } } -static int clk_div71_get_divider(struct clk *c, unsigned long rate) +static int clk_div71_get_divider(unsigned long parent_rate, unsigned long rate) { - unsigned long divider_u71; + s64 divider_u71 = parent_rate * 2; + divider_u71 += rate - 1; + do_div(divider_u71, rate); - divider_u71 = DIV_ROUND_UP(c->rate * 2, rate); + if (divider_u71 - 2 < 0) + return 0; - if (divider_u71 - 2 > 255 || divider_u71 - 2 < 0) + if (divider_u71 - 2 > 255) return -EINVAL; return divider_u71 - 2; } -static unsigned long tegra2_clk_recalculate_rate(struct clk *c) +static int clk_div16_get_divider(unsigned long parent_rate, unsigned long rate) { - unsigned long rate; - rate = c->parent->rate; + s64 divider_u16; - if (c->mul != 0 && c->div != 0) - c->rate = rate * c->mul / c->div; - else - c->rate = rate; - return c->rate; -} + divider_u16 = parent_rate; + divider_u16 += rate - 1; + do_div(divider_u16, rate); + if (divider_u16 - 1 < 0) + return 0; + + if (divider_u16 - 1 > 255) + return -EINVAL; + + return divider_u16 - 1; +} /* clk_m functions */ static unsigned long tegra2_clk_m_autodetect_rate(struct clk *c) @@ -244,7 +269,6 @@ static void tegra2_super_clk_init(struct clk *c) } BUG_ON(sel->input == NULL); c->parent = sel->input; - tegra2_clk_recalculate_rate(c); } static int tegra2_super_clk_enable(struct clk *c) @@ -266,6 +290,7 @@ static int tegra2_super_clk_set_parent(struct clk *c, struct clk *p) u32 val; const struct clk_mux_sel *sel; int shift; + val = clk_readl(c->reg + SUPER_CLK_MUX);; BUG_ON(((val & SUPER_STATE_MASK) != SUPER_STATE_RUN) && ((val & SUPER_STATE_MASK) != SUPER_STATE_IDLE)); @@ -273,11 +298,18 @@ static int tegra2_super_clk_set_parent(struct clk *c, struct clk *p) SUPER_IDLE_SOURCE_SHIFT : SUPER_RUN_SOURCE_SHIFT; for (sel = c->inputs; sel->input != NULL; sel++) { if (sel->input == p) { - clk_reparent(c, p); val &= ~(SUPER_SOURCE_MASK << shift); val |= sel->value << shift; + + if (c->refcnt) + clk_enable_locked(p); + clk_writel(val, c->reg); - c->rate = c->parent->rate; + + if (c->refcnt && c->parent) + clk_disable_locked(c->parent); + + clk_reparent(c, p); return 0; } } @@ -289,7 +321,61 @@ static struct clk_ops tegra_super_ops = { .enable = tegra2_super_clk_enable, .disable = tegra2_super_clk_disable, .set_parent = tegra2_super_clk_set_parent, - .recalculate_rate = tegra2_clk_recalculate_rate, +}; + +/* virtual cpu clock functions */ +/* some clocks can not be stopped (cpu, memory bus) while the SoC is running. + To change the frequency of these clocks, the parent pll may need to be + reprogrammed, so the clock must be moved off the pll, the pll reprogrammed, + and then the clock moved back to the pll. To hide this sequence, a virtual + clock handles it. + */ +static void tegra2_cpu_clk_init(struct clk *c) +{ +} + +static int tegra2_cpu_clk_enable(struct clk *c) +{ + return 0; +} + +static void tegra2_cpu_clk_disable(struct clk *c) +{ + pr_debug("%s on clock %s\n", __func__, c->name); + + /* oops - don't disable the CPU clock! */ + BUG(); +} + +static int tegra2_cpu_clk_set_rate(struct clk *c, unsigned long rate) +{ + int ret; + ret = clk_set_parent_locked(c->parent, c->backup); + if (ret) { + pr_err("Failed to switch cpu to clock %s\n", c->backup->name); + return ret; + } + + ret = clk_set_rate_locked(c->main, rate); + if (ret) { + pr_err("Failed to change cpu pll to %lu\n", rate); + return ret; + } + + ret = clk_set_parent_locked(c->parent, c->main); + if (ret) { + pr_err("Failed to switch cpu to clock %s\n", c->main->name); + return ret; + } + + return 0; +} + +static struct clk_ops tegra_cpu_ops = { + .init = tegra2_cpu_clk_init, + .enable = tegra2_cpu_clk_enable, + .disable = tegra2_cpu_clk_disable, + .set_rate = tegra2_cpu_clk_set_rate, }; /* bus clock functions */ @@ -299,7 +385,6 @@ static void tegra2_bus_clk_init(struct clk *c) c->state = ((val >> c->reg_shift) & BUS_CLK_DISABLE) ? OFF : ON; c->div = ((val >> c->reg_shift) & BUS_CLK_DIV_MASK) + 1; c->mul = 1; - tegra2_clk_recalculate_rate(c); } static int tegra2_bus_clk_enable(struct clk *c) @@ -340,27 +425,15 @@ static struct clk_ops tegra_bus_ops = { .enable = tegra2_bus_clk_enable, .disable = tegra2_bus_clk_disable, .set_rate = tegra2_bus_clk_set_rate, - .recalculate_rate = tegra2_clk_recalculate_rate, }; /* PLL Functions */ -static unsigned long tegra2_pll_clk_recalculate_rate(struct clk *c) -{ - u64 rate; - rate = c->parent->rate; - rate *= c->n; - do_div(rate, c->m); - if (c->p == 2) - rate >>= 1; - c->rate = rate; - return c->rate; -} - static int tegra2_pll_clk_wait_for_lock(struct clk *c) { ktime_t before; before = ktime_get(); + while (!(clk_readl(c->reg + PLL_BASE) & PLL_BASE_LOCK)) { if (ktime_us_delta(ktime_get(), before) > 5000) { pr_err("Timed out waiting for lock bit on pll %s", @@ -380,24 +453,19 @@ static void tegra2_pll_clk_init(struct clk *c) if (c->flags & PLL_FIXED && !(val & PLL_BASE_OVERRIDE)) { pr_warning("Clock %s has unknown fixed frequency\n", c->name); - c->n = 1; - c->m = 0; - c->p = 1; + c->mul = 1; + c->div = 1; } else if (val & PLL_BASE_BYPASS) { - c->n = 1; - c->m = 1; - c->p = 1; + c->mul = 1; + c->div = 1; } else { - c->n = (val & PLL_BASE_DIVN_MASK) >> PLL_BASE_DIVN_SHIFT; - c->m = (val & PLL_BASE_DIVM_MASK) >> PLL_BASE_DIVM_SHIFT; - c->p = (val & PLL_BASE_DIVP_MASK) ? 2 : 1; + c->mul = (val & PLL_BASE_DIVN_MASK) >> PLL_BASE_DIVN_SHIFT; + c->div = (val & PLL_BASE_DIVM_MASK) >> PLL_BASE_DIVM_SHIFT; + if (c->flags & PLLU) + c->div *= (val & PLLU_BASE_POST_DIV) ? 1 : 2; + else + c->div *= (val & PLL_BASE_DIVP_MASK) ? 2 : 1; } - - val = clk_readl(c->reg + PLL_MISC(c)); - if (c->flags & PLL_HAS_CPCON) - c->cpcon = (val & PLL_MISC_CPCON_MASK) >> PLL_MISC_CPCON_SHIFT; - - tegra2_pll_clk_recalculate_rate(c); } static int tegra2_pll_clk_enable(struct clk *c) @@ -411,7 +479,7 @@ static int tegra2_pll_clk_enable(struct clk *c) clk_writel(val, c->reg + PLL_BASE); val = clk_readl(c->reg + PLL_MISC(c)); - val |= PLL_MISC_LOCK_ENABLE; + val |= PLL_MISC_LOCK_ENABLE(c); clk_writel(val, c->reg + PLL_MISC(c)); tegra2_pll_clk_wait_for_lock(c); @@ -441,33 +509,36 @@ static int tegra2_pll_clk_set_rate(struct clk *c, unsigned long rate) input_rate = c->parent->rate; for (sel = c->pll_table; sel->input_rate != 0; sel++) { if (sel->input_rate == input_rate && sel->output_rate == rate) { - c->n = sel->n; - c->m = sel->m; - c->p = sel->p; - c->cpcon = sel->cpcon; + c->mul = sel->n; + c->div = sel->m * sel->p; val = clk_readl(c->reg + PLL_BASE); if (c->flags & PLL_FIXED) val |= PLL_BASE_OVERRIDE; val &= ~(PLL_BASE_DIVP_MASK | PLL_BASE_DIVN_MASK | PLL_BASE_DIVM_MASK); - val |= (c->m << PLL_BASE_DIVM_SHIFT) | - (c->n << PLL_BASE_DIVN_SHIFT); - BUG_ON(c->p > 2); - if (c->p == 2) - val |= 1 << PLL_BASE_DIVP_SHIFT; + val |= (sel->m << PLL_BASE_DIVM_SHIFT) | + (sel->n << PLL_BASE_DIVN_SHIFT); + BUG_ON(sel->p < 1 || sel->p > 2); + if (c->flags & PLLU) { + if (sel->p == 1) + val |= PLLU_BASE_POST_DIV; + } else { + if (sel->p == 2) + val |= 1 << PLL_BASE_DIVP_SHIFT; + } clk_writel(val, c->reg + PLL_BASE); if (c->flags & PLL_HAS_CPCON) { - val = c->cpcon << PLL_MISC_CPCON_SHIFT; - val |= PLL_MISC_LOCK_ENABLE; + val = clk_readl(c->reg + PLL_MISC(c)); + val &= ~PLL_MISC_CPCON_MASK; + val |= sel->cpcon << PLL_MISC_CPCON_SHIFT; clk_writel(val, c->reg + PLL_MISC(c)); } if (c->state == ON) tegra2_pll_clk_enable(c); - c->rate = rate; return 0; } } @@ -479,7 +550,21 @@ static struct clk_ops tegra_pll_ops = { .enable = tegra2_pll_clk_enable, .disable = tegra2_pll_clk_disable, .set_rate = tegra2_pll_clk_set_rate, - .recalculate_rate = tegra2_pll_clk_recalculate_rate, +}; + +static void tegra2_pllx_clk_init(struct clk *c) +{ + tegra2_pll_clk_init(c); + + if (tegra_sku_id() == 7) + c->max_rate = 750000000; +} + +static struct clk_ops tegra_pllx_ops = { + .init = tegra2_pllx_clk_init, + .enable = tegra2_pll_clk_enable, + .disable = tegra2_pll_clk_disable, + .set_rate = tegra2_pll_clk_set_rate, }; /* Clock divider ops */ @@ -503,8 +588,6 @@ static void tegra2_pll_div_clk_init(struct clk *c) c->div = 1; c->mul = 1; } - - tegra2_clk_recalculate_rate(c); } static int tegra2_pll_div_clk_enable(struct clk *c) @@ -565,7 +648,7 @@ static int tegra2_pll_div_clk_set_rate(struct clk *c, unsigned long rate) int divider_u71; pr_debug("%s: %s %lu\n", __func__, c->name, rate); if (c->flags & DIV_U71) { - divider_u71 = clk_div71_get_divider(c->parent, rate); + divider_u71 = clk_div71_get_divider(c->parent->rate, rate); if (divider_u71 >= 0) { val = clk_readl(c->reg); new_val = val >> c->reg_shift; @@ -580,25 +663,37 @@ static int tegra2_pll_div_clk_set_rate(struct clk *c, unsigned long rate) clk_writel(val, c->reg); c->div = divider_u71 + 2; c->mul = 2; - tegra2_clk_recalculate_rate(c); return 0; } } else if (c->flags & DIV_2) { - if (c->parent->rate == rate * 2) { - c->rate = rate; + if (c->parent->rate == rate * 2) return 0; - } } return -EINVAL; } +static long tegra2_pll_div_clk_round_rate(struct clk *c, unsigned long rate) +{ + int divider; + pr_debug("%s: %s %lu\n", __func__, c->name, rate); + + if (c->flags & DIV_U71) { + divider = clk_div71_get_divider(c->parent->rate, rate); + if (divider < 0) + return divider; + return c->parent->rate * 2 / (divider + 2); + } else if (c->flags & DIV_2) { + return c->parent->rate / 2; + } + return -EINVAL; +} static struct clk_ops tegra_pll_div_ops = { .init = tegra2_pll_div_clk_init, .enable = tegra2_pll_div_clk_enable, .disable = tegra2_pll_div_clk_disable, .set_rate = tegra2_pll_div_clk_set_rate, - .recalculate_rate = tegra2_clk_recalculate_rate, + .round_rate = tegra2_pll_div_clk_round_rate, }; /* Periph clk ops */ @@ -621,9 +716,13 @@ static void tegra2_periph_clk_init(struct clk *c) } if (c->flags & DIV_U71) { - u32 divu71 = val & PERIPH_CLK_SOURCE_DIV_MASK; + u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK; c->div = divu71 + 2; c->mul = 2; + } else if (c->flags & DIV_U16) { + u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK; + c->div = divu16 + 1; + c->mul = 1; } else { c->div = 1; c->mul = 1; @@ -637,7 +736,6 @@ static void tegra2_periph_clk_init(struct clk *c) if (clk_readl(RST_DEVICES + PERIPH_CLK_TO_ENB_REG(c)) & PERIPH_CLK_TO_ENB_BIT(c)) c->state = OFF; - tegra2_clk_recalculate_rate(c); } static int tegra2_periph_clk_enable(struct clk *c) @@ -692,12 +790,19 @@ static int tegra2_periph_clk_set_parent(struct clk *c, struct clk *p) pr_debug("%s: %s %s\n", __func__, c->name, p->name); for (sel = c->inputs; sel->input != NULL; sel++) { if (sel->input == p) { - clk_reparent(c, p); val = clk_readl(c->reg); val &= ~PERIPH_CLK_SOURCE_MASK; val |= (sel->value) << PERIPH_CLK_SOURCE_SHIFT; + + if (c->refcnt) + clk_enable_locked(p); + clk_writel(val, c->reg); - c->rate = c->parent->rate; + + if (c->refcnt && c->parent) + clk_disable_locked(c->parent); + + clk_reparent(c, p); return 0; } } @@ -708,20 +813,55 @@ static int tegra2_periph_clk_set_parent(struct clk *c, struct clk *p) static int tegra2_periph_clk_set_rate(struct clk *c, unsigned long rate) { u32 val; - int divider_u71; + int divider; pr_debug("%s: %lu\n", __func__, rate); if (c->flags & DIV_U71) { - divider_u71 = clk_div71_get_divider(c->parent, rate); - if (divider_u71 >= 0) { + divider = clk_div71_get_divider(c->parent->rate, rate); + if (divider >= 0) { val = clk_readl(c->reg); - val &= ~PERIPH_CLK_SOURCE_DIV_MASK; - val |= divider_u71; + val &= ~PERIPH_CLK_SOURCE_DIVU71_MASK; + val |= divider; clk_writel(val, c->reg); - c->div = divider_u71 + 2; + c->div = divider + 2; c->mul = 2; - tegra2_clk_recalculate_rate(c); return 0; } + } else if (c->flags & DIV_U16) { + divider = clk_div16_get_divider(c->parent->rate, rate); + if (divider >= 0) { + val = clk_readl(c->reg); + val &= ~PERIPH_CLK_SOURCE_DIVU16_MASK; + val |= divider; + clk_writel(val, c->reg); + c->div = divider + 1; + c->mul = 1; + return 0; + } + } else if (c->parent->rate <= rate) { + c->div = 1; + c->mul = 1; + return 0; + } + return -EINVAL; +} + +static long tegra2_periph_clk_round_rate(struct clk *c, + unsigned long rate) +{ + int divider; + pr_debug("%s: %s %lu\n", __func__, c->name, rate); + + if (c->flags & DIV_U71) { + divider = clk_div71_get_divider(c->parent->rate, rate); + if (divider < 0) + return divider; + + return c->parent->rate * 2 / (divider + 2); + } else if (c->flags & DIV_U16) { + divider = clk_div16_get_divider(c->parent->rate, rate); + if (divider < 0) + return divider; + return c->parent->rate / (divider + 1); } return -EINVAL; } @@ -732,7 +872,7 @@ static struct clk_ops tegra_periph_clk_ops = { .disable = &tegra2_periph_clk_disable, .set_parent = &tegra2_periph_clk_set_parent, .set_rate = &tegra2_periph_clk_set_rate, - .recalculate_rate = &tegra2_clk_recalculate_rate, + .round_rate = &tegra2_periph_clk_round_rate, }; /* Clock doubler ops */ @@ -744,21 +884,108 @@ static void tegra2_clk_double_init(struct clk *c) if (!(clk_readl(CLK_OUT_ENB + PERIPH_CLK_TO_ENB_REG(c)) & PERIPH_CLK_TO_ENB_BIT(c))) c->state = OFF; - tegra2_clk_recalculate_rate(c); }; +static int tegra2_clk_double_set_rate(struct clk *c, unsigned long rate) +{ + if (rate != 2 * c->parent->rate) + return -EINVAL; + c->mul = 2; + c->div = 1; + return 0; +} + static struct clk_ops tegra_clk_double_ops = { .init = &tegra2_clk_double_init, .enable = &tegra2_periph_clk_enable, .disable = &tegra2_periph_clk_disable, - .recalculate_rate = &tegra2_clk_recalculate_rate, + .set_rate = &tegra2_clk_double_set_rate, +}; + +static void tegra2_audio_sync_clk_init(struct clk *c) +{ + int source; + const struct clk_mux_sel *sel; + u32 val = clk_readl(c->reg); + c->state = (val & (1<<4)) ? OFF : ON; + source = val & 0xf; + for (sel = c->inputs; sel->input != NULL; sel++) + if (sel->value == source) + break; + BUG_ON(sel->input == NULL); + c->parent = sel->input; +} + +static int tegra2_audio_sync_clk_enable(struct clk *c) +{ + clk_writel(0, c->reg); + return 0; +} + +static void tegra2_audio_sync_clk_disable(struct clk *c) +{ + clk_writel(1, c->reg); +} + +static int tegra2_audio_sync_clk_set_parent(struct clk *c, struct clk *p) +{ + u32 val; + const struct clk_mux_sel *sel; + for (sel = c->inputs; sel->input != NULL; sel++) { + if (sel->input == p) { + val = clk_readl(c->reg); + val &= ~0xf; + val |= sel->value; + + if (c->refcnt) + clk_enable_locked(p); + + clk_writel(val, c->reg); + + if (c->refcnt && c->parent) + clk_disable_locked(c->parent); + + clk_reparent(c, p); + return 0; + } + } + + return -EINVAL; +} + +static int tegra2_audio_sync_clk_set_rate(struct clk *c, unsigned long rate) +{ + unsigned long parent_rate; + if (!c->parent) { + pr_err("%s: clock has no parent\n", __func__); + return -EINVAL; + } + parent_rate = c->parent->rate; + if (rate != parent_rate) { + pr_err("%s: %s/%ld differs from parent %s/%ld\n", + __func__, + c->name, rate, + c->parent->name, parent_rate); + return -EINVAL; + } + c->rate = parent_rate; + return 0; +} + +static struct clk_ops tegra_audio_sync_clk_ops = { + .init = tegra2_audio_sync_clk_init, + .enable = tegra2_audio_sync_clk_enable, + .disable = tegra2_audio_sync_clk_disable, + .set_rate = tegra2_audio_sync_clk_set_rate, + .set_parent = tegra2_audio_sync_clk_set_parent, }; /* Clock definitions */ static struct clk tegra_clk_32k = { .name = "clk_32k", - .rate = 32678, + .rate = 32768, .ops = NULL, + .max_rate = 32768, }; static struct clk_pll_table tegra_pll_s_table[] = { @@ -782,6 +1009,7 @@ static struct clk tegra_pll_s = { .vco_min = 12000000, .vco_max = 26000000, .pll_table = tegra_pll_s_table, + .max_rate = 26000000, }; static struct clk_mux_sel tegra_clk_m_sel[] = { @@ -797,6 +1025,7 @@ static struct clk tegra_clk_m = { .reg = 0x1fc, .reg_mask = (1<<28), .reg_shift = 28, + .max_rate = 26000000, }; static struct clk_pll_table tegra_pll_c_table[] = { @@ -816,6 +1045,7 @@ static struct clk tegra_pll_c = { .vco_min = 20000000, .vco_max = 1400000000, .pll_table = tegra_pll_c_table, + .max_rate = 600000000, }; static struct clk tegra_pll_c_out1 = { @@ -825,9 +1055,18 @@ static struct clk tegra_pll_c_out1 = { .parent = &tegra_pll_c, .reg = 0x84, .reg_shift = 0, + .max_rate = 600000000, }; static struct clk_pll_table tegra_pll_m_table[] = { + { 12000000, 666000000, 666, 12, 1, 8}, + { 13000000, 666000000, 666, 13, 1, 8}, + { 19200000, 666000000, 555, 16, 1, 8}, + { 26000000, 666000000, 666, 26, 1, 8}, + { 12000000, 600000000, 600, 12, 1, 8}, + { 13000000, 600000000, 600, 13, 1, 8}, + { 19200000, 600000000, 375, 12, 1, 6}, + { 26000000, 600000000, 600, 26, 1, 8}, { 0, 0, 0, 0, 0, 0 }, }; @@ -844,6 +1083,7 @@ static struct clk tegra_pll_m = { .vco_min = 20000000, .vco_max = 1200000000, .pll_table = tegra_pll_m_table, + .max_rate = 800000000, }; static struct clk tegra_pll_m_out1 = { @@ -853,6 +1093,7 @@ static struct clk tegra_pll_m_out1 = { .parent = &tegra_pll_m, .reg = 0x94, .reg_shift = 0, + .max_rate = 600000000, }; static struct clk_pll_table tegra_pll_p_table[] = { @@ -880,6 +1121,7 @@ static struct clk tegra_pll_p = { .vco_min = 20000000, .vco_max = 1400000000, .pll_table = tegra_pll_p_table, + .max_rate = 432000000, }; static struct clk tegra_pll_p_out1 = { @@ -889,6 +1131,7 @@ static struct clk tegra_pll_p_out1 = { .parent = &tegra_pll_p, .reg = 0xa4, .reg_shift = 0, + .max_rate = 432000000, }; static struct clk tegra_pll_p_out2 = { @@ -898,6 +1141,7 @@ static struct clk tegra_pll_p_out2 = { .parent = &tegra_pll_p, .reg = 0xa4, .reg_shift = 16, + .max_rate = 432000000, }; static struct clk tegra_pll_p_out3 = { @@ -907,6 +1151,7 @@ static struct clk tegra_pll_p_out3 = { .parent = &tegra_pll_p, .reg = 0xa8, .reg_shift = 0, + .max_rate = 432000000, }; static struct clk tegra_pll_p_out4 = { @@ -916,6 +1161,7 @@ static struct clk tegra_pll_p_out4 = { .parent = &tegra_pll_p, .reg = 0xa8, .reg_shift = 16, + .max_rate = 432000000, }; static struct clk_pll_table tegra_pll_a_table[] = { @@ -923,6 +1169,7 @@ static struct clk_pll_table tegra_pll_a_table[] = { { 28800000, 73728000, 64, 25, 1, 1}, { 28800000, 11289600, 49, 25, 1, 1}, { 28800000, 12288000, 64, 25, 1, 1}, + { 28800000, 24000000, 5, 6, 1, 1}, { 0, 0, 0, 0, 0, 0 }, }; @@ -939,6 +1186,7 @@ static struct clk tegra_pll_a = { .vco_min = 20000000, .vco_max = 1400000000, .pll_table = tegra_pll_a_table, + .max_rate = 56448000, }; static struct clk tegra_pll_a_out0 = { @@ -948,6 +1196,7 @@ static struct clk tegra_pll_a_out0 = { .parent = &tegra_pll_a, .reg = 0xb4, .reg_shift = 0, + .max_rate = 56448000, }; static struct clk_pll_table tegra_pll_d_table[] = { @@ -971,6 +1220,7 @@ static struct clk tegra_pll_d = { .vco_min = 40000000, .vco_max = 1000000000, .pll_table = tegra_pll_d_table, + .max_rate = 1000000000, }; static struct clk tegra_pll_d_out0 = { @@ -978,19 +1228,20 @@ static struct clk tegra_pll_d_out0 = { .ops = &tegra_pll_div_ops, .flags = DIV_2 | PLLD, .parent = &tegra_pll_d, + .max_rate = 500000000, }; static struct clk_pll_table tegra_pll_u_table[] = { - { 12000000, 480000000, 960, 12, 1, 0}, - { 13000000, 480000000, 960, 13, 1, 0}, - { 19200000, 480000000, 200, 4, 1, 0}, - { 26000000, 480000000, 960, 26, 1, 0}, + { 12000000, 480000000, 960, 12, 2, 0}, + { 13000000, 480000000, 960, 13, 2, 0}, + { 19200000, 480000000, 200, 4, 2, 0}, + { 26000000, 480000000, 960, 26, 2, 0}, { 0, 0, 0, 0, 0, 0 }, }; static struct clk tegra_pll_u = { .name = "pll_u", - .flags = 0, + .flags = PLLU, .ops = &tegra_pll_ops, .reg = 0xc0, .input_min = 2000000, @@ -1001,24 +1252,59 @@ static struct clk tegra_pll_u = { .vco_min = 480000000, .vco_max = 960000000, .pll_table = tegra_pll_u_table, + .max_rate = 480000000, }; static struct clk_pll_table tegra_pll_x_table[] = { + /* 1 GHz */ { 12000000, 1000000000, 1000, 12, 1, 12}, { 13000000, 1000000000, 1000, 13, 1, 12}, { 19200000, 1000000000, 625, 12, 1, 8}, { 26000000, 1000000000, 1000, 26, 1, 12}, - { 12000000, 750000000, 750, 12, 1, 12}, - { 13000000, 750000000, 750, 13, 1, 12}, - { 19200000, 750000000, 625, 16, 1, 8}, - { 26000000, 750000000, 750, 26, 1, 12}, + + /* 912 MHz */ + { 12000000, 912000000, 912, 12, 1, 12}, + { 13000000, 912000000, 912, 13, 1, 12}, + { 19200000, 912000000, 760, 16, 1, 8}, + { 26000000, 912000000, 912, 26, 1, 12}, + + /* 816 MHz */ + { 12000000, 816000000, 816, 12, 1, 12}, + { 13000000, 816000000, 816, 13, 1, 12}, + { 19200000, 816000000, 680, 16, 1, 8}, + { 26000000, 816000000, 816, 26, 1, 12}, + + /* 760 MHz */ + { 12000000, 760000000, 760, 12, 1, 12}, + { 13000000, 760000000, 760, 13, 1, 12}, + { 19200000, 760000000, 950, 24, 1, 8}, + { 26000000, 760000000, 760, 26, 1, 12}, + + /* 608 MHz */ + { 12000000, 608000000, 760, 12, 1, 12}, + { 13000000, 608000000, 760, 13, 1, 12}, + { 19200000, 608000000, 380, 12, 1, 8}, + { 26000000, 608000000, 760, 26, 1, 12}, + + /* 456 MHz */ + { 12000000, 456000000, 456, 12, 1, 12}, + { 13000000, 456000000, 456, 13, 1, 12}, + { 19200000, 456000000, 380, 16, 1, 8}, + { 26000000, 456000000, 456, 26, 1, 12}, + + /* 312 MHz */ + { 12000000, 312000000, 312, 12, 1, 12}, + { 13000000, 312000000, 312, 13, 1, 12}, + { 19200000, 312000000, 260, 16, 1, 8}, + { 26000000, 312000000, 312, 26, 1, 12}, + { 0, 0, 0, 0, 0, 0 }, }; static struct clk tegra_pll_x = { .name = "pll_x", .flags = PLL_HAS_CPCON | PLL_ALT_MISC_REG, - .ops = &tegra_pll_ops, + .ops = &tegra_pllx_ops, .reg = 0xe0, .input_min = 2000000, .input_max = 31000000, @@ -1028,6 +1314,7 @@ static struct clk tegra_pll_x = { .vco_min = 20000000, .vco_max = 1200000000, .pll_table = tegra_pll_x_table, + .max_rate = 1000000000, }; static struct clk tegra_clk_d = { @@ -1038,19 +1325,77 @@ static struct clk tegra_clk_d = { .reg = 0x34, .reg_shift = 12, .parent = &tegra_clk_m, + .max_rate = 52000000, +}; + +/* initialized before peripheral clocks */ +static struct clk_mux_sel mux_audio_sync_clk[8+1]; +static const struct audio_sources { + const char *name; + int value; +} mux_audio_sync_clk_sources[] = { + { .name = "spdif_in", .value = 0 }, + { .name = "i2s1", .value = 1 }, + { .name = "i2s2", .value = 2 }, + { .name = "pll_a_out0", .value = 4 }, +#if 0 /* FIXME: not implemented */ + { .name = "ac97", .value = 3 }, + { .name = "ext_audio_clk2", .value = 5 }, + { .name = "ext_audio_clk1", .value = 6 }, + { .name = "ext_vimclk", .value = 7 }, +#endif + { 0, 0 } +}; + +static struct clk tegra_clk_audio = { + .name = "audio", + .inputs = mux_audio_sync_clk, + .reg = 0x38, + .max_rate = 24000000, + .ops = &tegra_audio_sync_clk_ops }; -/* FIXME: need tegra_audio static struct clk tegra_clk_audio_2x = { - .name = "clk_d", + .name = "audio_2x", .flags = PERIPH_NO_RESET, + .max_rate = 48000000, .ops = &tegra_clk_double_ops, .clk_num = 89, .reg = 0x34, .reg_shift = 8, - .parent = &tegra_audio, + .parent = &tegra_clk_audio, +}; + +struct clk_lookup tegra_audio_clk_lookups[] = { + { .con_id = "audio", .clk = &tegra_clk_audio }, + { .con_id = "audio_2x", .clk = &tegra_clk_audio_2x } +}; + +/* This is called after peripheral clocks are initialized, as the + * audio_sync clock depends on some of the peripheral clocks. + */ + +static void init_audio_sync_clock_mux(void) +{ + int i; + struct clk_mux_sel *sel = mux_audio_sync_clk; + const struct audio_sources *src = mux_audio_sync_clk_sources; + struct clk_lookup *lookup; + + for (i = 0; src->name; i++, sel++, src++) { + sel->input = tegra_get_clock_by_name(src->name); + if (!sel->input) + pr_err("%s: could not find clk %s\n", __func__, + src->name); + sel->value = src->value; + } + + lookup = tegra_audio_clk_lookups; + for (i = 0; i < ARRAY_SIZE(tegra_audio_clk_lookups); i++, lookup++) { + clk_init(lookup->clk); + clkdev_add(lookup); + } } -*/ static struct clk_mux_sel mux_cclk[] = { { .input = &tegra_clk_m, .value = 0}, @@ -1077,27 +1422,40 @@ static struct clk_mux_sel mux_sclk[] = { { 0, 0}, }; -static struct clk tegra_clk_cpu = { - .name = "cpu", +static struct clk tegra_clk_cclk = { + .name = "cclk", .inputs = mux_cclk, .reg = 0x20, .ops = &tegra_super_ops, + .max_rate = 1000000000, }; -static struct clk tegra_clk_sys = { - .name = "sys", +static struct clk tegra_clk_sclk = { + .name = "sclk", .inputs = mux_sclk, .reg = 0x28, .ops = &tegra_super_ops, + .max_rate = 600000000, +}; + +static struct clk tegra_clk_virtual_cpu = { + .name = "cpu", + .parent = &tegra_clk_cclk, + .main = &tegra_pll_x, + .backup = &tegra_clk_m, + .ops = &tegra_cpu_ops, + .max_rate = 1000000000, + .dvfs = &tegra_dvfs_virtual_cpu_dvfs, }; static struct clk tegra_clk_hclk = { .name = "hclk", .flags = DIV_BUS, - .parent = &tegra_clk_sys, + .parent = &tegra_clk_sclk, .reg = 0x30, .reg_shift = 4, .ops = &tegra_bus_ops, + .max_rate = 240000000, }; static struct clk tegra_clk_pclk = { @@ -1107,6 +1465,7 @@ static struct clk tegra_clk_pclk = { .reg = 0x30, .reg_shift = 0, .ops = &tegra_bus_ops, + .max_rate = 108000000, }; static struct clk_mux_sel mux_pllm_pllc_pllp_plla[] = { @@ -1133,10 +1492,9 @@ static struct clk_mux_sel mux_pllp_pllc_pllm_clkm[] = { { 0, 0}, }; -static struct clk_mux_sel mux_plla_audio_pllp_clkm[] = { - {.input = &tegra_pll_a, .value = 0}, - /* FIXME: no mux defined for tegra_audio - {.input = &tegra_audio, .value = 1},*/ +static struct clk_mux_sel mux_pllaout0_audio2x_pllp_clkm[] = { + {.input = &tegra_pll_a_out0, .value = 0}, + {.input = &tegra_clk_audio_2x, .value = 1}, {.input = &tegra_pll_p, .value = 2}, {.input = &tegra_clk_m, .value = 3}, { 0, 0}, @@ -1153,8 +1511,7 @@ static struct clk_mux_sel mux_pllp_plld_pllc_clkm[] = { static struct clk_mux_sel mux_pllp_pllc_audio_clkm_clk32[] = { {.input = &tegra_pll_p, .value = 0}, {.input = &tegra_pll_c, .value = 1}, - /* FIXME: no mux defined for tegra_audio - {.input = &tegra_audio, .value = 2},*/ + {.input = &tegra_clk_audio, .value = 2}, {.input = &tegra_clk_m, .value = 3}, {.input = &tegra_clk_32k, .value = 4}, { 0, 0}, @@ -1187,7 +1544,7 @@ static struct clk_mux_sel mux_clk_32k[] = { { 0, 0}, }; -#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, _inputs, _flags) \ +#define PERIPH_CLK(_name, _dev, _con, _clk_num, _reg, _max, _inputs, _flags) \ { \ .name = _name, \ .lookup = { \ @@ -1199,72 +1556,76 @@ static struct clk_mux_sel mux_clk_32k[] = { .reg = _reg, \ .inputs = _inputs, \ .flags = _flags, \ + .max_rate = _max, \ } struct clk tegra_periph_clks[] = { - PERIPH_CLK("rtc", "rtc-tegra", NULL, 4, 0, mux_clk_32k, PERIPH_NO_RESET), - PERIPH_CLK("timer", "timer", NULL, 5, 0, mux_clk_m, 0), - PERIPH_CLK("i2s1", "i2s.0", NULL, 11, 0x100, mux_plla_audio_pllp_clkm, MUX | DIV_U71), - PERIPH_CLK("i2s2", "i2s.1", NULL, 18, 0x104, mux_plla_audio_pllp_clkm, MUX | DIV_U71), + PERIPH_CLK("rtc", "rtc-tegra", NULL, 4, 0, 32768, mux_clk_32k, PERIPH_NO_RESET), + PERIPH_CLK("timer", "timer", NULL, 5, 0, 26000000, mux_clk_m, 0), + PERIPH_CLK("i2s1", "i2s.0", NULL, 11, 0x100, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71), + PERIPH_CLK("i2s2", "i2s.1", NULL, 18, 0x104, 26000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71), /* FIXME: spdif has 2 clocks but 1 enable */ - PERIPH_CLK("spdif_out", "spdif_out", NULL, 10, 0x108, mux_plla_audio_pllp_clkm, MUX | DIV_U71), - PERIPH_CLK("spdif_in", "spdif_in", NULL, 10, 0x10c, mux_pllp_pllc_pllm, MUX | DIV_U71), - PERIPH_CLK("pwm", "pwm", NULL, 17, 0x110, mux_pllp_pllc_audio_clkm_clk32, MUX | DIV_U71), - PERIPH_CLK("spi", "spi", NULL, 43, 0x114, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), - PERIPH_CLK("xio", "xio", NULL, 45, 0x120, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), - PERIPH_CLK("twc", "twc", NULL, 16, 0x12c, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), - PERIPH_CLK("sbc1", "spi_tegra.0", NULL, 41, 0x134, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), - PERIPH_CLK("sbc2", "spi_tegra.1", NULL, 44, 0x118, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), - PERIPH_CLK("sbc3", "spi_tegra.2", NULL, 46, 0x11c, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), - PERIPH_CLK("sbc4", "spi_tegra.3", NULL, 68, 0x1b4, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), - PERIPH_CLK("ide", "ide", NULL, 25, 0x144, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), - PERIPH_CLK("ndflash", "tegra_nand", NULL, 13, 0x160, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), + PERIPH_CLK("spdif_out", "spdif_out", NULL, 10, 0x108, 100000000, mux_pllaout0_audio2x_pllp_clkm, MUX | DIV_U71), + PERIPH_CLK("spdif_in", "spdif_in", NULL, 10, 0x10c, 100000000, mux_pllp_pllc_pllm, MUX | DIV_U71), + PERIPH_CLK("pwm", "pwm", NULL, 17, 0x110, 432000000, mux_pllp_pllc_audio_clkm_clk32, MUX | DIV_U71), + PERIPH_CLK("spi", "spi", NULL, 43, 0x114, 40000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), + PERIPH_CLK("xio", "xio", NULL, 45, 0x120, 150000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), + PERIPH_CLK("twc", "twc", NULL, 16, 0x12c, 150000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), + PERIPH_CLK("sbc1", "spi_tegra.0", NULL, 41, 0x134, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), + PERIPH_CLK("sbc2", "spi_tegra.1", NULL, 44, 0x118, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), + PERIPH_CLK("sbc3", "spi_tegra.2", NULL, 46, 0x11c, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), + PERIPH_CLK("sbc4", "spi_tegra.3", NULL, 68, 0x1b4, 160000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), + PERIPH_CLK("ide", "ide", NULL, 25, 0x144, 100000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* requires min voltage */ + PERIPH_CLK("ndflash", "tegra_nand", NULL, 13, 0x160, 164000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */ /* FIXME: vfir shares an enable with uartb */ - PERIPH_CLK("vfir", "vfir", NULL, 7, 0x168, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), - PERIPH_CLK("sdmmc1", "sdhci-tegra.0", NULL, 14, 0x150, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), - PERIPH_CLK("sdmmc2", "sdhci-tegra.1", NULL, 9, 0x154, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), - PERIPH_CLK("sdmmc3", "sdhci-tegra.2", NULL, 69, 0x1bc, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), - PERIPH_CLK("sdmmc4", "sdhci-tegra.3", NULL, 15, 0x160, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), - PERIPH_CLK("vde", "vde", NULL, 61, 0x1c8, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), - PERIPH_CLK("csite", "csite", NULL, 73, 0x1d4, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), + PERIPH_CLK("vfir", "vfir", NULL, 7, 0x168, 72000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), + PERIPH_CLK("sdmmc1", "sdhci-tegra.0", NULL, 14, 0x150, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */ + PERIPH_CLK("sdmmc2", "sdhci-tegra.1", NULL, 9, 0x154, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */ + PERIPH_CLK("sdmmc3", "sdhci-tegra.2", NULL, 69, 0x1bc, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */ + PERIPH_CLK("sdmmc4", "sdhci-tegra.3", NULL, 15, 0x160, 52000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */ + PERIPH_CLK("vde", "vde", NULL, 61, 0x1c8, 250000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage and process_id */ + PERIPH_CLK("csite", "csite", NULL, 73, 0x1d4, 144000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* max rate ??? */ /* FIXME: what is la? */ - PERIPH_CLK("la", "la", NULL, 76, 0x1f8, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), - PERIPH_CLK("owr", "owr", NULL, 71, 0x1cc, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), - PERIPH_CLK("nor", "nor", NULL, 42, 0x1d0, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), - PERIPH_CLK("mipi", "mipi", NULL, 50, 0x174, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), - PERIPH_CLK("i2c1", "tegra-i2c.0", NULL, 12, 0x124, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), - PERIPH_CLK("i2c2", "tegra-i2c.1", NULL, 54, 0x198, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), - PERIPH_CLK("i2c3", "tegra-i2c.2", NULL, 67, 0x1b8, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), - PERIPH_CLK("dvc", "tegra-i2c.3", NULL, 47, 0x128, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), - PERIPH_CLK("i2c1_i2c", "tegra-i2c.0", "i2c", 0, 0, mux_pllp_out3, 0), - PERIPH_CLK("i2c2_i2c", "tegra-i2c.1", "i2c", 0, 0, mux_pllp_out3, 0), - PERIPH_CLK("i2c3_i2c", "tegra-i2c.2", "i2c", 0, 0, mux_pllp_out3, 0), - PERIPH_CLK("dvc_i2c", "tegra-i2c.3", "i2c", 0, 0, mux_pllp_out3, 0), - PERIPH_CLK("uarta", "uart.0", NULL, 6, 0x178, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), - PERIPH_CLK("uartb", "uart.1", NULL, 7, 0x17c, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), - PERIPH_CLK("uartc", "uart.2", NULL, 55, 0x1a0, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), - PERIPH_CLK("uartd", "uart.3", NULL, 65, 0x1c0, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), - PERIPH_CLK("uarte", "uart.4", NULL, 66, 0x1c4, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), - PERIPH_CLK("3d", "3d", NULL, 24, 0x158, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_MANUAL_RESET), - PERIPH_CLK("2d", "2d", NULL, 21, 0x15c, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), + PERIPH_CLK("la", "la", NULL, 76, 0x1f8, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), + PERIPH_CLK("owr", "tegra_w1", NULL, 71, 0x1cc, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), + PERIPH_CLK("nor", "nor", NULL, 42, 0x1d0, 92000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* requires min voltage */ + PERIPH_CLK("mipi", "mipi", NULL, 50, 0x174, 60000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* scales with voltage */ + PERIPH_CLK("i2c1", "tegra-i2c.0", NULL, 12, 0x124, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16), + PERIPH_CLK("i2c2", "tegra-i2c.1", NULL, 54, 0x198, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16), + PERIPH_CLK("i2c3", "tegra-i2c.2", NULL, 67, 0x1b8, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16), + PERIPH_CLK("dvc", "tegra-i2c.3", NULL, 47, 0x128, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U16), + PERIPH_CLK("i2c1_i2c", "tegra-i2c.0", "i2c", 0, 0, 72000000, mux_pllp_out3, 0), + PERIPH_CLK("i2c2_i2c", "tegra-i2c.1", "i2c", 0, 0, 72000000, mux_pllp_out3, 0), + PERIPH_CLK("i2c3_i2c", "tegra-i2c.2", "i2c", 0, 0, 72000000, mux_pllp_out3, 0), + PERIPH_CLK("dvc_i2c", "tegra-i2c.3", "i2c", 0, 0, 72000000, mux_pllp_out3, 0), + PERIPH_CLK("uarta", "uart.0", NULL, 6, 0x178, 216000000, mux_pllp_pllc_pllm_clkm, MUX), + PERIPH_CLK("uartb", "uart.1", NULL, 7, 0x17c, 216000000, mux_pllp_pllc_pllm_clkm, MUX), + PERIPH_CLK("uartc", "uart.2", NULL, 55, 0x1a0, 216000000, mux_pllp_pllc_pllm_clkm, MUX), + PERIPH_CLK("uartd", "uart.3", NULL, 65, 0x1c0, 216000000, mux_pllp_pllc_pllm_clkm, MUX), + PERIPH_CLK("uarte", "uart.4", NULL, 66, 0x1c4, 216000000, mux_pllp_pllc_pllm_clkm, MUX), + PERIPH_CLK("3d", "3d", NULL, 24, 0x158, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_MANUAL_RESET), /* scales with voltage and process_id */ + PERIPH_CLK("2d", "2d", NULL, 21, 0x15c, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */ /* FIXME: vi and vi_sensor share an enable */ - PERIPH_CLK("vi", "vi", NULL, 20, 0x148, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), - PERIPH_CLK("vi_sensor", "vi_sensor", NULL, 20, 0x1a8, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), - PERIPH_CLK("epp", "epp", NULL, 19, 0x16c, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), - PERIPH_CLK("mpe", "mpe", NULL, 60, 0x170, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), - PERIPH_CLK("host1x", "host1x", NULL, 28, 0x180, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), + PERIPH_CLK("vi", "vi", NULL, 20, 0x148, 150000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */ + PERIPH_CLK("vi_sensor", "vi_sensor", NULL, 20, 0x1a8, 150000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | PERIPH_NO_RESET), /* scales with voltage and process_id */ + PERIPH_CLK("epp", "epp", NULL, 19, 0x16c, 300000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */ + PERIPH_CLK("mpe", "mpe", NULL, 60, 0x170, 250000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */ + PERIPH_CLK("host1x", "host1x", NULL, 28, 0x180, 166000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71), /* scales with voltage and process_id */ /* FIXME: cve and tvo share an enable */ - PERIPH_CLK("cve", "cve", NULL, 49, 0x140, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), - PERIPH_CLK("tvo", "tvo", NULL, 49, 0x188, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), - PERIPH_CLK("hdmi", "hdmi", NULL, 51, 0x18c, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), - PERIPH_CLK("tvdac", "tvdac", NULL, 53, 0x194, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), - PERIPH_CLK("disp1", "tegrafb.0", NULL, 27, 0x138, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), - PERIPH_CLK("disp2", "tegrafb.1", NULL, 26, 0x13c, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), - PERIPH_CLK("usbd", "fsl-tegra-udc", NULL, 22, 0, mux_clk_m, 0), - PERIPH_CLK("usb2", "usb.1", NULL, 58, 0, mux_clk_m, 0), - PERIPH_CLK("usb3", "usb.2", NULL, 59, 0, mux_clk_m, 0), - PERIPH_CLK("emc", "emc", NULL, 57, 0x19c, mux_pllm_pllc_pllp_clkm, MUX | DIV_U71 | PERIPH_EMC_ENB), - PERIPH_CLK("dsi", "dsi", NULL, 48, 0, mux_plld, 0), + PERIPH_CLK("cve", "cve", NULL, 49, 0x140, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */ + PERIPH_CLK("tvo", "tvo", NULL, 49, 0x188, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */ + PERIPH_CLK("hdmi", "hdmi", NULL, 51, 0x18c, 148500000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */ + PERIPH_CLK("tvdac", "tvdac", NULL, 53, 0x194, 250000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */ + PERIPH_CLK("disp1", "tegrafb.0", NULL, 27, 0x138, 190000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* scales with voltage and process_id */ + PERIPH_CLK("disp2", "tegrafb.1", NULL, 26, 0x13c, 190000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* scales with voltage and process_id */ + PERIPH_CLK("usbd", "fsl-tegra-udc", NULL, 22, 0, 480000000, mux_clk_m, 0), /* requires min voltage */ + PERIPH_CLK("usb2", "tegra-ehci.1", NULL, 58, 0, 480000000, mux_clk_m, 0), /* requires min voltage */ + PERIPH_CLK("usb3", "tegra-ehci.2", NULL, 59, 0, 480000000, mux_clk_m, 0), /* requires min voltage */ + PERIPH_CLK("emc", "emc", NULL, 57, 0x19c, 800000000, mux_pllm_pllc_pllp_clkm, MUX | DIV_U71 | PERIPH_EMC_ENB), + PERIPH_CLK("dsi", "dsi", NULL, 48, 0, 500000000, mux_plld, 0), /* scales with voltage */ + PERIPH_CLK("csi", "csi", NULL, 52, 0, 72000000, mux_pllp_out3, 0), + PERIPH_CLK("isp", "isp", NULL, 23, 0, 150000000, mux_clk_m, 0), /* same frequency as VI */ + PERIPH_CLK("csus", "csus", NULL, 92, 0, 150000000, mux_clk_m, PERIPH_NO_RESET), }; #define CLK_DUPLICATE(_name, _dev, _con) \ @@ -1286,6 +1647,9 @@ struct clk_duplicate tegra_clk_duplicates[] = { CLK_DUPLICATE("uartc", "tegra_uart.2", NULL), CLK_DUPLICATE("uartd", "tegra_uart.3", NULL), CLK_DUPLICATE("uarte", "tegra_uart.4", NULL), + CLK_DUPLICATE("host1x", "tegrafb.0", "host1x"), + CLK_DUPLICATE("host1x", "tegrafb.1", "host1x"), + CLK_DUPLICATE("usbd", "tegra-ehci.0", NULL), }; #define CLK(dev, con, ck) \ @@ -1315,11 +1679,12 @@ struct clk_lookup tegra_clk_lookups[] = { CLK(NULL, "pll_d_out0", &tegra_pll_d_out0), CLK(NULL, "pll_u", &tegra_pll_u), CLK(NULL, "pll_x", &tegra_pll_x), - CLK(NULL, "cpu", &tegra_clk_cpu), - CLK(NULL, "sys", &tegra_clk_sys), + CLK(NULL, "cclk", &tegra_clk_cclk), + CLK(NULL, "sclk", &tegra_clk_sclk), CLK(NULL, "hclk", &tegra_clk_hclk), CLK(NULL, "pclk", &tegra_clk_pclk), CLK(NULL, "clk_d", &tegra_clk_d), + CLK(NULL, "cpu", &tegra_clk_virtual_cpu), }; void __init tegra2_init_clocks(void) @@ -1356,4 +1721,75 @@ void __init tegra2_init_clocks(void) cd->name); } } + + init_audio_sync_clock_mux(); +} + +#ifdef CONFIG_PM +static u32 clk_rst_suspend[RST_DEVICES_NUM + CLK_OUT_ENB_NUM + + PERIPH_CLK_SOURCE_NUM + 3]; + +void tegra_clk_suspend(void) +{ + unsigned long off, i; + u32 *ctx = clk_rst_suspend; + + *ctx++ = clk_readl(OSC_CTRL) & OSC_CTRL_MASK; + + for (off = PERIPH_CLK_SOURCE_I2S1; off <= PERIPH_CLK_SOURCE_OSC; + off += 4) { + if (off == PERIPH_CLK_SOURCE_EMC) + continue; + *ctx++ = clk_readl(off); + } + + off = RST_DEVICES; + for (i = 0; i < RST_DEVICES_NUM; i++, off += 4) + *ctx++ = clk_readl(off); + + off = CLK_OUT_ENB; + for (i = 0; i < CLK_OUT_ENB_NUM; i++, off += 4) + *ctx++ = clk_readl(off); + + *ctx++ = clk_readl(MISC_CLK_ENB); + *ctx++ = clk_readl(CLK_MASK_ARM); +} + +void tegra_clk_resume(void) +{ + unsigned long off, i; + const u32 *ctx = clk_rst_suspend; + u32 val; + + val = clk_readl(OSC_CTRL) & ~OSC_CTRL_MASK; + val |= *ctx++; + clk_writel(val, OSC_CTRL); + + /* enable all clocks before configuring clock sources */ + clk_writel(0xbffffff9ul, CLK_OUT_ENB); + clk_writel(0xfefffff7ul, CLK_OUT_ENB + 4); + clk_writel(0x77f01bfful, CLK_OUT_ENB + 8); + wmb(); + + for (off = PERIPH_CLK_SOURCE_I2S1; off <= PERIPH_CLK_SOURCE_OSC; + off += 4) { + if (off == PERIPH_CLK_SOURCE_EMC) + continue; + clk_writel(*ctx++, off); + } + wmb(); + + off = RST_DEVICES; + for (i = 0; i < RST_DEVICES_NUM; i++, off += 4) + clk_writel(*ctx++, off); + wmb(); + + off = CLK_OUT_ENB; + for (i = 0; i < CLK_OUT_ENB_NUM; i++, off += 4) + clk_writel(*ctx++, off); + wmb(); + + clk_writel(*ctx++, MISC_CLK_ENB); + clk_writel(*ctx++, CLK_MASK_ARM); } +#endif |