static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi, struct drm_display_mode *mode) { unsigned int i, pre; unsigned long mpclk, pllref, tmp; unsigned int m = 1, n = 1, target_mbps = 1000; unsigned int max_mbps = dptdin_map[ARRAY_SIZE(dptdin_map) - 1].max_mbps; int bpp; bpp = mipi_dsi_pixel_format_to_bpp(dsi->format); if (bpp < 0) { DRM_DEV_ERROR(dsi->dev, "failed to get bpp for pixel format %d\n", dsi->format); return bpp; } mpclk = DIV_ROUND_UP(mode->clock, MSEC_PER_SEC); if (mpclk) { /* take 1 / 0.8, since mbps must big than bandwidth of RGB */ tmp = mpclk * (bpp / dsi->lanes) * 10 / 8; if (tmp < max_mbps) target_mbps = tmp; else DRM_DEV_ERROR(dsi->dev, "DPHY clock frequency is out of range\n"); } pllref = DIV_ROUND_UP(clk_get_rate(dsi->pllref_clk), USEC_PER_SEC); tmp = pllref; /* * The limits on the PLL divisor are: * * 5MHz <= (pllref / n) <= 40MHz * * we walk over these values in descreasing order so that if we hit * an exact match for target_mbps it is more likely that "m" will be * even. * * TODO: ensure that "m" is even after this loop. */ for (i = pllref / 5; i > (pllref / 40); i--) { pre = pllref / i; if ((tmp > (target_mbps % pre)) && (target_mbps / pre < 512)) { tmp = target_mbps % pre; n = i; m = target_mbps / pre; } if (tmp == 0) break; } dsi->lane_mbps = pllref / n * m; dsi->input_div = n; dsi->feedback_div = m; return 0; }
static void assert_bpp_mismatch(enum mipi_dsi_pixel_format fmt, int pipe_bpp) { int bpp = mipi_dsi_pixel_format_to_bpp(fmt); WARN(bpp != pipe_bpp, "bpp match assertion failure (expected %d, current %d)\n", bpp, pipe_bpp); }
/* Get DSI clock from pixel clock */ static u32 dsi_clk_from_pclk(u32 pclk, enum mipi_dsi_pixel_format fmt, int lane_count) { u32 dsi_clk_khz; u32 bpp = mipi_dsi_pixel_format_to_bpp(fmt); /* DSI data rate = pixel clock * bits per pixel / lane count pixel clock is converted from KHz to Hz */ dsi_clk_khz = DIV_ROUND_CLOSEST(pclk * bpp, lane_count); return dsi_clk_khz; }
static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi) { unsigned int i, pre; unsigned long mpclk, pllref, tmp; unsigned int m = 1, n = 1, target_mbps = 1000; unsigned int max_mbps = dptdin_map[ARRAY_SIZE(dptdin_map) - 1].max_mbps; int bpp; bpp = mipi_dsi_pixel_format_to_bpp(dsi->format); if (bpp < 0) { dev_err(dsi->dev, "failed to get bpp for pixel format %d\n", dsi->format); return bpp; } mpclk = DIV_ROUND_UP(dsi->mode->clock, MSEC_PER_SEC); if (mpclk) { /* take 1 / 0.9, since mbps must big than bandwidth of RGB */ tmp = mpclk * (bpp / dsi->lanes) * 10 / 9; if (tmp < max_mbps) target_mbps = tmp; else dev_err(dsi->dev, "DPHY clock frequency is out of range\n"); } pllref = DIV_ROUND_UP(clk_get_rate(dsi->pllref_clk), USEC_PER_SEC); tmp = pllref; for (i = 1; i < 6; i++) { pre = pllref / i; if ((tmp > (target_mbps % pre)) && (target_mbps / pre < 512)) { tmp = target_mbps % pre; n = i; m = target_mbps / pre; } if (tmp == 0) break; } dsi->lane_mbps = pllref / n * m; dsi->input_div = n; dsi->feedback_div = m; return 0; }
static int dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode, unsigned long mode_flags, u32 lanes, u32 format, unsigned int *lane_mbps) { struct dw_mipi_dsi_stm *dsi = priv_data; unsigned int idf, ndiv, odf, pll_in_khz, pll_out_khz; int ret, bpp; u32 val; /* Update lane capabilities according to hw version */ dsi->lane_min_kbps = LANE_MIN_KBPS; dsi->lane_max_kbps = LANE_MAX_KBPS; if (dsi->hw_version == HWVER_131) { dsi->lane_min_kbps *= 2; dsi->lane_max_kbps *= 2; } pll_in_khz = (unsigned int)(clk_get_rate(dsi->pllref_clk) / 1000); /* Compute requested pll out */ bpp = mipi_dsi_pixel_format_to_bpp(format); pll_out_khz = mode->clock * bpp / lanes; /* Add 20% to pll out to be higher than pixel bw (burst mode only) */ pll_out_khz = (pll_out_khz * 12) / 10; if (pll_out_khz > dsi->lane_max_kbps) { pll_out_khz = dsi->lane_max_kbps; DRM_WARN("Warning max phy mbps is used\n"); } if (pll_out_khz < dsi->lane_min_kbps) { pll_out_khz = dsi->lane_min_kbps; DRM_WARN("Warning min phy mbps is used\n"); } /* Compute best pll parameters */ idf = 0; ndiv = 0; odf = 0; ret = dsi_pll_get_params(dsi, pll_in_khz, pll_out_khz, &idf, &ndiv, &odf); if (ret) DRM_WARN("Warning dsi_pll_get_params(): bad params\n"); /* Get the adjusted pll out value */ pll_out_khz = dsi_pll_get_clkout_khz(pll_in_khz, idf, ndiv, odf); /* Set the PLL division factors */ dsi_update_bits(dsi, DSI_WRPCR, WRPCR_NDIV | WRPCR_IDF | WRPCR_ODF, (ndiv << 2) | (idf << 11) | ((ffs(odf) - 1) << 16)); /* Compute uix4 & set the bit period in high-speed mode */ val = 4000000 / pll_out_khz; dsi_update_bits(dsi, DSI_WPCR0, WPCR0_UIX4, val); /* Select video mode by resetting DSIM bit */ dsi_clear(dsi, DSI_WCFGR, WCFGR_DSIM); /* Select the color coding */ dsi_update_bits(dsi, DSI_WCFGR, WCFGR_COLMUX, dsi_color_from_mipi(format) << 1); *lane_mbps = pll_out_khz / 1000; DRM_DEBUG_DRIVER("pll_in %ukHz pll_out %ukHz lane_mbps %uMHz\n", pll_in_khz, pll_out_khz, *lane_mbps); return 0; }