summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/tegra3_clocks.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-tegra/tegra3_clocks.c')
-rw-r--r--arch/arm/mach-tegra/tegra3_clocks.c301
1 files changed, 281 insertions, 20 deletions
diff --git a/arch/arm/mach-tegra/tegra3_clocks.c b/arch/arm/mach-tegra/tegra3_clocks.c
index 262b7a5cedad..110c8d4e601c 100644
--- a/arch/arm/mach-tegra/tegra3_clocks.c
+++ b/arch/arm/mach-tegra/tegra3_clocks.c
@@ -1,7 +1,7 @@
/*
* arch/arm/mach-tegra/tegra3_clocks.c
*
- * Copyright (C) 2010-2012 NVIDIA Corporation
+ * Copyright (C) 2010-2012 NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -228,6 +228,14 @@
#define PMC_PLLP_WB0_OVERRIDE 0xf8
#define PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE (1 << 12)
+#define PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE (1 << 11)
+#define PMC_PLLM_WB0_OVERRIDE 0x1dc
+#define PMC_PLLM_WB0_OVERRIDE_DIVP_MASK (0x7<<15)
+#define PMC_PLLM_WB0_OVERRIDE_DIVP_SHIFT 15
+#define PMC_PLLM_WB0_OVERRIDE_DIVN_MASK (0x3FF<<5)
+#define PMC_PLLM_WB0_OVERRIDE_DIVN_SHIFT 5
+#define PMC_PLLM_WB0_OVERRIDE_DIVM_MASK (0x1F)
+#define PMC_PLLM_WB0_OVERRIDE_DIVM_SHIFT 0
#define UTMIP_PLL_CFG2 0x488
#define UTMIP_PLL_CFG2_STABLE_COUNT(x) (((x) & 0xfff) << 6)
@@ -284,7 +292,7 @@
#define PLLE_SS_COEFFICIENTS_12MHZ \
((0x18<<PLLE_SS_INCINTRV_SHIFT) | (0x1<<PLLE_SS_INC_SHIFT) | \
(0x24<<PLLE_SS_MAX_SHIFT))
-#define PLLE_SS_DISABLE ((1<<12) | (1<<11) | (1<<10))
+#define PLLE_SS_DISABLE ((1<<14) | (1<<12) | (1<<11) | (1<<10))
#define PLLE_AUX 0x48c
#define PLLE_AUX_PLLP_SEL (1<<2)
@@ -306,6 +314,8 @@
static void tegra3_pllp_init_dependencies(unsigned long pllp_rate);
static int tegra3_clk_shared_bus_update(struct clk *bus);
+static int tegra3_emc_relock_set_rate(struct clk *emc, unsigned long old_rate,
+ unsigned long new_rate, unsigned long new_pll_rate);
static unsigned long cpu_stay_on_backup_max;
static struct clk *emc_bridge;
@@ -1457,6 +1467,30 @@ static void tegra3_utmi_param_configure(struct clk *c)
clk_writel(reg, UTMIP_PLL_CFG1);
}
+static void tegra3_pll_m_override_update(struct clk *c, bool init)
+{
+ u32 val = pmc_readl(PMC_PLLP_WB0_OVERRIDE);
+
+ if (!(val & PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE))
+ return;
+
+ /* override PLLM state with PMC settings */
+ c->state = (val & PMC_PLLP_WB0_OVERRIDE_PLLM_ENABLE) ? ON : OFF;
+
+ val = pmc_readl(PMC_PLLM_WB0_OVERRIDE);
+ c->mul = (val & PMC_PLLM_WB0_OVERRIDE_DIVN_MASK) >>
+ PMC_PLLM_WB0_OVERRIDE_DIVN_SHIFT;
+ c->div = (val & PMC_PLLM_WB0_OVERRIDE_DIVM_MASK) >>
+ PMC_PLLM_WB0_OVERRIDE_DIVM_SHIFT;
+ c->div *= (0x1 << ((val & PMC_PLLM_WB0_OVERRIDE_DIVP_MASK) >>
+ PMC_PLLM_WB0_OVERRIDE_DIVP_SHIFT));
+
+ /* Save initial override settings in Scratch2 register; will be used by
+ LP0 entry code to restore PLLM boot configuration */
+ if (init)
+ pmc_writel(val, PMC_SCRATCH2);
+}
+
static void tegra3_pll_clk_init(struct clk *c)
{
u32 val = clk_readl(c->reg + PLL_BASE);
@@ -1498,6 +1532,9 @@ static void tegra3_pll_clk_init(struct clk *c)
if (c->flags & PLLU) {
tegra3_utmi_param_configure(c);
}
+
+ if (c->flags & PLLM)
+ tegra3_pll_m_override_update(c, true);
}
static int tegra3_pll_clk_enable(struct clk *c)
@@ -1542,6 +1579,27 @@ static void tegra3_pll_clk_disable(struct clk *c)
}
}
+static int tegra3_pllm_override_rate(
+ struct clk *c, const struct clk_pll_freq_table *sel, u32 p_div)
+{
+ u32 val, old_base;
+
+ old_base = val = pmc_readl(PMC_PLLM_WB0_OVERRIDE);
+
+ /* Keep default CPCON and DCCON in override configuration */
+ val &= ~(PMC_PLLM_WB0_OVERRIDE_DIVM_MASK |
+ PMC_PLLM_WB0_OVERRIDE_DIVN_MASK |
+ PMC_PLLM_WB0_OVERRIDE_DIVP_MASK);
+ val |= (sel->m << PMC_PLLM_WB0_OVERRIDE_DIVM_SHIFT) |
+ (sel->n << PMC_PLLM_WB0_OVERRIDE_DIVN_SHIFT) |
+ (p_div << PMC_PLLM_WB0_OVERRIDE_DIVP_SHIFT);
+
+ if (val != old_base)
+ pmc_writel(val, PMC_PLLM_WB0_OVERRIDE);
+
+ return 0;
+}
+
static int tegra3_pll_clk_set_rate(struct clk *c, unsigned long rate)
{
u32 val, p_div, old_base;
@@ -1561,7 +1619,7 @@ static int tegra3_pll_clk_set_rate(struct clk *c, unsigned long rate)
return ret;
}
- if (c->flags & PLLM) {
+ if ((c->flags & PLLM) && (c->state == ON)) {
if (rate != clk_get_rate_locked(c)) {
pr_err("%s: Can not change memory %s rate in flight\n",
__func__, c->name);
@@ -1643,6 +1701,13 @@ static int tegra3_pll_clk_set_rate(struct clk *c, unsigned long rate)
c->mul = sel->n;
c->div = sel->m * sel->p;
+ if (c->flags & PLLM) {
+ val = pmc_readl(PMC_PLLP_WB0_OVERRIDE);
+ if (val & PMC_PLLP_WB0_OVERRIDE_PLLM_OVERRIDE)
+ return tegra3_pllm_override_rate(
+ c, sel, p_div >> PLL_BASE_DIVP_SHIFT);
+ }
+
old_base = val = clk_readl(c->reg + PLL_BASE);
val &= ~(PLL_BASE_DIVM_MASK | PLL_BASE_DIVN_MASK |
((c->flags & PLLU) ? PLLU_BASE_POST_DIV : PLL_BASE_DIVP_MASK));
@@ -1692,12 +1757,14 @@ static void tegra3_pllp_clk_init(struct clk *c)
tegra3_pllp_init_dependencies(c->u.pll.fixed_rate);
}
+#if defined(CONFIG_PM_SLEEP)
static void tegra3_pllp_clk_resume(struct clk *c)
{
unsigned long rate = c->u.pll.fixed_rate;
tegra3_pll_clk_init(c);
BUG_ON(rate != c->u.pll.fixed_rate);
}
+#endif
static struct clk_ops tegra_pllp_ops = {
.init = tegra3_pllp_clk_init,
@@ -2571,8 +2638,15 @@ static int tegra3_emc_clk_set_rate(struct clk *c, unsigned long rate)
* to achieve requested rate. */
p = tegra_emc_predict_parent(rate, &div_value);
div_value += 2; /* emc has fractional DIV_U71 divider */
+
+ /* No matching rate in emc dfs table */
+ if (IS_ERR(p))
+ return PTR_ERR(p);
+
+ /* Table rate found, but need to relock source pll */
if (!p)
- return -EINVAL;
+ return tegra3_emc_relock_set_rate(c, clk_get_rate_locked(c),
+ rate, rate * (div_value / 2));
if (p == c->parent) {
if (div_value == c->div)
@@ -2775,6 +2849,9 @@ static void tegra3_clk_cbus_init(struct clk *c)
{
c->state = OFF;
c->set = true;
+ c->shared_bus_backup.bus_rate =
+ clk_get_rate(c->shared_bus_backup.input) /
+ c->shared_bus_backup.value;
}
static int tegra3_clk_cbus_enable(struct clk *c)
@@ -3011,7 +3088,8 @@ static int tegra3_clk_shared_bus_update(struct clk *bus)
(c->u.shared_bus_user.mode == SHARED_CEILING)) {
switch (c->u.shared_bus_user.mode) {
case SHARED_BW:
- bw += c->u.shared_bus_user.rate;
+ if (bw < bus->max_rate)
+ bw += c->u.shared_bus_user.rate;
break;
case SHARED_CEILING:
ceiling = min(c->u.shared_bus_user.rate,
@@ -3024,6 +3102,16 @@ static int tegra3_clk_shared_bus_update(struct clk *bus)
}
}
}
+
+ if (bw) {
+ if (bus->flags & PERIPH_EMC_ENB) {
+ bw = tegra_emc_bw_efficiency ?
+ (bw / tegra_emc_bw_efficiency) : bus->max_rate;
+ bw = (bw < bus->max_rate / 100) ?
+ (bw * 100) : bus->max_rate;
+ }
+ bw = clk_round_rate_locked(bus, bw);
+ }
rate = min(max(rate, bw), ceiling);
old_rate = clk_get_rate_locked(bus);
@@ -3072,6 +3160,10 @@ static long tegra_clk_shared_bus_round_rate(struct clk *c, unsigned long rate)
if (c->u.shared_bus_user.mode == SHARED_AUTO)
rate = 0;
+ /* BW users should not be rounded until aggregated */
+ if (c->u.shared_bus_user.mode == SHARED_BW)
+ return rate;
+
return clk_round_rate(c->parent, rate);
}
@@ -3993,7 +4085,7 @@ static struct clk_mux_sel mux_pllm_pllc_pllp_plla[] = {
static struct clk_mux_sel mux_pllm_pllc_pllp_clkm[] = {
{ .input = &tegra_pll_m, .value = 0},
- /* { .input = &tegra_pll_c, .value = 1}, not used on tegra3 */
+ { .input = &tegra_pll_c, .value = 1},
{ .input = &tegra_pll_p, .value = 2},
{ .input = &tegra_clk_m, .value = 3},
{ 0, 0},
@@ -4117,6 +4209,9 @@ static struct clk tegra_clk_emc = {
.u.periph = {
.clk_num = 57,
},
+ .shared_bus_backup = {
+ .input = &tegra_pll_c,
+ },
.rate_change_nh = &emc_rate_change_nh,
};
@@ -4233,6 +4328,7 @@ struct clk tegra_list_clks[] = {
PERIPH_CLK("vcp", "tegra-avp", "vcp", 29, 0, 250000000, mux_clk_m, 0),
PERIPH_CLK("bsea", "tegra-avp", "bsea", 62, 0, 250000000, mux_clk_m, 0),
PERIPH_CLK("bsev", "tegra-aes", "bsev", 63, 0, 250000000, mux_clk_m, 0),
+ PERIPH_CLK("cec", "tegra_cec", NULL, 136, 0, 26000000, mux_clk_m, PERIPH_ON_APB),
PERIPH_CLK("vde", "vde", NULL, 61, 0x1c8, 600000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_INT),
PERIPH_CLK("csite", "csite", NULL, 73, 0x1d4, 144000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71), /* max rate ??? */
PERIPH_CLK("la", "la", NULL, 76, 0x1f8, 26000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71),
@@ -4274,11 +4370,13 @@ struct clk tegra_list_clks[] = {
PERIPH_CLK("tvdac", "tvdac", NULL, 53, 0x194, 220000000, mux_pllp_plld_pllc_clkm, MUX | DIV_U71), /* requires min voltage */
PERIPH_CLK("disp1", "tegradc.0", NULL, 27, 0x138, 600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm, MUX | MUX8),
PERIPH_CLK("disp2", "tegradc.1", NULL, 26, 0x13c, 600000000, mux_pllp_pllm_plld_plla_pllc_plld2_clkm, MUX | MUX8),
- PERIPH_CLK("usbd", "fsl-tegra-udc", NULL, 22, 0, 480000000, mux_clk_m, 0), /* requires min voltage */
+ PERIPH_CLK("usbd", "tegra-udc.0", 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("dsia", "tegradc.0", "dsia", 48, 0, 500000000, mux_plld_out0, 0),
PERIPH_CLK_EX("dsib", "tegradc.1", "dsib", 82, 0xd0, 500000000, mux_plld_out0_plld2_out0, MUX | PLLD, &tegra_dsib_clk_ops),
+ PERIPH_CLK("dsi1-fixed", "tegradc.0", "dsi-fixed", 0, 0, 108000000, mux_pllp_out3, PERIPH_NO_ENB),
+ PERIPH_CLK("dsi2-fixed", "tegradc.1", "dsi-fixed", 0, 0, 108000000, mux_pllp_out3, PERIPH_NO_ENB),
PERIPH_CLK("csi", "tegra_camera", "csi", 52, 0, 102000000, mux_pllp_out3, 0),
PERIPH_CLK("isp", "tegra_camera", "isp", 23, 0, 150000000, mux_clk_m, 0), /* same frequency as VI */
PERIPH_CLK("csus", "tegra_camera", "csus", 92, 0, 150000000, mux_clk_m, PERIPH_NO_RESET),
@@ -4296,7 +4394,7 @@ struct clk tegra_list_clks[] = {
SHARED_CLK("avp.sclk", "tegra-avp", "sclk", &tegra_clk_sbus_cmplx, NULL, 0, 0),
SHARED_CLK("bsea.sclk", "tegra-aes", "sclk", &tegra_clk_sbus_cmplx, NULL, 0, 0),
- SHARED_CLK("usbd.sclk", "fsl-tegra-udc", "sclk", &tegra_clk_sbus_cmplx, NULL, 0, 0),
+ SHARED_CLK("usbd.sclk", "tegra-udc.0", "sclk", &tegra_clk_sbus_cmplx, NULL, 0, 0),
SHARED_CLK("usb1.sclk", "tegra-ehci.0", "sclk", &tegra_clk_sbus_cmplx, NULL, 0, 0),
SHARED_CLK("usb2.sclk", "tegra-ehci.1", "sclk", &tegra_clk_sbus_cmplx, NULL, 0, 0),
SHARED_CLK("usb3.sclk", "tegra-ehci.2", "sclk", &tegra_clk_sbus_cmplx, NULL, 0, 0),
@@ -4316,7 +4414,7 @@ struct clk tegra_list_clks[] = {
SHARED_CLK("disp1.emc", "tegradc.0", "emc", &tegra_clk_emc, NULL, 0, SHARED_BW),
SHARED_CLK("disp2.emc", "tegradc.1", "emc", &tegra_clk_emc, NULL, 0, SHARED_BW),
SHARED_CLK("hdmi.emc", "hdmi", "emc", &tegra_clk_emc, NULL, 0, 0),
- SHARED_CLK("usbd.emc", "fsl-tegra-udc", "emc", &tegra_clk_emc, NULL, 0, 0),
+ SHARED_CLK("usbd.emc", "tegra-udc.0", "emc", &tegra_clk_emc, NULL, 0, 0),
SHARED_CLK("usb1.emc", "tegra-ehci.0", "emc", &tegra_clk_emc, NULL, 0, 0),
SHARED_CLK("usb2.emc", "tegra-ehci.1", "emc", &tegra_clk_emc, NULL, 0, 0),
SHARED_CLK("usb3.emc", "tegra-ehci.2", "emc", &tegra_clk_emc, NULL, 0, 0),
@@ -4325,7 +4423,8 @@ struct clk tegra_list_clks[] = {
SHARED_CLK("3d.emc", "tegra_gr3d", "emc", &tegra_clk_emc, NULL, 0, 0),
SHARED_CLK("2d.emc", "tegra_gr2d", "emc", &tegra_clk_emc, NULL, 0, 0),
SHARED_CLK("mpe.emc", "tegra_mpe", "emc", &tegra_clk_emc, NULL, 0, 0),
- SHARED_CLK("camera.emc", "tegra_camera", "emc", &tegra_clk_emc, NULL, 0, 0),
+ SHARED_CLK("camera.emc", "tegra_camera", "emc", &tegra_clk_emc, NULL, 0, SHARED_BW),
+ SHARED_CLK("sdmmc4.emc", "sdhci-tegra.3", "emc", &tegra_clk_emc, NULL, 0, 0),
SHARED_CLK("floor.emc", "floor.emc", NULL, &tegra_clk_emc, NULL, 0, 0),
SHARED_CLK("host1x.cbus", "tegra_host1x", "host1x", &tegra_clk_cbus, "host1x", 2, SHARED_AUTO),
@@ -4391,6 +4490,7 @@ struct clk_duplicate tegra_clk_duplicates[] = {
CLK_DUPLICATE("avp.sclk", "nvavp", "sclk"),
CLK_DUPLICATE("avp.emc", "nvavp", "emc"),
CLK_DUPLICATE("vde.cbus", "nvavp", "vde"),
+ CLK_DUPLICATE("epp.cbus", "tegra_isp", "epp"),
};
struct clk *tegra_ptr_clks[] = {
@@ -4438,6 +4538,86 @@ struct clk *tegra_ptr_clks[] = {
&tegra_clk_cbus,
};
+static int tegra3_emc_relock_set_rate(struct clk *emc, unsigned long old_rate,
+ unsigned long new_rate, unsigned long new_pll_rate)
+{
+ int ret;
+
+ struct clk *sbus = &tegra_clk_sbus_cmplx;
+ struct clk *cbus = &tegra_clk_cbus;
+ struct clk *pll_m = &tegra_pll_m;
+ unsigned long backup_rate = emc->shared_bus_backup.bus_rate;
+ unsigned long flags;
+
+ bool on_pllm = emc->parent == pll_m;
+
+ /*
+ * Relock procedure pre-conditions:
+ * - LPDDR2 only
+ * - EMC clock is enabled, and EMC backup rate is found in DFS table
+ * - All 3 shared buses: emc, sbus, cbus can sleep
+ */
+ if ((tegra_emc_get_dram_type() != DRAM_TYPE_LPDDR2) || !emc->refcnt ||
+ !backup_rate || (cbus->parent != emc->shared_bus_backup.input) ||
+ !clk_cansleep(emc) || !clk_cansleep(cbus) || !clk_cansleep(sbus))
+ return -ENOSYS;
+
+ /* Move sbus from PLLM by setting it at low rate threshold level */
+ clk_lock_save(sbus, &flags);
+ if (clk_get_rate_locked(sbus) > sbus->u.system.threshold) {
+ ret = clk_set_rate_locked(sbus, sbus->u.system.threshold);
+ if (ret)
+ goto _sbus_out;
+ }
+
+ /* If PLLM is current EMC parent set cbus to backup rate, and move EMC
+ to backup PLLC */
+ if (on_pllm) {
+ clk_lock_save(cbus, &flags);
+ clk_enable(cbus->parent);
+ ret = clk_set_rate_locked(cbus, backup_rate);
+ if (ret) {
+ clk_disable(cbus->parent);
+ goto _cbus_out;
+ }
+
+ ret = tegra_emc_backup(backup_rate);
+ if (ret) {
+ clk_disable(cbus->parent);
+ goto _cbus_out;
+ }
+ clk_disable(emc->parent);
+ clk_reparent(emc, cbus->parent);
+ }
+
+ /*
+ * Re-lock PLLM and switch EMC to it; relocking error indicates that
+ * PLLM has some other than EMC or sbus client. In this case PLLM has
+ * not been changed, and we still can safely switch back. Recursive
+ * tegra3_emc_clk_set_rate() call below will be resolved, since PLLM
+ * is now matching target rate.
+ */
+ ret = clk_set_rate(pll_m, new_pll_rate);
+ if (ret) {
+ if (on_pllm)
+ tegra3_emc_clk_set_rate(emc, old_rate);
+ } else
+ ret = tegra3_emc_clk_set_rate(emc, new_rate);
+
+
+_cbus_out:
+ if (on_pllm) {
+ tegra3_clk_shared_bus_update(cbus);
+ clk_unlock_restore(cbus, &flags);
+ }
+
+_sbus_out:
+ tegra3_clk_shared_bus_update(sbus);
+ clk_unlock_restore(sbus, &flags);
+
+ return ret;
+}
+
/*
* Backup rate targets for each CPU mode is selected below Fmax(Vmin), and
* high enough to avoid voltage droop when CPU clock is switched between
@@ -4620,13 +4800,14 @@ static struct cpufreq_frequency_table freq_table_1p7GHz[] = {
{ 5, 620000 },
{ 6, 760000 },
{ 7, 910000 },
- { 8, 1150000 },
- { 9, 1300000 },
- {10, 1400000 },
- {11, 1500000 },
- {12, 1600000 },
- {13, 1700000 },
- {14, CPUFREQ_TABLE_END },
+ { 8, 1000000 },
+ { 9, 1150000 },
+ {10, 1300000 },
+ {11, 1400000 },
+ {12, 1500000 },
+ {13, 1600000 },
+ {14, 1700000 },
+ {15, CPUFREQ_TABLE_END },
};
static struct tegra_cpufreq_table_data cpufreq_tables[] = {
@@ -4727,10 +4908,10 @@ unsigned long tegra_emc_to_cpu_ratio(unsigned long cpu_rate)
/* Vote on memory bus frequency based on cpu frequency;
cpu rate is in kHz, emc rate is in Hz */
- if (cpu_rate >= 750000)
- return emc_max_rate; /* cpu >= 750 MHz, emc max */
+ if (cpu_rate >= 925000)
+ return emc_max_rate; /* cpu >= 925 MHz, emc max */
else if (cpu_rate >= 450000)
- return emc_max_rate/2; /* cpu >= 500 MHz, emc max/2 */
+ return emc_max_rate/2; /* cpu >= 450 MHz, emc max/2 */
else if (cpu_rate >= 250000)
return 100000000; /* cpu >= 250 MHz, emc 100 MHz */
else
@@ -4963,6 +5144,7 @@ static void tegra_clk_resume(void)
/* Since EMC clock is not restored, and may not preserve parent across
suspend, update current state, and mark EMC DFS as out of sync */
+ tegra3_pll_m_override_update(&tegra_pll_m, false);
p = tegra_clk_emc.parent;
tegra3_periph_clk_init(&tegra_clk_emc);
@@ -5003,9 +5185,17 @@ static struct syscore_ops tegra_clk_syscore_ops = {
#define CLK_RSTENB_DEV_V_0_DAM1_BIT (1 << 13)
#define CLK_RSTENB_DEV_V_0_DAM0_BIT (1 << 12)
#define CLK_RSTENB_DEV_V_0_AUDIO_BIT (1 << 10)
+#define CLK_RSTENB_DEV_V_0_3D2_BIT (1 << 2)
#define CLK_RSTENB_DEV_L_0_HOST1X_BIT (1 << 28)
#define CLK_RSTENB_DEV_L_0_DISP1_BIT (1 << 27)
+#define CLK_RSTENB_DEV_L_0_3D_BIT (1 << 24)
+#define CLK_RSTENB_DEV_L_0_2D_BIT (1 << 21)
+#define CLK_RSTENB_DEV_L_0_VI_BIT (1 << 20)
+#define CLK_RSTENB_DEV_L_0_EPP_BIT (1 << 19)
+
+#define CLK_RSTENB_DEV_H_0_VDE_BIT (1 << 29)
+#define CLK_RSTENB_DEV_H_0_MPE_BIT (1 << 28)
#define DISP1_CLK_REG_OFFSET 0x138
#define DISP1_CLK_SRC_SHIFT 29
@@ -5052,6 +5242,31 @@ static struct syscore_ops tegra_clk_syscore_ops = {
#define AUDIO_CLK_DIV_DEFAULT (\
(0 << AUDIO_CLK_DIV_SHIFT))
+#define VCLK_SRC_SHIFT 30
+#define VCLK_SRC_MASK (0x3 << VCLK_SRC_SHIFT)
+#define VCLK_SRC_PLLM_OUT0 0
+#define VCLK_SRC_PLLC_OUT0 1
+#define VCLK_SRC_PLLP_OUT0 2
+#define VCLK_SRC_PLLA_OUT0 3
+#define VCLK_SRC_DEFAULT (VCLK_SRC_PLLM_OUT0 << VCLK_SRC_SHIFT)
+#define VCLK_IDLE_DIV_SHIFT 8
+#define VCLK_IDLE_DIV_MASK (0xff << VCLK_IDLE_DIV_SHIFT)
+#define VCLK_IDLE_DIV_DEFAULT (0 << VCLK_IDLE_DIV_SHIFT)
+#define VCLK_DIV_SHIFT 0
+#define VCLK_DIV_MASK (0xff << VCLK_DIV_SHIFT)
+#define VCLK_DIV_DEFAULT (0xa << VCLK_DIV_SHIFT)
+
+#define VI_CLK_REG_OFFSET 0x148
+#define VI_CLK_SEL_VI_SENSOR_CLK (1 << 25)
+#define VI_CLK_SEL_EXTERNAL_CLK (1 << 24)
+#define VI_SENSOR_CLK_REG_OFFSET 0x1a8
+#define G3D_CLK_REG_OFFSET 0x158
+#define G2D_CLK_REG_OFFSET 0x15c
+#define EPP_CLK_REG_OFFSET 0x16c
+#define MPE_CLK_REG_OFFSET 0x170
+#define VDE_CLK_REG_OFFSET 0x170
+#define G3D2_CLK_REG_OFFSET 0x3b0
+
static void __init clk_setbit(u32 reg, u32 bit)
{
u32 val = clk_readl(reg);
@@ -5086,6 +5301,43 @@ static void __init clk_setbits(u32 reg, u32 bits, u32 mask)
udelay(2);
}
+static void __init vclk_init(int tag, u32 src, u32 rebit)
+{
+ u32 rst, enb;
+
+ switch (tag) {
+ case 'L':
+ rst = RST_DEVICES_L;
+ enb = CLK_OUT_ENB_L;
+ break;
+ case 'H':
+ rst = RST_DEVICES_H;
+ enb = CLK_OUT_ENB_H;
+ break;
+ case 'U':
+ rst = RST_DEVICES_U;
+ enb = CLK_OUT_ENB_U;
+ break;
+ case 'V':
+ rst = RST_DEVICES_V;
+ enb = CLK_OUT_ENB_V;
+ break;
+ case 'W':
+ rst = RST_DEVICES_W;
+ enb = CLK_OUT_ENB_W;
+ break;
+ default:
+ /* Quietly ignore. */
+ return;
+ }
+
+ clk_setbit(rst, rebit);
+ clk_clrbit(enb, rebit);
+ clk_setbits(src, VCLK_SRC_DEFAULT, VCLK_SRC_MASK);
+ clk_setbits(src, VCLK_DIV_DEFAULT, VCLK_DIV_MASK);
+ clk_clrbit(rst, rebit);
+}
+
static int __init tegra_soc_preinit_clocks(void)
{
/*
@@ -5161,6 +5413,15 @@ static int __init tegra_soc_preinit_clocks(void)
AUDIO_CLK_SRC_DEFAULT, AUDIO_CLK_SRC_MASK);
clk_clrbit(RST_DEVICES_V, CLK_RSTENB_DEV_V_0_AUDIO_BIT);
+ /* Pre-initialize Video clocks. */
+ vclk_init('L', G3D_CLK_REG_OFFSET, CLK_RSTENB_DEV_L_0_3D_BIT);
+ vclk_init('L', G2D_CLK_REG_OFFSET, CLK_RSTENB_DEV_L_0_2D_BIT);
+ vclk_init('L', VI_CLK_REG_OFFSET, CLK_RSTENB_DEV_L_0_VI_BIT);
+ vclk_init('L', EPP_CLK_REG_OFFSET, CLK_RSTENB_DEV_L_0_EPP_BIT);
+ vclk_init('H', VDE_CLK_REG_OFFSET, CLK_RSTENB_DEV_H_0_VDE_BIT);
+ vclk_init('H', MPE_CLK_REG_OFFSET, CLK_RSTENB_DEV_H_0_MPE_BIT);
+ vclk_init('V', G3D2_CLK_REG_OFFSET, CLK_RSTENB_DEV_V_0_3D2_BIT);
+
return 0;
}
#endif /* CONFIG_TEGRA_PREINIT_CLOCKS */