diff options
author | Hung-Te Lin <hungte@chromium.org> | 2014-04-17 08:20:04 +0800 |
---|---|---|
committer | Marc Jones <marc.jones@se-eng.com> | 2014-12-16 23:31:09 +0100 |
commit | 0cbba8288fa169a74b5ab22f468ad8cfda3a7ac4 (patch) | |
tree | 2e1d4b7225e082296fb9c416dfc39a63ac6a71bc | |
parent | 066b16442956ad9297c40b040b110b92a0dab31d (diff) | |
download | coreboot-0cbba8288fa169a74b5ab22f468ad8cfda3a7ac4.tar.xz |
tegra124: Allow "best" PLLD parameters for unmatched pixel clock.
The pixel clock for some panel (ex: CMN N116BGE-EA2: 76420000) cannot be matched
by our PLLD params finding algorithm, after VCO/CF limitations are applied.
To support these panels, we want to allow "best matched" params.
BRANCH=nyan
BUG=none
TEST=emerge-nyan_big coreboot chromeos-bootimage;
emerge-nyan coreboot chromeos-bootimage;
# Successfully brings up display on Nyan_Big EVT2 and Nyan Norrin.
Original-Change-Id: If8143c2062abd2f843c07698ea55cab47bf1e41a
Original-Signed-off-by: Hung-Te Lin <hungte@chromium.org>
Original-Reviewed-on: https://chromium-review.googlesource.com/195327
Original-Reviewed-by: Julius Werner <jwerner@chromium.org>
(cherry picked from commit 8aa66e659e3c60296f05e59b4343496a850ea019)
Signed-off-by: Marc Jones <marc.jones@se-eng.com>
Change-Id: I623db44de35fecee5539e4d72f93f28b5fa0b59c
Reviewed-on: http://review.coreboot.org/7771
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Tested-by: build bot (Jenkins)
-rw-r--r-- | src/soc/nvidia/tegra124/clock.c | 68 |
1 files changed, 40 insertions, 28 deletions
diff --git a/src/soc/nvidia/tegra124/clock.c b/src/soc/nvidia/tegra124/clock.c index 765e447ecb..eed5116c32 100644 --- a/src/soc/nvidia/tegra124/clock.c +++ b/src/soc/nvidia/tegra124/clock.c @@ -304,18 +304,17 @@ clock_display(u32 frequency) * = (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. + * Assume p = 0, find best (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. + * work if the values are not in "safe" range by panel specification. */ - struct pllpad_dividers plld = { 0 }; u32 ref = clock_get_pll_input_khz() * 1000, m, n; u32 cf, vco = frequency; + u32 diff, best_diff = vco; 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; @@ -326,40 +325,53 @@ clock_display(u32 frequency) return -1; } - for (m = 1; m < max_m; m++) { + for (m = 1; m < max_m && best_diff; m++) { cf = ref / m; if (cf < min_cf) break; + if (cf > max_cf) + continue; n = vco / cf; - if (vco != cf * n || n >= max_n || cf > max_cf) + if (n >= max_n) + continue; + + diff = vco - n * cf; + if (n + 1 < max_n && diff > cf / 2) { + n++; + diff = cf - diff; + } + + if (diff >= best_diff) continue; + best_diff = diff; plld.m = m; plld.n = n; + } + + if (plld.n < 50) + plld.cpcon = 2; + else if (plld.n < 300) + plld.cpcon = 3; + else if (plld.n < 600) + plld.cpcon = 8; + else + plld.cpcon = 12; - 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; + if (best_diff) { + printk(BIOS_ERR, "%s: Failed to match output frequency %u, " + "best difference is %u.\n", __func__, frequency, + best_diff); } - printk(BIOS_ERR, "%s: Failed to match output frequency %u.\n", - __func__, frequency); - return -1; + 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; } /* Initialize the UART and put it on CLK_M so we can use it during clock_init(). |