clk: msm: mdss: Add support for DSI PLL 1 clock registration
Setup DSI 1 PLL clock heirarchy. This is needed for instances
where we need to turn off the second pll in case of current
leak issue.
Change-Id: I694af1fa9591b2345709687c9e7b1d69f15b56a9
Signed-off-by: Siddhartha Agrawal <agrawals@codeaurora.org>
Signed-off-by: Veera Sundaram Sankaran <veeras@codeaurora.org>
diff --git a/drivers/clk/qcom/mdss/mdss-dsi-pll-20nm.c b/drivers/clk/qcom/mdss/mdss-dsi-pll-20nm.c
index c5ef107..f6fada26 100644
--- a/drivers/clk/qcom/mdss/mdss-dsi-pll-20nm.c
+++ b/drivers/clk/qcom/mdss/mdss-dsi-pll-20nm.c
@@ -56,6 +56,20 @@
return rc;
}
+static int pll1_vco_set_rate_20nm(struct clk *c, unsigned long rate)
+{
+ struct dsi_pll_vco_clk *vco = to_vco_clk(c);
+ struct mdss_pll_resources *pll_res = vco->priv;
+
+ mdss_pll_resource_enable(pll_res, true);
+ __dsi_pll_disable(pll_res->pll_base);
+ mdss_pll_resource_enable(pll_res, false);
+
+ pr_debug("Configuring PLL1 registers.\n");
+
+ return 0;
+}
+
static int shadow_vco_set_rate_20nm(struct clk *c, unsigned long rate)
{
int rc;
@@ -111,6 +125,11 @@
}
/* Op structures */
+
+static const struct clk_ops pll1_clk_ops_dsi_vco = {
+ .set_rate = pll1_vco_set_rate_20nm,
+};
+
static const struct clk_ops clk_ops_dsi_vco = {
.set_rate = vco_set_rate_20nm,
.round_rate = pll_20nm_vco_round_rate,
@@ -175,6 +194,15 @@
.get_mux_sel = get_mdss_pixel_mux_sel,
};
+static struct dsi_pll_vco_clk mdss_dsi1_vco_clk_src = {
+ .c = {
+ .dbg_name = "mdss_dsi1_vco_clk_src",
+ .ops = &pll1_clk_ops_dsi_vco,
+ .flags = CLKFLAG_NO_RATE_CACHE,
+ CLK_INIT(mdss_dsi1_vco_clk_src.c),
+ },
+};
+
static struct dsi_pll_vco_clk dsi_vco_clk_8994 = {
.ref_clk_rate = 19200000,
.min_rate = 1000000000,
@@ -435,6 +463,10 @@
}
};
+static struct clk_lookup mdss_dsi_pll_1_cc_8994[] = {
+ CLK_LIST(mdss_dsi1_vco_clk_src),
+};
+
static struct clk_lookup mdss_dsi_pllcc_8994[] = {
CLK_LIST(mdss_pixel_clk_mux),
CLK_LIST(mdss_byte_clk_mux),
@@ -519,68 +551,88 @@
return -EPROBE_DEFER;
}
- /* Set client data to mux, div and vco clocks */
- byte_clk_src.priv = pll_res;
- pixel_clk_src.priv = pll_res;
- bypass_lp_div_mux_8994.priv = pll_res;
- indirect_path_div2_clk_8994.priv = pll_res;
- ndiv_clk_8994.priv = pll_res;
- fixed_hr_oclk2_div_clk_8994.priv = pll_res;
- hr_oclk3_div_clk_8994.priv = pll_res;
- dsi_vco_clk_8994.priv = pll_res;
+ /*
+ * Set client data to mux, div and vco clocks.
+ * This needs to be done only for PLL0 since, that is the one in
+ * use.
+ **/
+ if (!pll_res->index) {
+ byte_clk_src.priv = pll_res;
+ pixel_clk_src.priv = pll_res;
+ bypass_lp_div_mux_8994.priv = pll_res;
+ indirect_path_div2_clk_8994.priv = pll_res;
+ ndiv_clk_8994.priv = pll_res;
+ fixed_hr_oclk2_div_clk_8994.priv = pll_res;
+ hr_oclk3_div_clk_8994.priv = pll_res;
+ dsi_vco_clk_8994.priv = pll_res;
- shadow_byte_clk_src.priv = pll_res;
- shadow_pixel_clk_src.priv = pll_res;
- shadow_bypass_lp_div_mux_8994.priv = pll_res;
- shadow_indirect_path_div2_clk_8994.priv = pll_res;
- shadow_ndiv_clk_8994.priv = pll_res;
- shadow_fixed_hr_oclk2_div_clk_8994.priv = pll_res;
- shadow_hr_oclk3_div_clk_8994.priv = pll_res;
- shadow_dsi_vco_clk_8994.priv = pll_res;
+ shadow_byte_clk_src.priv = pll_res;
+ shadow_pixel_clk_src.priv = pll_res;
+ shadow_bypass_lp_div_mux_8994.priv = pll_res;
+ shadow_indirect_path_div2_clk_8994.priv = pll_res;
+ shadow_ndiv_clk_8994.priv = pll_res;
+ shadow_fixed_hr_oclk2_div_clk_8994.priv = pll_res;
+ shadow_hr_oclk3_div_clk_8994.priv = pll_res;
+ shadow_dsi_vco_clk_8994.priv = pll_res;
- pll_res->vco_delay = VCO_DELAY_USEC;
+ pll_res->vco_delay = VCO_DELAY_USEC;
- /* Set clock source operations */
- pixel_clk_src_ops = clk_ops_slave_div;
- pixel_clk_src_ops.prepare = dsi_pll_div_prepare;
+ /* Set clock source operations */
+ pixel_clk_src_ops = clk_ops_slave_div;
+ pixel_clk_src_ops.prepare = dsi_pll_div_prepare;
- ndiv_clk_ops = clk_ops_div;
- ndiv_clk_ops.prepare = dsi_pll_div_prepare;
+ ndiv_clk_ops = clk_ops_div;
+ ndiv_clk_ops.prepare = dsi_pll_div_prepare;
- byte_clk_src_ops = clk_ops_div;
- byte_clk_src_ops.prepare = dsi_pll_div_prepare;
+ byte_clk_src_ops = clk_ops_div;
+ byte_clk_src_ops.prepare = dsi_pll_div_prepare;
- bypass_lp_div_mux_clk_ops = clk_ops_gen_mux;
- bypass_lp_div_mux_clk_ops.prepare = dsi_pll_mux_prepare;
+ bypass_lp_div_mux_clk_ops = clk_ops_gen_mux;
+ bypass_lp_div_mux_clk_ops.prepare = dsi_pll_mux_prepare;
- clk_ops_gen_mux_dsi = clk_ops_gen_mux;
- clk_ops_gen_mux_dsi.round_rate = parent_round_rate;
- clk_ops_gen_mux_dsi.set_rate = parent_set_rate;
+ clk_ops_gen_mux_dsi = clk_ops_gen_mux;
+ clk_ops_gen_mux_dsi.round_rate = parent_round_rate;
+ clk_ops_gen_mux_dsi.set_rate = parent_set_rate;
- shadow_pixel_clk_src_ops = clk_ops_slave_div;
- shadow_pixel_clk_src_ops.prepare = dsi_pll_div_prepare;
+ shadow_pixel_clk_src_ops = clk_ops_slave_div;
+ shadow_pixel_clk_src_ops.prepare = dsi_pll_div_prepare;
- shadow_byte_clk_src_ops = clk_ops_div;
- shadow_byte_clk_src_ops.prepare = dsi_pll_div_prepare;
+ shadow_byte_clk_src_ops = clk_ops_div;
+ shadow_byte_clk_src_ops.prepare = dsi_pll_div_prepare;
+ } else {
+ mdss_dsi1_vco_clk_src.priv = pll_res;
+ }
if (pll_res->target_id == MDSS_PLL_TARGET_8994) {
- pll_res->gdsc_cb.notifier_call =
- dsi_pll_regulator_notifier_call;
- INIT_WORK(&pll_res->pll_off, dsi_pll_off_work);
+ if (pll_res->index) {
+ rc = of_msm_clock_register(pdev->dev.of_node,
+ mdss_dsi_pll_1_cc_8994,
+ ARRAY_SIZE(mdss_dsi_pll_1_cc_8994));
+ if (rc) {
+ pr_err("Clock register failed\n");
+ rc = -EPROBE_DEFER;
+ }
+ } else {
+ rc = of_msm_clock_register(pdev->dev.of_node,
+ mdss_dsi_pllcc_8994,
+ ARRAY_SIZE(mdss_dsi_pllcc_8994));
+ if (rc) {
+ pr_err("Clock register failed\n");
+ rc = -EPROBE_DEFER;
+ }
+ pll_res->gdsc_cb.notifier_call =
+ dsi_pll_regulator_notifier_call;
+ INIT_WORK(&pll_res->pll_off, dsi_pll_off_work);
- rc = of_msm_clock_register(pdev->dev.of_node,
- mdss_dsi_pllcc_8994, ARRAY_SIZE(mdss_dsi_pllcc_8994));
- if (rc) {
- pr_err("Clock register failed\n");
- rc = -EPROBE_DEFER;
+ pll_reg = mdss_pll_get_mp_by_reg_name(pll_res, "gdsc");
+ if (pll_reg) {
+ pr_debug("Registering for gdsc regulator events\n");
+ if (regulator_register_notifier(pll_reg->vreg,
+ &(pll_res->gdsc_cb)))
+ pr_err("Regulator notification registration failed!\n");
+ }
}
- pll_reg = mdss_pll_get_mp_by_reg_name(pll_res, "gdsc");
- if (pll_reg) {
- pr_debug("Registering for gdsc regulator events\n");
- if (regulator_register_notifier(pll_reg->vreg,
- &(pll_res->gdsc_cb)))
- pr_err("Regulator notification registration failed!\n");
- }
+
} else {
pr_err("Invalid target ID\n");
rc = -EINVAL;
diff --git a/drivers/clk/qcom/mdss/mdss-pll.c b/drivers/clk/qcom/mdss/mdss-pll.c
index 115878a..8e2acac 100644
--- a/drivers/clk/qcom/mdss/mdss-pll.c
+++ b/drivers/clk/qcom/mdss/mdss-pll.c
@@ -227,6 +227,13 @@
}
platform_set_drvdata(pdev, pll_res);
+ rc = of_property_read_u32(pdev->dev.of_node, "cell-index",
+ &pll_res->index);
+ if (rc) {
+ pr_err("Unable to get the cell-index rc=%d\n", rc);
+ pll_res->index = 0;
+ }
+
pll_base_reg = platform_get_resource_byname(pdev,
IORESOURCE_MEM, "pll_base");
if (!pll_base_reg) {
diff --git a/drivers/clk/qcom/mdss/mdss-pll.h b/drivers/clk/qcom/mdss/mdss-pll.h
index e90394a..20642a9 100644
--- a/drivers/clk/qcom/mdss/mdss-pll.h
+++ b/drivers/clk/qcom/mdss/mdss-pll.h
@@ -119,6 +119,12 @@
*/
struct work_struct pll_off;
+ /*
+ * PLL index if multiple index are available. Eg. in case of
+ * DSI we have 2 plls.
+ */
+ uint32_t index;
+
};
struct mdss_pll_vco_calc {