diff --git a/src/soc/nvidia/tegra124/bootblock.c b/src/soc/nvidia/tegra124/bootblock.c index 28d7013dbd..a264a348d3 100644 --- a/src/soc/nvidia/tegra124/bootblock.c +++ b/src/soc/nvidia/tegra124/bootblock.c @@ -30,9 +30,7 @@ void main(void) { void *entry; - clock_init(); - - clock_uart_config(); + clock_early_uart(); // Serial out, tristate off. pinmux_set_config(PINMUX_KB_ROW9_INDEX, PINMUX_KB_ROW9_FUNC_UA3); @@ -44,6 +42,8 @@ void main(void) if (CONFIG_BOOTBLOCK_CONSOLE) console_init(); + clock_init(); + bootblock_mainboard_init(); pinmux_set_config(PINMUX_CORE_PWR_REQ_INDEX, diff --git a/src/soc/nvidia/tegra124/clk_rst.h b/src/soc/nvidia/tegra124/clk_rst.h index 8ced6bf873..7b9c3e8bb6 100644 --- a/src/soc/nvidia/tegra124/clk_rst.h +++ b/src/soc/nvidia/tegra124/clk_rst.h @@ -443,17 +443,19 @@ enum { * get_periph_clock_source()) but it does not seem worth it since the code * already checks the ranges of values it is writing, in clk_get_divider(). */ -#define OUT_CLK_DIVISOR_SHIFT 0 -#define OUT_CLK_DIVISOR_MASK (0xffff << OUT_CLK_DIVISOR_SHIFT) +#define CLK_DIVISOR_SHIFT 0 +#define CLK_DIVISOR_MASK (0xffff << CLK_DIVISOR_SHIFT) -#define OUT_CLK_SOURCE_SHIFT 30 -#define OUT_CLK_SOURCE_MASK (3U << OUT_CLK_SOURCE_SHIFT) +#define CLK_SOURCE_SHIFT 30 +#define CLK_SOURCE_MASK (3U << CLK_SOURCE_SHIFT) -#define OUT_CLK_SOURCE3_SHIFT 29 -#define OUT_CLK_SOURCE3_MASK (7U << OUT_CLK_SOURCE3_SHIFT) +#define CLK_SOURCE3_SHIFT 29 +#define CLK_SOURCE3_MASK (7U << CLK_SOURCE3_SHIFT) -#define OUT_CLK_SOURCE4_SHIFT 28 -#define OUT_CLK_SOURCE4_MASK (15U << OUT_CLK_SOURCE4_SHIFT) +#define CLK_SOURCE4_SHIFT 28 +#define CLK_SOURCE4_MASK (15U << CLK_SOURCE4_SHIFT) + +#define CLK_UART_DIV_OVERRIDE (1 << 24) /* CLK_RST_CONTROLLER_SCLK_BURST_POLICY */ #define SCLK_SYS_STATE_SHIFT 28U diff --git a/src/soc/nvidia/tegra124/clock.c b/src/soc/nvidia/tegra124/clock.c index b345b9420a..16ce445bdb 100644 --- a/src/soc/nvidia/tegra124/clock.c +++ b/src/soc/nvidia/tegra124/clock.c @@ -60,11 +60,11 @@ void clock_ll_set_source_divisor(u32 *reg, u32 source, u32 divisor) value = readl(reg); - value &= ~OUT_CLK_SOURCE_MASK; - value |= source << OUT_CLK_SOURCE_SHIFT; + value &= ~CLK_SOURCE_MASK; + value |= source << CLK_SOURCE_SHIFT; - value &= ~OUT_CLK_DIVISOR_MASK; - value |= divisor << OUT_CLK_DIVISOR_SHIFT; + value &= ~CLK_DIVISOR_MASK; + value |= divisor << CLK_DIVISOR_SHIFT; writel(value, reg); } @@ -81,6 +81,28 @@ static int clock_get_osc_freq(void) return reg; } +int clock_get_osc_khz(void) +{ + /* Implemented better in the next patch, sorry, hard to split this up */ + switch (clock_get_osc_freq()) { + case OSC_FREQ_OSC13: + return 13000; + case OSC_FREQ_OSC19P2: + return 19200; + default: + case OSC_FREQ_OSC12: + return 12000; + case OSC_FREQ_OSC26: + return 26000; + case OSC_FREQ_OSC16P8: + return 16800; + case OSC_FREQ_OSC38P4: + return 38400; + case OSC_FREQ_OSC48: + return 48000; + } +} + static void adjust_pllp_out_freqs(void) { u32 reg; @@ -146,14 +168,17 @@ static void init_pllx(void) adjust_pllp_out_freqs(); } -void clock_uart_config(void) +/* Initialize the UART and put it on CLK_M so we can use it during clock_init(). + * Will later move it to PLLP in clock_config(). The divisor must be very small + * to accomodate 12KHz OSCs, so we override the 16.0 UART divider with the 15.1 + * CLK_SOURCE divider to get more precision. (This might still not be enough for + * some OSCs... if you use 13KHz, be prepared to have a bad time.) The 1800 has + * been determined through trial and error (must lead to div 13 at 24MHz). */ +void clock_early_uart(void) { - /* Enable clocks to required peripherals. TBD - minimize this list */ - /* The UART is super special so Just Do It right here. */ - - setbits_le32(&clk_rst->rst_dev_l, CLK_L_UARTA); + clock_ll_set_source_divisor(&clk_rst->clk_src_uarta, 3, + CLK_UART_DIV_OVERRIDE | CLK_DIVIDER(clock_get_osc_khz(), 1800)); setbits_le32(&clk_rst->clk_out_enb_l, CLK_L_UARTA); - clock_ll_set_source_divisor(&clk_rst->clk_src_uarta, 0, 2); udelay(2); clrbits_le32(&clk_rst->rst_dev_l, CLK_L_UARTA); } @@ -285,6 +310,9 @@ void clock_config(void) /* I2C5 (PMU) gets CLK_M and a divisor of 17 */ clock_ll_set_source_divisor(&clk_rst->clk_src_i2c5, 3, 16); + /* UARTA gets PLLP, deactivate CLK_UART_DIV_OVERRIDE */ + writel(0 << CLK_SOURCE_SHIFT, &clk_rst->clk_src_uarta); + /* Give clock time to stabilize. */ udelay(IO_STABILIZATION_DELAY); diff --git a/src/soc/nvidia/tegra124/clock.h b/src/soc/nvidia/tegra124/clock.h index 84090ece5d..d5268fcd44 100644 --- a/src/soc/nvidia/tegra124/clock.h +++ b/src/soc/nvidia/tegra124/clock.h @@ -160,7 +160,8 @@ enum { #define NVBL_PLLC_KHZ (600000) #define NVBL_PLLD_KHZ (925000) -void clock_uart_config(void); +int clock_get_osc_khz(void); +void clock_early_uart(void); void clock_cpu0_config_and_reset(void * entry); void clock_config(void); void clock_init(void);