diff options
author | Hung-Te Lin <hungte@chromium.org> | 2014-04-08 20:03:40 +0800 |
---|---|---|
committer | Marc Jones <marc.jones@se-eng.com> | 2014-12-15 20:17:48 +0100 |
commit | 1a8e0af78b1886acc96d1e80be5871d287d148c5 (patch) | |
tree | 1019c994ddb15910833a59b5c11254105ce6e528 /src/soc/nvidia/tegra124/clock.c | |
parent | 0c9cc5ee3be406901a52a8151408bb13253bf39b (diff) |
tegra124: Setup clock PLLD by approximating display panel pixel clock.
PLLD, the clock for display, was previously hard-coded to 306MHz. To support
more different panels, we should calcualte PLLD by panel pixel clock
configuration.
Note existing pixel clock configurations for nyan* boards won't work (they used
to rely on hard-coded approximated values) so the device trees are also
modified.
BRANCH=none
BUG=chrome-os-partner:25933
TEST=emerge-nyan_big coreboot chromeos-bootimage
See panel correctly initialized and got DEV screen.
Original-Change-Id: I8d592f0cc044e7c4e4803c45955642e791210ad3
Original-Signed-off-by: Hung-Te Lin <hungte@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/193565
(cherry picked from commit 4f9b793633ebb2d104b0544e3b72fa0d105951c4)
Signed-off-by: Marc Jones <marc.jones@se-eng.com>
Change-Id: Ib2cabbad60af010e872505e888eab485ba8c2916
Reviewed-on: http://review.coreboot.org/7762
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Diffstat (limited to 'src/soc/nvidia/tegra124/clock.c')
-rw-r--r-- | src/soc/nvidia/tegra124/clock.c | 92 |
1 files changed, 80 insertions, 12 deletions
diff --git a/src/soc/nvidia/tegra124/clock.c b/src/soc/nvidia/tegra124/clock.c index 4675b7b124..d12c4b2e89 100644 --- a/src/soc/nvidia/tegra124/clock.c +++ b/src/soc/nvidia/tegra124/clock.c @@ -88,7 +88,6 @@ struct { int khz; struct pllcx_dividers pllx; /* target: CONFIG_PLLX_KHZ */ struct pllcx_dividers pllc; /* target: 600 MHz */ - struct pllpad_dividers plld; /* target: 306 MHz */ 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. @@ -99,7 +98,6 @@ struct { .khz = 12000, .pllx = {.n = TEGRA_PLLX_KHZ / 12000, .m = 1, .p = 0}, .pllc = {.n = 50, .m = 1, .p = 0}, - .plld = {.n = 306, .m = 12, .p = 0, .cpcon = 8}, .pllu = {.n = 960, .m = 12, .p = 0, .cpcon = 12, .lfcon = 2}, .plldp = {.n = 90, .m = 1, .p = 3}, }, @@ -107,7 +105,6 @@ struct { .khz = 13000, .pllx = {.n = TEGRA_PLLX_KHZ / 13000, .m = 1, .p = 0}, .pllc = {.n = 231, .m = 5, .p = 0}, /* 600.6 MHz */ - .plld = {.n = 306, .m = 13, .p = 0, .cpcon = 8}, .pllu = {.n = 960, .m = 13, .p = 0, .cpcon = 12, .lfcon = 2}, .plldp = {.n = 83, .m = 1, .p = 3}, /* 269.75 MHz */ }, @@ -115,7 +112,6 @@ struct { .khz = 16800, .pllx = {.n = TEGRA_PLLX_KHZ / 16800, .m = 1, .p = 0}, .pllc = {.n = 250, .m = 7, .p = 0}, - .plld = {.n = 309, .m = 17, .p = 0, .cpcon = 8}, /* 305.4 MHz*/ .pllu = {.n = 400, .m = 7, .p = 0, .cpcon = 5, .lfcon = 2}, .plldp = {.n = 64, .m = 1, .p = 3}, /* 268.8 MHz */ }, @@ -123,7 +119,6 @@ struct { .khz = 19200, .pllx = {.n = TEGRA_PLLX_KHZ / 19200, .m = 1, .p = 0}, .pllc = {.n = 125, .m = 4, .p = 0}, - .plld = {.n = 271, .m = 17, .p = 0, .cpcon = 8}, /* 306.1 MHz */ .pllu = {.n = 200, .m = 4, .p = 0, .cpcon = 3, .lfcon = 2}, .plldp = {.n = 56, .m = 1, .p = 3}, /* 270.75 MHz */ }, @@ -131,7 +126,6 @@ struct { .khz = 26000, .pllx = {.n = TEGRA_PLLX_KHZ / 26000, .m = 1, .p = 0}, .pllc = {.n = 23, .m = 1, .p = 0}, /* 598 MHz */ - .plld = {.n = 306, .m = 26, .p = 0, .cpcon = 8}, .pllu = {.n = 960, .m = 26, .p = 0, .cpcon = 12, .lfcon = 2}, .plldp = {.n = 83, .m = 2, .p = 3}, /* 266.50 MHz */ }, @@ -143,7 +137,6 @@ struct { */ .pllx = {.n = TEGRA_PLLX_KHZ / 19200, .m = 1, .p = 0}, .pllc = {.n = 125, .m = 4, .p = 0}, - .plld = {.n = 271, .m = 17, .p = 0, .cpcon = 8}, /* 306.1 MHz */ .pllu = {.n = 200, .m = 4, .p = 0, .cpcon = 3, .lfcon = 2}, .plldp = {.n = 56, .m = 2, .p = 3}, /* 268 MHz */ }, @@ -155,7 +148,6 @@ struct { */ .pllx = {.n = TEGRA_PLLX_KHZ / 12000, .m = 1, .p = 0}, .pllc = {.n = 50, .m = 1, .p = 0}, - .plld = {.n = 306, .m = 12, .p = 0, .cpcon = 8}, .pllu = {.n = 960, .m = 12, .p = 0, .cpcon = 12, .lfcon = 2}, .plldp = {.n = 90, .m = 4, .p = 3}, /* 264 MHz */ }, @@ -288,10 +280,86 @@ static void graphics_pll(void) scfg = (1<<28) | (1<<24); writel(scfg, cfg); - /* Init clock source for disp1: plld (actually plld_out0) */ - init_pll(&clk_rst->plld_base, &clk_rst->plld_misc, - osc_table[osc].plld, - (PLLUD_MISC_LOCK_ENABLE | PLLD_MISC_CLK_ENABLE)); + /* disp1 will be set when panel information (pixel clock) is + * retrieved (clock_display). + */ +} + +/* Init PLLD clock source. */ +int +clock_display(u32 frequency) +{ + /** + * plld (fo) = vco >> p, where 500MHz < vco < 1000MHz + * = (cf * n) >> p, where 1MHz < cf < 6MHz + * = ((ref / m) * n) >> p + * + * Assume p = 0, find (m, n). since m has only 5 bits, we can iterate + * all possible values. Note Tegra 124 supports 11 bits for n, but our + * pll_fields has only 10 bits for n. + * + * Note values undershoot or overshoot target output frequency may not + * work if the value is not in "safe" range in panel specification, so + * we want exact match. + */ + + struct pllpad_dividers plld = { 0 }; + u32 ref = clock_get_osc_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); + return -1; + } + + for (m = 1; m < max_m; m++) { + cf = ref / m; + if (cf < min_cf) + break; + + n = vco / cf; + if (vco != cf * n || n >= max_n || cf > max_cf) + continue; + + plld.m = m; + plld.n = n; + + if (n < 50) + plld.cpcon = 2; + else if (n < 300) + plld.cpcon = 3; + else if (n < 600) + plld.cpcon = 8; + else + plld.cpcon = 12; + + printk(BIOS_DEBUG, "%s: PLLD=%u ref=%u, m/n/p/cpcon=" + "%u/%u/%u/%u\n", __func__, + (ref / plld.m * plld.n) >> plld.p, ref, + plld.m, plld.n, plld.p, plld.cpcon); + + init_pll(&clk_rst->plld_base, &clk_rst->plld_misc, plld, + (PLLUD_MISC_LOCK_ENABLE | PLLD_MISC_CLK_ENABLE)); + return 0; + } + + printk(BIOS_ERR, "%s: Failed to match output frequency %u.\n", + __func__, frequency); + return -1; } /* Initialize the UART and put it on CLK_M so we can use it during clock_init(). |