summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLin Huang <hl@rock-chips.com>2017-11-16 10:03:47 +0800
committerJulius Werner <jwerner@chromium.org>2017-11-28 19:14:39 +0000
commitf4acb92c77e0dbadc01b84c62bbe5bb80b91ca5c (patch)
treee4dfe6edd8c16f1e5a4bf283dbc865c7f7af7a36
parent2e3ebb604a64d19641c6ebf387fd1535c08baea4 (diff)
downloadcoreboot-f4acb92c77e0dbadc01b84c62bbe5bb80b91ca5c.tar.xz
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>
-rw-r--r--src/soc/rockchip/rk3399/mipi.c89
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;
}