diff options
Diffstat (limited to 'arch/arm/mach-tegra/tegra30/clock.c')
-rw-r--r-- | arch/arm/mach-tegra/tegra30/clock.c | 90 |
1 files changed, 84 insertions, 6 deletions
diff --git a/arch/arm/mach-tegra/tegra30/clock.c b/arch/arm/mach-tegra/tegra30/clock.c index 449b66e3b2..1dc9d09dba 100644 --- a/arch/arm/mach-tegra/tegra30/clock.c +++ b/arch/arm/mach-tegra/tegra30/clock.c @@ -19,6 +19,8 @@ #include <fdtdec.h> #include <linux/delay.h> +#include <dt-bindings/clock/tegra30-car.h> + /* * Clock types that we can use as a source. The Tegra30 has muxes for the * peripheral clocks, and in most cases there are four options for the clock @@ -377,9 +379,9 @@ static s8 periph_id_to_internal_id[PERIPH_ID_COUNT] = { PERIPHC_ACTMON, /* 24 */ - NONE(RESERVED24), - NONE(RESERVED25), - NONE(RESERVED26), + PERIPHC_EXTPERIPH1, + PERIPHC_EXTPERIPH2, + PERIPHC_EXTPERIPH3, NONE(RESERVED27), PERIPHC_SATA, PERIPHC_HDA, @@ -628,11 +630,87 @@ enum periph_id clk_id_to_periph_id(int clk_id) return clk_id; } } + +/* + * Convert a device tree clock ID to our PLL ID. + * + * @param clk_id Clock ID according to tegra30 device tree binding + * Return: clock ID, or CLOCK_ID_NONE if the clock ID is invalid + */ +enum clock_id clk_id_to_pll_id(int clk_id) +{ + switch (clk_id) { + case TEGRA30_CLK_PLL_C: + return CLOCK_ID_CGENERAL; + case TEGRA30_CLK_PLL_M: + return CLOCK_ID_MEMORY; + case TEGRA30_CLK_PLL_P: + return CLOCK_ID_PERIPH; + case TEGRA30_CLK_PLL_A: + return CLOCK_ID_AUDIO; + case TEGRA30_CLK_PLL_U: + return CLOCK_ID_USB; + case TEGRA30_CLK_PLL_D: + case TEGRA30_CLK_PLL_D_OUT0: + return CLOCK_ID_DISPLAY; + case TEGRA30_CLK_PLL_X: + return CLOCK_ID_XCPU; + case TEGRA30_CLK_PLL_E: + return CLOCK_ID_EPCI; + case TEGRA30_CLK_CLK_32K: + return CLOCK_ID_32KHZ; + case TEGRA30_CLK_CLK_M: + return CLOCK_ID_CLK_M; + default: + return CLOCK_ID_NONE; + } +} #endif /* CONFIG_IS_ENABLED(OF_CONTROL) */ void clock_early_init(void) { + struct clk_rst_ctlr *clkrst = + (struct clk_rst_ctlr *)NV_PA_CLK_RST_BASE; + struct clk_pll_info *pllinfo; + u32 data; + tegra30_set_up_pllp(); + + /* + * PLLD output frequency set to 925Mhz + */ + switch (clock_get_osc_freq()) { + case CLOCK_OSC_FREQ_12_0: /* OSC is 12Mhz */ + case CLOCK_OSC_FREQ_48_0: /* OSC is 48Mhz */ + clock_set_rate(CLOCK_ID_DISPLAY, 925, 12, 0, 12); + break; + + case CLOCK_OSC_FREQ_26_0: /* OSC is 26Mhz */ + clock_set_rate(CLOCK_ID_DISPLAY, 925, 26, 0, 12); + break; + + case CLOCK_OSC_FREQ_13_0: /* OSC is 13Mhz */ + case CLOCK_OSC_FREQ_16_8: /* OSC is 16.8Mhz */ + clock_set_rate(CLOCK_ID_DISPLAY, 925, 13, 0, 12); + break; + + case CLOCK_OSC_FREQ_19_2: + case CLOCK_OSC_FREQ_38_4: + default: + /* + * These are not supported. It is too early to print a + * message and the UART likely won't work anyway due to the + * oscillator being wrong. + */ + break; + } + + /* PLLD_MISC: Set CLKENABLE, CPCON 12, LFCON 1, and enable lock */ + pllinfo = &tegra_pll_info_table[CLOCK_ID_DISPLAY]; + data = (12 << pllinfo->kcp_shift) | (1 << pllinfo->kvco_shift); + data |= (1 << PLLD_CLKENABLE) | (1 << pllinfo->lock_ena); + writel(data, &clkrst->crc_pll[CLOCK_ID_DISPLAY].pll_misc); + udelay(2); } void arch_timer_init(void) @@ -799,14 +877,14 @@ struct periph_clk_init periph_clk_init_table[] = { { PERIPH_ID_SBC4, CLOCK_ID_PERIPH }, { PERIPH_ID_SBC5, CLOCK_ID_PERIPH }, { PERIPH_ID_SBC6, CLOCK_ID_PERIPH }, - { PERIPH_ID_HOST1X, CLOCK_ID_PERIPH }, - { PERIPH_ID_DISP1, CLOCK_ID_CGENERAL }, + { PERIPH_ID_HOST1X, CLOCK_ID_CGENERAL }, + { PERIPH_ID_DISP1, CLOCK_ID_PERIPH }, { PERIPH_ID_NDFLASH, CLOCK_ID_PERIPH }, { PERIPH_ID_SDMMC1, CLOCK_ID_PERIPH }, { PERIPH_ID_SDMMC2, CLOCK_ID_PERIPH }, { PERIPH_ID_SDMMC3, CLOCK_ID_PERIPH }, { PERIPH_ID_SDMMC4, CLOCK_ID_PERIPH }, - { PERIPH_ID_PWM, CLOCK_ID_SFROM32KHZ }, + { PERIPH_ID_PWM, CLOCK_ID_PERIPH }, { PERIPH_ID_DVC_I2C, CLOCK_ID_PERIPH }, { PERIPH_ID_I2C1, CLOCK_ID_PERIPH }, { PERIPH_ID_I2C2, CLOCK_ID_PERIPH }, |