msm: mdss: add support to switch the DSI clock dynamically

Add change to support changing the DSI bit clock dynamically
for video mode panels. This helps to avoid interference of
DSI clock with other subsystems runtime.

Change-Id: I05790a6dd9d8a2fc3cf31727d032e5220d6164e5
Signed-off-by: Padmanabhan Komanduru <pkomandu@codeaurora.org>
This commit is contained in:
Padmanabhan Komanduru 2018-09-25 07:47:48 +05:30 committed by codeworkx
parent 8a2a881b50
commit 22e10c082a
9 changed files with 3396 additions and 3160 deletions

View file

@ -165,6 +165,9 @@ Optional properties:
- qcom,mdss-dsi-border-color: Defines the border color value if border is present.
0 = default value.
- qcom,mdss-dsi-pan-enable-dynamic-fps: Boolean used to enable change in frame rate dynamically.
- qcom,mdss-dsi-pan-enable-dynamic-bitclk: Boolean used to enable change in DSI clock dynamically.
- qcom,mdss-dsi-dynamic-bitclk_freq: An array of integers that specifies the DSI bit clock
frequencies supported as part of dynamic bit clock feature.
- qcom,mdss-dsi-pan-fps-update: A string that specifies when to change the frame rate.
"dfps_suspend_resume_mode"= FPS change request is
implemented during suspend/resume.
@ -696,6 +699,9 @@ Example:
qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_wled";
qcom,mdss-dsi-pan-enable-dynamic-fps;
qcom,mdss-dsi-pan-fps-update = "dfps_suspend_resume_mode";
qcom,mdss-dsi-pan-enable-dynamic-bitclk;
qcom,mdss-dsi-dynamic-bitclk_freq = <711037824 724453632 737869440
751285248 764701056 778116864 791532672 804948480>;
qcom,min-refresh-rate = <30>;
qcom,max-refresh-rate = <60>;
qcom,mdss-dsi-bl-pmic-bank-select = <0>;

View file

@ -2075,10 +2075,9 @@ static void __mdss_dsi_calc_dfps_delay(struct mdss_panel_data *pdata)
}
static int __mdss_dsi_dfps_calc_clks(struct mdss_panel_data *pdata,
int new_fps)
u64 new_clk_rate)
{
int rc = 0;
u64 clk_rate;
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
struct mdss_panel_info *pinfo;
u32 phy_rev;
@ -2098,14 +2097,9 @@ static int __mdss_dsi_dfps_calc_clks(struct mdss_panel_data *pdata,
pinfo = &pdata->panel_info;
phy_rev = ctrl_pdata->shared_data->phy_rev;
rc = mdss_dsi_clk_div_config
(&ctrl_pdata->panel_data.panel_info, new_fps);
if (rc) {
pr_err("%s: unable to initialize the clk dividers\n",
__func__);
return rc;
}
pinfo->clk_rate = new_clk_rate;
pinfo->mipi.dsi_pclk_rate = mdss_dsi_get_pclk_rate(pinfo,
new_clk_rate);
__mdss_dsi_dyn_refresh_config(ctrl_pdata);
if (phy_rev == DSI_PHY_REV_20)
@ -2118,9 +2112,8 @@ static int __mdss_dsi_dfps_calc_clks(struct mdss_panel_data *pdata,
ctrl_pdata->byte_clk_rate_bkp = ctrl_pdata->byte_clk_rate;
ctrl_pdata->pclk_rate = pinfo->mipi.dsi_pclk_rate;
clk_rate = pinfo->clk_rate;
do_div(clk_rate, 8U);
ctrl_pdata->byte_clk_rate = (u32) clk_rate;
do_div(new_clk_rate, 8U);
ctrl_pdata->byte_clk_rate = (u32) new_clk_rate;
pr_debug("byte_rate=%i\n", ctrl_pdata->byte_clk_rate);
pr_debug("pclk_rate=%i\n", ctrl_pdata->pclk_rate);
@ -2128,8 +2121,7 @@ static int __mdss_dsi_dfps_calc_clks(struct mdss_panel_data *pdata,
return rc;
}
static int __mdss_dsi_dfps_update_clks(struct mdss_panel_data *pdata,
int new_fps)
static int __mdss_dsi_dfps_update_clks(struct mdss_panel_data *pdata)
{
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
struct mdss_dsi_ctrl_pdata *sctrl_pdata = NULL;
@ -2280,12 +2272,6 @@ static int __mdss_dsi_dfps_update_clks(struct mdss_panel_data *pdata,
clk_disable_unprepare(ctrl_pdata->pll_byte_clk);
clk_disable_unprepare(ctrl_pdata->pll_pixel_clk);
/* update new fps that at this point is already updated in hw */
pinfo->current_fps = new_fps;
if (sctrl_pdata) {
spinfo->current_fps = new_fps;
}
return rc;
dfps_timeout:
@ -2362,13 +2348,65 @@ static void mdss_dsi_avr_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata,
MDSS_XLOG(ctrl_pdata->ndx, enabled, data);
}
static int mdss_dsi_dfps_config(struct mdss_panel_data *pdata, int new_fps)
static int __mdss_dsi_dynamic_clock_switch(struct mdss_panel_data *pdata,
u64 new_clk_rate)
{
int rc = 0;
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
struct mdss_panel_info *pinfo;
u32 phy_rev;
u32 frame_rate_bkp;
u64 clk_rate_bkp;
pr_debug("%s+:\n", __func__);
ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata,
panel_data);
phy_rev = ctrl_pdata->shared_data->phy_rev;
pinfo = &pdata->panel_info;
/* get the fps configured in HW */
clk_rate_bkp = pinfo->clk_rate;
__mdss_dsi_mask_dfps_errors(ctrl_pdata, true);
if (phy_rev == DSI_PHY_REV_20) {
rc = mdss_dsi_phy_calc_timing_param(pinfo, phy_rev,
new_clk_rate);
if (rc) {
pr_err("PHY calculations failed-%lld\n", new_clk_rate);
goto end_update;
}
}
rc = __mdss_dsi_dfps_calc_clks(pdata, new_clk_rate);
if (rc) {
pr_err("error calculating clocks for %lld\n", new_clk_rate);
goto error_clks;
}
rc = __mdss_dsi_dfps_update_clks(pdata);
if (rc) {
pr_err("Dynamic refresh failed-%lld\n", new_clk_rate);
goto error_dfps;
}
return rc;
error_dfps:
if (__mdss_dsi_dfps_calc_clks(pdata, clk_rate_bkp))
pr_err("error reverting clock calculations for %lld\n",
clk_rate_bkp);
error_clks:
if (mdss_dsi_phy_calc_timing_param(pinfo, phy_rev, clk_rate_bkp))
pr_err("Unable to revert phy timing-%lld\n", clk_rate_bkp);
end_update:
return rc;
}
static int mdss_dsi_dfps_config(struct mdss_panel_data *pdata, int new_fps)
{
int rc = 0;
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
struct mdss_panel_info *pinfo;
pr_debug("%s+:\n", __func__);
@ -2385,12 +2423,8 @@ static int mdss_dsi_dfps_config(struct mdss_panel_data *pdata, int new_fps)
return -EINVAL;
}
phy_rev = ctrl_pdata->shared_data->phy_rev;
pinfo = &pdata->panel_info;
/* get the fps configured in HW */
frame_rate_bkp = pinfo->current_fps;
if (new_fps == pinfo->current_fps) {
/*
* This is unlikely as mdss driver checks for previously
@ -2406,39 +2440,45 @@ static int mdss_dsi_dfps_config(struct mdss_panel_data *pdata, int new_fps)
__mdss_dsi_update_video_mode_total(pdata, new_fps);
} else if (pinfo->dfps_update == DFPS_IMMEDIATE_CLK_UPDATE_MODE) {
/* Clock update method */
u64 new_clk_rate = mdss_dsi_calc_bitclk
(&ctrl_pdata->panel_data.panel_info, new_fps);
if (!new_clk_rate) {
pr_err("%s: unable to get the new bit clock rate\n",
__func__);
rc = -EINVAL;
goto end_update;
}
__mdss_dsi_mask_dfps_errors(ctrl_pdata, true);
rc = __mdss_dsi_dynamic_clock_switch(pdata, new_clk_rate);
if (!rc) {
struct mdss_dsi_ctrl_pdata *mctrl_pdata = NULL;
struct mdss_panel_info *mpinfo = NULL;
if (phy_rev == DSI_PHY_REV_20) {
rc = mdss_dsi_phy_calc_timing_param(pinfo, phy_rev,
new_fps);
if (rc) {
pr_err("PHY calculations failed-%d\n", new_fps);
if (mdss_dsi_is_hw_config_split
(ctrl_pdata->shared_data) &&
mdss_dsi_is_ctrl_clk_master(ctrl_pdata))
goto end_update;
if (mdss_dsi_is_hw_config_split
(ctrl_pdata->shared_data) &&
mdss_dsi_is_ctrl_clk_slave(ctrl_pdata)) {
mctrl_pdata = mdss_dsi_get_ctrl_clk_master();
if (IS_ERR_OR_NULL(mctrl_pdata)) {
pr_err("Invalid mctrl_pdata\n");
goto end_update;
}
mpinfo = &mctrl_pdata->panel_data.panel_info;
}
}
rc = __mdss_dsi_dfps_calc_clks(pdata, new_fps);
if (rc) {
pr_err("error calculating clocks for %d\n", new_fps);
goto error_clks;
}
rc = __mdss_dsi_dfps_update_clks(pdata, new_fps);
if (rc) {
pr_err("Dynamic refresh failed-%d\n", new_fps);
goto error_dfps;
/*
* update new fps that at this point is already
* updated in hw
*/
pinfo->current_fps = new_fps;
if (mctrl_pdata && mpinfo)
mpinfo->current_fps = new_fps;
}
}
return rc;
error_dfps:
if (__mdss_dsi_dfps_calc_clks(pdata, frame_rate_bkp))
pr_err("error reverting clock calculations for %d\n",
frame_rate_bkp);
error_clks:
if (mdss_dsi_phy_calc_timing_param(pinfo, phy_rev, frame_rate_bkp))
pr_err("Unable to revert phy timing-%d\n", frame_rate_bkp);
end_update:
return rc;
}
@ -2712,6 +2752,163 @@ static void mdss_dsi_timing_db_ctrl(struct mdss_dsi_ctrl_pdata *ctrl,
MDSS_DSI_CORE_CLK, MDSS_DSI_CLK_OFF);
}
static struct mdss_dsi_ctrl_pdata *mdss_dsi_get_drvdata(struct device *dev)
{
struct msm_fb_data_type *mfd;
struct mdss_panel_data *pdata;
struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL;
struct fb_info *fbi = dev_get_drvdata(dev);
if (fbi) {
mfd = (struct msm_fb_data_type *)fbi->par;
pdata = dev_get_platdata(&mfd->pdev->dev);
ctrl_pdata = container_of(pdata,
struct mdss_dsi_ctrl_pdata, panel_data);
}
return ctrl_pdata;
}
static ssize_t supp_bitclk_list_sysfs_rda(struct device *dev,
struct device_attribute *attr, char *buf)
{
ssize_t ret = 0;
int i = 0;
struct mdss_dsi_ctrl_pdata *ctrl_pdata = mdss_dsi_get_drvdata(dev);
struct mdss_panel_info *pinfo = NULL;
if (!ctrl_pdata) {
pr_err("%s: invalid input\n", __func__);
return -EINVAL;
}
pinfo = &ctrl_pdata->panel_data.panel_info;
if (!pinfo) {
pr_err("no panel connected\n");
return -ENODEV;
}
if (!pinfo->dynamic_bitclk) {
pr_err_once("%s: Dynamic bitclk not enabled for this panel\n",
__func__);
return -EINVAL;
}
buf[0] = 0;
for (i = 0; i < pinfo->supp_bitclk_len; i++) {
if (ret > 0)
ret += scnprintf(buf + ret, PAGE_SIZE - ret,
",%d", pinfo->supp_bitclks[i]);
else
ret += scnprintf(buf + ret, PAGE_SIZE - ret,
"%d", pinfo->supp_bitclks[i]);
}
ret += scnprintf(buf + ret, PAGE_SIZE - ret, "\n");
return ret;
}
static ssize_t dynamic_bitclk_sysfs_wta(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
int rc = 0, i = 0;
struct mdss_dsi_ctrl_pdata *ctrl_pdata = mdss_dsi_get_drvdata(dev);
struct mdss_panel_info *pinfo = NULL;
int clk_rate = 0;
if (!ctrl_pdata) {
pr_err("%s: invalid input\n", __func__);
return -EINVAL;
}
pinfo = &ctrl_pdata->panel_data.panel_info;
if (!pinfo) {
pr_err("no panel connected\n");
return -ENODEV;
}
if (!pinfo->dynamic_bitclk) {
pr_err_once("%s: Dynamic bitclk not enabled for this panel\n",
__func__);
return -EINVAL;
}
if (mdss_panel_is_power_off(pinfo->panel_power_state)) {
pr_err_once("%s: Panel powered off!\n", __func__);
return -EINVAL;
}
rc = kstrtoint(buf, 10, &clk_rate);
if (rc) {
pr_err("%s: kstrtoint failed. rc=%d\n", __func__, rc);
return rc;
}
for (i = 0; i < pinfo->supp_bitclk_len; i++) {
if (pinfo->supp_bitclks[i] == clk_rate)
break;
}
if (i == pinfo->supp_bitclk_len) {
pr_err("Requested bitclk: %d not supported\n", clk_rate);
return -EINVAL;
}
rc = __mdss_dsi_dynamic_clock_switch(&ctrl_pdata->panel_data,
clk_rate);
if (!rc && mdss_dsi_is_hw_config_split(ctrl_pdata->shared_data)) {
struct mdss_dsi_ctrl_pdata *octrl =
mdss_dsi_get_other_ctrl(ctrl_pdata);
rc = __mdss_dsi_dynamic_clock_switch(&octrl->panel_data,
clk_rate);
if (rc)
pr_err("failed to switch DSI bitclk for sctrl\n");
} else if (rc) {
pr_err("failed to switch DSI bitclk\n");
}
return count;
} /* dynamic_bitclk_sysfs_wta */
static ssize_t dynamic_bitclk_sysfs_rda(struct device *dev,
struct device_attribute *attr, char *buf)
{
ssize_t ret;
struct mdss_dsi_ctrl_pdata *ctrl_pdata = mdss_dsi_get_drvdata(dev);
struct mdss_panel_info *pinfo = NULL;
if (!ctrl_pdata) {
pr_err("%s: invalid input\n", __func__);
return -EINVAL;
}
pinfo = &ctrl_pdata->panel_data.panel_info;
if (!pinfo) {
pr_err("no panel connected\n");
return -ENODEV;
}
ret = snprintf(buf, PAGE_SIZE, "%llu\n", pinfo->clk_rate);
pr_debug("%s: '%llu'\n", __func__, pinfo->clk_rate);
return ret;
} /* dynamic_bitclk_sysfs_rda */
static DEVICE_ATTR(dynamic_bitclk, S_IRUGO | S_IWUSR | S_IWGRP,
dynamic_bitclk_sysfs_rda, dynamic_bitclk_sysfs_wta);
static DEVICE_ATTR(supported_bitclk, S_IRUGO, supp_bitclk_list_sysfs_rda, NULL);
static struct attribute *dynamic_bitclk_fs_attrs[] = {
&dev_attr_dynamic_bitclk.attr,
&dev_attr_supported_bitclk.attr,
NULL,
};
static struct attribute_group mdss_dsi_fs_attrs_group = {
.attrs = dynamic_bitclk_fs_attrs,
};
static int mdss_dsi_event_handler(struct mdss_panel_data *pdata,
int event, void *arg)
{
@ -2878,6 +3075,14 @@ static int mdss_dsi_event_handler(struct mdss_panel_data *pdata,
ctrl_pdata->kobj = &fbi->dev->kobj;
ctrl_pdata->fb_node = fbi->node;
if (!mdss_dsi_is_hw_config_split(ctrl_pdata->shared_data) ||
(mdss_dsi_is_hw_config_split(ctrl_pdata->shared_data) &&
mdss_dsi_is_ctrl_clk_master(ctrl_pdata))) {
if (sysfs_create_group(&fbi->dev->kobj,
&mdss_dsi_fs_attrs_group))
pr_err("failed to create DSI sysfs group\n");
}
if (IS_ENABLED(CONFIG_MSM_DBA) &&
pdata->panel_info.is_dba_panel) {
queue_delayed_work(ctrl_pdata->workq,
@ -3512,7 +3717,7 @@ static int mdss_dsi_ctrl_probe(struct platform_device *pdev)
pinfo = &(ctrl_pdata->panel_data.panel_info);
if (!(mdss_dsi_is_hw_config_split(ctrl_pdata->shared_data) &&
mdss_dsi_is_ctrl_clk_slave(ctrl_pdata)) &&
pinfo->dynamic_fps) {
(pinfo->dynamic_fps || pinfo->dynamic_bitclk)) {
rc = mdss_dsi_shadow_clk_init(pdev, ctrl_pdata);
if (rc) {
@ -4536,11 +4741,19 @@ int dsi_panel_device_register(struct platform_device *ctrl_pdev,
((mipi->mode == DSI_VIDEO_MODE)
? MIPI_VIDEO_PANEL : MIPI_CMD_PANEL);
rc = mdss_dsi_clk_div_config(pinfo, mipi->frame_rate);
if (rc) {
pr_err("%s: unable to initialize the clk dividers\n", __func__);
return rc;
pinfo->clk_rate = mdss_dsi_calc_bitclk(pinfo, mipi->frame_rate);
if (!pinfo->clk_rate) {
pr_err("%s: unable to calculate the DSI bit clock\n", __func__);
return -EINVAL;
}
pinfo->mipi.dsi_pclk_rate = mdss_dsi_get_pclk_rate(pinfo,
pinfo->clk_rate);
if (!pinfo->mipi.dsi_pclk_rate) {
pr_err("%s: unable to calculate the DSI pclk\n", __func__);
return -EINVAL;
}
ctrl_pdata->pclk_rate = mipi->dsi_pclk_rate;
clk_rate = pinfo->clk_rate;
do_div(clk_rate, 8U);

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -720,8 +720,8 @@ void disable_esd_thread(void);
void mdss_dsi_irq_handler_config(struct mdss_dsi_ctrl_pdata *ctrl_pdata);
void mdss_dsi_set_tx_power_mode(int mode, struct mdss_panel_data *pdata);
int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info,
int frame_rate);
u64 mdss_dsi_calc_bitclk(struct mdss_panel_info *panel_info, int frame_rate);
u32 mdss_dsi_get_pclk_rate(struct mdss_panel_info *panel_info, u64 clk_rate);
int mdss_dsi_clk_refresh(struct mdss_panel_data *pdata, bool update_phy);
int mdss_dsi_link_clk_init(struct platform_device *pdev,
struct mdss_dsi_ctrl_pdata *ctrl_pdata);

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2015-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2016, 2018 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -1034,15 +1034,10 @@ static void mdss_dsi_phy_update_timing_param_v3(struct mdss_panel_info *pinfo,
}
int mdss_dsi_phy_calc_timing_param(struct mdss_panel_info *pinfo, u32 phy_rev,
u32 frate_hz)
u64 clk_rate)
{
struct dsi_phy_t_clk_param t_clk;
struct dsi_phy_timing t_param;
int hsync_period;
int vsync_period;
unsigned long inter_num;
uint32_t lane_config = 0;
unsigned long x, y;
int rc = 0;
if (!pinfo) {
@ -1050,30 +1045,12 @@ int mdss_dsi_phy_calc_timing_param(struct mdss_panel_info *pinfo, u32 phy_rev,
return -EINVAL;
}
hsync_period = mdss_panel_get_htotal(pinfo, true);
vsync_period = mdss_panel_get_vtotal(pinfo);
inter_num = pinfo->bpp * frate_hz;
if (pinfo->mipi.data_lane0)
lane_config++;
if (pinfo->mipi.data_lane1)
lane_config++;
if (pinfo->mipi.data_lane2)
lane_config++;
if (pinfo->mipi.data_lane3)
lane_config++;
x = mult_frac(vsync_period * hsync_period, inter_num, lane_config);
y = rounddown(x, 1);
t_clk.bitclk_mbps = rounddown(mult_frac(y, 1, 1000000), 1);
t_clk.bitclk_mbps = rounddown((uint32_t) div_u64(clk_rate, 1000000), 1);
t_clk.escclk_numer = ESC_CLK_MHZ;
t_clk.escclk_denom = ESCCLK_MMSS_CC_PREDIV;
t_clk.tlpx_numer_ns = TLPX_NUMER;
t_clk.treot_ns = TR_EOT;
pr_debug("hperiod=%d, vperiod=%d, inter_num=%lu, lane_cfg=%d\n",
hsync_period, vsync_period, inter_num, lane_config);
pr_debug("x=%lu, y=%lu, bitrate=%d\n", x, y, t_clk.bitclk_mbps);
pr_debug("bitrate=%d\n", t_clk.bitclk_mbps);
rc = mdss_dsi_phy_initialize_defaults(&t_clk, &t_param, phy_rev);
if (rc) {

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2015-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2015-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -42,7 +42,7 @@ enum phy_mode {
* @frate_hz - Frame rate for which phy timing parameters are to be calculated.
*/
int mdss_dsi_phy_calc_timing_param(struct mdss_panel_info *pinfo, u32 phy_rev,
u32 frate_hz);
u64 clk_rate);
/*
* mdss_dsi_phy_v3_init() - initialization sequence for DSI PHY rev v3

View file

@ -1,7 +1,7 @@
/*
* Core MDSS framebuffer driver.
*
* Copyright (c) 2008-2017, The Linux Foundation. All rights reserved.
* Copyright (c) 2008-2018, The Linux Foundation. All rights reserved.
* Copyright (C) 2007 Google Incorporated
*
* This software is licensed under the terms of the GNU General Public
@ -610,7 +610,7 @@ static ssize_t mdss_fb_get_panel_info(struct device *dev,
"red_chromaticity_x=%d\nred_chromaticity_y=%d\n"
"green_chromaticity_x=%d\ngreen_chromaticity_y=%d\n"
"blue_chromaticity_x=%d\nblue_chromaticity_y=%d\n"
"panel_orientation=%d\n",
"panel_orientation=%d\ndyn_bitclk_en=%d\n",
pinfo->partial_update_enabled,
pinfo->roi_alignment.xstart_pix_align,
pinfo->roi_alignment.width_pix_align,
@ -636,7 +636,7 @@ static ssize_t mdss_fb_get_panel_info(struct device *dev,
pinfo->hdr_properties.display_primaries[5],
pinfo->hdr_properties.display_primaries[6],
pinfo->hdr_properties.display_primaries[7],
pinfo->panel_orientation);
pinfo->panel_orientation, pinfo->dynamic_bitclk);
return ret;
}

View file

@ -818,6 +818,9 @@ struct mdss_panel_info {
int pwm_lpg_chan;
int pwm_period;
bool dynamic_fps;
bool dynamic_bitclk;
u32 *supp_bitclks;
u32 supp_bitclk_len;
bool ulps_feature_enabled;
bool ulps_suspend_enabled;
bool panel_ack_disabled;

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@ -1489,13 +1489,19 @@ int mdss_dsi_clk_refresh(struct mdss_panel_data *pdata, bool update_phy)
__func__, pinfo->mipi.frame_rate);
}
rc = mdss_dsi_clk_div_config(&pdata->panel_info,
pdata->panel_info.mipi.frame_rate);
if (rc) {
pr_err("%s: unable to initialize the clk dividers\n",
__func__);
return rc;
pinfo->clk_rate = mdss_dsi_calc_bitclk(pinfo, pinfo->mipi.frame_rate);
if (!pinfo->clk_rate) {
pr_err("%s: unable to calculate the DSI bit clock\n", __func__);
return -EINVAL;
}
pinfo->mipi.dsi_pclk_rate = mdss_dsi_get_pclk_rate(pinfo,
pinfo->clk_rate);
if (!pinfo->mipi.dsi_pclk_rate) {
pr_err("%s: unable to calculate the DSI pclk\n", __func__);
return -EINVAL;
}
ctrl_pdata->refresh_clk_rate = false;
ctrl_pdata->pclk_rate = pdata->panel_info.mipi.dsi_pclk_rate;
ctrl_pdata->byte_clk_rate = pdata->panel_info.clk_rate / 8;
@ -1524,7 +1530,7 @@ int mdss_dsi_clk_refresh(struct mdss_panel_data *pdata, bool update_phy)
/* phy panel timing calaculation */
rc = mdss_dsi_phy_calc_timing_param(pinfo,
ctrl_pdata->shared_data->phy_rev,
pinfo->mipi.frame_rate);
pdata->panel_info.clk_rate);
if (rc) {
pr_err("Error in calculating phy timings\n");
return rc;
@ -1811,16 +1817,9 @@ bool is_diff_frame_rate(struct mdss_panel_info *panel_info,
return (frame_rate != panel_info->mipi.frame_rate);
}
int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info,
int frame_rate)
static u8 mdss_dsi_get_lane_cnt(struct mdss_panel_info *panel_info)
{
struct mdss_panel_data *pdata = container_of(panel_info,
struct mdss_panel_data, panel_info);
struct mdss_dsi_ctrl_pdata *ctrl_pdata = container_of(pdata,
struct mdss_dsi_ctrl_pdata, panel_data);
u64 h_period, v_period, clk_rate;
u32 dsi_pclk_rate;
u8 lanes = 0, bpp;
u8 lanes = 0;
if (!panel_info)
return -EINVAL;
@ -1834,7 +1833,17 @@ int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info,
if (panel_info->mipi.data_lane0)
lanes += 1;
switch (panel_info->mipi.dst_format) {
if (!lanes)
lanes = 1;
return lanes;
}
static u8 mdss_dsi_get_bpp(char dst_format)
{
u8 bpp = 0;
switch (dst_format) {
case DSI_CMD_DST_FORMAT_RGB888:
case DSI_VIDEO_DST_FORMAT_RGB888:
case DSI_VIDEO_DST_FORMAT_RGB666_LOOSE:
@ -1848,6 +1857,21 @@ int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info,
bpp = 3; /* Default format set to RGB888 */
break;
}
return bpp;
}
u64 mdss_dsi_calc_bitclk(struct mdss_panel_info *panel_info, int frame_rate)
{
struct mdss_panel_data *pdata = container_of(panel_info,
struct mdss_panel_data, panel_info);
struct mdss_dsi_ctrl_pdata *ctrl_pdata = container_of(pdata,
struct mdss_dsi_ctrl_pdata, panel_data);
u64 h_period, v_period, clk_rate = 0;
u8 lanes = 0, bpp;
lanes = mdss_dsi_get_lane_cnt(panel_info);
bpp = mdss_dsi_get_bpp(panel_info->mipi.dst_format);
h_period = mdss_panel_get_htotal(panel_info, true);
if (panel_info->split_link_enabled)
@ -1855,35 +1879,40 @@ int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info,
v_period = mdss_panel_get_vtotal(panel_info);
if (ctrl_pdata->refresh_clk_rate || is_diff_frame_rate(panel_info,
frame_rate) || (!panel_info->clk_rate)) {
if (lanes > 0) {
panel_info->clk_rate = h_period * v_period * frame_rate
* bpp * 8;
do_div(panel_info->clk_rate, lanes);
} else {
pr_err("%s: forcing mdss_dsi lanes to 1\n", __func__);
panel_info->clk_rate =
h_period * v_period * frame_rate * bpp * 8;
}
frame_rate) || (!panel_info->clk_rate)) {
clk_rate = h_period * v_period * frame_rate * bpp * 8;
do_div(clk_rate, lanes);
} else if (panel_info->clk_rate) {
clk_rate = panel_info->clk_rate;
}
if (panel_info->clk_rate == 0)
panel_info->clk_rate = 454000000;
if (clk_rate == 0)
clk_rate = 454000000;
return clk_rate;
}
u32 mdss_dsi_get_pclk_rate(struct mdss_panel_info *panel_info, u64 clk_rate)
{
u8 lanes = 0, bpp;
u32 pclk_rate = 0;
lanes = mdss_dsi_get_lane_cnt(panel_info);
bpp = mdss_dsi_get_bpp(panel_info->mipi.dst_format);
clk_rate = panel_info->clk_rate;
do_div(clk_rate, 8 * bpp);
if (panel_info->split_link_enabled)
dsi_pclk_rate = (u32) clk_rate *
pclk_rate = (u32) clk_rate *
panel_info->mipi.lanes_per_sublink;
else
dsi_pclk_rate = (u32) clk_rate * lanes;
pclk_rate = (u32) clk_rate * lanes;
if ((dsi_pclk_rate < 3300000) || (dsi_pclk_rate > 250000000))
dsi_pclk_rate = 35000000;
panel_info->mipi.dsi_pclk_rate = dsi_pclk_rate;
if ((pclk_rate < 3300000) || (pclk_rate > 250000000))
pclk_rate = 35000000;
return 0;
return pclk_rate;
}
static bool mdss_dsi_is_ulps_req_valid(struct mdss_dsi_ctrl_pdata *ctrl,