diff options
-rw-r--r-- | drivers/gpu/drm/msm/dsi/dsi_host.c | 191 |
1 files changed, 186 insertions, 5 deletions
diff --git a/drivers/gpu/drm/msm/dsi/dsi_host.c b/drivers/gpu/drm/msm/dsi/dsi_host.c index 56c75354fe03..6ec217879c1b 100644 --- a/drivers/gpu/drm/msm/dsi/dsi_host.c +++ b/drivers/gpu/drm/msm/dsi/dsi_host.c @@ -113,6 +113,14 @@ struct msm_dsi_host { struct clk *pixel_clk_src; u32 byte_clk_rate; + u32 esc_clk_rate; + + /* DSI v2 specific clocks */ + struct clk *src_clk; + struct clk *esc_clk_src; + struct clk *dsi_clk_src; + + u32 src_clk_rate; struct gpio_desc *disp_en_gpio; struct gpio_desc *te_gpio; @@ -318,7 +326,8 @@ static int dsi_regulator_init(struct msm_dsi_host *msm_host) static int dsi_clk_init(struct msm_dsi_host *msm_host) { struct device *dev = &msm_host->pdev->dev; - const struct msm_dsi_config *cfg = msm_host->cfg_hnd->cfg; + const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; + const struct msm_dsi_config *cfg = cfg_hnd->cfg; int i, ret = 0; /* get bus clocks */ @@ -372,8 +381,34 @@ static int dsi_clk_init(struct msm_dsi_host *msm_host) if (!msm_host->pixel_clk_src) { ret = -ENODEV; pr_err("%s: can't find pixel_clk_src. ret=%d\n", __func__, ret); + goto exit; } + if (cfg_hnd->major == MSM_DSI_VER_MAJOR_V2) { + msm_host->src_clk = devm_clk_get(dev, "src_clk"); + if (IS_ERR(msm_host->src_clk)) { + ret = PTR_ERR(msm_host->src_clk); + pr_err("%s: can't find dsi_src_clk. ret=%d\n", + __func__, ret); + msm_host->src_clk = NULL; + goto exit; + } + + msm_host->esc_clk_src = clk_get_parent(msm_host->esc_clk); + if (!msm_host->esc_clk_src) { + ret = -ENODEV; + pr_err("%s: can't get esc_clk_src. ret=%d\n", + __func__, ret); + goto exit; + } + + msm_host->dsi_clk_src = clk_get_parent(msm_host->src_clk); + if (!msm_host->dsi_clk_src) { + ret = -ENODEV; + pr_err("%s: can't get dsi_clk_src. ret=%d\n", + __func__, ret); + } + } exit: return ret; } @@ -413,7 +448,7 @@ static void dsi_bus_clk_disable(struct msm_dsi_host *msm_host) clk_disable_unprepare(msm_host->bus_clks[i]); } -static int dsi_link_clk_enable(struct msm_dsi_host *msm_host) +static int dsi_link_clk_enable_6g(struct msm_dsi_host *msm_host) { int ret; @@ -460,11 +495,98 @@ error: return ret; } -static void dsi_link_clk_disable(struct msm_dsi_host *msm_host) +static int dsi_link_clk_enable_v2(struct msm_dsi_host *msm_host) { + int ret; + + DBG("Set clk rates: pclk=%d, byteclk=%d, esc_clk=%d, dsi_src_clk=%d", + msm_host->mode->clock, msm_host->byte_clk_rate, + msm_host->esc_clk_rate, msm_host->src_clk_rate); + + ret = clk_set_rate(msm_host->byte_clk, msm_host->byte_clk_rate); + if (ret) { + pr_err("%s: Failed to set rate byte clk, %d\n", __func__, ret); + goto error; + } + + ret = clk_set_rate(msm_host->esc_clk, msm_host->esc_clk_rate); + if (ret) { + pr_err("%s: Failed to set rate esc clk, %d\n", __func__, ret); + goto error; + } + + ret = clk_set_rate(msm_host->src_clk, msm_host->src_clk_rate); + if (ret) { + pr_err("%s: Failed to set rate src clk, %d\n", __func__, ret); + goto error; + } + + ret = clk_set_rate(msm_host->pixel_clk, msm_host->mode->clock * 1000); + if (ret) { + pr_err("%s: Failed to set rate pixel clk, %d\n", __func__, ret); + goto error; + } + + ret = clk_prepare_enable(msm_host->byte_clk); + if (ret) { + pr_err("%s: Failed to enable dsi byte clk\n", __func__); + goto error; + } + + ret = clk_prepare_enable(msm_host->esc_clk); + if (ret) { + pr_err("%s: Failed to enable dsi esc clk\n", __func__); + goto esc_clk_err; + } + + ret = clk_prepare_enable(msm_host->src_clk); + if (ret) { + pr_err("%s: Failed to enable dsi src clk\n", __func__); + goto src_clk_err; + } + + ret = clk_prepare_enable(msm_host->pixel_clk); + if (ret) { + pr_err("%s: Failed to enable dsi pixel clk\n", __func__); + goto pixel_clk_err; + } + + return 0; + +pixel_clk_err: + clk_disable_unprepare(msm_host->src_clk); +src_clk_err: clk_disable_unprepare(msm_host->esc_clk); - clk_disable_unprepare(msm_host->pixel_clk); +esc_clk_err: clk_disable_unprepare(msm_host->byte_clk); +error: + return ret; +} + +static int dsi_link_clk_enable(struct msm_dsi_host *msm_host) +{ + const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; + + if (cfg_hnd->major == MSM_DSI_VER_MAJOR_6G) + return dsi_link_clk_enable_6g(msm_host); + else + return dsi_link_clk_enable_v2(msm_host); +} + +static void dsi_link_clk_disable(struct msm_dsi_host *msm_host) +{ + const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; + + if (cfg_hnd->major == MSM_DSI_VER_MAJOR_6G) { + clk_disable_unprepare(msm_host->esc_clk); + clk_disable_unprepare(msm_host->pixel_clk); + clk_disable_unprepare(msm_host->byte_clk); + } else { + clk_disable_unprepare(msm_host->pixel_clk); + clk_disable_unprepare(msm_host->src_clk); + clk_disable_unprepare(msm_host->esc_clk); + clk_disable_unprepare(msm_host->byte_clk); + } } static int dsi_clk_ctrl(struct msm_dsi_host *msm_host, bool enable) @@ -499,6 +621,7 @@ unlock_ret: static int dsi_calc_clk_rate(struct msm_dsi_host *msm_host) { struct drm_display_mode *mode = msm_host->mode; + const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; u8 lanes = msm_host->lanes; u32 bpp = dsi_get_bpp(msm_host->format); u32 pclk_rate; @@ -518,6 +641,47 @@ static int dsi_calc_clk_rate(struct msm_dsi_host *msm_host) DBG("pclk=%d, bclk=%d", pclk_rate, msm_host->byte_clk_rate); + msm_host->esc_clk_rate = clk_get_rate(msm_host->esc_clk); + + if (cfg_hnd->major == MSM_DSI_VER_MAJOR_V2) { + unsigned int esc_mhz, esc_div; + unsigned long byte_mhz; + + msm_host->src_clk_rate = (pclk_rate * bpp) / 8; + + /* + * esc clock is byte clock followed by a 4 bit divider, + * we need to find an escape clock frequency within the + * mipi DSI spec range within the maximum divider limit + * We iterate here between an escape clock frequencey + * between 20 Mhz to 5 Mhz and pick up the first one + * that can be supported by our divider + */ + + byte_mhz = msm_host->byte_clk_rate / 1000000; + + for (esc_mhz = 20; esc_mhz >= 5; esc_mhz--) { + esc_div = DIV_ROUND_UP(byte_mhz, esc_mhz); + + /* + * TODO: Ideally, we shouldn't know what sort of divider + * is available in mmss_cc, we're just assuming that + * it'll always be a 4 bit divider. Need to come up with + * a better way here. + */ + if (esc_div >= 1 && esc_div <= 16) + break; + } + + if (esc_mhz < 5) + return -EINVAL; + + msm_host->esc_clk_rate = msm_host->byte_clk_rate / esc_div; + + DBG("esc=%d, src=%d", msm_host->esc_clk_rate, + msm_host->src_clk_rate); + } + return 0; } @@ -1750,6 +1914,7 @@ int msm_dsi_host_set_src_pll(struct mipi_dsi_host *host, struct msm_dsi_pll *src_pll) { struct msm_dsi_host *msm_host = to_msm_dsi_host(host); + const struct msm_dsi_cfg_handler *cfg_hnd = msm_host->cfg_hnd; struct clk *byte_clk_provider, *pixel_clk_provider; int ret; @@ -1775,6 +1940,22 @@ int msm_dsi_host_set_src_pll(struct mipi_dsi_host *host, goto exit; } + if (cfg_hnd->major == MSM_DSI_VER_MAJOR_V2) { + ret = clk_set_parent(msm_host->dsi_clk_src, pixel_clk_provider); + if (ret) { + pr_err("%s: can't set parent to dsi_clk_src. ret=%d\n", + __func__, ret); + goto exit; + } + + ret = clk_set_parent(msm_host->esc_clk_src, byte_clk_provider); + if (ret) { + pr_err("%s: can't set parent to esc_clk_src. ret=%d\n", + __func__, ret); + goto exit; + } + } + exit: return ret; } @@ -1846,7 +2027,7 @@ int msm_dsi_host_power_on(struct mipi_dsi_host *host) dsi_phy_sw_reset(msm_host); ret = msm_dsi_manager_phy_enable(msm_host->id, msm_host->byte_clk_rate * 8, - clk_get_rate(msm_host->esc_clk), + msm_host->esc_clk_rate, &clk_pre, &clk_post); dsi_bus_clk_disable(msm_host); if (ret) { |