diff options
| author | Aravind Venkateswaran <aravindh@codeaurora.org> | 2015-04-22 15:18:39 -0700 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 20:42:19 -0700 |
| commit | 142b8c778451f3e315664c2bb073aa04adc68308 (patch) | |
| tree | 215bb175d75b4389a0e4f26a3761933349ae72a0 | |
| parent | db5a26a52cfa551c1ee6ab4d20c58510bdb3d6cd (diff) | |
msm: mdss: add support to configure DSI branch clock source
Based on the board configuration, the two DSI controllers can either
drive two independent panels or drive a single panel in split display
mode. DSI0 PLL can drive split display configuration ands it is not
supported by DSI1 PLL. DSI0 PLL can drive a single DSI panel on either
DSI0 or DSI1 controller whereas DSI1 PLL can drive a DSI panel only on
DSI1 controller. Based on this, it is necessary to configure the
source for the DSI link clocks dynamically. Implement this by adding
support for a new pll source configuration entry.
Change-Id: Ie57afbfe8cb14b80d0b52ed3825972ae34af27e2
Signed-off-by: Kuogee Hsieh <khsieh@codeaurora.org>
Signed-off-by: Aravind Venkateswaran <aravindh@codeaurora.org>
[cip@codeaurora.org: Removed .dtsi file updates]
Signed-off-by: Clarence Ip <cip@codeaurora.org>
| -rw-r--r-- | Documentation/devicetree/bindings/fb/mdss-dsi.txt | 14 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_dsi.c | 213 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_dsi.h | 71 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/msm_mdss_io_8974.c | 332 |
4 files changed, 471 insertions, 159 deletions
diff --git a/Documentation/devicetree/bindings/fb/mdss-dsi.txt b/Documentation/devicetree/bindings/fb/mdss-dsi.txt index 0e23a0f607f8..5da746487c06 100644 --- a/Documentation/devicetree/bindings/fb/mdss-dsi.txt +++ b/Documentation/devicetree/bindings/fb/mdss-dsi.txt @@ -31,6 +31,19 @@ Optional properties: -- 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 +- pll-src-config Specified the source PLL for the DSI + link clocks: + "PLL0" - Clocks sourced out of DSI PLL0 + "PLL1" - Clocks sourced out of DSI PLL1 + This property is only valid for + certain DSI hardware configurations + mentioned in the "hw-config" binding above. + For example, in split_dsi config, the clocks can + only be sourced out of PLL0. For + dual_dsi, both PLL would be active. + For single DSI, it is possible to + select either PLL. If no value is specified, + the default value for single DSI is set as PLL0. - 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. @@ -93,6 +106,7 @@ Example: mdss_dsi: qcom,mdss_dsi@0 { compatible = "qcom,mdss-dsi"; hw-config = "single_dsi"; + pll-src-config = "PLL0"; #address-cells = <1>; #size-cells = <1>; vdda-supply = <&pm8226_l4>; diff --git a/drivers/video/fbdev/msm/mdss_dsi.c b/drivers/video/fbdev/msm/mdss_dsi.c index 8f04dc4786d7..ceb25b1224bc 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.c +++ b/drivers/video/fbdev/msm/mdss_dsi.c @@ -48,6 +48,125 @@ static struct mdss_dsi_ctrl_pdata *mdss_dsi_get_ctrl(u32 ctrl_id) return mdss_dsi_res->ctrl_pdata[ctrl_id]; } +static void mdss_dsi_config_clk_src(struct platform_device *pdev) +{ + struct mdss_dsi_data *dsi_res = platform_get_drvdata(pdev); + struct dsi_shared_data *sdata = dsi_res->shared_data; + + if (!sdata->ext_byte0_clk || !sdata->ext_byte1_clk || + !sdata->ext_pixel0_clk || !sdata->ext_pixel1_clk) { + pr_debug("%s: config_clk_src not needed\n", __func__); + return; + } + + if (!mdss_dsi_is_hw_config_dual(sdata)) { + /* + * For split-dsi and single-dsi use cases, map the PLL source + * based on the pll source configuration. It is possible that + * for split-dsi case, the only supported config is to source + * the clocks from PLL0. This is not explictly checked here as + * it should have been already enforced when validating the + * board configuration. + */ + if (mdss_dsi_is_pll_src_pll0(sdata)) { + pr_debug("%s: single source: PLL0", __func__); + sdata->byte0_parent = sdata->ext_byte0_clk; + sdata->pixel0_parent = sdata->ext_pixel0_clk; + } else { + pr_debug("%s: single source: PLL1", __func__); + sdata->byte0_parent = sdata->ext_byte1_clk; + sdata->pixel0_parent = sdata->ext_pixel1_clk; + } + sdata->byte1_parent = sdata->byte0_parent; + sdata->pixel1_parent = sdata->pixel0_parent; + } else { + /* + * For dual-dsi use cases, map: + * DSI0 <--> PLL0 + * DSI1 <--> PLL1 + */ + pr_debug("%s: dual-dsi: DSI0 <--> PLL0, DSI1 <--> PLL1", + __func__); + sdata->byte0_parent = sdata->ext_byte0_clk; + sdata->byte1_parent = sdata->ext_byte1_clk; + sdata->pixel0_parent = sdata->ext_pixel0_clk; + sdata->pixel1_parent = sdata->ext_pixel1_clk; + } + + return; +} + +static char const *mdss_dsi_get_clk_src(struct mdss_dsi_ctrl_pdata *ctrl) +{ + struct dsi_shared_data *sdata; + + if (!ctrl) { + pr_err("%s: Invalid input data\n", __func__); + return "????"; + } + + sdata = ctrl->shared_data; + + if (mdss_dsi_is_left_ctrl(ctrl)) { + if (sdata->byte0_parent == sdata->ext_byte0_clk) + return "PLL0"; + else + return "PLL1"; + } else { + if (sdata->byte1_parent == sdata->ext_byte0_clk) + return "PLL0"; + else + return "PLL1"; + } +} + +static int mdss_dsi_set_clk_src(struct mdss_dsi_ctrl_pdata *ctrl) +{ + int rc; + struct dsi_shared_data *sdata; + struct clk *byte_parent, *pixel_parent; + + if (!ctrl) { + pr_err("%s: Invalid input data\n", __func__); + return -EINVAL; + } + + sdata = ctrl->shared_data; + + if (!ctrl->byte_clk_rcg || !ctrl->pixel_clk_rcg) { + pr_debug("%s: set_clk_src not needed\n", __func__); + return 0; + } + + if (mdss_dsi_is_left_ctrl(ctrl)) { + byte_parent = sdata->byte0_parent; + pixel_parent = sdata->pixel0_parent; + } else { + byte_parent = sdata->byte1_parent; + pixel_parent = sdata->pixel1_parent; + } + + rc = clk_set_parent(ctrl->byte_clk_rcg, byte_parent); + if (rc) { + pr_err("%s: failed to set parent for byte clk for ctrl%d. rc=%d\n", + __func__, ctrl->ndx, rc); + goto error; + } + + rc = clk_set_parent(ctrl->pixel_clk_rcg, pixel_parent); + if (rc) { + pr_err("%s: failed to set parent for pixel clk for ctrl%d. rc=%d\n", + __func__, ctrl->ndx, rc); + goto error; + } + + pr_debug("%s: ctrl%d clock source set to %s", __func__, ctrl->ndx, + mdss_dsi_get_clk_src(ctrl)); + +error: + return rc; +} + static int mdss_dsi_regulator_init(struct platform_device *pdev, struct dsi_shared_data *sdata) { @@ -1079,10 +1198,16 @@ int mdss_dsi_on(struct mdss_panel_data *pdata) ret = mdss_dsi_panel_power_ctrl(pdata, MDSS_PANEL_POWER_ON); if (ret) { pr_err("%s:Panel power on failed. rc=%d\n", __func__, ret); - return ret; + goto end; + } + + ret = mdss_dsi_set_clk_src(ctrl_pdata); + if (ret) { + pr_err("%s: failed to set clk src. rc=%d\n", __func__, ret); + goto end; } - if (cur_power_state != MDSS_PANEL_POWER_OFF) { + if (mdss_panel_is_power_on(cur_power_state)) { pr_debug("%s: dsi_on from panel low power state\n", __func__); goto end; } @@ -1123,7 +1248,7 @@ int mdss_dsi_on(struct mdss_panel_data *pdata) end: pr_debug("%s-:\n", __func__); - return 0; + return ret; } static int mdss_dsi_pinctrl_set_state( @@ -2220,7 +2345,7 @@ static void mdss_dsi_res_deinit(struct platform_device *pdev) &sdata->power_data[i]); } - mdss_dsi_bus_clk_deinit(&pdev->dev, sdata); + mdss_dsi_core_clk_deinit(&pdev->dev, sdata); if (sdata) devm_kfree(&pdev->dev, sdata); @@ -2270,9 +2395,9 @@ static int mdss_dsi_res_init(struct platform_device *pdev) goto mem_fail; } - rc = mdss_dsi_bus_clk_init(pdev, sdata); + rc = mdss_dsi_core_clk_init(pdev, sdata); if (rc) { - pr_err("%s: failed to initialize DSI Bus clocks\n", + pr_err("%s: failed to initialize DSI core clocks\n", __func__); goto mem_fail; } @@ -2369,6 +2494,65 @@ static int mdss_dsi_parse_hw_cfg(struct platform_device *pdev) return 0; } +static void mdss_dsi_parse_pll_src_cfg(struct platform_device *pdev) +{ + const char *data; + struct dsi_shared_data *sdata = mdss_dsi_res->shared_data; + + sdata->pll_src_config = PLL_SRC_0; + data = of_get_property(pdev->dev.of_node, "pll-src-config", NULL); + if (data) { + if (!strcmp(data, "PLL0")) + sdata->pll_src_config = PLL_SRC_0; + else if (!strcmp(data, "PLL1")) + sdata->pll_src_config = PLL_SRC_1; + else + pr_err("%s: invalid pll src config %s. Using PLL_SRC_0 as default\n", + __func__, data); + } else { + pr_debug("%s: PLL src config not present. Using PLL0 by default\n", + __func__); + } + + pr_debug("%s: pll_src_config = %d", __func__, sdata->pll_src_config); + + return; +} + +static int mdss_dsi_validate_pll_src_config(struct dsi_shared_data *sdata) +{ + int rc = 0; + + /* + * DSI PLL1 can only drive DSI PHY1. As such: + * - For split dsi config, only PLL0 is supported + * - For dual dsi config, DSI0-PLL0 and DSI1-PLL1 is the only + * possible configuration + * - For single dsi, it is not possible to source the clocks for + * DSI0 from PLL1. + */ + + if (mdss_dsi_is_hw_config_split(sdata) && + mdss_dsi_is_pll_src_pll1(sdata)) { + pr_err("%s: unsupported PLL config: using PLL1 for split-dsi\n", + __func__); + rc = -EINVAL; + goto error; + } + + /* todo: enforce remaining checks */ + +error: + return rc; +} + +static int mdss_dsi_validate_config(struct platform_device *pdev) +{ + struct dsi_shared_data *sdata = mdss_dsi_res->shared_data; + + return mdss_dsi_validate_pll_src_config(sdata); +} + static const struct of_device_id mdss_dsi_ctrl_dt_match[] = { {.compatible = "qcom,mdss-dsi-ctrl"}, {} @@ -2419,10 +2603,21 @@ static int mdss_dsi_probe(struct platform_device *pdev) return rc; } + mdss_dsi_parse_pll_src_cfg(pdev); + of_platform_populate(pdev->dev.of_node, mdss_dsi_ctrl_dt_match, NULL, &pdev->dev); - return 0; + rc = mdss_dsi_validate_config(pdev); + if (rc) { + pr_err("%s: Invalid DSI hw configuration\n", __func__); + goto error; + } + + mdss_dsi_config_clk_src(pdev); + +error: + return rc; } static int mdss_dsi_remove(struct platform_device *pdev) @@ -2770,10 +2965,6 @@ int dsi_panel_device_register(struct platform_device *ctrl_pdev, return -EPERM; } - rc = mdss_dsi_pll_1_clk_init(ctrl_pdev, ctrl_pdata); - if (rc) - pr_err("PLL 1 Clock's did not register\n"); - if (pinfo->dynamic_fps && pinfo->dfps_update == DFPS_IMMEDIATE_CLK_UPDATE_MODE) { if (mdss_dsi_shadow_clk_init(ctrl_pdev, ctrl_pdata)) { diff --git a/drivers/video/fbdev/msm/mdss_dsi.h b/drivers/video/fbdev/msm/mdss_dsi.h index e6963c1426ae..05148337e762 100644 --- a/drivers/video/fbdev/msm/mdss_dsi.h +++ b/drivers/video/fbdev/msm/mdss_dsi.h @@ -219,6 +219,7 @@ enum { */ struct dsi_shared_data { u32 hw_config; /* DSI setup configuration i.e. single/dual/split */ + u32 pll_src_config; /* PLL source selection for DSI link clocks */ u32 hw_rev; /* DSI h/w revision */ /* DSI ULPS clamp register offsets */ @@ -234,6 +235,18 @@ struct dsi_shared_data { struct clk *axi_clk; struct clk *mmss_misc_ahb_clk; + /* Other shared clocks */ + struct clk *ext_byte0_clk; + struct clk *ext_pixel0_clk; + struct clk *ext_byte1_clk; + struct clk *ext_pixel1_clk; + + /* Clock sources for branch clocks */ + struct clk *byte0_parent; + struct clk *pixel0_parent; + struct clk *byte1_parent; + struct clk *pixel1_parent; + /* DSI core regulators */ struct dss_module_power power_data[DSI_MAX_PM]; }; @@ -264,6 +277,17 @@ enum mdss_dsi_hw_config { SPLIT_DSI, }; +/* + * enum mdss_dsi_pll_src_config - The PLL source for DSI link clocks + * + * @PLL_SRC_0: The link clocks are sourced out of PLL0. + * @PLL_SRC_1: The link clocks are sourced out of PLL1. + */ +enum mdss_dsi_pll_src_config { + PLL_SRC_0, + PLL_SRC_1, +}; + struct dsi_panel_cmds { char *buf; int blen; @@ -300,9 +324,9 @@ struct panel_horizontal_idle { #define DSI_CTRL_CLK_SLAVE DSI_CTRL_RIGHT #define DSI_CTRL_CLK_MASTER DSI_CTRL_LEFT -#define DSI_BUS_CLKS BIT(0) +#define DSI_CORE_CLKS BIT(0) #define DSI_LINK_CLKS BIT(1) -#define DSI_ALL_CLKS ((DSI_BUS_CLKS) | (DSI_LINK_CLKS)) +#define DSI_ALL_CLKS ((DSI_CORE_CLKS) | (DSI_LINK_CLKS)) #define DSI_EV_PLL_UNLOCKED 0x0001 #define DSI_EV_MDP_FIFO_UNDERFLOW 0x0002 @@ -334,7 +358,7 @@ struct mdss_dsi_ctrl_pdata { struct dss_io_data mmss_misc_io; struct dss_io_data phy_io; int reg_size; - u32 bus_clk_cnt; + u32 core_clk_cnt; u32 link_clk_cnt; u32 flags; struct clk *byte_clk; @@ -346,7 +370,9 @@ struct mdss_dsi_ctrl_pdata { struct clk *pll_pixel_clk; struct clk *shadow_byte_clk; struct clk *shadow_pixel_clk; - struct clk *vco_clk; + struct clk *byte_clk_rcg; + struct clk *pixel_clk_rcg; + struct clk *vco_dummy_clk; u8 ctrl_state; int panel_mode; int irq_cnt; @@ -483,18 +509,14 @@ 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, +int mdss_dsi_core_clk_init(struct platform_device *pdev, struct dsi_shared_data *sdata); -void mdss_dsi_bus_clk_deinit(struct device *dev, +void mdss_dsi_core_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); -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); void mdss_dsi_phy_disable(struct mdss_dsi_ctrl_pdata *ctrl); void mdss_dsi_cmd_test_pattern(struct mdss_dsi_ctrl_pdata *ctrl); @@ -572,6 +594,35 @@ 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 u32 mdss_dsi_get_pll_src_config(struct dsi_shared_data *sdata) +{ + return sdata->pll_src_config; +} + +/* + * mdss_dsi_is_pll_src_pll0: Check if the PLL source for a DSI device is PLL0 + * The function is only valid if the DSI configuration is single/split DSI. + * Not valid for dual DSI configuration. + * + * @sdata: pointer to DSI shared data structure + */ +static inline u32 mdss_dsi_is_pll_src_pll0(struct dsi_shared_data *sdata) +{ + return sdata->pll_src_config == PLL_SRC_0; +} + +/* + * mdss_dsi_is_pll_src_pll1: Check if the PLL source for a DSI device is PLL1 + * The function is only valid if the DSI configuration is single/split DSI. + * Not valid for dual DSI configuration. + * + * @sdata: pointer to DSI shared data structure + */ +static inline u32 mdss_dsi_is_pll_src_pll1(struct dsi_shared_data *sdata) +{ + return sdata->pll_src_config == PLL_SRC_1; +} + static inline bool mdss_dsi_sync_wait_enable(struct mdss_dsi_ctrl_pdata *ctrl) { return ctrl->cmd_sync_wait_broadcast; diff --git a/drivers/video/fbdev/msm/msm_mdss_io_8974.c b/drivers/video/fbdev/msm/msm_mdss_io_8974.c index 941e1c188221..166e138dea95 100644 --- a/drivers/video/fbdev/msm/msm_mdss_io_8974.c +++ b/drivers/video/fbdev/msm/msm_mdss_io_8974.c @@ -66,6 +66,14 @@ static void mdss_dsi_ctrl_phy_reset(struct mdss_dsi_ctrl_pdata *ctrl) static void mdss_dsi_phy_sw_reset(struct mdss_dsi_ctrl_pdata *ctrl) { struct mdss_dsi_ctrl_pdata *sctrl = NULL; + struct dsi_shared_data *sdata; + + if (ctrl == NULL) { + pr_err("%s: Invalid input data\n", __func__); + return; + } + + sdata = ctrl->shared_data; if (ctrl == NULL) { pr_err("%s: Invalid input data\n", __func__); @@ -85,14 +93,20 @@ static void mdss_dsi_phy_sw_reset(struct mdss_dsi_ctrl_pdata *ctrl) if (sctrl) mdss_dsi_ctrl_phy_reset(sctrl); - /* - * phy sw reset will wipe out the pll settings for PLL. - * Need to turn off the PLL1 to avoid current leakage issues - */ - if (ctrl->ndx == DSI_CTRL_1) { - 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); + if ((sdata->hw_rev == MDSS_DSI_HW_REV_103) && + !mdss_dsi_is_hw_config_dual(sdata) && + mdss_dsi_is_right_ctrl(ctrl)) { + + /* + * phy sw reset will wipe out the pll settings for PLL. + * Need to explicitly turn off PLL1 if unused to avoid + * current leakage issues. + */ + if ((mdss_dsi_is_hw_config_split(sdata) || + mdss_dsi_is_pll_src_pll0(sdata)) && + ctrl->vco_dummy_clk) { + pr_debug("Turn off unused PLL1 registers\n"); + clk_set_rate(ctrl->vco_dummy_clk, 1); } } } @@ -589,11 +603,18 @@ static void mdss_dsi_phy_init(struct mdss_dsi_ctrl_pdata *ctrl) } } -void mdss_dsi_bus_clk_deinit(struct device *dev, - struct dsi_shared_data *sdata) +void mdss_dsi_core_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->ext_pixel1_clk) + devm_clk_put(dev, sdata->ext_pixel1_clk); + if (sdata->ext_byte1_clk) + devm_clk_put(dev, sdata->ext_byte1_clk); + if (sdata->ext_pixel0_clk) + devm_clk_put(dev, sdata->ext_pixel0_clk); + if (sdata->ext_byte0_clk) + devm_clk_put(dev, sdata->ext_byte0_clk); if (sdata->axi_clk) devm_clk_put(dev, sdata->axi_clk); if (sdata->ahb_clk) @@ -602,7 +623,7 @@ void mdss_dsi_bus_clk_deinit(struct device *dev, devm_clk_put(dev, sdata->mdp_core_clk); } -int mdss_dsi_bus_clk_init(struct platform_device *pdev, +int mdss_dsi_core_clk_init(struct platform_device *pdev, struct dsi_shared_data *sdata) { struct device *dev = NULL; @@ -610,16 +631,18 @@ int mdss_dsi_bus_clk_init(struct platform_device *pdev, if (!pdev) { pr_err("%s: Invalid pdev\n", __func__); - goto clk_err; + goto error; } dev = &pdev->dev; + + /* Mandatory Clocks */ 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 clk_err; + goto error; } sdata->ahb_clk = devm_clk_get(dev, "iface_clk"); @@ -627,7 +650,7 @@ int mdss_dsi_bus_clk_init(struct platform_device *pdev, rc = PTR_ERR(sdata->ahb_clk); pr_err("%s: Unable to get mdss ahb clk. rc=%d\n", __func__, rc); - goto clk_err; + goto error; } sdata->axi_clk = devm_clk_get(dev, "bus_clk"); @@ -635,25 +658,60 @@ int mdss_dsi_bus_clk_init(struct platform_device *pdev, rc = PTR_ERR(sdata->axi_clk); pr_err("%s: Unable to get axi bus clk. rc=%d\n", __func__, rc); - goto clk_err; + goto error; + } + + /* Optional Clocks */ + sdata->ext_byte0_clk = devm_clk_get(dev, "ext_byte0_clk"); + if (IS_ERR(sdata->ext_byte0_clk)) { + pr_debug("%s: unable to get byte0 clk rcg. rc=%d\n", + __func__, rc); + sdata->ext_byte0_clk = NULL; + } + + sdata->ext_pixel0_clk = devm_clk_get(dev, "ext_pixel0_clk"); + if (IS_ERR(sdata->ext_pixel0_clk)) { + pr_debug("%s: unable to get pixel0 clk rcg. rc=%d\n", + __func__, rc); + sdata->ext_pixel0_clk = NULL; + } + + sdata->ext_byte1_clk = devm_clk_get(dev, "ext_byte1_clk"); + if (IS_ERR(sdata->ext_byte1_clk)) { + pr_debug("%s: unable to get byte1 clk rcg. rc=%d\n", + __func__, rc); + sdata->ext_byte1_clk = NULL; + } + + sdata->ext_pixel1_clk = devm_clk_get(dev, "ext_pixel1_clk"); + if (IS_ERR(sdata->ext_pixel1_clk)) { + pr_debug("%s: unable to get pixel1 clk rcg. rc=%d\n", + __func__, rc); + sdata->ext_pixel1_clk = NULL; } 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", + pr_debug("%s: Unable to get mmss misc ahb clk\n", __func__); } -clk_err: +error: if (rc) - mdss_dsi_bus_clk_deinit(dev, sdata); + mdss_dsi_core_clk_deinit(dev, sdata); return rc; } void mdss_dsi_link_clk_deinit(struct device *dev, struct mdss_dsi_ctrl_pdata *ctrl) { + if (ctrl->vco_dummy_clk) + devm_clk_put(dev, ctrl->vco_dummy_clk); + if (ctrl->pixel_clk_rcg) + devm_clk_put(dev, ctrl->pixel_clk_rcg); + if (ctrl->byte_clk_rcg) + devm_clk_put(dev, ctrl->byte_clk_rcg); if (ctrl->byte_clk) devm_clk_put(dev, ctrl->byte_clk); if (ctrl->esc_clk) @@ -674,6 +732,8 @@ int mdss_dsi_link_clk_init(struct platform_device *pdev, } dev = &pdev->dev; + + /* Mandatory Clocks */ ctrl->byte_clk = devm_clk_get(dev, "byte_clk"); if (IS_ERR(ctrl->byte_clk)) { rc = PTR_ERR(ctrl->byte_clk); @@ -701,32 +761,28 @@ int mdss_dsi_link_clk_init(struct platform_device *pdev, goto error; } -error: - if (rc) - mdss_dsi_link_clk_deinit(dev, ctrl); - return rc; -} - -int mdss_dsi_pll_1_clk_init(struct platform_device *pdev, - struct mdss_dsi_ctrl_pdata *ctrl) -{ - struct device *dev = NULL; - int rc = 0; + /* Optional Clocks */ + ctrl->byte_clk_rcg = devm_clk_get(dev, "byte_clk_rcg"); + if (IS_ERR(ctrl->byte_clk_rcg)) { + pr_debug("%s: can't find byte clk rcg. rc=%d\n", __func__, rc); + ctrl->byte_clk_rcg = NULL; + } - if (!pdev) { - pr_err("%s: Invalid pdev\n", __func__); - return -EINVAL; + ctrl->pixel_clk_rcg = devm_clk_get(dev, "pixel_clk_rcg"); + if (IS_ERR(ctrl->pixel_clk_rcg)) { + pr_debug("%s: can't find pixel clk rcg. rc=%d\n", __func__, rc); + ctrl->pixel_clk_rcg = NULL; } - dev = &pdev->dev; - ctrl->vco_clk = clk_get(dev, "pll1_vco_clk_src"); - if (IS_ERR(ctrl->vco_clk)) { - rc = PTR_ERR(ctrl->vco_clk); - pr_err("%s: can't find vco_clk. rc=%d\n", - __func__, rc); - ctrl->vco_clk = NULL; + ctrl->vco_dummy_clk = devm_clk_get(dev, "pll_vco_dummy_clk"); + if (IS_ERR(ctrl->vco_dummy_clk)) { + pr_debug("%s: can't find vco dummy clk. rc=%d\n", __func__, rc); + ctrl->vco_dummy_clk = NULL; } +error: + if (rc) + mdss_dsi_link_clk_deinit(dev, ctrl); return rc; } @@ -885,7 +941,7 @@ int mdss_dsi_clk_div_config(struct mdss_panel_info *panel_info, return 0; } -static int mdss_dsi_bus_clk_start(struct mdss_dsi_ctrl_pdata *ctrl_pdata) +static int mdss_dsi_core_clk_start(struct mdss_dsi_ctrl_pdata *ctrl_pdata) { int rc = 0; struct dsi_shared_data *sdata = ctrl_pdata->shared_data; @@ -933,7 +989,7 @@ error: return rc; } -static void mdss_dsi_bus_clk_stop(struct mdss_dsi_ctrl_pdata *ctrl_pdata) +static void mdss_dsi_core_clk_stop(struct mdss_dsi_ctrl_pdata *ctrl_pdata) { struct dsi_shared_data *sdata = ctrl_pdata->shared_data; if (sdata->mmss_misc_ahb_clk) @@ -993,36 +1049,34 @@ static int mdss_dsi_link_clk_set_rate(struct mdss_dsi_ctrl_pdata *ctrl_pdata) u32 esc_clk_rate = 19200000; int rc = 0; - if (!ctrl_pdata) { - pr_err("%s: Invalid input data\n", __func__); - return -EINVAL; + if (ctrl_pdata->panel_data.panel_info.cont_splash_enabled) { + pr_debug("%s: cont splash enabled, not setting rate\n", + __func__); + return rc; } - if (!ctrl_pdata->panel_data.panel_info.cont_splash_enabled) { - pr_debug("%s: Set clk rates: pclk=%d, byteclk=%d escclk=%d\n", - __func__, ctrl_pdata->pclk_rate, - ctrl_pdata->byte_clk_rate, esc_clk_rate); - rc = clk_set_rate(ctrl_pdata->esc_clk, esc_clk_rate); - if (rc) { - pr_err("%s: dsi_esc_clk - clk_set_rate failed\n", - __func__); - goto error; - } + pr_debug("%s: Set clk rates: pclk=%d, byteclk=%d escclk=%d\n", + __func__, ctrl_pdata->pclk_rate, + ctrl_pdata->byte_clk_rate, esc_clk_rate); + rc = clk_set_rate(ctrl_pdata->esc_clk, esc_clk_rate); + if (rc) { + pr_err("%s: dsi_esc_clk - clk_set_rate failed\n", + __func__); + goto error; + } - rc = clk_set_rate(ctrl_pdata->byte_clk, - ctrl_pdata->byte_clk_rate); - if (rc) { - pr_err("%s: dsi_byte_clk - clk_set_rate failed\n", - __func__); - goto error; - } + rc = clk_set_rate(ctrl_pdata->byte_clk, ctrl_pdata->byte_clk_rate); + if (rc) { + pr_err("%s: dsi_byte_clk - clk_set_rate failed\n", + __func__); + goto error; + } - rc = clk_set_rate(ctrl_pdata->pixel_clk, ctrl_pdata->pclk_rate); - if (rc) { - pr_err("%s: dsi_pixel_clk - clk_set_rate failed\n", - __func__); - goto error; - } + rc = clk_set_rate(ctrl_pdata->pixel_clk, ctrl_pdata->pclk_rate); + if (rc) { + pr_err("%s: dsi_pixel_clk - clk_set_rate failed\n", + __func__); + goto error; } error: @@ -1125,7 +1179,7 @@ static void mdss_dsi_link_clk_stop(struct mdss_dsi_ctrl_pdata *ctrl) * * This function executes the necessary programming sequence to enter/exit * DSI Ultra-Low Power State (ULPS). This function assumes that the link and - * bus clocks are already on. + * core clocks are already on. */ static int mdss_dsi_ulps_config(struct mdss_dsi_ctrl_pdata *ctrl, int enable) @@ -1394,7 +1448,7 @@ static int mdss_dsi_clamp_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, int enable) * @ctrl: pointer to DSI controller structure * @enable: 1 to enable power, 0 to disable power * - * When all DSI bus clocks are disabled, DSI core power module can be turned + * When all DSI core clocks are disabled, DSI core power module can be turned * off to save any leakage current. This function implements the necessary * programming sequence for the same. For command mode panels, the core power * can be turned off for idle-screen usecases, where additional programming is @@ -1450,11 +1504,11 @@ static int mdss_dsi_core_power_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, ctrl->core_power = true; } - rc = mdss_dsi_bus_clk_start(ctrl); + rc = mdss_dsi_core_clk_start(ctrl); if (rc) { - pr_err("%s: Failed to start bus clocks. rc=%d\n", + pr_err("%s: Failed to start core clocks. rc=%d\n", __func__, rc); - goto error_bus_clk_start; + goto error_core_clk_start; } if (!pdata->panel_info.cont_splash_enabled) @@ -1526,10 +1580,10 @@ static int mdss_dsi_core_power_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, } /* - * disable bus clocks irrespective of whether dsi phy was + * disable core clocks irrespective of whether dsi phy was * successfully clamped or not */ - mdss_dsi_bus_clk_stop(ctrl); + mdss_dsi_core_clk_stop(ctrl); /* disable DSI core power if dsi phy was successfully clamped */ if (rc) { @@ -1558,8 +1612,8 @@ static int mdss_dsi_core_power_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, return rc; error_ulps: - mdss_dsi_bus_clk_stop(ctrl); -error_bus_clk_start: + mdss_dsi_core_clk_stop(ctrl); +error_core_clk_start: 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))) @@ -1615,7 +1669,7 @@ static int mdss_dsi_clk_ctrl_sub(struct mdss_dsi_ctrl_pdata *ctrl, ctrl->ndx, clk_type, enable); if (enable) { - if (clk_type & DSI_BUS_CLKS) { + if (clk_type & DSI_CORE_CLKS) { rc = mdss_dsi_core_power_ctrl(ctrl, enable); if (rc) { pr_err("%s: Failed to enable core power. rc=%d\n", @@ -1645,7 +1699,7 @@ static int mdss_dsi_clk_ctrl_sub(struct mdss_dsi_ctrl_pdata *ctrl, mdss_dsi_ulps_config(ctrl, 1); mdss_dsi_link_clk_stop(ctrl); } - if (clk_type & DSI_BUS_CLKS) { + if (clk_type & DSI_CORE_CLKS) { rc = mdss_dsi_core_power_ctrl(ctrl, enable); if (rc) { pr_err("%s: Failed to disable core power. rc=%d\n", @@ -1659,7 +1713,7 @@ static int mdss_dsi_clk_ctrl_sub(struct mdss_dsi_ctrl_pdata *ctrl, error_ulps_exit: mdss_dsi_link_clk_stop(ctrl); error_link_clk_start: - if ((clk_type & DSI_BUS_CLKS) && + if ((clk_type & DSI_CORE_CLKS) && (mdss_dsi_core_power_ctrl(ctrl, !enable))) pr_warn("%s: Failed to disable core power. rc=%d\n", __func__, rc); @@ -1671,25 +1725,25 @@ static DEFINE_MUTEX(dsi_clk_lock); /* per system */ bool __mdss_dsi_clk_enabled(struct mdss_dsi_ctrl_pdata *ctrl, u8 clk_type) { - bool bus_enabled = true; + bool core_enabled = true; bool link_enabled = true; mutex_lock(&dsi_clk_lock); - if (clk_type & DSI_BUS_CLKS) - bus_enabled = ctrl->bus_clk_cnt ? true : false; + if (clk_type & DSI_CORE_CLKS) + core_enabled = ctrl->core_clk_cnt ? true : false; if (clk_type & DSI_LINK_CLKS) link_enabled = ctrl->link_clk_cnt ? true : false; mutex_unlock(&dsi_clk_lock); - return bus_enabled && link_enabled; + return core_enabled && link_enabled; } int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, u8 clk_type, int enable) { int rc = 0; - int link_changed = 0, bus_changed = 0; - int m_link_changed = 0, m_bus_changed = 0; + int link_changed = 0, core_changed = 0; + int m_link_changed = 0, m_core_changed = 0; struct mdss_dsi_ctrl_pdata *mctrl = NULL; if (!ctrl) { @@ -1720,21 +1774,22 @@ int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, __func__); } - pr_debug("%s++: ndx=%d clk_type=%d bus_clk_cnt=%d link_clk_cnt=%d\n", - __func__, ctrl->ndx, clk_type, ctrl->bus_clk_cnt, + pr_debug("%s++: ndx=%d clk_type=%d core_clk_cnt=%d link_clk_cnt=%d\n", + __func__, ctrl->ndx, clk_type, ctrl->core_clk_cnt, ctrl->link_clk_cnt); - pr_debug("%s++: mctrl=%s m_bus_clk_cnt=%d m_link_clk_cnt=%d, enable=%d\n", - __func__, mctrl ? "yes" : "no", mctrl ? mctrl->bus_clk_cnt : -1, + pr_debug("%s++: mctrl=%s m_core_clk_cnt=%d m_link_clk_cnt=%d, enable=%d\n", + __func__, mctrl ? "yes" : "no", + mctrl ? mctrl->core_clk_cnt : -1, mctrl ? mctrl->link_clk_cnt : -1, enable); mutex_lock(&dsi_clk_lock); - if (clk_type & DSI_BUS_CLKS) { - bus_changed = __mdss_dsi_update_clk_cnt(&ctrl->bus_clk_cnt, + if (clk_type & DSI_CORE_CLKS) { + core_changed = __mdss_dsi_update_clk_cnt(&ctrl->core_clk_cnt, enable); - if (bus_changed && mctrl) - m_bus_changed = __mdss_dsi_update_clk_cnt( - &mctrl->bus_clk_cnt, enable); + if (core_changed && mctrl) + m_core_changed = __mdss_dsi_update_clk_cnt( + &mctrl->core_clk_cnt, enable); } if (clk_type & DSI_LINK_CLKS) { @@ -1745,37 +1800,37 @@ int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, &mctrl->link_clk_cnt, enable); } - if (!link_changed && !bus_changed) + if (!link_changed && !core_changed) goto no_error; /* clk cnts updated, nothing else needed */ /* - * If updating link clock, need to make sure that the bus + * If updating link clock, need to make sure that the core * clocks are enabled */ - if (link_changed && (!bus_changed && !ctrl->bus_clk_cnt)) { - pr_err("%s: Trying to enable link clks w/o enabling bus clks for ctrl%d", - __func__, mctrl->ndx); - goto error_mctrl_bus_start; + if (link_changed && (!core_changed && !ctrl->core_clk_cnt)) { + pr_err("%s: Trying to enable link clks w/o enabling core clks for ctrl%d", + __func__, ctrl->ndx); + goto error_mctrl_core_start; } - if (m_link_changed && (!m_bus_changed && !mctrl->bus_clk_cnt)) { - pr_err("%s: Trying to enable link clks w/o enabling bus clks for ctrl%d", + if (m_link_changed && (!m_core_changed && !mctrl->core_clk_cnt)) { + pr_err("%s: Trying to enable link clks w/o enabling core clks for ctrl%d", __func__, ctrl->ndx); - goto error_mctrl_bus_start; + goto error_mctrl_core_start; } - if (enable && m_bus_changed) { - rc = mdss_dsi_clk_ctrl_sub(mctrl, DSI_BUS_CLKS, 1); + if (enable && m_core_changed) { + rc = mdss_dsi_clk_ctrl_sub(mctrl, DSI_CORE_CLKS, 1); if (rc) { - pr_err("Failed to start mctrl bus clocks rc=%d\n", rc); - goto error_mctrl_bus_start; + pr_err("Failed to start mctrl core clocks rc=%d\n", rc); + goto error_mctrl_core_start; } } - if (enable && bus_changed) { - rc = mdss_dsi_clk_ctrl_sub(ctrl, DSI_BUS_CLKS, 1); + if (enable && core_changed) { + rc = mdss_dsi_clk_ctrl_sub(ctrl, DSI_CORE_CLKS, 1); if (rc) { - pr_err("Failed to start ctrl bus clocks rc=%d\n", rc); - goto error_ctrl_bus_start; + pr_err("Failed to start ctrl core clocks rc=%d\n", rc); + goto error_ctrl_core_start; } } @@ -1796,44 +1851,44 @@ int mdss_dsi_clk_ctrl(struct mdss_dsi_ctrl_pdata *ctrl, } } - if (!enable && m_bus_changed) { - rc = mdss_dsi_clk_ctrl_sub(mctrl, DSI_BUS_CLKS, 0); + if (!enable && m_core_changed) { + rc = mdss_dsi_clk_ctrl_sub(mctrl, DSI_CORE_CLKS, 0); if (rc) { - pr_err("Failed to stop mctrl bus clocks rc=%d\n", rc); - goto error_mctrl_bus_stop; + pr_err("Failed to stop mctrl core clocks rc=%d\n", rc); + goto error_mctrl_core_stop; } } - if (!enable && bus_changed) { - rc = mdss_dsi_clk_ctrl_sub(ctrl, DSI_BUS_CLKS, 0); + if (!enable && core_changed) { + rc = mdss_dsi_clk_ctrl_sub(ctrl, DSI_CORE_CLKS, 0); if (rc) { - pr_err("Failed to stop ctrl bus clocks\n rc=%d", rc); - goto error_ctrl_bus_stop; + pr_err("Failed to stop ctrl core clocks\n rc=%d", rc); + goto error_ctrl_core_stop; } } goto no_error; -error_ctrl_bus_stop: - if (m_bus_changed) - mdss_dsi_clk_ctrl_sub(mctrl, DSI_BUS_CLKS, 1); -error_mctrl_bus_stop: +error_ctrl_core_stop: + if (m_core_changed) + mdss_dsi_clk_ctrl_sub(mctrl, DSI_CORE_CLKS, 1); +error_mctrl_core_stop: if (link_changed) mdss_dsi_clk_ctrl_sub(ctrl, DSI_LINK_CLKS, enable ? 0 : 1); error_ctrl_link_change: if (m_link_changed) mdss_dsi_clk_ctrl_sub(mctrl, DSI_LINK_CLKS, enable ? 0 : 1); error_mctrl_link_change: - if (bus_changed && enable) - mdss_dsi_clk_ctrl_sub(ctrl, DSI_BUS_CLKS, 0); -error_ctrl_bus_start: - if (m_bus_changed && enable) - mdss_dsi_clk_ctrl_sub(mctrl, DSI_BUS_CLKS, 0); -error_mctrl_bus_start: - if (clk_type & DSI_BUS_CLKS) { + if (core_changed && enable) + mdss_dsi_clk_ctrl_sub(ctrl, DSI_CORE_CLKS, 0); +error_ctrl_core_start: + if (m_core_changed && enable) + mdss_dsi_clk_ctrl_sub(mctrl, DSI_CORE_CLKS, 0); +error_mctrl_core_start: + if (clk_type & DSI_CORE_CLKS) { if (mctrl) - __mdss_dsi_update_clk_cnt(&mctrl->bus_clk_cnt, + __mdss_dsi_update_clk_cnt(&mctrl->core_clk_cnt, enable ? 0 : 1); - __mdss_dsi_update_clk_cnt(&ctrl->bus_clk_cnt, enable ? 0 : 1); + __mdss_dsi_update_clk_cnt(&ctrl->core_clk_cnt, enable ? 0 : 1); } if (clk_type & DSI_LINK_CLKS) { if (mctrl) @@ -1844,13 +1899,14 @@ error_mctrl_bus_start: no_error: mutex_unlock(&dsi_clk_lock); - pr_debug("%s--: ndx=%d clk_type=%d bus_clk_cnt=%d link_clk_cnt=%d changed=%d\n", - __func__, ctrl->ndx, clk_type, ctrl->bus_clk_cnt, - ctrl->link_clk_cnt, link_changed && bus_changed); - pr_debug("%s--: mctrl=%s m_bus_clk_cnt=%d m_link_clk_cnt=%d, m_changed=%d, enable=%d\n", - __func__, mctrl ? "yes" : "no", mctrl ? mctrl->bus_clk_cnt : -1, + pr_debug("%s--: ndx=%d clk_type=%d core_clk_cnt=%d link_clk_cnt=%d changed=%d\n", + __func__, ctrl->ndx, clk_type, ctrl->core_clk_cnt, + ctrl->link_clk_cnt, link_changed && core_changed); + pr_debug("%s--: mctrl=%s m_core_clk_cnt=%d m_link_clk_cnt=%d, m_changed=%d, enable=%d\n", + __func__, mctrl ? "yes" : "no", + mctrl ? mctrl->core_clk_cnt : -1, mctrl ? mctrl->link_clk_cnt : -1, - m_link_changed && m_bus_changed, enable); + m_link_changed && m_core_changed, enable); return rc; } |
