diff options
author | Lin Huang <hl@rock-chips.com> | 2017-11-16 10:03:47 +0800 |
---|---|---|
committer | Julius Werner <jwerner@chromium.org> | 2017-11-28 19:14:39 +0000 |
commit | f4acb92c77e0dbadc01b84c62bbe5bb80b91ca5c (patch) | |
tree | e4dfe6edd8c16f1e5a4bf283dbc865c7f7af7a36 /src/soc/rockchip | |
parent | 2e3ebb604a64d19641c6ebf387fd1535c08baea4 (diff) |
rockchip/rk3399: mipi: correct Feedback divider setting
This patch correct Feedback divider setting:
1. Due to the use of a "by 2 pre-scaler," the range of the
feedback multiplication Feedback divider is limited to even
division numbers, and Feedback divider must be greater than
12, less than 1000.
2. Make the previously configured Feedback divider(LSB)
factors effective
Change-Id: Ic7c5c59be1d00c65c3b17cb3c4bfba8d7459e960
Signed-off-by: Lin Huang <hl@rock-chips.com>
Reviewed-on: https://review.coreboot.org/22468
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Julius Werner <jwerner@chromium.org>
Diffstat (limited to 'src/soc/rockchip')
-rw-r--r-- | src/soc/rockchip/rk3399/mipi.c | 89 |
1 files changed, 67 insertions, 22 deletions
diff --git a/src/soc/rockchip/rk3399/mipi.c b/src/soc/rockchip/rk3399/mipi.c index f44c7993ca..18d02c89d7 100644 --- a/src/soc/rockchip/rk3399/mipi.c +++ b/src/soc/rockchip/rk3399/mipi.c @@ -162,6 +162,15 @@ static int rk_mipi_dsi_phy_init(struct rk_mipi_dsi *dsi) rk_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO, LOOP_DIV_LOW_SEL(dsi->feedback_div) | LOW_PROGRAM_EN); + + /* + * we need set divider control register immediately to make + * the configured LSB effective according to IP simulation + * and lab test results. Only in this way can we get correct + * mipi phy pll frequency. + */ + rk_mipi_dsi_phy_write(dsi, PLL_INPUT_AND_LOOP_DIVIDER_RATIOS_CONTROL, + PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN); rk_mipi_dsi_phy_write(dsi, PLL_LOOP_DIVIDER_RATIO, LOOP_DIV_HIGH_SEL(dsi->feedback_div) | HIGH_PROGRAM_EN); @@ -209,11 +218,15 @@ static inline int mipi_dsi_pixel_format_to_bpp(enum mipi_dsi_pixel_format fmt) static int rk_mipi_dsi_get_lane_bps(struct rk_mipi_dsi *dsi, const struct edid *edid) { - u32 i, pre; - u64 pclk, pllref, tmp, target_bps; - u32 m = 1, n = 1; + u64 pclk, target_bps; u32 max_bps = dppa_map[ARRAY_SIZE(dppa_map) - 1].max_mbps * MHz; int bpp; + u64 best_freq = 0; + u64 fvco_min, fvco_max, fref; + u32 min_prediv, max_prediv; + u32 prediv, best_prediv; + u64 fbdiv, best_fbdiv; + u32 min_delta; bpp = mipi_dsi_pixel_format_to_bpp(dsi->format); if (bpp < 0) { @@ -222,32 +235,64 @@ static int rk_mipi_dsi_get_lane_bps(struct rk_mipi_dsi *dsi, return bpp; } pclk = edid->mode.pixel_clock * MSECS_PER_SEC; + /* take 1 / 0.8, since mbps must bigger than bandwidth of RGB */ target_bps = pclk / dsi->lanes * bpp / 8 * 10; if (target_bps >= max_bps) { printk(BIOS_DEBUG, "DPHY clock frequency is out of range\n"); return -1; } - pllref = OSC_HZ; - tmp = pllref; - /* - * The limits on the PLL divisor are: - * - * 5MHz <= (pllref / n) <= 40MHz - */ - for (i = pllref / (5 * MHz); i > div_round_up(pllref, 40 * MHz); i--) { - pre = pllref / i; - if ((tmp > (target_bps % pre)) && (target_bps / pre < 512)) { - tmp = target_bps % pre; - n = i; - m = target_bps / pre; - } - if (tmp == 0) - break; + + fref = OSC_HZ; + + /* constraint: 5Mhz <= Fref / N <= 40MHz */ + min_prediv = div_round_up(fref, 40 * MHz); + max_prediv = fref / (5 * MHz); + + /* constraint: 80MHz <= Fvco <= 1500Mhz */ + fvco_min = 80 * MHz; + fvco_max = 1500 * MHz; + min_delta = 1500 * MHz; + + for (prediv = min_prediv; prediv <= max_prediv; prediv++) { + u64 freq; + int delta; + + /* Fvco = Fref * M / N */ + fbdiv = target_bps * prediv / fref; + + /* + * Due to the use of a "by 2 pre-scaler", the range of the + * feedback multiplication value M is limited to even division + * numbers, and m must be in 6 <= m <= 512. + */ + fbdiv += fbdiv % 2; + if (fbdiv < 6 || fbdiv > 512) + continue; + + freq = (u64)fbdiv * fref / prediv; + if (freq < fvco_min || freq > fvco_max) + continue; + + delta = target_bps - freq; + delta = ABS(delta); + if (delta >= min_delta) + continue; + + best_prediv = prediv; + best_fbdiv = fbdiv; + min_delta = delta; + best_freq = freq; + } + + if (best_freq) { + dsi->lane_bps = best_freq; + dsi->input_div = best_prediv; + dsi->feedback_div = best_fbdiv; + } else { + printk(BIOS_ERR, "Can not find best_freq for DPHY\n"); + return -1; } - dsi->lane_bps = pllref / n * m; - dsi->input_div = n; - dsi->feedback_div = m; return 0; } |