diff options
-rw-r--r-- | Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt | 6 | ||||
-rw-r--r-- | arch/arm/boot/dts/qcom/sdm630-mdss-pll.dtsi | 7 | ||||
-rw-r--r-- | arch/arm/boot/dts/qcom/sdm630-mdss.dtsi | 15 | ||||
-rw-r--r-- | arch/arm/boot/dts/qcom/sdm630.dtsi | 7 | ||||
-rw-r--r-- | arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi | 3 | ||||
-rw-r--r-- | arch/arm/boot/dts/qcom/sdm660-mdss-pll.dtsi | 13 | ||||
-rw-r--r-- | arch/arm/boot/dts/qcom/sdm660-mdss.dtsi | 28 | ||||
-rw-r--r-- | arch/arm/boot/dts/qcom/sdm660.dtsi | 7 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_dsi.c | 329 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_dsi.h | 6 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_dsi_panel.c | 32 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_dsi_phy.c | 31 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_dsi_phy.h | 4 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_fb.c | 6 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/mdss_panel.h | 3 | ||||
-rw-r--r-- | drivers/video/fbdev/msm/msm_mdss_io_8974.c | 103 |
16 files changed, 449 insertions, 151 deletions
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt index cc55f6e2bfa0..4d0e1d5e12a2 100644 --- a/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt +++ b/Documentation/devicetree/bindings/fb/mdss-dsi-panel.txt @@ -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>; diff --git a/arch/arm/boot/dts/qcom/sdm630-mdss-pll.dtsi b/arch/arm/boot/dts/qcom/sdm630-mdss-pll.dtsi index 42eac0ab223a..3adf92a76347 100644 --- a/arch/arm/boot/dts/qcom/sdm630-mdss-pll.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-mdss-pll.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-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 @@ -19,8 +19,9 @@ #clock-cells = <1>; reg = <0xc994400 0x588>, - <0xc8c2300 0x8>; - reg-names = "pll_base", "gdsc_base"; + <0xc8c2300 0x8>, + <0xc994200 0x98>; + reg-names = "pll_base", "gdsc_base", "dynamic_pll_base"; gdsc-supply = <&gdsc_mdss>; diff --git a/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi b/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi index d7fef426d4b6..de06a67db1b9 100644 --- a/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630-mdss.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2017-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 @@ -359,10 +359,19 @@ <&clock_mmss MMSS_MDSS_ESC0_CLK>, <&clock_mmss BYTE0_CLK_SRC>, <&clock_mmss PCLK0_CLK_SRC>, - <&clock_mmss MMSS_MDSS_BYTE0_INTF_CLK>; + <&clock_mmss MMSS_MDSS_BYTE0_INTF_CLK>, + <&mdss_dsi0_pll BYTE0_MUX_CLK>, + <&mdss_dsi0_pll PIX0_MUX_CLK>, + <&mdss_dsi0_pll BYTE0_SRC_CLK>, + <&mdss_dsi0_pll PIX0_SRC_CLK>, + <&mdss_dsi0_pll SHADOW_BYTE0_SRC_CLK>, + <&mdss_dsi0_pll SHADOW_PIX0_SRC_CLK>; clock-names = "byte_clk", "pixel_clk", "core_clk", "byte_clk_rcg", "pixel_clk_rcg", - "byte_intf_clk"; + "byte_intf_clk", "pll_byte_clk_mux", + "pll_pixel_clk_mux", "pll_byte_clk_src", + "pll_pixel_clk_src", "pll_shadow_byte_clk_src", + "pll_shadow_pixel_clk_src"; qcom,platform-strength-ctrl = [ff 06 ff 06 diff --git a/arch/arm/boot/dts/qcom/sdm630.dtsi b/arch/arm/boot/dts/qcom/sdm630.dtsi index 1e767b4648b1..808421c763ea 100644 --- a/arch/arm/boot/dts/qcom/sdm630.dtsi +++ b/arch/arm/boot/dts/qcom/sdm630.dtsi @@ -406,9 +406,14 @@ }; cont_splash_mem: splash_region@9d400000 { - reg = <0x0 0x9d400000 0x0 0x02400000>; + reg = <0x0 0x9d400000 0x0 0x23ff000>; label = "cont_splash_mem"; }; + + dfps_data_mem: dfps_data_mem@0x9f7ff000 { + reg = <0 0x9f7ff000 0 0x00001000>; + label = "dfps_data_mem"; + }; }; bluetooth: bt_wcn3990 { diff --git a/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi b/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi index b2f4a8ce47d3..4232c8c5d41b 100644 --- a/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-mdss-panels.dtsi @@ -144,6 +144,9 @@ qcom,mdss-dsi-panel-max-error-count = <3>; qcom,mdss-dsi-min-refresh-rate = <53>; qcom,mdss-dsi-max-refresh-rate = <60>; + qcom,mdss-dsi-pan-enable-dynamic-bitclk; + qcom,mdss-dsi-dynamic-bitclk_freq = <711037824 724453632 737869440 + 751285248 764701056 778116864 791532672 804948480>; qcom,mdss-dsi-pan-enable-dynamic-fps; qcom,mdss-dsi-pan-fps-update = "dfps_immediate_porch_mode_vfp"; }; diff --git a/arch/arm/boot/dts/qcom/sdm660-mdss-pll.dtsi b/arch/arm/boot/dts/qcom/sdm660-mdss-pll.dtsi index 69d3736d4ba8..a3b6aadd893e 100644 --- a/arch/arm/boot/dts/qcom/sdm660-mdss-pll.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-mdss-pll.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 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 @@ -19,8 +19,9 @@ #clock-cells = <1>; reg = <0xc994400 0x588>, - <0xc8c2300 0x8>; - reg-names = "pll_base", "gdsc_base"; + <0xc8c2300 0x8>, + <0xc994200 0x98>; + reg-names = "pll_base", "gdsc_base", "dynamic_pll_base"; gdsc-supply = <&gdsc_mdss>; @@ -29,6 +30,7 @@ clock-rate = <0>; qcom,dsi-pll-ssc-en; qcom,dsi-pll-ssc-mode = "down-spread"; + memory-region = <&dfps_data_mem>; qcom,platform-supply-entries { #address-cells = <1>; @@ -54,8 +56,9 @@ #clock-cells = <1>; reg = <0xc996400 0x588>, - <0xc8c2300 0x8>; - reg-names = "pll_base", "gdsc_base"; + <0xc8c2300 0x8>, + <0xc996200 0x98>; + reg-names = "pll_base", "gdsc_base", "dynamic_pll_base"; gdsc-supply = <&gdsc_mdss>; diff --git a/arch/arm/boot/dts/qcom/sdm660-mdss.dtsi b/arch/arm/boot/dts/qcom/sdm660-mdss.dtsi index ab4e71e3cd65..b4fbb23c51e4 100644 --- a/arch/arm/boot/dts/qcom/sdm660-mdss.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660-mdss.dtsi @@ -1,4 +1,4 @@ -/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 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 @@ -382,10 +382,19 @@ <&clock_mmss MMSS_MDSS_ESC0_CLK>, <&clock_mmss BYTE0_CLK_SRC>, <&clock_mmss PCLK0_CLK_SRC>, - <&clock_mmss MMSS_MDSS_BYTE0_INTF_CLK>; + <&clock_mmss MMSS_MDSS_BYTE0_INTF_CLK>, + <&mdss_dsi0_pll BYTE0_MUX_CLK>, + <&mdss_dsi0_pll PIX0_MUX_CLK>, + <&mdss_dsi0_pll BYTE0_SRC_CLK>, + <&mdss_dsi0_pll PIX0_SRC_CLK>, + <&mdss_dsi0_pll SHADOW_BYTE0_SRC_CLK>, + <&mdss_dsi0_pll SHADOW_PIX0_SRC_CLK>; clock-names = "byte_clk", "pixel_clk", "core_clk", "byte_clk_rcg", "pixel_clk_rcg", - "byte_intf_clk"; + "byte_intf_clk", "pll_byte_clk_mux", + "pll_pixel_clk_mux", "pll_byte_clk_src", + "pll_pixel_clk_src", "pll_shadow_byte_clk_src", + "pll_shadow_pixel_clk_src"; qcom,null-insertion-enabled; qcom,platform-strength-ctrl = [ff 06 @@ -423,10 +432,19 @@ <&clock_mmss MMSS_MDSS_ESC1_CLK>, <&clock_mmss BYTE1_CLK_SRC>, <&clock_mmss PCLK1_CLK_SRC>, - <&clock_mmss MMSS_MDSS_BYTE1_INTF_CLK>; + <&clock_mmss MMSS_MDSS_BYTE1_INTF_CLK>, + <&mdss_dsi1_pll BYTE1_MUX_CLK>, + <&mdss_dsi1_pll PIX1_MUX_CLK>, + <&mdss_dsi1_pll BYTE1_SRC_CLK>, + <&mdss_dsi1_pll PIX1_SRC_CLK>, + <&mdss_dsi1_pll SHADOW_BYTE1_SRC_CLK>, + <&mdss_dsi1_pll SHADOW_PIX1_SRC_CLK>; clock-names = "byte_clk", "pixel_clk", "core_clk", "byte_clk_rcg", "pixel_clk_rcg", - "byte_intf_clk"; + "byte_intf_clk", "pll_byte_clk_mux", + "pll_pixel_clk_mux", "pll_byte_clk_src", + "pll_pixel_clk_src", "pll_shadow_byte_clk_src", + "pll_shadow_pixel_clk_src"; qcom,null-insertion-enabled; qcom,platform-strength-ctrl = [ff 06 diff --git a/arch/arm/boot/dts/qcom/sdm660.dtsi b/arch/arm/boot/dts/qcom/sdm660.dtsi index ef72d6bed86f..27bc0cebfc2a 100644 --- a/arch/arm/boot/dts/qcom/sdm660.dtsi +++ b/arch/arm/boot/dts/qcom/sdm660.dtsi @@ -404,9 +404,14 @@ }; cont_splash_mem: splash_region@9d400000 { - reg = <0x0 0x9d400000 0x0 0x02400000>; + reg = <0x0 0x9d400000 0x0 0x23ff000>; label = "cont_splash_mem"; }; + + dfps_data_mem: dfps_data_mem@0x9f7ff000 { + reg = <0 0x9f7ff000 0 0x00001000>; + label = "dfps_data_mem"; + }; }; bluetooth: bt_wcn3990 { 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 dbd58f93e907..5ba0480436a2 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_panel.c +++ b/drivers/video/fbdev/msm/mdss_dsi_panel.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 @@ -2324,14 +2324,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); @@ -2361,6 +2362,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_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, |