summaryrefslogtreecommitdiff
path: root/drivers/video
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/fbdev/core/modedb.c41
-rw-r--r--drivers/video/fbdev/goldfishfb.c1
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.c329
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.h6
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_panel.c30
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_phy.c31
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi_phy.h4
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.c6
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_ctl.c3
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c4
-rw-r--r--drivers/video/fbdev/msm/mdss_panel.h3
-rw-r--r--drivers/video/fbdev/msm/msm_mdss_io_8974.c103
-rw-r--r--drivers/video/fbdev/omap/omapfb_main.c2
-rw-r--r--drivers/video/fbdev/via/viafbdev.c3
14 files changed, 419 insertions, 147 deletions
diff --git a/drivers/video/fbdev/core/modedb.c b/drivers/video/fbdev/core/modedb.c
index 2510fa728d77..de119f11b78f 100644
--- a/drivers/video/fbdev/core/modedb.c
+++ b/drivers/video/fbdev/core/modedb.c
@@ -644,7 +644,7 @@ static int fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info,
*
* Valid mode specifiers for @mode_option:
*
- * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m] or
+ * <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][p][m] or
* <name>[-<bpp>][@<refresh>]
*
* with <xres>, <yres>, <bpp> and <refresh> decimal numbers and
@@ -653,10 +653,10 @@ static int fb_try_mode(struct fb_var_screeninfo *var, struct fb_info *info,
* If 'M' is present after yres (and before refresh/bpp if present),
* the function will compute the timings using VESA(tm) Coordinated
* Video Timings (CVT). If 'R' is present after 'M', will compute with
- * reduced blanking (for flatpanels). If 'i' is present, compute
- * interlaced mode. If 'm' is present, add margins equal to 1.8%
- * of xres rounded down to 8 pixels, and 1.8% of yres. The char
- * 'i' and 'm' must be after 'M' and 'R'. Example:
+ * reduced blanking (for flatpanels). If 'i' or 'p' are present, compute
+ * interlaced or progressive mode. If 'm' is present, add margins equal
+ * to 1.8% of xres rounded down to 8 pixels, and 1.8% of yres. The chars
+ * 'i', 'p' and 'm' must be after 'M' and 'R'. Example:
*
* 1024x768MR-8@60m - Reduced blank with margins at 60Hz.
*
@@ -697,7 +697,8 @@ int fb_find_mode(struct fb_var_screeninfo *var,
unsigned int namelen = strlen(name);
int res_specified = 0, bpp_specified = 0, refresh_specified = 0;
unsigned int xres = 0, yres = 0, bpp = default_bpp, refresh = 0;
- int yres_specified = 0, cvt = 0, rb = 0, interlace = 0;
+ int yres_specified = 0, cvt = 0, rb = 0;
+ int interlace_specified = 0, interlace = 0;
int margins = 0;
u32 best, diff, tdiff;
@@ -748,9 +749,17 @@ int fb_find_mode(struct fb_var_screeninfo *var,
if (!cvt)
margins = 1;
break;
+ case 'p':
+ if (!cvt) {
+ interlace = 0;
+ interlace_specified = 1;
+ }
+ break;
case 'i':
- if (!cvt)
+ if (!cvt) {
interlace = 1;
+ interlace_specified = 1;
+ }
break;
default:
goto done;
@@ -819,11 +828,21 @@ done:
if ((name_matches(db[i], name, namelen) ||
(res_specified && res_matches(db[i], xres, yres))) &&
!fb_try_mode(var, info, &db[i], bpp)) {
- if (refresh_specified && db[i].refresh == refresh)
- return 1;
+ const int db_interlace = (db[i].vmode &
+ FB_VMODE_INTERLACED ? 1 : 0);
+ int score = abs(db[i].refresh - refresh);
+
+ if (interlace_specified)
+ score += abs(db_interlace - interlace);
+
+ if (!interlace_specified ||
+ db_interlace == interlace)
+ if (refresh_specified &&
+ db[i].refresh == refresh)
+ return 1;
- if (abs(db[i].refresh - refresh) < diff) {
- diff = abs(db[i].refresh - refresh);
+ if (score < diff) {
+ diff = score;
best = i;
}
}
diff --git a/drivers/video/fbdev/goldfishfb.c b/drivers/video/fbdev/goldfishfb.c
index 88adb2970b44..39662b2e3537 100644
--- a/drivers/video/fbdev/goldfishfb.c
+++ b/drivers/video/fbdev/goldfishfb.c
@@ -368,6 +368,7 @@ static int goldfish_fb_remove(struct platform_device *pdev)
dma_free_coherent(&pdev->dev, framesize, (void *)fb->fb.screen_base,
fb->fb.fix.smem_start);
iounmap(fb->reg_base);
+ kfree(fb);
return 0;
}
diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c
index 0d41f41371dd..69b9149cd750 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.c
+++ b/drivers/video/fbdev/msm/mdss_dsi.c
@@ -2043,10 +2043,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;
@@ -2066,14 +2065,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)
@@ -2086,9 +2080,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);
@@ -2096,8 +2089,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;
@@ -2248,12 +2240,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:
@@ -2330,13 +2316,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__);
@@ -2353,12 +2391,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
@@ -2374,39 +2408,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;
- }
- }
- rc = __mdss_dsi_dfps_calc_clks(pdata, new_fps);
- if (rc) {
- pr_err("error calculating clocks for %d\n", new_fps);
- goto error_clks;
- }
+ 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;
+ }
- rc = __mdss_dsi_dfps_update_clks(pdata, new_fps);
- if (rc) {
- pr_err("Dynamic refresh failed-%d\n", new_fps);
- goto error_dfps;
+ mpinfo = &mctrl_pdata->panel_data.panel_info;
+ }
+ /*
+ * 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;
}
@@ -2678,6 +2718,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)
{
@@ -2844,6 +3041,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,
@@ -3392,7 +3597,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) {
@@ -4359,11 +4564,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);
diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h
index 9847016fed29..900513931547 100644
--- a/drivers/video/fbdev/msm/mdss_dsi.h
+++ b/drivers/video/fbdev/msm/mdss_dsi.h
@@ -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
@@ -633,8 +633,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);
diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c
index e691f40e96bb..bf695ae0beaf 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_panel.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c
@@ -2320,14 +2320,15 @@ static void mdss_dsi_parse_dfps_config(struct device_node *pan_node,
struct mdss_dsi_ctrl_pdata *ctrl_pdata)
{
const char *data;
- bool dynamic_fps;
+ bool dynamic_fps, dynamic_bitclk;
struct mdss_panel_info *pinfo = &(ctrl_pdata->panel_data.panel_info);
+ int rc = 0;
dynamic_fps = of_property_read_bool(pan_node,
"qcom,mdss-dsi-pan-enable-dynamic-fps");
if (!dynamic_fps)
- return;
+ goto dynamic_bitclk;
pinfo->dynamic_fps = true;
data = of_get_property(pan_node, "qcom,mdss-dsi-pan-fps-update", NULL);
@@ -2357,6 +2358,31 @@ static void mdss_dsi_parse_dfps_config(struct device_node *pan_node,
pinfo->new_fps = pinfo->mipi.frame_rate;
pinfo->current_fps = pinfo->mipi.frame_rate;
+dynamic_bitclk:
+ dynamic_bitclk = of_property_read_bool(pan_node,
+ "qcom,mdss-dsi-pan-enable-dynamic-bitclk");
+ if (!dynamic_bitclk)
+ return;
+
+ of_find_property(pan_node, "qcom,mdss-dsi-dynamic-bitclk_freq",
+ &pinfo->supp_bitclk_len);
+ pinfo->supp_bitclk_len = pinfo->supp_bitclk_len/sizeof(u32);
+ if (pinfo->supp_bitclk_len < 1)
+ return;
+
+ pinfo->supp_bitclks = kzalloc((sizeof(u32) * pinfo->supp_bitclk_len),
+ GFP_KERNEL);
+ if (!pinfo->supp_bitclks)
+ return;
+
+ rc = of_property_read_u32_array(pan_node,
+ "qcom,mdss-dsi-dynamic-bitclk_freq", pinfo->supp_bitclks,
+ pinfo->supp_bitclk_len);
+ if (rc) {
+ pr_err("Error from dynamic bitclk freq u64 array read\n");
+ return;
+ }
+ pinfo->dynamic_bitclk = true;
return;
}
diff --git a/drivers/video/fbdev/msm/mdss_dsi_phy.c b/drivers/video/fbdev/msm/mdss_dsi_phy.c
index 2d2498643c3f..e8e903e6ce88 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_phy.c
+++ b/drivers/video/fbdev/msm/mdss_dsi_phy.c
@@ -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) {
diff --git a/drivers/video/fbdev/msm/mdss_dsi_phy.h b/drivers/video/fbdev/msm/mdss_dsi_phy.h
index 03df17d81f69..b0f7d68556d5 100644
--- a/drivers/video/fbdev/msm/mdss_dsi_phy.h
+++ b/drivers/video/fbdev/msm/mdss_dsi_phy.h
@@ -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
diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c
index 6c4db0f1f5bd..1b408e2838d6 100644
--- a/drivers/video/fbdev/msm/mdss_fb.c
+++ b/drivers/video/fbdev/msm/mdss_fb.c
@@ -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;
}
diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
index 8cbe32940887..710aebbd9c59 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
@@ -4894,7 +4894,8 @@ static inline void __mdss_mdp_mixer_write_layer(struct mdss_mdp_ctl *ctl,
u32 off[NUM_MIXERCFG_REGS];
int i;
- BUG_ON(!values || count < NUM_MIXERCFG_REGS);
+ if (WARN_ON(!values || count < NUM_MIXERCFG_REGS))
+ return;
__mdss_mdp_mixer_get_offsets(mixer_num, off, ARRAY_SIZE(off));
diff --git a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
index 478dca59db2b..83ab9c3973af 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_intf_cmd.c
@@ -745,7 +745,9 @@ int mdss_mdp_resource_control(struct mdss_mdp_ctl *ctl, u32 sw_event)
}
/* Get both controllers in the correct order for dual displays */
- mdss_mdp_get_split_display_ctls(&ctl, &sctl);
+ rc = mdss_mdp_get_split_display_ctls(&ctl, &sctl);
+ if (rc)
+ goto exit;
ctx = (struct mdss_mdp_cmd_ctx *) ctl->intf_ctx[MASTER_CTX];
if (!ctx) {
diff --git a/drivers/video/fbdev/msm/mdss_panel.h b/drivers/video/fbdev/msm/mdss_panel.h
index acac672662c1..de3ff0c77625 100644
--- a/drivers/video/fbdev/msm/mdss_panel.h
+++ b/drivers/video/fbdev/msm/mdss_panel.h
@@ -805,6 +805,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;
diff --git a/drivers/video/fbdev/msm/msm_mdss_io_8974.c b/drivers/video/fbdev/msm/msm_mdss_io_8974.c
index bb3b4b3fa929..922c4440ba82 100644
--- a/drivers/video/fbdev/msm/msm_mdss_io_8974.c
+++ b/drivers/video/fbdev/msm/msm_mdss_io_8974.c
@@ -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,
diff --git a/drivers/video/fbdev/omap/omapfb_main.c b/drivers/video/fbdev/omap/omapfb_main.c
index 393ae1bc07e8..a8a6f072fb78 100644
--- a/drivers/video/fbdev/omap/omapfb_main.c
+++ b/drivers/video/fbdev/omap/omapfb_main.c
@@ -977,7 +977,7 @@ int omapfb_register_client(struct omapfb_notifier_block *omapfb_nb,
{
int r;
- if ((unsigned)omapfb_nb->plane_idx > OMAPFB_PLANE_NUM)
+ if ((unsigned)omapfb_nb->plane_idx >= OMAPFB_PLANE_NUM)
return -EINVAL;
if (!notifier_inited) {
diff --git a/drivers/video/fbdev/via/viafbdev.c b/drivers/video/fbdev/via/viafbdev.c
index badee04ef496..71b5dca95bdb 100644
--- a/drivers/video/fbdev/via/viafbdev.c
+++ b/drivers/video/fbdev/via/viafbdev.c
@@ -19,6 +19,7 @@
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#include <linux/compiler.h>
#include <linux/module.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
@@ -1468,7 +1469,7 @@ static const struct file_operations viafb_vt1636_proc_fops = {
#endif /* CONFIG_FB_VIA_DIRECT_PROCFS */
-static int viafb_sup_odev_proc_show(struct seq_file *m, void *v)
+static int __maybe_unused viafb_sup_odev_proc_show(struct seq_file *m, void *v)
{
via_odev_to_seq(m, supported_odev_map[
viaparinfo->shared->chip_info.gfx_chip_name]);