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)
This commit is contained in:
parent
066b164429
commit
0cbba8288f
|
@ -304,18 +304,17 @@ clock_display(u32 frequency)
|
||||||
* = (cf * n) >> p, where 1MHz < cf < 6MHz
|
* = (cf * n) >> p, where 1MHz < cf < 6MHz
|
||||||
* = ((ref / m) * n) >> p
|
* = ((ref / m) * n) >> p
|
||||||
*
|
*
|
||||||
* Assume p = 0, find (m, n). since m has only 5 bits, we can iterate
|
* Assume p = 0, find best (m, n). since m has only 5 bits, we can
|
||||||
* all possible values. Note Tegra 124 supports 11 bits for n, but our
|
* iterate all possible values. Note Tegra 124 supports 11 bits for n,
|
||||||
* pll_fields has only 10 bits for n.
|
* but our pll_fields has only 10 bits for n.
|
||||||
*
|
*
|
||||||
* Note values undershoot or overshoot target output frequency may not
|
* Note values undershoot or overshoot target output frequency may not
|
||||||
* work if the value is not in "safe" range in panel specification, so
|
* work if the values are not in "safe" range by panel specification.
|
||||||
* we want exact match.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct pllpad_dividers plld = { 0 };
|
struct pllpad_dividers plld = { 0 };
|
||||||
u32 ref = clock_get_pll_input_khz() * 1000, m, n;
|
u32 ref = clock_get_pll_input_khz() * 1000, m, n;
|
||||||
u32 cf, vco = frequency;
|
u32 cf, vco = frequency;
|
||||||
|
u32 diff, best_diff = vco;
|
||||||
const u32 max_m = 1 << 5, max_n = 1 << 10, mhz = 1000 * 1000,
|
const u32 max_m = 1 << 5, max_n = 1 << 10, mhz = 1000 * 1000,
|
||||||
min_vco = 500 * mhz, max_vco = 1000 * mhz,
|
min_vco = 500 * mhz, max_vco = 1000 * mhz,
|
||||||
min_cf = 1 * mhz, max_cf = 6 * mhz;
|
min_cf = 1 * mhz, max_cf = 6 * mhz;
|
||||||
|
@ -326,42 +325,55 @@ clock_display(u32 frequency)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (m = 1; m < max_m; m++) {
|
for (m = 1; m < max_m && best_diff; m++) {
|
||||||
cf = ref / m;
|
cf = ref / m;
|
||||||
if (cf < min_cf)
|
if (cf < min_cf)
|
||||||
break;
|
break;
|
||||||
|
if (cf > max_cf)
|
||||||
n = vco / cf;
|
|
||||||
if (vco != cf * n || n >= max_n || cf > max_cf)
|
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
n = vco / 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.m = m;
|
||||||
plld.n = n;
|
plld.n = n;
|
||||||
|
}
|
||||||
|
|
||||||
if (n < 50)
|
if (plld.n < 50)
|
||||||
plld.cpcon = 2;
|
plld.cpcon = 2;
|
||||||
else if (n < 300)
|
else if (plld.n < 300)
|
||||||
plld.cpcon = 3;
|
plld.cpcon = 3;
|
||||||
else if (n < 600)
|
else if (plld.n < 600)
|
||||||
plld.cpcon = 8;
|
plld.cpcon = 8;
|
||||||
else
|
else
|
||||||
plld.cpcon = 12;
|
plld.cpcon = 12;
|
||||||
|
|
||||||
printk(BIOS_DEBUG, "%s: PLLD=%u ref=%u, m/n/p/cpcon="
|
if (best_diff) {
|
||||||
"%u/%u/%u/%u\n", __func__,
|
printk(BIOS_ERR, "%s: Failed to match output frequency %u, "
|
||||||
(ref / plld.m * plld.n) >> plld.p, ref,
|
"best difference is %u.\n", __func__, frequency,
|
||||||
plld.m, plld.n, plld.p, plld.cpcon);
|
best_diff);
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
init_pll(&clk_rst->plld_base, &clk_rst->plld_misc, plld,
|
||||||
(PLLUD_MISC_LOCK_ENABLE | PLLD_MISC_CLK_ENABLE));
|
(PLLUD_MISC_LOCK_ENABLE | PLLD_MISC_CLK_ENABLE));
|
||||||
return 0;
|
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().
|
/* 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
|
* 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
|
* to accomodate 12KHz OSCs, so we override the 16.0 UART divider with the 15.1
|
||||||
|
|
Loading…
Reference in New Issue