diff options
| -rw-r--r-- | Documentation/devicetree/bindings/fb/mdss-dsi.txt | 172 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_dsi.c | 251 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_dsi.h | 89 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_dsi_host.c | 31 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_dsi_panel.c | 7 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/msm_mdss_io_8974.c | 274 |
6 files changed, 484 insertions, 340 deletions
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi.txt b/Documentation/devicetree/bindings/fb/mdss-dsi.txt index 2c520a7f72e0..0e23a0f607f8 100644 --- a/Documentation/devicetree/bindings/fb/mdss-dsi.txt +++ b/Documentation/devicetree/bindings/fb/mdss-dsi.txt @@ -11,6 +11,30 @@ Required properties: "hw-config" = "split_dsi" - ranges: The standard property which specifies the child address space, parent address space and the length. +- vdda-supply: Phandle for vreg regulator device node. + +Optional properties: +- vcca-supply: Phandle for vcca regulator device node. +- qcom,<type>-supply-entries: A node that lists the elements of the supply used by the + a particular "type" of DSI modulee. The module "types" + can be "core", "ctrl", and "phy". Within the same type, + there can be more than one instance of this binding, + in which case the entry would be appended with the + supply entry index. + e.g. qcom,ctrl-supply-entry@0 + -- qcom,supply-name: name of the supply (vdd/vdda/vddio) + -- qcom,supply-min-voltage: minimum voltage level (uV) + -- qcom,supply-max-voltage: maximum voltage level (uV) + -- qcom,supply-enable-load: load drawn (uA) from enabled supply + -- qcom,supply-disable-load: load drawn (uA) from disabled supply + -- qcom,supply-pre-on-sleep: time to sleep (ms) before turning on + -- qcom,supply-post-on-sleep: time to sleep (ms) after turning on + -- qcom,supply-pre-off-sleep: time to sleep (ms) before turning off + -- qcom,supply-post-off-sleep: time to sleep (ms) after turning off +- qcom,mmss-ulp-clamp-ctrl-offset: Specifies the offset for dsi ulps clamp control register. +- qcom,mmss-phyreset-ctrl-offset: Specifies the offset for dsi phy reset control register. +- qcom,timing-db-mode: Boolean specifies dsi timing mode registers are supported or not. +- qcom,dsi-clk-ln-recovery: Boolean which enables the clk lane recovery mdss-dsi-ctrl is a dsi controller device which is treated as a subnode of the mdss-dsi device. @@ -22,10 +46,10 @@ Required properties: - reg-names: A list of strings that map in order to the list of regs. "dsi_ctrl" - MDSS DSI controller register region "dsi_phy" - MDSS DSI PHY register region + "dsi_phy_regulator" - MDSS DSI PHY REGULATOR region "mmss_misc_phys" - Register region for MMSS DSI clamps - vdd-supply: Phandle for vdd regulator device node. - vddio-supply: Phandle for vdd-io regulator device node. -- vdda-supply: Phandle for vreg regulator device node. - qcom,mdss-fb-map: pHandle that specifies the framebuffer to which the interface is mapped. - qcom,mdss-mdp: pHandle that specifies the mdss-mdp device. @@ -35,33 +59,13 @@ Required properties: strengthCtrl settings. It use 10 bytes for 8996 pll. - qcom,platform-lane-config: An array of length 45 or 20 that specifies the PHY lane configuration settings. It use 20 bytes for 8996 pll. +- qcom,platform-bist-ctrl: An array of length 6 that specifies the PHY + BIST ctrl settings. - qcom,dsi-pref-prim-pan: phandle that specifies the primary panel to be used with the controller. Optional properties: - label: A string used to describe the controller used. - -- reg-names: A list of strings that map in order to the list of regs. - "dsi_phy_regulator" - MDSS DSI PHY REGULATOR region -- qcom,platform-bist-ctrl: An array of length 6 that specifies the PHY - BIST ctrl settings. -- vcca-supply: Phandle for vcca regulator device node. -- qcom,<type>-supply-entries: A node that lists the elements of the supply used by the - a particular "type" of DSI modulee. The module "types" - can be "core", "ctrl", and "phy". Within the same type, - there can be more than one instance of this binding, - in which case the entry would be appended with the - supply entry index. - e.g. qcom,ctrl-supply-entry@0 - -- qcom,supply-name: name of the supply (vdd/vdda/vddio) - -- qcom,supply-min-voltage: minimum voltage level (uV) - -- qcom,supply-max-voltage: maximum voltage level (uV) - -- qcom,supply-enable-load: load drawn (uA) from enabled supply - -- qcom,supply-disable-load: load drawn (uA) from disabled supply - -- qcom,supply-pre-on-sleep: time to sleep (ms) before turning on - -- qcom,supply-post-on-sleep: time to sleep (ms) after turning on - -- qcom,supply-pre-off-sleep: time to sleep (ms) before turning off - -- qcom,supply-post-off-sleep: time to sleep (ms) after turning off - qcom,platform-enable-gpio: Specifies the panel lcd/display enable gpio. - qcom,platform-reset-gpio: Specifies the panel reset gpio. - qcom,platform-te-gpio: Specifies the gpio used for TE. @@ -74,11 +78,7 @@ Optional properties: controller. These pin configurations are installed in the pinctrl device node. Refer to pinctrl-bindings.txt - qcom,regulator-ldo-mode: Boolean to enable ldo mode for the dsi phy regulator -- qcom,mmss-ulp-clamp-ctrl-offset: Specifies the offset for dsi ulps clamp control register. -- qcom,mmss-phyreset-ctrl-offset: Specifies the offset for dsi phy reset control register. - qcom,dsi-irq-line: Boolean specifies if DSI has a different irq line than mdp. -- qcom,timing-db-mode: Boolean specifies dsi timing mode registers are supported or not. -- qcom,dsi-clk-ln-recovery: Boolean which enables the clk lane recovery - qcom,lane-map: Specifies the data lane swap configuration. "lane_map_0123" = <0 1 2 3> (default value) "lane_map_3012" = <3 0 1 2> @@ -95,11 +95,70 @@ Example: hw-config = "single_dsi"; #address-cells = <1>; #size-cells = <1>; + vdda-supply = <&pm8226_l4>; + vcca-supply = <&pm8226_l28>; reg = <0x1a98000 0x1a98000 0x25c 0x1a98500 0x1a98500 0x280 0x1a98780 0x1a98780 0x30 0x193e000 0x193e000 0x30>; + qcom,timing-db-mode; + qcom,dsi-clk-ln-recovery; + + qcom,core-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,core-supply-entry@0 { + reg = <0>; + qcom,supply-name = "gdsc"; + qcom,supply-min-voltage = <0>; + qcom,supply-max-voltage = <0>; + qcom,supply-enable-load = <0>; + qcom,supply-disable-load = <0>; + qcom,supply-pre-on-sleep = <0>; + qcom,supply-post-on-sleep = <0>; + qcom,supply-pre-off-sleep = <0>; + qcom,supply-post-off-sleep = <0>; + }; + }; + + qcom,phy-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,phy-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-pre-on-sleep = <0>; + qcom,supply-post-on-sleep = <20>; + qcom,supply-pre-off-sleep = <0>; + qcom,supply-post-off-sleep = <0>; + }; + }; + + qcom,ctrl-supply-entries { + #address-cells = <1>; + #size-cells = <0>; + + qcom,ctrl-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vdda"; + qcom,supply-min-voltage = <1200000>; + qcom,supply-max-voltage = <1200000>; + qcom,supply-enable-load = <100000>; + qcom,supply-disable-load = <100>; + qcom,supply-pre-on-sleep = <0>; + qcom,supply-post-on-sleep = <20>; + qcom,supply-pre-off-sleep = <0>; + qcom,supply-post-off-sleep = <0>; + }; + }; + mdss_dsi0: mdss_dsi_ctrl0@fd922800 { compatible = "qcom,mdss-dsi-ctrl"; label = "MDSS DSI CTRL->0"; @@ -113,8 +172,6 @@ Example: vdd-supply = <&pm8226_l15>; vddio-supply = <&pm8226_l8>; - vdda-supply = <&pm8226_l4>; - vcca-supply = <&pm8226_l28>; qcom,mdss-fb-map = <&mdss_fb0>; qcom,mdss-mdp = <&mdss_mdp>; @@ -142,63 +199,6 @@ Example: qcom,platform-bklight-en-gpio = <&msmgpio 86 0>; qcom,platform-mode-gpio = <&msmgpio 7 0>; qcom,dsi-irq-line; - qcom,timing-db-mode; - qcom,dsi-clk-ln-recovery; qcom,lane-map = "lane_map_3012"; - - qcom,core-supply-entries { - #address-cells = <1>; - #size-cells = <0>; - - qcom,core-supply-entry@0 { - reg = <0>; - qcom,supply-name = "gdsc"; - qcom,supply-min-voltage = <0>; - qcom,supply-max-voltage = <0>; - qcom,supply-enable-load = <0>; - qcom,supply-disable-load = <0>; - qcom,supply-pre-on-sleep = <0>; - qcom,supply-post-on-sleep = <0>; - qcom,supply-pre-off-sleep = <0>; - qcom,supply-post-off-sleep = <0>; - }; - }; - - qcom,phy-supply-entries { - #address-cells = <1>; - #size-cells = <0>; - - qcom,phy-supply-entry@0 { - reg = <0>; - qcom,supply-name = "vddio"; - qcom,supply-min-voltage = <1800000>; - qcom,supply-max-voltage = <1800000>; - qcom,supply-enable-load = <100000>; - qcom,supply-disable-load = <100>; - qcom,supply-pre-on-sleep = <0>; - qcom,supply-post-on-sleep = <20>; - qcom,supply-pre-off-sleep = <0>; - qcom,supply-post-off-sleep = <0>; - }; - }; - - qcom,ctrl-supply-entries { - #address-cells = <1>; - #size-cells = <0>; - - qcom,ctrl-supply-entry@0 { - reg = <0>; - qcom,supply-name = "vdda"; - qcom,supply-min-voltage = <1200000>; - qcom,supply-max-voltage = <1200000>; - qcom,supply-enable-load = <100000>; - qcom,supply-disable-load = <100>; - qcom,supply-pre-on-sleep = <0>; - qcom,supply-post-on-sleep = <20>; - qcom,supply-pre-off-sleep = <0>; - qcom,supply-post-off-sleep = <0>; - }; - }; - }; }; diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c index aa7d870fd4a7..8f04dc4786d7 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.c +++ b/drivers/video/fbdev/msm/mdss_dsi.c @@ -48,31 +48,29 @@ static struct mdss_dsi_ctrl_pdata *mdss_dsi_get_ctrl(u32 ctrl_id) return mdss_dsi_res->ctrl_pdata[ctrl_id]; } -static int mdss_dsi_regulator_init(struct platform_device *pdev) +static int mdss_dsi_regulator_init(struct platform_device *pdev, + struct dsi_shared_data *sdata) { - int rc = 0; - - struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; - int i = 0; + int rc = 0, i = 0, j = 0; - if (!pdev) { + if (!pdev || !sdata) { pr_err("%s: invalid input\n", __func__); return -EINVAL; } - ctrl_pdata = platform_get_drvdata(pdev); - if (!ctrl_pdata) { - pr_err("%s: invalid driver data\n", __func__); - return -EINVAL; - } - - for (i = 0; !rc && (i < DSI_MAX_PM); i++) { + for (i = DSI_CORE_PM; !rc && (i < DSI_MAX_PM); i++) { rc = msm_dss_config_vreg(&pdev->dev, - ctrl_pdata->power_data[i].vreg_config, - ctrl_pdata->power_data[i].num_vreg, 1); - if (rc) + sdata->power_data[i].vreg_config, + sdata->power_data[i].num_vreg, 1); + if (rc) { pr_err("%s: failed to init vregs for %s\n", __func__, __mdss_dsi_pm_name(i)); + for (j = i-1; j >= DSI_CORE_PM; j--) { + msm_dss_config_vreg(&pdev->dev, + sdata->power_data[j].vreg_config, + sdata->power_data[j].num_vreg, 0); + } + } } return rc; @@ -102,8 +100,8 @@ static int mdss_dsi_panel_power_off(struct mdss_panel_data *pdata) pr_debug("reset disable: pinctrl not enabled\n"); ret = msm_dss_enable_vreg( - ctrl_pdata->power_data[DSI_PANEL_PM].vreg_config, - ctrl_pdata->power_data[DSI_PANEL_PM].num_vreg, 0); + ctrl_pdata->panel_power_data.vreg_config, + ctrl_pdata->panel_power_data.num_vreg, 0); if (ret) pr_err("%s: failed to disable vregs for %s\n", __func__, __mdss_dsi_pm_name(DSI_PANEL_PM)); @@ -126,8 +124,8 @@ static int mdss_dsi_panel_power_on(struct mdss_panel_data *pdata) panel_data); ret = msm_dss_enable_vreg( - ctrl_pdata->power_data[DSI_PANEL_PM].vreg_config, - ctrl_pdata->power_data[DSI_PANEL_PM].num_vreg, 1); + ctrl_pdata->panel_power_data.vreg_config, + ctrl_pdata->panel_power_data.num_vreg, 1); if (ret) { pr_err("%s: failed to enable vregs for %s\n", __func__, __mdss_dsi_pm_name(DSI_PANEL_PM)); @@ -1138,6 +1136,13 @@ static int mdss_dsi_pinctrl_set_state( if (IS_ERR_OR_NULL(ctrl_pdata->pin_res.pinctrl)) return PTR_ERR(ctrl_pdata->pin_res.pinctrl); + if (mdss_dsi_is_right_ctrl(ctrl_pdata) && + mdss_dsi_is_hw_config_split(ctrl_pdata->shared_data)) { + pr_debug("%s:%d, right ctrl pinctrl config not needed\n", + __func__, __LINE__); + return 0; + } + pin_state = active ? ctrl_pdata->pin_res.gpio_state_active : ctrl_pdata->pin_res.gpio_state_suspend; if (!IS_ERR_OR_NULL(pin_state)) { @@ -1412,7 +1417,7 @@ static void __mdss_dsi_update_video_mode_total(struct mdss_panel_data *pdata, } ctrl_rev = MIPI_INP(ctrl_pdata->ctrl_base); /* Flush DSI TIMING registers for 8916/8939 */ - if (ctrl_pdata->timing_db_mode) + if (ctrl_pdata->shared_data->timing_db_mode) MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x1e4, 0x1); ctrl_pdata->panel_data.panel_info.mipi.frame_rate = new_fps; @@ -1615,7 +1620,7 @@ static int mdss_dsi_dfps_config(struct mdss_panel_data *pdata, int new_fps) * reguest. */ pinfo = &pdata->panel_info; - if (pinfo->is_split_display) { + if (mdss_dsi_is_hw_config_split(ctrl_pdata->shared_data)) { if (mdss_dsi_is_right_ctrl(ctrl_pdata)) { pr_debug("%s DFPS already updated.\n", __func__); return rc; @@ -2060,7 +2065,7 @@ static struct device_node *mdss_dsi_config_panel(struct platform_device *pdev) static int mdss_dsi_ctrl_probe(struct platform_device *pdev) { - int rc = 0, i = 0; + int rc = 0; u32 index; struct mdss_dsi_ctrl_pdata *ctrl_pdata = NULL; struct device_node *dsi_pan_node = NULL; @@ -2113,19 +2118,6 @@ static int mdss_dsi_ctrl_probe(struct platform_device *pdev) if (rc) pr_warn("%s: failed to get pin resources\n", __func__); - /* Parse the regulator information */ - for (i = 0; i < DSI_MAX_PM; i++) { - if (DSI_PANEL_PM == i) - continue; - rc = mdss_dsi_get_dt_vreg_data(&pdev->dev, pdev->dev.of_node, - &ctrl_pdata->power_data[i], i); - if (rc) { - DEV_ERR("%s: '%s' get_dt_vreg_data failed.rc=%d\n", - __func__, __mdss_dsi_pm_name(i), rc); - goto error_vreg; - } - } - if (index == 0) ctrl_pdata->panel_data.panel_info.pdest = DISPLAY_1; else @@ -2134,13 +2126,11 @@ static int mdss_dsi_ctrl_probe(struct platform_device *pdev) dsi_pan_node = mdss_dsi_config_panel(pdev); if (!dsi_pan_node) { pr_err("%s: panel configuration failed\n", __func__); - i--; - rc = -EINVAL; - goto error_vreg; + return -EINVAL; } - if ((mdss_dsi_res->hw_config != SPLIT_DSI) || - ((mdss_dsi_res->hw_config == SPLIT_DSI) && + if (!mdss_dsi_is_hw_config_split(ctrl_pdata->shared_data) || + (mdss_dsi_is_hw_config_split(ctrl_pdata->shared_data) && (ctrl_pdata->panel_data.panel_info.pdest == DISPLAY_1))) { rc = mdss_panel_parse_bl_settings(dsi_pan_node, ctrl_pdata); if (rc) { @@ -2173,18 +2163,38 @@ static int mdss_dsi_ctrl_probe(struct platform_device *pdev) error_pan_node: of_node_put(dsi_pan_node); - i--; -error_vreg: - for (; i >= 0; i--) - mdss_dsi_put_dt_vreg_data(&pdev->dev, - &ctrl_pdata->power_data[i]); return rc; } +static int mdss_dsi_parse_dt_params(struct platform_device *pdev, + struct dsi_shared_data *sdata) +{ + int rc = 0; + + rc = of_property_read_u32(pdev->dev.of_node, + "qcom,mmss-ulp-clamp-ctrl-offset", + &sdata->ulps_clamp_ctrl_off); + if (!rc) { + rc = of_property_read_u32(pdev->dev.of_node, + "qcom,mmss-phyreset-ctrl-offset", + &sdata->ulps_phyrst_ctrl_off); + } + + sdata->timing_db_mode = of_property_read_bool( + pdev->dev.of_node, "qcom,timing-db-mode"); + + sdata->cmd_clk_ln_recovery_en = + of_property_read_bool(pdev->dev.of_node, + "qcom,dsi-clk-ln-recovery"); + + return 0; +} + static void mdss_dsi_res_deinit(struct platform_device *pdev) { int i; struct mdss_dsi_data *dsi_res = platform_get_drvdata(pdev); + struct dsi_shared_data *sdata; if (!dsi_res) { pr_err("%s: DSI root device drvdata not found\n", __func__); @@ -2196,6 +2206,26 @@ static void mdss_dsi_res_deinit(struct platform_device *pdev) devm_kfree(&pdev->dev, dsi_res->ctrl_pdata[i]); } + sdata = dsi_res->shared_data; + if (!sdata) + goto res_release; + + for (i = (DSI_MAX_PM - 1); i >= DSI_CORE_PM; i--) { + if (msm_dss_config_vreg(&pdev->dev, + sdata->power_data[i].vreg_config, + sdata->power_data[i].num_vreg, 1) < 0) + pr_err("%s: failed to de-init vregs for %s\n", + __func__, __mdss_dsi_pm_name(i)); + mdss_dsi_put_dt_vreg_data(&pdev->dev, + &sdata->power_data[i]); + } + + mdss_dsi_bus_clk_deinit(&pdev->dev, sdata); + + if (sdata) + devm_kfree(&pdev->dev, sdata); + +res_release: if (dsi_res) devm_kfree(&pdev->dev, dsi_res); @@ -2205,6 +2235,7 @@ static void mdss_dsi_res_deinit(struct platform_device *pdev) static int mdss_dsi_res_init(struct platform_device *pdev) { int rc = 0, i; + struct dsi_shared_data *sdata; mdss_dsi_res = platform_get_drvdata(pdev); if (!mdss_dsi_res) { @@ -2218,18 +2249,69 @@ static int mdss_dsi_res_init(struct platform_device *pdev) goto mem_fail; } + mdss_dsi_res->shared_data = devm_kzalloc(&pdev->dev, + sizeof(struct dsi_shared_data), + GFP_KERNEL); + pr_debug("%s Allocated shared_data=%p\n", __func__, + mdss_dsi_res->shared_data); + if (!mdss_dsi_res->shared_data) { + pr_err("%s Unable to alloc mem for shared_data\n", + __func__); + rc = -ENOMEM; + goto mem_fail; + } + + sdata = mdss_dsi_res->shared_data; + + rc = mdss_dsi_parse_dt_params(pdev, sdata); + if (rc) { + pr_err("%s: failed to parse mdss dsi DT params\n", + __func__); + goto mem_fail; + } + + rc = mdss_dsi_bus_clk_init(pdev, sdata); + if (rc) { + pr_err("%s: failed to initialize DSI Bus clocks\n", + __func__); + goto mem_fail; + } + + /* Parse the regulator information */ + for (i = DSI_CORE_PM; i < DSI_MAX_PM; i++) { + rc = mdss_dsi_get_dt_vreg_data(&pdev->dev, + pdev->dev.of_node, &sdata->power_data[i], i); + if (rc) { + pr_err("%s: '%s' get_dt_vreg_data failed.rc=%d\n", + __func__, __mdss_dsi_pm_name(i), rc); + i--; + for (; i >= DSI_CORE_PM; i--) + mdss_dsi_put_dt_vreg_data(&pdev->dev, + &sdata->power_data[i]); + goto mem_fail; + } + } + rc = mdss_dsi_regulator_init(pdev, sdata); + if (rc) { + pr_err("%s: failed to init regulator, rc=%d\n", + __func__, rc); + goto mem_fail; + } + for (i = 0; i < DSI_CTRL_MAX; i++) { mdss_dsi_res->ctrl_pdata[i] = devm_kzalloc(&pdev->dev, sizeof(struct mdss_dsi_ctrl_pdata), GFP_KERNEL); - pr_debug("%s Allocated ctrl_pdata[%d]=%p\n", - __func__, i, mdss_dsi_res->ctrl_pdata[i]); if (!mdss_dsi_res->ctrl_pdata[i]) { pr_err("%s Unable to alloc mem for ctrl=%d\n", __func__, i); rc = -ENOMEM; goto mem_fail; } + pr_debug("%s Allocated ctrl_pdata[%d]=%p\n", + __func__, i, mdss_dsi_res->ctrl_pdata[i]); + mdss_dsi_res->ctrl_pdata[i]->shared_data = + mdss_dsi_res->shared_data; } platform_set_drvdata(pdev, mdss_dsi_res); @@ -2249,22 +2331,29 @@ static int mdss_dsi_parse_hw_cfg(struct platform_device *pdev) { const char *data; struct mdss_dsi_data *dsi_res = platform_get_drvdata(pdev); + struct dsi_shared_data *sdata; if (!dsi_res) { pr_err("%s: DSI root device drvdata not found\n", __func__); return -EINVAL; } - dsi_res->hw_config = SINGLE_DSI; + sdata = mdss_dsi_res->shared_data; + if (!sdata) { + pr_err("%s: DSI shared data not found\n", __func__); + return -EINVAL; + } + + sdata->hw_config = SINGLE_DSI; data = of_get_property(pdev->dev.of_node, "hw-config", NULL); if (data) { if (!strcmp(data, "dual_dsi")) - dsi_res->hw_config = DUAL_DSI; + sdata->hw_config = DUAL_DSI; else if (!strcmp(data, "split_dsi")) - dsi_res->hw_config = SPLIT_DSI; + sdata->hw_config = SPLIT_DSI; else if (!strcmp(data, "single_dsi")) - dsi_res->hw_config = SINGLE_DSI; + sdata->hw_config = SINGLE_DSI; else pr_err("%s: Incorrect string for DSI config:%s. Setting default as SINGLE_DSI\n", __func__, data); @@ -2275,7 +2364,7 @@ static int mdss_dsi_parse_hw_cfg(struct platform_device *pdev) } pr_debug("%s: DSI h/w configuration is %d\n", __func__, - dsi_res->hw_config); + sdata->hw_config); return 0; } @@ -2346,22 +2435,18 @@ static int mdss_dsi_ctrl_remove(struct platform_device *pdev) { struct msm_fb_data_type *mfd; struct mdss_dsi_ctrl_pdata *ctrl_pdata = platform_get_drvdata(pdev); - int i = 0; if (!ctrl_pdata) { pr_err("%s: no driver data\n", __func__); return -ENODEV; } - for (i = DSI_MAX_PM - 1; i >= 0; i--) { - if (msm_dss_config_vreg(&pdev->dev, - ctrl_pdata->power_data[i].vreg_config, - ctrl_pdata->power_data[i].num_vreg, 1) < 0) - pr_err("%s: failed to de-init vregs for %s\n", - __func__, __mdss_dsi_pm_name(i)); - mdss_dsi_put_dt_vreg_data(&pdev->dev, - &ctrl_pdata->power_data[i]); - } + if (msm_dss_config_vreg(&pdev->dev, + ctrl_pdata->panel_power_data.vreg_config, + ctrl_pdata->panel_power_data.num_vreg, 1) < 0) + pr_err("%s: failed to de-init vregs for %s\n", + __func__, __mdss_dsi_pm_name(DSI_PANEL_PM)); + mdss_dsi_put_dt_vreg_data(&pdev->dev, &ctrl_pdata->panel_power_data); mfd = platform_get_drvdata(pdev); msm_dss_iounmap(&ctrl_pdata->mmss_misc_io); @@ -2500,7 +2585,7 @@ static void mdss_dsi_parse_lane_swap(struct device_node *np, char *dlane_swap) static int mdss_dsi_parse_ctrl_params(struct platform_device *ctrl_pdev, struct device_node *pan_node, struct mdss_dsi_ctrl_pdata *ctrl_pdata) { - int rc, i, len; + int i, len; struct mdss_panel_info *pinfo = &(ctrl_pdata->panel_data.panel_info); const char *data; @@ -2552,26 +2637,11 @@ static int mdss_dsi_parse_ctrl_params(struct platform_device *ctrl_pdev, pinfo->mipi.dsi_phy_db.lanecfg[i] = data[i]; } - rc = of_property_read_u32(ctrl_pdev->dev.of_node, - "qcom,mmss-ulp-clamp-ctrl-offset", - &ctrl_pdata->ulps_clamp_ctrl_off); - if (rc && pinfo->mipi.mode == DSI_CMD_MODE) { - pr_err("%s: dsi clamp register settings missing\n", - __func__); - return -EINVAL; - } - rc = of_property_read_u32(ctrl_pdev->dev.of_node, - "qcom,mmss-phyreset-ctrl-offset", - &ctrl_pdata->ulps_phyrst_ctrl_off); - if (rc && pinfo->mipi.mode == DSI_CMD_MODE) - pr_debug("%s: dsi phyreset register settings missing\n", - __func__); - ctrl_pdata->cmd_sync_wait_broadcast = of_property_read_bool( pan_node, "qcom,cmd-sync-wait-broadcast"); if (ctrl_pdata->cmd_sync_wait_broadcast && - (mdss_dsi_res->hw_config == SPLIT_DSI) && + mdss_dsi_is_hw_config_split(ctrl_pdata->shared_data) && (pinfo->pdest == DISPLAY_2)) ctrl_pdata->cmd_sync_wait_trigger = true; @@ -2579,12 +2649,6 @@ static int mdss_dsi_parse_ctrl_params(struct platform_device *ctrl_pdev, ctrl_pdata->cmd_sync_wait_broadcast, ctrl_pdata->cmd_sync_wait_trigger); - ctrl_pdata->timing_db_mode = of_property_read_bool( - ctrl_pdev->dev.of_node, "qcom,timing-db-mode"); - - ctrl_pdata->cmd_clk_ln_recovery_en = of_property_read_bool( - ctrl_pdev->dev.of_node, "qcom,dsi-clk-ln-recovery"); - mdss_dsi_parse_lane_swap(ctrl_pdev->dev.of_node, &(ctrl_pdata->dlane_swap)); @@ -2650,6 +2714,7 @@ int dsi_panel_device_register(struct platform_device *ctrl_pdev, { struct mipi_panel_info *mipi; int rc; + struct dsi_shared_data *sdata; struct mdss_panel_info *pinfo = &(ctrl_pdata->panel_data.panel_info); struct resource *res; u64 clk_rate; @@ -2667,14 +2732,16 @@ int dsi_panel_device_register(struct platform_device *ctrl_pdev, } rc = mdss_dsi_get_dt_vreg_data(&ctrl_pdev->dev, pan_node, - &ctrl_pdata->power_data[DSI_PANEL_PM], DSI_PANEL_PM); + &ctrl_pdata->panel_power_data, DSI_PANEL_PM); if (rc) { DEV_ERR("%s: '%s' get_dt_vreg_data failed.rc=%d\n", __func__, __mdss_dsi_pm_name(DSI_PANEL_PM), rc); return rc; } - rc = mdss_dsi_regulator_init(ctrl_pdev); + rc = msm_dss_config_vreg(&ctrl_pdev->dev, + ctrl_pdata->panel_power_data.vreg_config, + ctrl_pdata->panel_power_data.num_vreg, 1); if (rc) { pr_err("%s: failed to init regulator, rc=%d\n", __func__, rc); @@ -2698,7 +2765,7 @@ int dsi_panel_device_register(struct platform_device *ctrl_pdev, return rc; } - if (mdss_dsi_clk_init(ctrl_pdev, ctrl_pdata)) { + if (mdss_dsi_link_clk_init(ctrl_pdev, ctrl_pdata)) { pr_err("%s: unable to initialize Dsi ctrl clks\n", __func__); return -EPERM; } @@ -2773,10 +2840,12 @@ int dsi_panel_device_register(struct platform_device *ctrl_pdev, * This is needed for the DSI PHY to maintain ULPS state during * suspend also. */ + sdata = ctrl_pdata->shared_data; + if (pinfo->ulps_suspend_enabled) { rc = msm_dss_enable_vreg( - ctrl_pdata->power_data[DSI_CTRL_PM].vreg_config, - ctrl_pdata->power_data[DSI_CTRL_PM].num_vreg, 1); + sdata->power_data[DSI_PHY_PM].vreg_config, + sdata->power_data[DSI_PHY_PM].num_vreg, 1); if (rc) { pr_err("%s: failed to enable vregs for DSI_CTRL_PM\n", __func__); diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h index a8076b6cac91..e6963c1426ae 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.h +++ b/drivers/video/fbdev/msm/mdss_dsi.h @@ -120,10 +120,11 @@ enum dsi_lane_map_type { }; enum dsi_pm_type { + /* PANEL_PM not used as part of power_data in dsi_shared_data */ + DSI_PANEL_PM, DSI_CORE_PM, DSI_CTRL_PM, DSI_PHY_PM, - DSI_PANEL_PM, DSI_MAX_PM }; @@ -210,12 +211,43 @@ enum { DSI_CTRL_MAX, }; -struct mdss_dsi_data { +/* + * Common DSI properties for each controller. The DSI root probe will create the + * shared_data struct which should be accessible to each controller. The goal is + * to only access ctrl_pdata and ctrl_pdata->shared_data during the lifetime of + * each controller i.e. mdss_dsi_res should not be used directly. + */ +struct dsi_shared_data { u32 hw_config; /* DSI setup configuration i.e. single/dual/split */ + u32 hw_rev; /* DSI h/w revision */ + + /* DSI ULPS clamp register offsets */ + u32 ulps_clamp_ctrl_off; + u32 ulps_phyrst_ctrl_off; + + bool timing_db_mode; + bool cmd_clk_ln_recovery_en; + + /* DSI bus clocks */ + struct clk *mdp_core_clk; + struct clk *ahb_clk; + struct clk *axi_clk; + struct clk *mmss_misc_ahb_clk; + + /* DSI core regulators */ + struct dss_module_power power_data[DSI_MAX_PM]; +}; + +struct mdss_dsi_data { bool res_init; struct platform_device *pdev; /* List of controller specific struct data */ struct mdss_dsi_ctrl_pdata *ctrl_pdata[DSI_CTRL_MAX]; + /* + * This structure should hold common data structures like + * mutex, clocks, regulator information, setup information + */ + struct dsi_shared_data *shared_data; }; /* @@ -298,7 +330,6 @@ struct mdss_dsi_ctrl_pdata { void (*switch_mode) (struct mdss_panel_data *pdata, int mode); struct mdss_panel_data panel_data; unsigned char *ctrl_base; - u32 hw_rev; struct dss_io_data ctrl_io; struct dss_io_data mmss_misc_io; struct dss_io_data phy_io; @@ -306,10 +337,6 @@ struct mdss_dsi_ctrl_pdata { u32 bus_clk_cnt; u32 link_clk_cnt; u32 flags; - struct clk *mdp_core_clk; - struct clk *ahb_clk; - struct clk *axi_clk; - struct clk *mmss_misc_ahb_clk; struct clk *byte_clk; struct clk *esc_clk; struct clk *pixel_clk; @@ -342,7 +369,6 @@ struct mdss_dsi_ctrl_pdata { bool dcs_cmd_insert; atomic_t te_irq_ready; - bool cmd_clk_ln_recovery_en; bool cmd_sync_wait_broadcast; bool cmd_sync_wait_trigger; @@ -352,7 +378,8 @@ struct mdss_dsi_ctrl_pdata { u32 pclk_rate; u32 byte_clk_rate; bool refresh_clk_rate; /* flag to recalculate clk_rate */ - struct dss_module_power power_data[DSI_MAX_PM]; + struct dss_module_power panel_power_data; + struct dss_module_power power_data[DSI_MAX_PM]; /* for 8x10 */ u32 dsi_irq_mask; struct mdss_hw *dsi_hw; struct mdss_intf_recovery *recovery; @@ -385,12 +412,9 @@ struct mdss_dsi_ctrl_pdata { struct regulator *ibb; /* vreg handle */ struct mutex clk_lane_mutex; - u32 ulps_clamp_ctrl_off; - u32 ulps_phyrst_ctrl_off; bool ulps; bool core_power; bool mmss_clamp; - bool timing_db_mode; char dlane_swap; /* data lane swap */ struct dsi_buf tx_buf; @@ -409,6 +433,7 @@ struct mdss_dsi_ctrl_pdata { int horizontal_idle_cnt; struct panel_horizontal_idle *line_idle; struct mdss_util_intf *mdss_util; + struct dsi_shared_data *shared_data; /* debugfs structure */ struct mdss_dsi_debugfs_info *debugfs_info; @@ -454,14 +479,20 @@ 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); -int mdss_dsi_clk_init(struct platform_device *pdev, +int mdss_dsi_link_clk_init(struct platform_device *pdev, struct mdss_dsi_ctrl_pdata *ctrl_pdata); +void mdss_dsi_link_clk_deinit(struct device *dev, + struct mdss_dsi_ctrl_pdata *ctrl_pdata); +int mdss_dsi_bus_clk_init(struct platform_device *pdev, + struct dsi_shared_data *sdata); +void mdss_dsi_bus_clk_deinit(struct device *dev, + struct dsi_shared_data *sdata); int mdss_dsi_shadow_clk_init(struct platform_device *pdev, struct mdss_dsi_ctrl_pdata *ctrl_pdata); +void mdss_dsi_shadow_clk_deinit(struct device *dev, + struct mdss_dsi_ctrl_pdata *ctrl_pdata); int mdss_dsi_pll_1_clk_init(struct platform_device *pdev, struct mdss_dsi_ctrl_pdata *ctrl_pdata); -void mdss_dsi_clk_deinit(struct mdss_dsi_ctrl_pdata *ctrl_pdata); -void mdss_dsi_shadow_clk_deinit(struct mdss_dsi_ctrl_pdata *ctrl_pdata); int mdss_dsi_enable_bus_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata); void mdss_dsi_disable_bus_clocks(struct mdss_dsi_ctrl_pdata *ctrl_pdata); int mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable); @@ -521,14 +552,24 @@ static inline const char *__mdss_dsi_pm_supply_node_name( } } -static inline bool mdss_dsi_split_display_enabled(void) +static inline u32 mdss_dsi_get_hw_config(struct dsi_shared_data *sdata) { - /* - * currently the only supported mode is split display. - * So, if both controllers are initialized, then assume that - * split display mode is enabled. - */ - return ctrl_list[DSI_CTRL_LEFT] && ctrl_list[DSI_CTRL_RIGHT]; + return sdata->hw_config; +} + +static inline bool mdss_dsi_is_hw_config_single(struct dsi_shared_data *sdata) +{ + return mdss_dsi_get_hw_config(sdata) == SINGLE_DSI; +} + +static inline bool mdss_dsi_is_hw_config_split(struct dsi_shared_data *sdata) +{ + return mdss_dsi_get_hw_config(sdata) == SPLIT_DSI; +} + +static inline bool mdss_dsi_is_hw_config_dual(struct dsi_shared_data *sdata) +{ + return mdss_dsi_get_hw_config(sdata) == DUAL_DSI; } static inline bool mdss_dsi_sync_wait_enable(struct mdss_dsi_ctrl_pdata *ctrl) @@ -571,13 +612,13 @@ static inline struct mdss_dsi_ctrl_pdata *mdss_dsi_get_ctrl_by_index(int ndx) static inline bool mdss_dsi_is_ctrl_clk_master(struct mdss_dsi_ctrl_pdata *ctrl) { - return mdss_dsi_split_display_enabled() && + return mdss_dsi_is_hw_config_split(ctrl->shared_data) && (ctrl->ndx == DSI_CTRL_CLK_MASTER); } static inline bool mdss_dsi_is_ctrl_clk_slave(struct mdss_dsi_ctrl_pdata *ctrl) { - return mdss_dsi_split_display_enabled() && + return mdss_dsi_is_hw_config_split(ctrl->shared_data) && (ctrl->ndx == DSI_CTRL_CLK_SLAVE); } diff --git a/drivers/video/fbdev/msm/mdss_dsi_host.c b/drivers/video/fbdev/msm/mdss_dsi_host.c index 530d69d03a81..1f2257064866 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_host.c +++ b/drivers/video/fbdev/msm/mdss_dsi_host.c @@ -260,17 +260,17 @@ void mdss_dsi_cmd_test_pattern(struct mdss_dsi_ctrl_pdata *ctrl) void mdss_dsi_read_hw_revision(struct mdss_dsi_ctrl_pdata *ctrl) { /* clock must be on */ - ctrl->hw_rev = MIPI_INP(ctrl->ctrl_base); + ctrl->shared_data->hw_rev = MIPI_INP(ctrl->ctrl_base); } void mdss_dsi_get_hw_revision(struct mdss_dsi_ctrl_pdata *ctrl) { mdss_dsi_clk_ctrl(ctrl, DSI_ALL_CLKS, 1); - ctrl->hw_rev = MIPI_INP(ctrl->ctrl_base); + ctrl->shared_data->hw_rev = MIPI_INP(ctrl->ctrl_base); mdss_dsi_clk_ctrl(ctrl, DSI_ALL_CLKS, 0); pr_debug("%s: ndx=%d hw_rev=%x\n", __func__, - ctrl->ndx, ctrl->hw_rev); + ctrl->ndx, ctrl->shared_data->hw_rev); } void mdss_dsi_host_init(struct mdss_panel_data *pdata) @@ -636,7 +636,7 @@ static void mdss_dsi_ctl_phy_reset(struct mdss_dsi_ctrl_pdata *ctrl) pr_debug("%s: MDSS DSI CTRL and PHY reset. ctrl-num = %d\n", __func__, ctrl->ndx); - if (ctrl->panel_data.panel_info.is_split_display) { + if (mdss_dsi_is_hw_config_split(ctrl->shared_data)) { pr_debug("%s: Split display enabled\n", __func__); ctrl0 = mdss_dsi_get_ctrl_by_index(DSI_CTRL_0); ctrl1 = mdss_dsi_get_ctrl_by_index(DSI_CTRL_1); @@ -1106,7 +1106,7 @@ static void mdss_dsi_mode_setup(struct mdss_panel_data *pdata) mipi = &pdata->panel_info.mipi; if (pdata->panel_info.type == MIPI_VIDEO_PANEL) { - if (ctrl_pdata->timing_db_mode) + if (ctrl_pdata->shared_data->timing_db_mode) MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x1e8, 0x1); MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x24, ((hspw + hbp + width + dummy_xres) << 16 | @@ -1121,7 +1121,7 @@ static void mdss_dsi_mode_setup(struct mdss_panel_data *pdata) MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x30, (hspw << 16)); MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x34, 0); MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x38, (vspw << 16)); - if (ctrl_pdata->timing_db_mode) + if (ctrl_pdata->shared_data->timing_db_mode) MIPI_OUTP((ctrl_pdata->ctrl_base) + 0x1e4, 0x1); } else { /* command mode */ if (mipi->dst_format == DSI_CMD_DST_FORMAT_RGB888) @@ -1526,7 +1526,7 @@ do_send: goto end; } - if (ctrl->hw_rev >= MDSS_DSI_HW_REV_101) { + if (ctrl->shared_data->hw_rev >= MDSS_DSI_HW_REV_101) { /* clear the RDBK_DATA registers */ MIPI_OUTP(ctrl->ctrl_base + 0x01d4, 0x1); wmb(); /* make sure the RDBK registers are cleared */ @@ -1767,7 +1767,7 @@ static int mdss_dsi_cmd_dma_rx(struct mdss_dsi_ctrl_pdata *ctrl, if (cnt > 4) cnt = 4; /* 4 x 32 bits registers only */ - if (ctrl->hw_rev >= MDSS_DSI_HW_REV_101) { + if (ctrl->shared_data->hw_rev >= MDSS_DSI_HW_REV_101) { rp->read_cnt = (MIPI_INP((ctrl->ctrl_base) + 0x01d4) >> 16); pr_debug("%s: bytes read:%d\n", __func__, rp->read_cnt); @@ -1949,7 +1949,7 @@ static int mdss_dsi_mdp_busy_tout_check(struct mdss_dsi_ctrl_pdata *ctrl) MIPI_OUTP(ctrl->ctrl_base + 0x0110, isr); mdss_dsi_disable_irq_nosync(ctrl, DSI_MDP_TERM); ctrl->mdp_busy = false; - if (ctrl->cmd_clk_ln_recovery_en && + if (ctrl->shared_data->cmd_clk_ln_recovery_en && ctrl->panel_mode == DSI_CMD_MODE) { /* has hs_lane_recovery do the work */ stop_hs_clk = true; @@ -2087,12 +2087,12 @@ int mdss_dsi_cmdlist_commit(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp) * will followed. */ if (!roi || (roi->w != 0 || roi->h != 0)) { - if (ctrl->cmd_clk_ln_recovery_en && + if (ctrl->shared_data->cmd_clk_ln_recovery_en && ctrl->panel_mode == DSI_CMD_MODE) mdss_dsi_start_hs_clk_lane(ctrl); } } else { /* from dcs send */ - if (ctrl->cmd_clk_ln_recovery_en && + if (ctrl->shared_data->cmd_clk_ln_recovery_en && ctrl->panel_mode == DSI_CMD_MODE && (req->flags & CMD_REQ_HS_MODE)) mdss_dsi_cmd_start_hs_clk_lane(ctrl); @@ -2163,7 +2163,7 @@ need_lock: mutex_unlock(&ctrl->cmd_mutex); } else { /* from dcs send */ - if (ctrl->cmd_clk_ln_recovery_en && + if (ctrl->shared_data->cmd_clk_ln_recovery_en && ctrl->panel_mode == DSI_CMD_MODE && (req && (req->flags & CMD_REQ_HS_MODE))) mdss_dsi_cmd_stop_hs_clk_lane(ctrl); @@ -2262,7 +2262,8 @@ static int dsi_event_thread(void *data) pr_debug("%s: lane_status: 0x%x\n", __func__, ln_status); if (ctrl->recovery - && (ctrl->hw_rev != MDSS_DSI_HW_REV_103) + && (ctrl->shared_data->hw_rev + != MDSS_DSI_HW_REV_103) && !(force_clk_ln_hs) && (ln_status & DSI_DATA_LANES_STOP_STATE) @@ -2276,7 +2277,7 @@ static int dsi_event_thread(void *data) DSI_INTR_ERROR_MASK, 1); mdss_dsi_clk_ctrl(ctrl, DSI_ALL_CLKS, 0); } else if (ctrl->recovery - && (ctrl->hw_rev + && (ctrl->shared_data->hw_rev == MDSS_DSI_HW_REV_103)) { pr_debug("%s: Handle overflow->Rev_103\n", __func__); @@ -2511,7 +2512,7 @@ irqreturn_t mdss_dsi_isr(int irq, void *ptr) MDSS_XLOG(ctrl->ndx, ctrl->mdp_busy, isr, 0x99); spin_lock(&ctrl->mdp_lock); mdss_dsi_disable_irq_nosync(ctrl, DSI_MDP_TERM); - if (ctrl->cmd_clk_ln_recovery_en && + if (ctrl->shared_data->cmd_clk_ln_recovery_en && ctrl->panel_mode == DSI_CMD_MODE) { /* stop force clk lane hs */ mdss_dsi_cfg_lane_ctrl(ctrl, BIT(28), 0); diff --git a/drivers/video/fbdev/msm/mdss_dsi_panel.c b/drivers/video/fbdev/msm/mdss_dsi_panel.c index b05689da9ec5..d6ad191cdf67 100644 --- a/drivers/video/fbdev/msm/mdss_dsi_panel.c +++ b/drivers/video/fbdev/msm/mdss_dsi_panel.c @@ -293,6 +293,13 @@ int mdss_dsi_panel_reset(struct mdss_panel_data *pdata, int enable) ctrl_pdata = container_of(pdata, struct mdss_dsi_ctrl_pdata, panel_data); + if (mdss_dsi_is_right_ctrl(ctrl_pdata) && + mdss_dsi_is_hw_config_split(ctrl_pdata->shared_data)) { + pr_debug("%s:%d, right ctrl gpio configuration not needed\n", + __func__, __LINE__); + return rc; + } + if (!gpio_is_valid(ctrl_pdata->disp_en_gpio)) { pr_debug("%s:%d, reset line not configured\n", __func__, __LINE__); diff --git a/drivers/video/fbdev/msm/msm_mdss_io_8974.c b/drivers/video/fbdev/msm/msm_mdss_io_8974.c index 6d2c28acb3a1..9f616789f7a1 100644 --- a/drivers/video/fbdev/msm/msm_mdss_io_8974.c +++ b/drivers/video/fbdev/msm/msm_mdss_io_8974.c @@ -72,7 +72,8 @@ static void mdss_dsi_phy_sw_reset(struct mdss_dsi_ctrl_pdata *ctrl) return; } - if (IS_MDSS_MAJOR_MINOR_SAME(ctrl->hw_rev, MDSS_DSI_HW_REV_104)) { + if (IS_MDSS_MAJOR_MINOR_SAME(ctrl->shared_data->hw_rev, + MDSS_DSI_HW_REV_104)) { if (mdss_dsi_is_ctrl_clk_master(ctrl)) sctrl = mdss_dsi_get_ctrl_clk_slave(); else @@ -89,7 +90,7 @@ static void mdss_dsi_phy_sw_reset(struct mdss_dsi_ctrl_pdata *ctrl) * Need to turn off the PLL1 to avoid current leakage issues */ if (ctrl->ndx == DSI_CTRL_1) { - if (ctrl->hw_rev == MDSS_DSI_HW_REV_103) { + if (ctrl->shared_data->hw_rev == MDSS_DSI_HW_REV_103) { pr_debug("Turn off PLL 1 registers\n"); clk_set_rate(ctrl->vco_clk, 1); } @@ -103,7 +104,8 @@ static void mdss_dsi_phy_regulator_disable(struct mdss_dsi_ctrl_pdata *ctrl) return; } - if (IS_MDSS_MAJOR_MINOR_SAME(ctrl->hw_rev, MDSS_DSI_HW_REV_104)) + if (IS_MDSS_MAJOR_MINOR_SAME(ctrl->shared_data->hw_rev, + MDSS_DSI_HW_REV_104)) return; MIPI_OUTP(ctrl->shared_ctrl_data->phy_regulator_io.base @@ -117,7 +119,8 @@ static void mdss_dsi_phy_lane_shutdown(struct mdss_dsi_ctrl_pdata *ctrl) return; } - if (IS_MDSS_MAJOR_MINOR_SAME(ctrl->hw_rev, MDSS_DSI_HW_REV_104)) + if (IS_MDSS_MAJOR_MINOR_SAME(ctrl->shared_data->hw_rev, + MDSS_DSI_HW_REV_104)) MIPI_OUTP(ctrl->phy_io.base + DSIPHY_CMN_CTRL_0, ~0x1F); else MIPI_OUTP(ctrl->phy_io.base + MDSS_DSI_DSIPHY_CTRL_0, 0x000); @@ -135,11 +138,11 @@ void mdss_dsi_phy_disable(struct mdss_dsi_ctrl_pdata *ctrl) ctrl->shared_ctrl_data->phy_disable_refcount++; /* - * In dual-dsi configuration, the phy should be disabled for the + * In split-dsi configuration, the phy should be disabled for the * first controller only when the second controller is disabled. * This is true regardless of whether broadcast mode is enabled. */ - if (!mdss_dsi_split_display_enabled() || + if (!mdss_dsi_is_hw_config_split(ctrl->shared_data) || ctrl->shared_ctrl_data->phy_disable_refcount == 2) { other_ctrl = mdss_dsi_get_other_ctrl(ctrl); @@ -175,7 +178,8 @@ void mdss_dsi_lp_cd_rx(struct mdss_dsi_ctrl_pdata *ctrl) return; } - if (IS_MDSS_MAJOR_MINOR_SAME(ctrl->hw_rev, MDSS_DSI_HW_REV_104)) + if (IS_MDSS_MAJOR_MINOR_SAME(ctrl->shared_data->hw_rev, + MDSS_DSI_HW_REV_104)) return; pd = &(((ctrl->panel_data).panel_info.mipi).dsi_phy_db); @@ -298,7 +302,7 @@ static void mdss_dsi_28nm_phy_init(struct mdss_dsi_ctrl_pdata *ctrl_pdata) /* DSI_0_PHY_DSIPHY_GLBL_TEST_CTRL */ if (((ctrl_pdata->panel_data).panel_info.pdest == DISPLAY_1) || - (ctrl_pdata->hw_rev == MDSS_DSI_HW_REV_103_1)) + (ctrl_pdata->shared_data->hw_rev == MDSS_DSI_HW_REV_103_1)) MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x01d4, 0x01); else MIPI_OUTP((ctrl_pdata->phy_io.base) + 0x01d4, 0x00); @@ -530,7 +534,7 @@ static void mdss_dsi_8996_phy_config(struct mdss_dsi_ctrl_pdata *ctrl) udelay(100); MIPI_OUTP((ctrl->phy_io.base) + DSIPHY_CMN_CTRL_1, 0x00); - if (mdss_dsi_split_display_enabled()) { + if (mdss_dsi_is_hw_config_split(ctrl->shared_data)) { if (mdss_dsi_is_left_ctrl(ctrl)) mdss_dsi_8996_pll_source_from_left(ctrl); else @@ -571,7 +575,7 @@ static void mdss_dsi_phy_init(struct mdss_dsi_ctrl_pdata *ctrl) return; } - switch (ctrl->hw_rev) { + switch (ctrl->shared_data->hw_rev) { case MDSS_DSI_HW_REV_104: case MDSS_DSI_HW_REV_104_1: mdss_dsi_8996_phy_init(ctrl); @@ -585,83 +589,121 @@ static void mdss_dsi_phy_init(struct mdss_dsi_ctrl_pdata *ctrl) } } -int mdss_dsi_clk_init(struct platform_device *pdev, - struct mdss_dsi_ctrl_pdata *ctrl) +void mdss_dsi_bus_clk_deinit(struct device *dev, + struct dsi_shared_data *sdata) +{ + if (sdata->mmss_misc_ahb_clk) + devm_clk_put(dev, sdata->mmss_misc_ahb_clk); + if (sdata->axi_clk) + devm_clk_put(dev, sdata->axi_clk); + if (sdata->ahb_clk) + devm_clk_put(dev, sdata->ahb_clk); + if (sdata->mdp_core_clk) + devm_clk_put(dev, sdata->mdp_core_clk); +} + +int mdss_dsi_bus_clk_init(struct platform_device *pdev, + struct dsi_shared_data *sdata) { struct device *dev = NULL; int rc = 0; if (!pdev) { pr_err("%s: Invalid pdev\n", __func__); - goto mdss_dsi_clk_err; + goto clk_err; } dev = &pdev->dev; - ctrl->mdp_core_clk = clk_get(dev, "mdp_core_clk"); - if (IS_ERR(ctrl->mdp_core_clk)) { - rc = PTR_ERR(ctrl->mdp_core_clk); + sdata->mdp_core_clk = devm_clk_get(dev, "mdp_core_clk"); + if (IS_ERR(sdata->mdp_core_clk)) { + rc = PTR_ERR(sdata->mdp_core_clk); pr_err("%s: Unable to get mdp core clk. rc=%d\n", __func__, rc); - goto mdss_dsi_clk_err; + goto clk_err; } - ctrl->ahb_clk = clk_get(dev, "iface_clk"); - if (IS_ERR(ctrl->ahb_clk)) { - rc = PTR_ERR(ctrl->ahb_clk); + sdata->ahb_clk = devm_clk_get(dev, "iface_clk"); + if (IS_ERR(sdata->ahb_clk)) { + rc = PTR_ERR(sdata->ahb_clk); pr_err("%s: Unable to get mdss ahb clk. rc=%d\n", __func__, rc); - goto mdss_dsi_clk_err; + goto clk_err; } - ctrl->axi_clk = clk_get(dev, "bus_clk"); - if (IS_ERR(ctrl->axi_clk)) { - rc = PTR_ERR(ctrl->axi_clk); + sdata->axi_clk = devm_clk_get(dev, "bus_clk"); + if (IS_ERR(sdata->axi_clk)) { + rc = PTR_ERR(sdata->axi_clk); pr_err("%s: Unable to get axi bus clk. rc=%d\n", __func__, rc); - goto mdss_dsi_clk_err; + goto clk_err; } - if ((ctrl->panel_data.panel_info.type == MIPI_CMD_PANEL) || - ctrl->panel_data.panel_info.mipi.dms_mode || - ctrl->panel_data.panel_info.ulps_suspend_enabled) { - ctrl->mmss_misc_ahb_clk = clk_get(dev, "core_mmss_clk"); - if (IS_ERR(ctrl->mmss_misc_ahb_clk)) { - ctrl->mmss_misc_ahb_clk = NULL; - pr_info("%s: Unable to get mmss misc ahb clk\n", - __func__); - } + sdata->mmss_misc_ahb_clk = devm_clk_get(dev, "core_mmss_clk"); + if (IS_ERR(sdata->mmss_misc_ahb_clk)) { + sdata->mmss_misc_ahb_clk = NULL; + pr_info("%s: Unable to get mmss misc ahb clk\n", + __func__); } - ctrl->byte_clk = clk_get(dev, "byte_clk"); +clk_err: + if (rc) + mdss_dsi_bus_clk_deinit(dev, sdata); + return rc; +} + +void mdss_dsi_link_clk_deinit(struct device *dev, + struct mdss_dsi_ctrl_pdata *ctrl) +{ + if (ctrl->byte_clk) + devm_clk_put(dev, ctrl->byte_clk); + if (ctrl->esc_clk) + devm_clk_put(dev, ctrl->esc_clk); + if (ctrl->pixel_clk) + devm_clk_put(dev, ctrl->pixel_clk); +} + +int mdss_dsi_link_clk_init(struct platform_device *pdev, + struct mdss_dsi_ctrl_pdata *ctrl) +{ + struct device *dev = NULL; + int rc = 0; + + if (!pdev) { + pr_err("%s: Invalid pdev\n", __func__); + goto error; + } + + dev = &pdev->dev; + ctrl->byte_clk = devm_clk_get(dev, "byte_clk"); if (IS_ERR(ctrl->byte_clk)) { rc = PTR_ERR(ctrl->byte_clk); pr_err("%s: can't find dsi_byte_clk. rc=%d\n", __func__, rc); ctrl->byte_clk = NULL; - goto mdss_dsi_clk_err; + goto error; } - ctrl->pixel_clk = clk_get(dev, "pixel_clk"); + ctrl->pixel_clk = devm_clk_get(dev, "pixel_clk"); if (IS_ERR(ctrl->pixel_clk)) { rc = PTR_ERR(ctrl->pixel_clk); pr_err("%s: can't find dsi_pixel_clk. rc=%d\n", __func__, rc); ctrl->pixel_clk = NULL; - goto mdss_dsi_clk_err; + goto error; } - ctrl->esc_clk = clk_get(dev, "core_clk"); + ctrl->esc_clk = devm_clk_get(dev, "core_clk"); if (IS_ERR(ctrl->esc_clk)) { rc = PTR_ERR(ctrl->esc_clk); pr_err("%s: can't find dsi_esc_clk. rc=%d\n", __func__, rc); ctrl->esc_clk = NULL; - goto mdss_dsi_clk_err; + goto error; } -mdss_dsi_clk_err: +error: if (rc) - mdss_dsi_clk_deinit(ctrl); + mdss_dsi_link_clk_deinit(dev, ctrl); return rc; } @@ -688,6 +730,23 @@ int mdss_dsi_pll_1_clk_init(struct platform_device *pdev, return rc; } +void mdss_dsi_shadow_clk_deinit(struct device *dev, + struct mdss_dsi_ctrl_pdata *ctrl) +{ + if (ctrl->mux_byte_clk) + devm_clk_put(dev, ctrl->mux_byte_clk); + if (ctrl->mux_pixel_clk) + devm_clk_put(dev, ctrl->mux_pixel_clk); + if (ctrl->pll_byte_clk) + devm_clk_put(dev, ctrl->pll_byte_clk); + if (ctrl->pll_pixel_clk) + devm_clk_put(dev, ctrl->pll_pixel_clk); + if (ctrl->shadow_byte_clk) + devm_clk_put(dev, ctrl->shadow_byte_clk); + if (ctrl->shadow_pixel_clk) + devm_clk_put(dev, ctrl->shadow_pixel_clk); +} + int mdss_dsi_shadow_clk_init(struct platform_device *pdev, struct mdss_dsi_ctrl_pdata *ctrl) { @@ -700,101 +759,66 @@ int mdss_dsi_shadow_clk_init(struct platform_device *pdev, } dev = &pdev->dev; - ctrl->mux_byte_clk = clk_get(dev, "mdss_byte_clk_mux"); + ctrl->mux_byte_clk = devm_clk_get(dev, "mdss_byte_clk_mux"); if (IS_ERR(ctrl->mux_byte_clk)) { rc = PTR_ERR(ctrl->mux_byte_clk); pr_err("%s: can't find mux_byte_clk. rc=%d\n", __func__, rc); ctrl->mux_byte_clk = NULL; - goto mdss_dsi_shadow_clk_err; + goto error; } - ctrl->mux_pixel_clk = clk_get(dev, "mdss_pixel_clk_mux"); + ctrl->mux_pixel_clk = devm_clk_get(dev, "mdss_pixel_clk_mux"); if (IS_ERR(ctrl->mux_pixel_clk)) { rc = PTR_ERR(ctrl->mux_pixel_clk); pr_err("%s: can't find mdss_mux_pixel_clk. rc=%d\n", __func__, rc); ctrl->mux_pixel_clk = NULL; - goto mdss_dsi_shadow_clk_err; + goto error; } - ctrl->pll_byte_clk = clk_get(dev, "byte_clk_src"); + ctrl->pll_byte_clk = devm_clk_get(dev, "byte_clk_src"); if (IS_ERR(ctrl->pll_byte_clk)) { rc = PTR_ERR(ctrl->pll_byte_clk); pr_err("%s: can't find pll_byte_clk. rc=%d\n", __func__, rc); ctrl->pll_byte_clk = NULL; - goto mdss_dsi_shadow_clk_err; + goto error; } - ctrl->pll_pixel_clk = clk_get(dev, "pixel_clk_src"); + ctrl->pll_pixel_clk = devm_clk_get(dev, "pixel_clk_src"); if (IS_ERR(ctrl->pll_pixel_clk)) { rc = PTR_ERR(ctrl->pll_pixel_clk); pr_err("%s: can't find pll_pixel_clk. rc=%d\n", __func__, rc); ctrl->pll_pixel_clk = NULL; - goto mdss_dsi_shadow_clk_err; + goto error; } - ctrl->shadow_byte_clk = clk_get(dev, "shadow_byte_clk_src"); + ctrl->shadow_byte_clk = devm_clk_get(dev, "shadow_byte_clk_src"); if (IS_ERR(ctrl->shadow_byte_clk)) { rc = PTR_ERR(ctrl->shadow_byte_clk); pr_err("%s: can't find shadow_byte_clk. rc=%d\n", __func__, rc); ctrl->shadow_byte_clk = NULL; - goto mdss_dsi_shadow_clk_err; + goto error; } - ctrl->shadow_pixel_clk = clk_get(dev, "shadow_pixel_clk_src"); + ctrl->shadow_pixel_clk = devm_clk_get(dev, "shadow_pixel_clk_src"); if (IS_ERR(ctrl->shadow_pixel_clk)) { rc = PTR_ERR(ctrl->shadow_pixel_clk); pr_err("%s: can't find shadow_pixel_clk. rc=%d\n", __func__, rc); ctrl->shadow_pixel_clk = NULL; - goto mdss_dsi_shadow_clk_err; + goto error; } -mdss_dsi_shadow_clk_err: +error: if (rc) - mdss_dsi_shadow_clk_deinit(ctrl); + mdss_dsi_shadow_clk_deinit(dev, ctrl); return rc; } -void mdss_dsi_clk_deinit(struct mdss_dsi_ctrl_pdata *ctrl) -{ - if (ctrl->byte_clk) - clk_put(ctrl->byte_clk); - if (ctrl->esc_clk) - clk_put(ctrl->esc_clk); - if (ctrl->pixel_clk) - clk_put(ctrl->pixel_clk); - if (ctrl->mmss_misc_ahb_clk) - clk_put(ctrl->mmss_misc_ahb_clk); - if (ctrl->axi_clk) - clk_put(ctrl->axi_clk); - if (ctrl->ahb_clk) - clk_put(ctrl->ahb_clk); - if (ctrl->mdp_core_clk) - clk_put(ctrl->mdp_core_clk); -} - -void mdss_dsi_shadow_clk_deinit(struct mdss_dsi_ctrl_pdata *ctrl) -{ - if (ctrl->mux_byte_clk) - clk_put(ctrl->mux_byte_clk); - if (ctrl->mux_pixel_clk) - clk_put(ctrl->mux_pixel_clk); - if (ctrl->pll_byte_clk) - clk_put(ctrl->pll_byte_clk); - if (ctrl->pll_pixel_clk) - clk_put(ctrl->pll_pixel_clk); - if (ctrl->shadow_byte_clk) - clk_put(ctrl->shadow_byte_clk); - if (ctrl->shadow_pixel_clk) - clk_put(ctrl->shadow_pixel_clk); -} - - int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info, int frame_rate) { @@ -864,10 +888,11 @@ int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info, static int mdss_dsi_bus_clk_start(struct mdss_dsi_ctrl_pdata *ctrl_pdata) { int rc = 0; + struct dsi_shared_data *sdata = ctrl_pdata->shared_data; pr_debug("%s: ndx=%d\n", __func__, ctrl_pdata->ndx); - rc = clk_prepare_enable(ctrl_pdata->mdp_core_clk); + rc = clk_prepare_enable(sdata->mdp_core_clk); if (rc) { pr_err("%s: failed to enable mdp_core_clock. rc=%d\n", __func__, rc); @@ -875,20 +900,20 @@ static int mdss_dsi_bus_clk_start(struct mdss_dsi_ctrl_pdata *ctrl_pdata) } mdss_update_reg_bus_vote(VOTE_INDEX_19_MHZ); - rc = clk_prepare_enable(ctrl_pdata->ahb_clk); + rc = clk_prepare_enable(sdata->ahb_clk); if (rc) { pr_err("%s: failed to enable ahb clock. rc=%d\n", __func__, rc); goto disable_core_clk; } - rc = clk_prepare_enable(ctrl_pdata->axi_clk); + rc = clk_prepare_enable(sdata->axi_clk); if (rc) { pr_err("%s: failed to enable ahb clock. rc=%d\n", __func__, rc); goto disable_ahb_clk; } - if (ctrl_pdata->mmss_misc_ahb_clk) { - rc = clk_prepare_enable(ctrl_pdata->mmss_misc_ahb_clk); + if (sdata->mmss_misc_ahb_clk) { + rc = clk_prepare_enable(sdata->mmss_misc_ahb_clk); if (rc) { pr_err("%s: failed to enable mmss misc ahb clk.rc=%d\n", __func__, rc); @@ -898,24 +923,25 @@ static int mdss_dsi_bus_clk_start(struct mdss_dsi_ctrl_pdata *ctrl_pdata) return rc; disable_axi_clk: - clk_disable_unprepare(ctrl_pdata->axi_clk); + clk_disable_unprepare(sdata->axi_clk); disable_ahb_clk: - clk_disable_unprepare(ctrl_pdata->ahb_clk); + clk_disable_unprepare(sdata->ahb_clk); disable_core_clk: mdss_update_reg_bus_vote(VOTE_INDEX_DISABLE); - clk_disable_unprepare(ctrl_pdata->mdp_core_clk); + clk_disable_unprepare(sdata->mdp_core_clk); error: return rc; } static void mdss_dsi_bus_clk_stop(struct mdss_dsi_ctrl_pdata *ctrl_pdata) { - if (ctrl_pdata->mmss_misc_ahb_clk) - clk_disable_unprepare(ctrl_pdata->mmss_misc_ahb_clk); - clk_disable_unprepare(ctrl_pdata->axi_clk); - clk_disable_unprepare(ctrl_pdata->ahb_clk); + struct dsi_shared_data *sdata = ctrl_pdata->shared_data; + if (sdata->mmss_misc_ahb_clk) + clk_disable_unprepare(sdata->mmss_misc_ahb_clk); + clk_disable_unprepare(sdata->axi_clk); + clk_disable_unprepare(sdata->ahb_clk); mdss_update_reg_bus_vote(VOTE_INDEX_DISABLE); - clk_disable_unprepare(ctrl_pdata->mdp_core_clk); + clk_disable_unprepare(sdata->mdp_core_clk); } static int mdss_dsi_link_clk_prepare(struct mdss_dsi_ctrl_pdata *ctrl_pdata) @@ -1255,13 +1281,14 @@ static int mdss_dsi_clamp_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable) return -EINVAL; } - if (IS_MDSS_MAJOR_MINOR_SAME(ctrl->hw_rev, MDSS_DSI_HW_REV_104)) { + if (IS_MDSS_MAJOR_MINOR_SAME(ctrl->shared_data->hw_rev, + MDSS_DSI_HW_REV_104)) { pr_debug("%s: clamp ctrl configuration is skipped\n", __func__); return 0; } - clamp_reg_off = ctrl->ulps_clamp_ctrl_off; - phyrst_reg_off = ctrl->ulps_phyrst_ctrl_off; + clamp_reg_off = ctrl->shared_data->ulps_clamp_ctrl_off; + phyrst_reg_off = ctrl->shared_data->ulps_phyrst_ctrl_off; mipi = &ctrl->panel_data.panel_info.mipi; /* clock lane will always be clamped */ @@ -1313,7 +1340,7 @@ static int mdss_dsi_clamp_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable) * reset when mdss ahb clock reset is asserted while coming * out of power collapse */ - if (IS_MDSS_MAJOR_MINOR_SAME(ctrl->hw_rev, + if (IS_MDSS_MAJOR_MINOR_SAME(ctrl->shared_data->hw_rev, MDSS_DSI_HW_REV_104)) { regval = MIPI_INP(ctrl->mmss_misc_io.base + @@ -1328,7 +1355,7 @@ static int mdss_dsi_clamp_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable) wmb(); ctrl->mmss_clamp = true; } else if (!enable && ctrl->mmss_clamp) { - if (IS_MDSS_MAJOR_MINOR_SAME(ctrl->hw_rev, + if (IS_MDSS_MAJOR_MINOR_SAME(ctrl->shared_data->hw_rev, MDSS_DSI_HW_REV_104)) { regval = MIPI_INP(ctrl->mmss_misc_io.base + @@ -1379,12 +1406,14 @@ static int mdss_dsi_core_power_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int rc = 0; int i = 0; struct mdss_panel_data *pdata = NULL; + struct dsi_shared_data *sdata; if (!ctrl) { pr_err("%s: invalid input\n", __func__); return -EINVAL; } + sdata = ctrl->shared_data; pdata = &ctrl->panel_data; if (!pdata) { pr_err("%s: Invalid panel data\n", __func__); @@ -1402,16 +1431,15 @@ static int mdss_dsi_core_power_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, * not be changed during static screen. */ pr_debug("%s: Enable DSI core power\n", __func__); - for (i = 0; i < DSI_MAX_PM; i++) { - if ((DSI_PANEL_PM == i) || - ((DSI_CORE_PM != i) && + for (i = DSI_CORE_PM; i < DSI_MAX_PM; i++) { + if (((DSI_CORE_PM != i) && (pdata->panel_info.blank_state != MDSS_PANEL_BLANK_BLANK) && !pdata->panel_info.cont_splash_enabled)) continue; rc = msm_dss_enable_vreg( - ctrl->power_data[i].vreg_config, - ctrl->power_data[i].num_vreg, 1); + sdata->power_data[i].vreg_config, + sdata->power_data[i].num_vreg, 1); if (rc) { pr_err("%s: failed to enable vregs for %s\n", __func__, @@ -1508,15 +1536,14 @@ static int mdss_dsi_core_power_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, pr_debug("%s: leaving DSI core power on\n", __func__); } else { pr_debug("%s: Disable DSI core power\n", __func__); - for (i = DSI_MAX_PM - 1; i >= 0; i--) { - if ((DSI_PANEL_PM == i) || - ((DSI_CORE_PM != i) && + for (i = DSI_MAX_PM - 1; i >= DSI_CORE_PM; i--) { + if (((DSI_CORE_PM != i) && (pdata->panel_info.blank_state != MDSS_PANEL_BLANK_BLANK))) continue; rc = msm_dss_enable_vreg( - ctrl->power_data[i].vreg_config, - ctrl->power_data[i].num_vreg, 0); + sdata->power_data[i].vreg_config, + sdata->power_data[i].num_vreg, 0); if (rc) { pr_warn("%s: failed to disable vregs for %s\n", __func__, @@ -1533,13 +1560,12 @@ static int mdss_dsi_core_power_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, error_ulps: mdss_dsi_bus_clk_stop(ctrl); error_bus_clk_start: - for (i = DSI_MAX_PM - 1; i >= 0; i--) { - if ((DSI_PANEL_PM == i) || ((DSI_CORE_PM != i) && - (pdata->panel_info.blank_state != + for (i = DSI_MAX_PM - 1; i >= DSI_CORE_PM; i--) { + if (((DSI_CORE_PM != i) && (pdata->panel_info.blank_state != MDSS_PANEL_BLANK_BLANK))) continue; - rc = msm_dss_enable_vreg(ctrl->power_data[i].vreg_config, - ctrl->power_data[i].num_vreg, 0); + rc = msm_dss_enable_vreg(sdata->power_data[i].vreg_config, + sdata->power_data[i].num_vreg, 0); if (rc) { pr_warn("%s: failed to disable vregs for %s\n", __func__, __mdss_dsi_pm_name(i)); |
