diff options
Diffstat (limited to 'drivers/clk/tegra/clk-tegra124.c')
-rw-r--r-- | drivers/clk/tegra/clk-tegra124.c | 168 |
1 files changed, 139 insertions, 29 deletions
diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c index f5f9baca7bb6..9a893f2fe8e9 100644 --- a/drivers/clk/tegra/clk-tegra124.c +++ b/drivers/clk/tegra/clk-tegra124.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2012-2014 NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -28,6 +28,14 @@ #include "clk.h" #include "clk-id.h" +/* + * TEGRA124_CAR_BANK_COUNT: the number of peripheral clock register + * banks present in the Tegra124/132 CAR IP block. The banks are + * identified by single letters, e.g.: L, H, U, V, W, X. See + * periph_regs[] in drivers/clk/tegra/clk.c + */ +#define TEGRA124_CAR_BANK_COUNT 6 + #define CLK_SOURCE_CSITE 0x1d4 #define CLK_SOURCE_EMC 0x19c @@ -128,7 +136,6 @@ static unsigned long osc_freq; static unsigned long pll_ref_freq; static DEFINE_SPINLOCK(pll_d_lock); -static DEFINE_SPINLOCK(pll_d2_lock); static DEFINE_SPINLOCK(pll_e_lock); static DEFINE_SPINLOCK(pll_re_lock); static DEFINE_SPINLOCK(pll_u_lock); @@ -145,11 +152,6 @@ static unsigned long tegra124_input_freq[] = { [12] = 260000000, }; -static const char *mux_plld_out0_plld2_out0[] = { - "pll_d_out0", "pll_d2_out0", -}; -#define mux_plld_out0_plld2_out0_idx NULL - static const char *mux_pllmcp_clkm[] = { "pll_m", "pll_c", "pll_p", "clk_m", "pll_m_ud", "pll_c2", "pll_c3", }; @@ -783,7 +785,6 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = { [tegra_clk_sbc2] = { .dt_id = TEGRA124_CLK_SBC2, .present = true }, [tegra_clk_sbc3] = { .dt_id = TEGRA124_CLK_SBC3, .present = true }, [tegra_clk_i2c5] = { .dt_id = TEGRA124_CLK_I2C5, .present = true }, - [tegra_clk_dsia] = { .dt_id = TEGRA124_CLK_DSIA, .present = true }, [tegra_clk_mipi] = { .dt_id = TEGRA124_CLK_MIPI, .present = true }, [tegra_clk_hdmi] = { .dt_id = TEGRA124_CLK_HDMI, .present = true }, [tegra_clk_csi] = { .dt_id = TEGRA124_CLK_CSI, .present = true }, @@ -809,7 +810,6 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = { [tegra_clk_soc_therm] = { .dt_id = TEGRA124_CLK_SOC_THERM, .present = true }, [tegra_clk_dtv] = { .dt_id = TEGRA124_CLK_DTV, .present = true }, [tegra_clk_i2cslow] = { .dt_id = TEGRA124_CLK_I2CSLOW, .present = true }, - [tegra_clk_dsib] = { .dt_id = TEGRA124_CLK_DSIB, .present = true }, [tegra_clk_tsec] = { .dt_id = TEGRA124_CLK_TSEC, .present = true }, [tegra_clk_xusb_host] = { .dt_id = TEGRA124_CLK_XUSB_HOST, .present = true }, [tegra_clk_msenc] = { .dt_id = TEGRA124_CLK_MSENC, .present = true }, @@ -949,8 +949,6 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = { [tegra_clk_clk_out_1_mux] = { .dt_id = TEGRA124_CLK_CLK_OUT_1_MUX, .present = true }, [tegra_clk_clk_out_2_mux] = { .dt_id = TEGRA124_CLK_CLK_OUT_2_MUX, .present = true }, [tegra_clk_clk_out_3_mux] = { .dt_id = TEGRA124_CLK_CLK_OUT_3_MUX, .present = true }, - [tegra_clk_dsia_mux] = { .dt_id = TEGRA124_CLK_DSIA_MUX, .present = true }, - [tegra_clk_dsib_mux] = { .dt_id = TEGRA124_CLK_DSIB_MUX, .present = true }, }; static struct tegra_devclk devclks[] __initdata = { @@ -1112,17 +1110,17 @@ static __init void tegra124_periph_clk_init(void __iomem *clk_base, 1, 2); clks[TEGRA124_CLK_XUSB_SS_DIV2] = clk; - /* dsia mux */ - clk = clk_register_mux(NULL, "dsia_mux", mux_plld_out0_plld2_out0, - ARRAY_SIZE(mux_plld_out0_plld2_out0), 0, - clk_base + PLLD_BASE, 25, 1, 0, &pll_d_lock); - clks[TEGRA124_CLK_DSIA_MUX] = clk; + clk = clk_register_gate(NULL, "plld_dsi", "plld_out0", 0, + clk_base + PLLD_MISC, 30, 0, &pll_d_lock); + clks[TEGRA124_CLK_PLLD_DSI] = clk; + + clk = tegra_clk_register_periph_gate("dsia", "plld_dsi", 0, clk_base, + 0, 48, periph_clk_enb_refcnt); + clks[TEGRA124_CLK_DSIA] = clk; - /* dsib mux */ - clk = clk_register_mux(NULL, "dsib_mux", mux_plld_out0_plld2_out0, - ARRAY_SIZE(mux_plld_out0_plld2_out0), 0, - clk_base + PLLD2_BASE, 25, 1, 0, &pll_d2_lock); - clks[TEGRA124_CLK_DSIB_MUX] = clk; + clk = tegra_clk_register_periph_gate("dsib", "plld_dsi", 0, clk_base, + 0, 82, periph_clk_enb_refcnt); + clks[TEGRA124_CLK_DSIB] = clk; /* emc mux */ clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm, @@ -1351,7 +1349,7 @@ static const struct of_device_id pmc_match[] __initconst = { {}, }; -static struct tegra_clk_init_table init_table[] __initdata = { +static struct tegra_clk_init_table common_init_table[] __initdata = { {TEGRA124_CLK_UARTA, TEGRA124_CLK_PLL_P, 408000000, 0}, {TEGRA124_CLK_UARTB, TEGRA124_CLK_PLL_P, 408000000, 0}, {TEGRA124_CLK_UARTC, TEGRA124_CLK_PLL_P, 408000000, 0}, @@ -1368,6 +1366,8 @@ static struct tegra_clk_init_table init_table[] __initdata = { {TEGRA124_CLK_I2S4, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0}, {TEGRA124_CLK_VDE, TEGRA124_CLK_PLL_P, 0, 0}, {TEGRA124_CLK_HOST1X, TEGRA124_CLK_PLL_P, 136000000, 1}, + {TEGRA124_CLK_DSIALP, TEGRA124_CLK_PLL_P, 68000000, 0}, + {TEGRA124_CLK_DSIBLP, TEGRA124_CLK_PLL_P, 68000000, 0}, {TEGRA124_CLK_SCLK, TEGRA124_CLK_PLL_P_OUT2, 102000000, 1}, {TEGRA124_CLK_DFLL_SOC, TEGRA124_CLK_PLL_P, 51000000, 1}, {TEGRA124_CLK_DFLL_REF, TEGRA124_CLK_PLL_P, 51000000, 1}, @@ -1385,27 +1385,73 @@ static struct tegra_clk_init_table init_table[] __initdata = { {TEGRA124_CLK_SATA, TEGRA124_CLK_PLL_P, 104000000, 0}, {TEGRA124_CLK_SATA_OOB, TEGRA124_CLK_PLL_P, 204000000, 0}, {TEGRA124_CLK_EMC, TEGRA124_CLK_CLK_MAX, 0, 1}, - {TEGRA124_CLK_CCLK_G, TEGRA124_CLK_CLK_MAX, 0, 1}, {TEGRA124_CLK_MSELECT, TEGRA124_CLK_CLK_MAX, 0, 1}, {TEGRA124_CLK_CSITE, TEGRA124_CLK_CLK_MAX, 0, 1}, {TEGRA124_CLK_TSENSOR, TEGRA124_CLK_CLK_M, 400000, 0}, + /* This MUST be the last entry. */ + {TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0}, +}; + +static struct tegra_clk_init_table tegra124_init_table[] __initdata = { {TEGRA124_CLK_SOC_THERM, TEGRA124_CLK_PLL_P, 51000000, 0}, + {TEGRA124_CLK_CCLK_G, TEGRA124_CLK_CLK_MAX, 0, 1}, + /* This MUST be the last entry. */ + {TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0}, +}; + +/* Tegra132 requires the SOC_THERM clock to remain active */ +static struct tegra_clk_init_table tegra132_init_table[] __initdata = { + {TEGRA124_CLK_SOC_THERM, TEGRA124_CLK_PLL_P, 51000000, 1}, /* This MUST be the last entry. */ {TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0}, }; +/** + * tegra124_clock_apply_init_table - initialize clocks on Tegra124 SoCs + * + * Program an initial clock rate and enable or disable clocks needed + * by the rest of the kernel, for Tegra124 SoCs. It is intended to be + * called by assigning a pointer to it to tegra_clk_apply_init_table - + * this will be called as an arch_initcall. No return value. + */ static void __init tegra124_clock_apply_init_table(void) { - tegra_init_from_table(init_table, clks, TEGRA124_CLK_CLK_MAX); + tegra_init_from_table(common_init_table, clks, TEGRA124_CLK_CLK_MAX); + tegra_init_from_table(tegra124_init_table, clks, TEGRA124_CLK_CLK_MAX); } -static void __init tegra124_clock_init(struct device_node *np) +/** + * tegra132_clock_apply_init_table - initialize clocks on Tegra132 SoCs + * + * Program an initial clock rate and enable or disable clocks needed + * by the rest of the kernel, for Tegra132 SoCs. It is intended to be + * called by assigning a pointer to it to tegra_clk_apply_init_table - + * this will be called as an arch_initcall. No return value. + */ +static void __init tegra132_clock_apply_init_table(void) +{ + tegra_init_from_table(common_init_table, clks, TEGRA124_CLK_CLK_MAX); + tegra_init_from_table(tegra132_init_table, clks, TEGRA124_CLK_CLK_MAX); +} + +/** + * tegra124_132_clock_init_pre - clock initialization preamble for T124/T132 + * @np: struct device_node * of the DT node for the SoC CAR IP block + * + * Register most of the clocks controlled by the CAR IP block, along + * with a few clocks controlled by the PMC IP block. Everything in + * this function should be common to Tegra124 and Tegra132. XXX The + * PMC clock initialization should probably be moved to PMC-specific + * driver code. No return value. + */ +static void __init tegra124_132_clock_init_pre(struct device_node *np) { struct device_node *node; + u32 plld_base; clk_base = of_iomap(np, 0); if (!clk_base) { - pr_err("ioremap tegra124 CAR failed\n"); + pr_err("ioremap tegra124/tegra132 CAR failed\n"); return; } @@ -1423,7 +1469,8 @@ static void __init tegra124_clock_init(struct device_node *np) return; } - clks = tegra_clk_init(clk_base, TEGRA124_CLK_CLK_MAX, 6); + clks = tegra_clk_init(clk_base, TEGRA124_CLK_CLK_MAX, + TEGRA124_CAR_BANK_COUNT); if (!clks) return; @@ -1437,13 +1484,76 @@ static void __init tegra124_clock_init(struct device_node *np) tegra_audio_clk_init(clk_base, pmc_base, tegra124_clks, &pll_a_params); tegra_pmc_clk_init(pmc_base, tegra124_clks); + /* For Tegra124 & Tegra132, PLLD is the only source for DSIA & DSIB */ + plld_base = clk_readl(clk_base + PLLD_BASE); + plld_base &= ~BIT(25); + clk_writel(plld_base, clk_base + PLLD_BASE); +} + +/** + * tegra124_132_clock_init_post - clock initialization postamble for T124/T132 + * @np: struct device_node * of the DT node for the SoC CAR IP block + * + * Register most of the along with a few clocks controlled by the PMC + * IP block. Everything in this function should be common to Tegra124 + * and Tegra132. This function must be called after + * tegra124_132_clock_init_pre(), otherwise clk_base and pmc_base will + * not be set. No return value. + */ +static void __init tegra124_132_clock_init_post(struct device_node *np) +{ tegra_super_clk_gen4_init(clk_base, pmc_base, tegra124_clks, - &pll_x_params); + &pll_x_params); tegra_add_of_provider(np); tegra_register_devclks(devclks, ARRAY_SIZE(devclks)); + tegra_cpu_car_ops = &tegra124_cpu_car_ops; +} + +/** + * tegra124_clock_init - Tegra124-specific clock initialization + * @np: struct device_node * of the DT node for the SoC CAR IP block + * + * Register most SoC clocks for the Tegra124 system-on-chip. Most of + * this code is shared between the Tegra124 and Tegra132 SoCs, + * although some of the initial clock settings and CPU clocks differ. + * Intended to be called by the OF init code when a DT node with the + * "nvidia,tegra124-car" string is encountered, and declared with + * CLK_OF_DECLARE. No return value. + */ +static void __init tegra124_clock_init(struct device_node *np) +{ + tegra124_132_clock_init_pre(np); tegra_clk_apply_init_table = tegra124_clock_apply_init_table; + tegra124_132_clock_init_post(np); +} - tegra_cpu_car_ops = &tegra124_cpu_car_ops; +/** + * tegra132_clock_init - Tegra132-specific clock initialization + * @np: struct device_node * of the DT node for the SoC CAR IP block + * + * Register most SoC clocks for the Tegra132 system-on-chip. Most of + * this code is shared between the Tegra124 and Tegra132 SoCs, + * although some of the initial clock settings and CPU clocks differ. + * Intended to be called by the OF init code when a DT node with the + * "nvidia,tegra132-car" string is encountered, and declared with + * CLK_OF_DECLARE. No return value. + */ +static void __init tegra132_clock_init(struct device_node *np) +{ + tegra124_132_clock_init_pre(np); + + /* + * On Tegra132, these clocks are controlled by the + * CLUSTER_clocks IP block, located in the CPU complex + */ + tegra124_clks[tegra_clk_cclk_g].present = false; + tegra124_clks[tegra_clk_cclk_lp].present = false; + tegra124_clks[tegra_clk_pll_x].present = false; + tegra124_clks[tegra_clk_pll_x_out0].present = false; + + tegra_clk_apply_init_table = tegra132_clock_apply_init_table; + tegra124_132_clock_init_post(np); } CLK_OF_DECLARE(tegra124, "nvidia,tegra124-car", tegra124_clock_init); +CLK_OF_DECLARE(tegra132, "nvidia,tegra132-car", tegra132_clock_init); |