diff --git a/src/soc/nvidia/tegra124/clk_rst.h b/src/soc/nvidia/tegra124/clk_rst.h index 4280f3ccd4..c9c595d9e8 100644 --- a/src/soc/nvidia/tegra124/clk_rst.h +++ b/src/soc/nvidia/tegra124/clk_rst.h @@ -425,24 +425,10 @@ enum { #define OSC_XOFS_MASK (0x3F << OSC_XOFS_SHIFT) #define OSC_DRIVE_STRENGTH 7 -/* - * CLK_RST_CONTROLLER_CLK_SOURCE_x_OUT_0 - the mask here is normally 8 bits - * but can be 16. We could use knowledge we have to restrict the mask in - * the 8-bit cases (the divider_bits value returned by - * 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 CLK_DIVISOR_SHIFT 0 -#define CLK_DIVISOR_MASK (0xffff << CLK_DIVISOR_SHIFT) +#define CLK_DIVISOR_MASK (0xffff) -#define CLK_SOURCE_SHIFT 30 -#define CLK_SOURCE_MASK (3U << CLK_SOURCE_SHIFT) - -#define CLK_SOURCE3_SHIFT 29 -#define CLK_SOURCE3_MASK (7U << CLK_SOURCE3_SHIFT) - -#define CLK_SOURCE4_SHIFT 28 -#define CLK_SOURCE4_MASK (15U << CLK_SOURCE4_SHIFT) +#define CLK_SOURCE_SHIFT 29 +#define CLK_SOURCE_MASK (0x7 << CLK_SOURCE_SHIFT) #define CLK_UART_DIV_OVERRIDE (1 << 24) diff --git a/src/soc/nvidia/tegra124/clock.c b/src/soc/nvidia/tegra124/clock.c index 7be06fb30c..22c0f3897c 100644 --- a/src/soc/nvidia/tegra124/clock.c +++ b/src/soc/nvidia/tegra124/clock.c @@ -23,6 +23,13 @@ #include "flow.h" #include "pmc.h" +/* Warning: Some devices just use different bits for the same sources for no + * apparent reason. *Always* double-check the TRM before trusting this macro. */ +#define clock_configure_source(device, src, freq) \ + clrsetbits_le32(&clk_rst->clk_src_##device, \ + CLK_SOURCE_MASK | CLK_DIVISOR_MASK, \ + src << CLK_SOURCE_SHIFT | CLK_DIVIDER(TEGRA_##src##_KHZ, freq)); + static struct clk_rst_ctlr *clk_rst = (void *)TEGRA_CLK_RST_BASE; static struct flow_ctlr *flow = (void *)TEGRA_FLOW_BASE; static struct tegra_pmc_regs *pmc = (void*)TEGRA_PMC_BASE; @@ -143,23 +150,6 @@ struct { }, }; -// TODO(hungte) Some clock source are assigned in 3 or 4 bits -// (OUT_CLK_SOURCE*_MASK/SHIFT), not always OUT_CLK_SOURCE_MASK/SHIFT. -void clock_ll_set_source_divisor(u32 *reg, u32 source, u32 divisor) -{ - u32 value; - - value = readl(reg); - - value &= ~CLK_SOURCE_MASK; - value |= source << CLK_SOURCE_SHIFT; - - value &= ~CLK_DIVISOR_MASK; - value |= divisor << CLK_DIVISOR_SHIFT; - - writel(value, reg); -} - /* Get the oscillator frequency, from the corresponding hardware * configuration field. This is actually a per-soc thing. Avoid the * temptation to make it common. @@ -214,8 +204,8 @@ static void init_pll(u32 *base, u32 *misc, const union pll_fields pll) * been determined through trial and error (must lead to div 13 at 24MHz). */ void clock_early_uart(void) { - clock_ll_set_source_divisor(&clk_rst->clk_src_uarta, 3, - CLK_UART_DIV_OVERRIDE | CLK_DIVIDER(clock_get_osc_khz(), 1800)); + write32(CLK_M << CLK_SOURCE_SHIFT | CLK_UART_DIV_OVERRIDE | + CLK_DIVIDER(TEGRA_CLK_M_KHZ, 1800), &clk_rst->clk_src_uarta); setbits_le32(&clk_rst->clk_out_enb_l, CLK_L_UARTA); udelay(2); clrbits_le32(&clk_rst->rst_dev_l, CLK_L_UARTA); @@ -332,7 +322,7 @@ void clock_config(void) /* TODO: can (should?) we use the _SET and _CLR registers here? */ setbits_le32(&clk_rst->clk_out_enb_l, CLK_L_CACHE2 | CLK_L_GPIO | CLK_L_TMR | CLK_L_I2C1 | - CLK_L_SDMMC4); + CLK_L_SDMMC4 | CLK_L_DISP1 | CLK_L_HOST1X); setbits_le32(&clk_rst->clk_out_enb_h, CLK_H_EMC | CLK_H_I2C2 | CLK_H_I2C5 | CLK_H_SBC1 | CLK_H_PMC | CLK_H_APBDMA | CLK_H_MEM); @@ -341,43 +331,37 @@ void clock_config(void) setbits_le32(&clk_rst->clk_out_enb_v, CLK_V_MSELECT | CLK_V_I2C4); setbits_le32(&clk_rst->clk_out_enb_w, CLK_W_DVFS); - /* - * Set MSELECT clock source as PLLP (00)_REG, and ask for a clock - * divider that would set the MSELECT clock at 102MHz for a - * PLLP base of 408MHz. - */ - clock_ll_set_source_divisor(&clk_rst->clk_src_mselect, 0, - CLK_DIVIDER(TEGRA_PLLP_KHZ, 102000)); - /* Give clock time to stabilize */ udelay(IO_STABILIZATION_DELAY); - /* I2C1 gets CLK_M and a divisor of 17 */ - clock_ll_set_source_divisor(&clk_rst->clk_src_i2c1, 3, 16); - /* I2C2 gets CLK_M and a divisor of 17 */ - clock_ll_set_source_divisor(&clk_rst->clk_src_i2c2, 3, 16); - /* I2C3 (cam) gets CLK_M and a divisor of 17 */ - clock_ll_set_source_divisor(&clk_rst->clk_src_i2c3, 3, 16); - /* I2C4 (ddc) gets CLK_M and a divisor of 17 */ - clock_ll_set_source_divisor(&clk_rst->clk_src_i2c4, 3, 16); - /* I2C5 (PMU) gets CLK_M and a divisor of 17 */ - clock_ll_set_source_divisor(&clk_rst->clk_src_i2c5, 3, 16); + clock_configure_source(mselect, PLLP, 102000); - /* UARTA gets PLLP, deactivate CLK_UART_DIV_OVERRIDE */ - writel(0 << CLK_SOURCE_SHIFT, &clk_rst->clk_src_uarta); + /* TODO: is the 1.333MHz correct? This may have always been bogus... */ + clock_configure_source(i2c1, CLK_M, 1333); + clock_configure_source(i2c2, CLK_M, 1333); + clock_configure_source(i2c3, CLK_M, 1333); + clock_configure_source(i2c4, CLK_M, 1333); + clock_configure_source(i2c5, CLK_M, 1333); + + /* Move UARTA to PLLP and remove the CLK_UART_DIV_OVERRIDE */ + write32(PLLP << CLK_SOURCE_SHIFT, &clk_rst->clk_src_uarta); /* MMC3 and MMC4: Set base clock frequency for SD Clock to Tegra MMC's * maximum speed (48MHz) so we can change SDCLK by second stage divisor * in payloads, without touching base clock. - * - * Note, parent clock source for MMC3/4 is PLLP_OUT0. MMC clock source - * should be specified in 3 bits, but since PLLP_OUT0 is #0, it's OK to - * simply call clock_ll_set_source_divisor (2 bits). */ - clock_ll_set_source_divisor(&clk_rst->clk_src_sdmmc3, 0, - CLK_DIVIDER(TEGRA_PLLP_KHZ, 48000)); - clock_ll_set_source_divisor(&clk_rst->clk_src_sdmmc4, 0, - CLK_DIVIDER(TEGRA_PLLP_KHZ, 48000)); + clock_configure_source(sdmmc3, PLLP, 48000); + clock_configure_source(sdmmc4, PLLP, 48000); + + /* PLLP and PLLM are switched for HOST1x for no apparent reason. */ + write32(4 /* PLLP! */ << CLK_SOURCE_SHIFT | + /* TODO(rminnich): The divisor isn't accurate enough to get to + * 144MHz (it goes to 163 instead). What should we do here? */ + CLK_DIVIDER(TEGRA_PLLP_KHZ, 144000), + &clk_rst->clk_src_host1x); + + /* DISP1 doesn't support a divisor. Use PLLC which runs at 600MHz. */ + clock_configure_source(disp1, PLLC, 600000); /* Give clock time to stabilize. */ udelay(IO_STABILIZATION_DELAY); @@ -386,7 +370,7 @@ void clock_config(void) clrbits_le32(&clk_rst->rst_dev_l, CLK_L_CACHE2 | CLK_L_GPIO | CLK_L_TMR | CLK_L_I2C1 | - CLK_L_SDMMC4); + CLK_L_SDMMC4 | CLK_L_DISP1 | CLK_L_HOST1X); clrbits_le32(&clk_rst->rst_dev_h, CLK_H_EMC | CLK_H_I2C2 | CLK_H_I2C5 | CLK_H_SBC1 | CLK_H_PMC | CLK_H_APBDMA | CLK_H_MEM); diff --git a/src/soc/nvidia/tegra124/display.c b/src/soc/nvidia/tegra124/display.c index b7993008d5..2eb02965b8 100644 --- a/src/soc/nvidia/tegra124/display.c +++ b/src/soc/nvidia/tegra124/display.c @@ -32,12 +32,9 @@ #include #include #include -#include "clk_rst.h" #include "chip.h" #include -static struct clk_rst_ctlr *clk_rst = (void *)TEGRA_CLK_RST_BASE; - static const u32 rgb_enb_tab[PIN_REG_COUNT] = { 0x00000000, 0x00000000, @@ -281,20 +278,6 @@ void display_startup(device_t dev) * The panel_vdd is done in the romstage, so we need only * light things up here once we're sure it's all working. */ - setbits_le32(&clk_rst->rst_dev_l, CLK_L_DISP1 | CLK_L_HOST1X); - - clock_ll_set_source_divisor(&clk_rst->clk_src_host1x, 4, - CLK_DIVIDER(TEGRA_PLLP_KHZ, 144000)); - - /* DISP1 doesn't support a divisor. Use PLLC which runs at 600MHz. */ - val = readl(&clk_rst->clk_src_disp1); - val &= ~CLK_SOURCE3_MASK; - val |= (4 << CLK_SOURCE3_SHIFT); - writel(val, &clk_rst->clk_src_disp1); - - udelay(2); - - clrbits_le32(&clk_rst->rst_dev_l, CLK_L_DISP1|CLK_L_HOST1X); writel(0x00000100, &dc->cmd.gen_incr_syncpt_ctrl); writel(0x0000011a, &dc->cmd.cont_syncpt_vsync); diff --git a/src/soc/nvidia/tegra124/include/soc/clock.h b/src/soc/nvidia/tegra124/include/soc/clock.h index 056a38b2e0..fe4f391724 100644 --- a/src/soc/nvidia/tegra124/include/soc/clock.h +++ b/src/soc/nvidia/tegra124/include/soc/clock.h @@ -155,7 +155,20 @@ enum { /* Calculate clock frequency value from reference and clock divider value */ #define CLK_FREQUENCY(REF, REG) (((REF) * 2) / (REG + 2)) +enum clock_source { /* Careful: Not true for all sources, always check TRM! */ + PLLP = 0, + PLLC2 = 1, + PLLC = 2, + PLLD = 2, + PLLC3 = 3, + PLLA = 3, + PLLM = 4, + PLLD2 = 5, + CLK_M = 6, +}; + /* soc-specific */ +#define TEGRA_CLK_M_KHZ clock_get_osc_khz() #define TEGRA_PLLX_KHZ (1900000) #define TEGRA_PLLP_KHZ (408000) #define TEGRA_PLLC_KHZ (600000) @@ -167,5 +180,4 @@ void clock_early_uart(void); void clock_cpu0_config_and_reset(void * entry); void clock_config(void); void clock_init(void); -void clock_ll_set_source_divisor(u32 *reg, u32 source, u32 divisor); #endif /* __SOC_NVIDIA_TEGRA124_CLOCK_H__ */