diff options
Diffstat (limited to 'arch/arm/mach-tegra/tegra3_clocks.c')
-rw-r--r-- | arch/arm/mach-tegra/tegra3_clocks.c | 301 |
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 */ |