diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/soc/nvidia/tegra/usb.c | 2 | ||||
-rw-r--r-- | src/soc/nvidia/tegra124/clk_rst.h | 38 | ||||
-rw-r--r-- | src/soc/nvidia/tegra124/clock.c | 90 | ||||
-rw-r--r-- | src/soc/nvidia/tegra124/include/soc/clock.h | 1 | ||||
-rw-r--r-- | src/soc/nvidia/tegra124/sdram.c | 2 |
5 files changed, 67 insertions, 66 deletions
diff --git a/src/soc/nvidia/tegra/usb.c b/src/soc/nvidia/tegra/usb.c index 39477e17d3..e0455ed05c 100644 --- a/src/soc/nvidia/tegra/usb.c +++ b/src/soc/nvidia/tegra/usb.c @@ -28,7 +28,7 @@ void usb_setup_utmip(struct usb_ctlr *usb) { /* KHz formulas were guessed from U-Boot constants. Formats unclear. */ - int khz = clock_get_osc_khz(); + int khz = clock_get_pll_input_khz(); /* Stop UTMI+ crystal clock while we mess with its settings */ clrbits_le32(&usb->utmip.misc1, 1 << 30); /* PHY_XTAL_CLKEN */ diff --git a/src/soc/nvidia/tegra124/clk_rst.h b/src/soc/nvidia/tegra124/clk_rst.h index efceec5f31..d2249f7669 100644 --- a/src/soc/nvidia/tegra124/clk_rst.h +++ b/src/soc/nvidia/tegra124/clk_rst.h @@ -325,15 +325,25 @@ check_member(clk_rst_ctlr, clk_src_soc_therm, 0x644); #define CPU0_CLK_STP_MASK (1U << CPU0_CLK_STP_SHIFT) /* CRC_OSC_CTRL_0 0x50 */ -#define OSC_CTRL_OSC_FREQ (0xf << 28) -#define OSC_CTRL_OSC_FREQ_SHIFT 28 -#define OSC_FREQ_OSC13 0 /* 13.0MHz */ -#define OSC_FREQ_OSC19P2 4 /* 19.2MHz */ -#define OSC_FREQ_OSC12 8 /* 12.0MHz */ -#define OSC_FREQ_OSC26 12 /* 26.0MHz */ -#define OSC_FREQ_OSC16P8 1 /* 16.8MHz */ -#define OSC_FREQ_OSC38P4 5 /* 38.4MHz */ -#define OSC_FREQ_OSC48 9 /* 48.0MHz */ +#define OSC_FREQ_SHIFT 28 +#define OSC_FREQ_MASK (0xf << OSC_FREQ_SHIFT) +#define OSC_PREDIV_SHIFT 26 +#define OSC_PREDIV_MASK (0x3 << OSC_PREDIV_SHIFT) +#define OSC_XOFS_SHIFT 4 +#define OSC_XOFS_MASK (0x3F << OSC_XOFS_SHIFT) +#define OSC_DRIVE_STRENGTH 7 +#define OSC_XOBP (1 << 1) +#define OSC_XOE (1 << 0) + +enum { + OSC_FREQ_12 = 8, /* 12.0MHz */ + OSC_FREQ_13 = 0, /* 13.0MHz */ + OSC_FREQ_16P8 = 1, /* 16.8MHz */ + OSC_FREQ_19P2 = 4, /* 19.2MHz */ + OSC_FREQ_26 = 12, /* 26.0MHz */ + OSC_FREQ_38P4 = 5, /* 38.4MHz */ + OSC_FREQ_48 = 9, /* 48.0MHz */ +}; /* CLK_RST_CONTROLLER_PLL*_BASE_0 */ #define PLL_BASE_BYPASS (1U << 31) @@ -409,16 +419,6 @@ check_member(clk_rst_ctlr, clk_src_soc_therm, 0x644); #define PLLX_IDDQ_SHIFT 3 #define PLLX_IDDQ_MASK (1U << PLLX_IDDQ_SHIFT) -/* CLK_RST_CONTROLLER_OSC_CTRL_0 0x50 */ -#define OSC_XOE_SHIFT 0 -#define OSC_XOE_MASK (1 << OSC_XOE_SHIFT) -#define OSC_XOE_ENABLE (1 << OSC_XOE_SHIFT) -#define OSC_XOBP_SHIFT 1 -#define OSC_XOBP_MASK (1U << OSC_XOBP_SHIFT) -#define OSC_XOFS_SHIFT 4 -#define OSC_XOFS_MASK (0x3F << OSC_XOFS_SHIFT) -#define OSC_DRIVE_STRENGTH 7 - #define CLK_DIVISOR_MASK (0xffff) #define CLK_SOURCE_SHIFT 29 diff --git a/src/soc/nvidia/tegra124/clock.c b/src/soc/nvidia/tegra124/clock.c index d12c4b2e89..765e447ecb 100644 --- a/src/soc/nvidia/tegra124/clock.c +++ b/src/soc/nvidia/tegra124/clock.c @@ -81,75 +81,77 @@ union __attribute__((transparent_union)) pll_fields { /* This table defines the frequency dividers for every PLL to turn the external * OSC clock into the frequencies defined by TEGRA_PLL*_KHZ in soc/clock.h. - * All PLLs have three dividers (N, M and P), with the governing formula for - * the output frequency being OUT = (IN / m) * N / (2^P). - * Yes, it really is one equation with three unknowns ... */ + * All PLLs have three dividers (n, m and p), with the governing formula for + * the output frequency being CF = (IN / m), VCO = CF * n and OUT = VCO / (2^p). + * All divisor configurations must meet the PLL's constraints for VCO and CF: + * PLLX: 12 MHz < CF < 50 MHz, 700 MHz < VCO < 3000 MHz + * PLLC: 12 MHz < CF < 50 MHz, 600 MHz < VCO < 1400 MHz + * PLLM: 12 MHz < CF < 50 MHz, 400 MHz < VCO < 1066 MHz + * PLLP: 1 MHz < CF < 6 MHz, 200 MHz < VCO < 700 MHz + * PLLD: 1 MHz < CF < 6 MHz, 500 MHz < VCO < 1000 MHz + * PLLU: 1 MHz < CF < 6 MHz, 480 MHz < VCO < 960 MHz + * PLLDP: 12 MHz < CF < 38 MHz, 600 MHz < VCO < 1200 MHz + * (values taken from Linux' drivers/clk/tegra/clk-tegra124.c). */ struct { int khz; struct pllcx_dividers pllx; /* target: CONFIG_PLLX_KHZ */ struct pllcx_dividers pllc; /* target: 600 MHz */ + /* PLLM is set up dynamically by clock_sdram(). */ + /* PLLP is hardwired to 408 MHz in HW (unless we set BASE_OVRD). */ struct pllu_dividers pllu; /* target; 960 MHz */ struct pllcx_dividers plldp; /* target; 270 MHz */ - /* Based on T124 TRM (to be updatd), PLLP is set to 408MHz in HW. - * Unless configuring PLLP to a frequency other than 408MHz, - * software configuration on PLLP is unneeded. */ + /* PLLDP treats p differently (OUT = VCO / (p + 1) for p < 6). */ } static const osc_table[16] = { - [OSC_FREQ_OSC12]{ + [OSC_FREQ_12]{ .khz = 12000, .pllx = {.n = TEGRA_PLLX_KHZ / 12000, .m = 1, .p = 0}, .pllc = {.n = 50, .m = 1, .p = 0}, .pllu = {.n = 960, .m = 12, .p = 0, .cpcon = 12, .lfcon = 2}, .plldp = {.n = 90, .m = 1, .p = 3}, }, - [OSC_FREQ_OSC13]{ + [OSC_FREQ_13]{ .khz = 13000, .pllx = {.n = TEGRA_PLLX_KHZ / 13000, .m = 1, .p = 0}, - .pllc = {.n = 231, .m = 5, .p = 0}, /* 600.6 MHz */ + .pllc = {.n = 46, .m = 1, .p = 0}, /* 598.0 MHz */ .pllu = {.n = 960, .m = 13, .p = 0, .cpcon = 12, .lfcon = 2}, - .plldp = {.n = 83, .m = 1, .p = 3}, /* 269.75 MHz */ + .plldp = {.n = 83, .m = 1, .p = 3}, /* 269.8 MHz */ }, - [OSC_FREQ_OSC16P8]{ + [OSC_FREQ_16P8]{ .khz = 16800, .pllx = {.n = TEGRA_PLLX_KHZ / 16800, .m = 1, .p = 0}, - .pllc = {.n = 250, .m = 7, .p = 0}, + .pllc = {.n = 71, .m = 1, .p = 1}, /* 596.4 MHz */ .pllu = {.n = 400, .m = 7, .p = 0, .cpcon = 5, .lfcon = 2}, - .plldp = {.n = 64, .m = 1, .p = 3}, /* 268.8 MHz */ + .plldp = {.n = 64, .m = 1, .p = 3}, /* 268.8 MHz */ }, - [OSC_FREQ_OSC19P2]{ + [OSC_FREQ_19P2]{ .khz = 19200, .pllx = {.n = TEGRA_PLLX_KHZ / 19200, .m = 1, .p = 0}, - .pllc = {.n = 125, .m = 4, .p = 0}, + .pllc = {.n = 62, .m = 1, .p = 1}, /* 595.2 MHz */ .pllu = {.n = 200, .m = 4, .p = 0, .cpcon = 3, .lfcon = 2}, - .plldp = {.n = 56, .m = 1, .p = 3}, /* 270.75 MHz */ + .plldp = {.n = 56, .m = 1, .p = 3}, /* 268.8 MHz */ }, - [OSC_FREQ_OSC26]{ + [OSC_FREQ_26]{ .khz = 26000, .pllx = {.n = TEGRA_PLLX_KHZ / 26000, .m = 1, .p = 0}, - .pllc = {.n = 23, .m = 1, .p = 0}, /* 598 MHz */ + .pllc = {.n = 23, .m = 1, .p = 0}, /* 598.0 MHz */ .pllu = {.n = 960, .m = 26, .p = 0, .cpcon = 12, .lfcon = 2}, - .plldp = {.n = 83, .m = 2, .p = 3}, /* 266.50 MHz */ + .plldp = {.n = 83, .m = 2, .p = 3}, /* 269.8 MHz */ }, - [OSC_FREQ_OSC38P4]{ + /* These oscillators get predivided as PLL inputs... n/m/p divisors for + * 38.4 should always match 19.2, and 48 should always match 12. */ + [OSC_FREQ_38P4]{ .khz = 38400, - /* - * There is a predivide by 2 before this PLL. Its values - * should match the 19.2MHz values. - */ .pllx = {.n = TEGRA_PLLX_KHZ / 19200, .m = 1, .p = 0}, - .pllc = {.n = 125, .m = 4, .p = 0}, + .pllc = {.n = 62, .m = 1, .p = 1}, /* 595.2 MHz */ .pllu = {.n = 200, .m = 4, .p = 0, .cpcon = 3, .lfcon = 2}, - .plldp = {.n = 56, .m = 2, .p = 3}, /* 268 MHz */ + .plldp = {.n = 56, .m = 1, .p = 3}, /* 268.8 MHz */ }, - [OSC_FREQ_OSC48]{ + [OSC_FREQ_48]{ .khz = 48000, - /* - * There is a predivide by 4 before this PLL. Its values - * should match the 12MHz values. - */ .pllx = {.n = TEGRA_PLLX_KHZ / 12000, .m = 1, .p = 0}, .pllc = {.n = 50, .m = 1, .p = 0}, .pllu = {.n = 960, .m = 12, .p = 0, .cpcon = 12, .lfcon = 2}, - .plldp = {.n = 90, .m = 4, .p = 3}, /* 264 MHz */ + .plldp = {.n = 90, .m = 1, .p = 3}, }, }; @@ -159,7 +161,7 @@ struct { */ static u32 clock_get_osc_bits(void) { - return readl(&clk_rst->osc_ctrl) >> OSC_CTRL_OSC_FREQ_SHIFT; + return (readl(&clk_rst->osc_ctrl) & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT; } int clock_get_osc_khz(void) @@ -167,6 +169,14 @@ int clock_get_osc_khz(void) return osc_table[clock_get_osc_bits()].khz; } +int clock_get_pll_input_khz(void) +{ + u32 osc_ctrl = readl(&clk_rst->osc_ctrl); + u32 osc_bits = (osc_ctrl & OSC_FREQ_MASK) >> OSC_FREQ_SHIFT; + u32 pll_ref_div = (osc_ctrl & OSC_PREDIV_MASK) >> OSC_PREDIV_SHIFT; + return osc_table[osc_bits].khz >> pll_ref_div; +} + void clock_init_arm_generic_timer(void) { uint32_t freq = clock_get_osc_khz() * 1000; @@ -225,7 +235,7 @@ static void init_pll(u32 *base, u32 *misc, const union pll_fields pll, u32 lock) static void init_utmip_pll(void) { - int khz = clock_get_osc_khz(); + int khz = clock_get_pll_input_khz(); /* Shut off PLL crystal clock while we mess with it */ clrbits_le32(&clk_rst->utmip_pll_cfg2, 1 << 30); /* PHY_XTAL_CLKEN */ @@ -304,22 +314,12 @@ clock_display(u32 frequency) */ struct pllpad_dividers plld = { 0 }; - u32 ref = clock_get_osc_khz() * 1000, m, n; + u32 ref = clock_get_pll_input_khz() * 1000, m, n; u32 cf, vco = frequency; const u32 max_m = 1 << 5, max_n = 1 << 10, mhz = 1000 * 1000, min_vco = 500 * mhz, max_vco = 1000 * mhz, min_cf = 1 * mhz, max_cf = 6 * mhz; - /* TODO(hungte) Replace this by clock_get_pll_input_khz */ - switch (clock_get_osc_bits()) { - case OSC_FREQ_OSC48: - ref /= 4; - break; - case OSC_FREQ_OSC38P4: - ref /= 2; - break; - } - if (vco < min_vco || vco > max_vco) { printk(BIOS_ERR, "%s: VCO (%d) out of range. Cannot support.\n", __func__, vco); diff --git a/src/soc/nvidia/tegra124/include/soc/clock.h b/src/soc/nvidia/tegra124/include/soc/clock.h index aff6abe505..73274a5c71 100644 --- a/src/soc/nvidia/tegra124/include/soc/clock.h +++ b/src/soc/nvidia/tegra124/include/soc/clock.h @@ -278,6 +278,7 @@ enum clock_source { /* Careful: Not true for all sources, always check TRM! */ #define TEGRA_PLLU_KHZ (960000) int clock_get_osc_khz(void); +int clock_get_pll_input_khz(void); int clock_display(u32 frequency); void clock_early_uart(void); void clock_external_output(int clk_id); diff --git a/src/soc/nvidia/tegra124/sdram.c b/src/soc/nvidia/tegra124/sdram.c index 1854e1dbd9..f0797db652 100644 --- a/src/soc/nvidia/tegra124/sdram.c +++ b/src/soc/nvidia/tegra124/sdram.c @@ -570,7 +570,7 @@ void sdram_init(const struct sdram_params *param) struct tegra_emc_regs *emc = (struct tegra_emc_regs*)TEGRA_EMC_BASE; printk(BIOS_DEBUG, "Initializing SDRAM of type %d with %dKHz\n", - param->MemoryType, clock_get_osc_khz() * + param->MemoryType, clock_get_pll_input_khz() * param->PllMFeedbackDivider / param->PllMInputDivider / (1 + param->PllMSelectDiv2)); if (param->MemoryType != NvBootMemoryType_Ddr3) |