diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-tegra/clock.h | 3 | ||||
-rw-r--r-- | arch/arm/mach-tegra/tegra3_clocks.c | 89 |
2 files changed, 66 insertions, 26 deletions
diff --git a/arch/arm/mach-tegra/clock.h b/arch/arm/mach-tegra/clock.h index 3f159ced1103..25ba88bc4893 100644 --- a/arch/arm/mach-tegra/clock.h +++ b/arch/arm/mach-tegra/clock.h @@ -48,11 +48,12 @@ #define PLLX (1 << 15) #define MUX_PWM (1 << 16) #define MUX8 (1 << 17) -#define DIV_U71_UART (1 << 18) +#define DIV_U151_UART (1 << 18) #define MUX_CLK_OUT (1 << 19) #define PLLM (1 << 20) #define DIV_U71_INT (1 << 21) #define DIV_U71_IDLE (1 << 22) +#define DIV_U151 (1 << 23) #define ENABLE_ON_INIT (1 << 28) #define PERIPH_ON_APB (1 << 29) #define PERIPH_ON_CBUS (1 << 30) diff --git a/arch/arm/mach-tegra/tegra3_clocks.c b/arch/arm/mach-tegra/tegra3_clocks.c index 743e8eeeabc4..39a1712c7225 100644 --- a/arch/arm/mach-tegra/tegra3_clocks.c +++ b/arch/arm/mach-tegra/tegra3_clocks.c @@ -414,28 +414,44 @@ unsigned long clk_measure_input_freq(void) } } -static int clk_div71_get_divider(unsigned long parent_rate, unsigned long rate, - u32 flags, u32 round_mode) +static int clk_div_x1_get_divider(unsigned long parent_rate, unsigned long rate, + u32 max_x, u32 flags, u32 round_mode) { - s64 divider_u71 = parent_rate; + s64 divider_ux1 = parent_rate; if (!rate) return -EINVAL; if (!(flags & DIV_U71_INT)) - divider_u71 *= 2; + divider_ux1 *= 2; + if (round_mode == ROUND_DIVIDER_UP) - divider_u71 += rate - 1; - do_div(divider_u71, rate); + divider_ux1 += rate - 1; + do_div(divider_ux1, rate); + if (flags & DIV_U71_INT) - divider_u71 *= 2; + divider_ux1 *= 2; - if (divider_u71 - 2 < 0) + if (divider_ux1 - 2 < 0) return 0; - if (divider_u71 - 2 > 255) + if (divider_ux1 - 2 > max_x) return -EINVAL; - return divider_u71 - 2; + return divider_ux1 - 2; +} + +static int clk_div71_get_divider(unsigned long parent_rate, unsigned long rate, + u32 flags, u32 round_mode) +{ + return clk_div_x1_get_divider(parent_rate, rate, 0xFF, + flags, round_mode); +} + +static int clk_div151_get_divider(unsigned long parent_rate, unsigned long rate, + u32 flags, u32 round_mode) +{ + return clk_div_x1_get_divider(parent_rate, rate, 0xFFFF, + flags, round_mode); } static int clk_div16_get_divider(unsigned long parent_rate, unsigned long rate) @@ -1947,10 +1963,6 @@ static void tegra3_periph_clk_init(struct clk *c) if (c->flags & DIV_U71) { u32 divu71 = val & PERIPH_CLK_SOURCE_DIVU71_MASK; - if ((c->flags & DIV_U71_UART) && - (!(val & PERIPH_CLK_UART_DIV_ENB))) { - divu71 = 0; - } if (c->flags & DIV_U71_IDLE) { val &= ~(PERIPH_CLK_SOURCE_DIVU71_MASK << PERIPH_CLK_SOURCE_DIVIDLE_SHIFT); @@ -1960,6 +1972,14 @@ static void tegra3_periph_clk_init(struct clk *c) } c->div = divu71 + 2; c->mul = 2; + } else if (c->flags & DIV_U151) { + u32 divu151 = val & PERIPH_CLK_SOURCE_DIVU16_MASK; + if ((c->flags & DIV_U151_UART) && + (!(val & PERIPH_CLK_UART_DIV_ENB))) { + divu151 = 0; + } + c->div = divu151 + 2; + c->mul = 2; } else if (c->flags & DIV_U16) { u32 divu16 = val & PERIPH_CLK_SOURCE_DIVU16_MASK; c->div = divu16 + 1; @@ -2085,7 +2105,19 @@ static int tegra3_periph_clk_set_rate(struct clk *c, unsigned long rate) val = clk_readl(c->reg); val &= ~PERIPH_CLK_SOURCE_DIVU71_MASK; val |= divider; - if (c->flags & DIV_U71_UART) { + clk_writel_delay(val, c->reg); + c->div = divider + 2; + c->mul = 2; + return 0; + } + } else if (c->flags & DIV_U151) { + divider = clk_div151_get_divider( + parent_rate, rate, c->flags, ROUND_DIVIDER_UP); + if (divider >= 0) { + val = clk_readl(c->reg); + val &= ~PERIPH_CLK_SOURCE_DIVU16_MASK; + val |= divider; + if (c->flags & DIV_U151_UART) { if (divider) val |= PERIPH_CLK_UART_DIV_ENB; else @@ -2129,6 +2161,13 @@ static long tegra3_periph_clk_round_rate(struct clk *c, return divider; return DIV_ROUND_UP(parent_rate * 2, divider + 2); + } else if (c->flags & DIV_U151) { + divider = clk_div151_get_divider( + parent_rate, rate, c->flags, ROUND_DIVIDER_UP); + if (divider < 0) + return divider; + + return DIV_ROUND_UP(parent_rate * 2, divider + 2); } else if (c->flags & DIV_U16) { divider = clk_div16_get_divider(parent_rate, rate); if (divider < 0) @@ -4046,16 +4085,16 @@ struct clk tegra_list_clks[] = { PERIPH_CLK("i2c3", "tegra-i2c.2", NULL, 67, 0x1b8, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB), PERIPH_CLK("i2c4", "tegra-i2c.3", NULL, 103, 0x3c4, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB), PERIPH_CLK("i2c5", "tegra-i2c.4", NULL, 47, 0x128, 26000000, mux_pllp_clkm, MUX | DIV_U16 | PERIPH_ON_APB), - PERIPH_CLK("uarta", "tegra_uart.0", NULL, 6, 0x178, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB), - PERIPH_CLK("uartb", "tegra_uart.1", NULL, 7, 0x17c, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB), - PERIPH_CLK("uartc", "tegra_uart.2", NULL, 55, 0x1a0, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB), - PERIPH_CLK("uartd", "tegra_uart.3", NULL, 65, 0x1c0, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB), - PERIPH_CLK("uarte", "tegra_uart.4", NULL, 66, 0x1c4, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB), - PERIPH_CLK("uarta_dbg", "serial8250.0", "uarta",6, 0x178, 800000000, mux_pllp_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB), - PERIPH_CLK("uartb_dbg", "serial8250.0", "uartb",7, 0x17c, 800000000, mux_pllp_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB), - PERIPH_CLK("uartc_dbg", "serial8250.0", "uartc",55, 0x1a0, 800000000, mux_pllp_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB), - PERIPH_CLK("uartd_dbg", "serial8250.0", "uartd",65, 0x1c0, 800000000, mux_pllp_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB), - PERIPH_CLK("uarte_dbg", "serial8250.0", "uarte",66, 0x1c4, 800000000, mux_pllp_clkm, MUX | DIV_U71 | DIV_U71_UART | PERIPH_ON_APB), + PERIPH_CLK("uarta", "tegra_uart.0", NULL, 6, 0x178, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U151 | DIV_U151_UART | PERIPH_ON_APB), + PERIPH_CLK("uartb", "tegra_uart.1", NULL, 7, 0x17c, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U151 | DIV_U151_UART | PERIPH_ON_APB), + PERIPH_CLK("uartc", "tegra_uart.2", NULL, 55, 0x1a0, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U151 | DIV_U151_UART | PERIPH_ON_APB), + PERIPH_CLK("uartd", "tegra_uart.3", NULL, 65, 0x1c0, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U151 | DIV_U151_UART | PERIPH_ON_APB), + PERIPH_CLK("uarte", "tegra_uart.4", NULL, 66, 0x1c4, 800000000, mux_pllp_pllc_pllm_clkm, MUX | DIV_U151 | DIV_U151_UART | PERIPH_ON_APB), + PERIPH_CLK("uarta_dbg", "serial8250.0", "uarta",6, 0x178, 800000000, mux_pllp_clkm, MUX | DIV_U151 | DIV_U151_UART | PERIPH_ON_APB), + PERIPH_CLK("uartb_dbg", "serial8250.0", "uartb",7, 0x17c, 800000000, mux_pllp_clkm, MUX | DIV_U151 | DIV_U151_UART | PERIPH_ON_APB), + PERIPH_CLK("uartc_dbg", "serial8250.0", "uartc",55, 0x1a0, 800000000, mux_pllp_clkm, MUX | DIV_U151 | DIV_U151_UART | PERIPH_ON_APB), + PERIPH_CLK("uartd_dbg", "serial8250.0", "uartd",65, 0x1c0, 800000000, mux_pllp_clkm, MUX | DIV_U151 | DIV_U151_UART | PERIPH_ON_APB), + PERIPH_CLK("uarte_dbg", "serial8250.0", "uarte",66, 0x1c4, 800000000, mux_pllp_clkm, MUX | DIV_U151 | DIV_U151_UART | PERIPH_ON_APB), PERIPH_CLK_EX("vi", "tegra_camera", "vi", 20, 0x148, 425000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT, &tegra_vi_clk_ops), PERIPH_CLK("3d", "3d", NULL, 24, 0x158, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET), PERIPH_CLK("3d2", "3d2", NULL, 98, 0x3b0, 520000000, mux_pllm_pllc_pllp_plla, MUX | DIV_U71 | DIV_U71_INT | DIV_U71_IDLE | PERIPH_MANUAL_RESET), |