summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAravind Venkateswaran <aravindh@codeaurora.org>2015-04-22 15:18:39 -0700
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-23 20:42:19 -0700
commit142b8c778451f3e315664c2bb073aa04adc68308 (patch)
tree215bb175d75b4389a0e4f26a3761933349ae72a0
parentdb5a26a52cfa551c1ee6ab4d20c58510bdb3d6cd (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.txt14
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.c213
-rw-r--r--drivers/video/fbdev/msm/mdss_dsi.h71
-rw-r--r--drivers/video/fbdev/msm/msm_mdss_io_8974.c332
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;
}