Loading drivers/clk/qcom/mdss/mdss-dsi-20nm-pll-util.c +23 −2 Original line number Diff line number Diff line Loading @@ -481,6 +481,19 @@ int dsi_20nm_pll_lock_status(struct mdss_pll_resources *dsi_pll_res) return pll_locked; } void __dsi_pll_disable(void __iomem *pll_base) { if (!pll_base) { pr_err("Invalid pll base\n"); return; } pr_debug("Disabling PHY PLL for PLL_BASE=%p\n", pll_base); MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_PLL_VCOTAIL_EN, 0x042); MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_BIAS_EN_CLKBUFLR_EN, 0x02); MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_RESETSM_CNTRL3, 0x02); } static int dsi_pll_enable(struct clk *c) { int i, rc; Loading @@ -501,6 +514,9 @@ static int dsi_pll_enable(struct clk *c) if (!rc) break; } /* Disable PLL1 to avoid current leakage while toggling MDSS GDSC */ if (dsi_pll_res->pll_1_base) __dsi_pll_disable(dsi_pll_res->pll_1_base); if (rc) { mdss_pll_resource_enable(dsi_pll_res, false); Loading @@ -524,8 +540,11 @@ static void dsi_pll_disable(struct clk *c) dsi_pll_res->handoff_resources = false; MDSS_PLL_REG_W(dsi_pll_res->pll_base, MMSS_DSI_PHY_PLL_PLL_VCOTAIL_EN, 0x02); __dsi_pll_disable(dsi_pll_res->pll_base); /* Disable PLL1 to avoid current leakage while toggling MDSS GDSC */ if (dsi_pll_res->pll_1_base) __dsi_pll_disable(dsi_pll_res->pll_1_base); mdss_pll_resource_enable(dsi_pll_res, false); dsi_pll_res->pll_on = false; Loading Loading @@ -779,6 +798,8 @@ int pll_20nm_vco_set_rate(struct dsi_pll_vco_clk *vco, unsigned long rate) udelay(1000); /* memory barrier */ wmb(); if (dsi_pll_res->pll_1_base) __dsi_pll_disable(dsi_pll_res->pll_1_base); return 0; } Loading drivers/clk/qcom/mdss/mdss-dsi-pll-20nm.c +62 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include <linux/delay.h> #include <linux/clk/msm-clk-provider.h> #include <linux/clk/msm-clk.h> #include <linux/workqueue.h> #include <linux/clk/msm-clock-generic.h> #include <dt-bindings/clock/msm-clocks-8994.h> Loading Loading @@ -47,6 +48,8 @@ static int vco_set_rate_20nm(struct clk *c, unsigned long rate) return rc; } pr_debug("Cancel pending pll off work\n"); cancel_work_sync(&dsi_pll_res->pll_off); rc = pll_20nm_vco_set_rate(vco, rate); mdss_pll_resource_enable(dsi_pll_res, false); Loading Loading @@ -453,10 +456,58 @@ static struct clk_lookup mdss_dsi_pllcc_8994[] = { CLK_LIST(shadow_dsi_vco_clk_8994), }; static void dsi_pll_off_work(struct work_struct *work) { struct mdss_pll_resources *pll_res; if (!work) { pr_err("pll_resource is invalid\n"); return; } pr_debug("Starting PLL off Worker%s\n", __func__); pll_res = container_of(work, struct mdss_pll_resources, pll_off); mdss_pll_resource_enable(pll_res, true); __dsi_pll_disable(pll_res->pll_base); if (pll_res->pll_1_base) __dsi_pll_disable(pll_res->pll_1_base); mdss_pll_resource_enable(pll_res, false); } static int dsi_pll_regulator_notifier_call(struct notifier_block *self, unsigned long event, void *data) { struct mdss_pll_resources *pll_res; if (!self) { pr_err("pll_resource is invalid\n"); goto error; } pll_res = container_of(self, struct mdss_pll_resources, gdsc_cb); if (event & REGULATOR_EVENT_ENABLE) { pr_debug("Regulator ON event. Scheduling pll off worker\n"); schedule_work(&pll_res->pll_off); } if (event & REGULATOR_EVENT_DISABLE) pr_debug("Regulator OFF event.\n"); error: return NOTIFY_OK; } int dsi_pll_clock_register_20nm(struct platform_device *pdev, struct mdss_pll_resources *pll_res) { int rc; struct dss_vreg *pll_reg; if (!pdev || !pdev->dev.of_node) { pr_err("Invalid input parameters\n"); Loading Loading @@ -513,12 +564,23 @@ int dsi_pll_clock_register_20nm(struct platform_device *pdev, shadow_byte_clk_src_ops.prepare = dsi_pll_div_prepare; 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); 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"); } } else { pr_err("Invalid target ID\n"); rc = -EINVAL; Loading drivers/clk/qcom/mdss/mdss-dsi-pll.h +1 −0 Original line number Diff line number Diff line Loading @@ -99,6 +99,7 @@ int hr_oclk3_get_div(struct div_clk *clk); int ndiv_set_div(struct div_clk *clk, int div); int shadow_ndiv_set_div(struct div_clk *clk, int div); int ndiv_get_div(struct div_clk *clk); void __dsi_pll_disable(void __iomem *pll_base); int set_mdss_pixel_mux_sel(struct mux_clk *clk, int sel); int get_mdss_pixel_mux_sel(struct mux_clk *clk); Loading drivers/clk/qcom/mdss/mdss-pll-util.c +34 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,40 @@ int mdss_pll_util_resource_init(struct platform_device *pdev, return rc; } /** * mdss_pll_get_mp_by_reg_name() -- Find power module by regulator name *@pll_res: Pointer to the PLL resource *@name: Regulator name as specified in the pll dtsi * * This is a helper function to retrieve the regulator information * for each pll resource. */ struct dss_vreg *mdss_pll_get_mp_by_reg_name(struct mdss_pll_resources *pll_res , char *name) { struct dss_vreg *regulator = NULL; int i; if ((pll_res == NULL) || (pll_res->mp.vreg_config == NULL)) { pr_err("%s Invalid PLL resource\n", __func__); goto error; } regulator = pll_res->mp.vreg_config; for (i = 0; i < pll_res->mp.num_vreg; i++) { if (!strcmp(name, regulator->vreg_name)) { pr_debug("Found regulator match for %s\n", name); break; } regulator++; } error: return regulator; } void mdss_pll_util_resource_deinit(struct platform_device *pdev, struct mdss_pll_resources *pll_res) { Loading drivers/clk/qcom/mdss/mdss-pll.c +22 −0 Original line number Diff line number Diff line Loading @@ -249,6 +249,26 @@ static int mdss_pll_probe(struct platform_device *pdev) goto res_parse_error; } /* * DSI PLL 1 is leaking current whenever MDSS GDSC is toggled. Need to * map PLL1 registers along with the PLl0 so that we can manually turn * off PLL1. */ if (pll_res->pll_interface_type == MDSS_DSI_PLL_20NM) { struct resource *pll_1_base_reg; pll_1_base_reg = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll_1_base"); if (pll_1_base_reg) { pll_res->pll_1_base = ioremap(pll_1_base_reg->start, resource_size(pll_1_base_reg)); if (!pll_res->pll_1_base) pr_err("Unable to remap pll 1 base resources\n"); } else { pr_err("Unable to get the pll 1 base resource\n"); } } phy_base_reg = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_base"); if (!phy_base_reg) { Loading Loading @@ -303,6 +323,8 @@ static int mdss_pll_probe(struct platform_device *pdev) if (pll_res->phy_base) iounmap(pll_res->phy_base); phy_io_error: if (pll_res->pll_1_base) iounmap(pll_res->pll_1_base); mdss_pll_resource_release(pdev, pll_res); res_parse_error: iounmap(pll_res->pll_base); Loading Loading
drivers/clk/qcom/mdss/mdss-dsi-20nm-pll-util.c +23 −2 Original line number Diff line number Diff line Loading @@ -481,6 +481,19 @@ int dsi_20nm_pll_lock_status(struct mdss_pll_resources *dsi_pll_res) return pll_locked; } void __dsi_pll_disable(void __iomem *pll_base) { if (!pll_base) { pr_err("Invalid pll base\n"); return; } pr_debug("Disabling PHY PLL for PLL_BASE=%p\n", pll_base); MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_PLL_VCOTAIL_EN, 0x042); MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_BIAS_EN_CLKBUFLR_EN, 0x02); MDSS_PLL_REG_W(pll_base, MMSS_DSI_PHY_PLL_RESETSM_CNTRL3, 0x02); } static int dsi_pll_enable(struct clk *c) { int i, rc; Loading @@ -501,6 +514,9 @@ static int dsi_pll_enable(struct clk *c) if (!rc) break; } /* Disable PLL1 to avoid current leakage while toggling MDSS GDSC */ if (dsi_pll_res->pll_1_base) __dsi_pll_disable(dsi_pll_res->pll_1_base); if (rc) { mdss_pll_resource_enable(dsi_pll_res, false); Loading @@ -524,8 +540,11 @@ static void dsi_pll_disable(struct clk *c) dsi_pll_res->handoff_resources = false; MDSS_PLL_REG_W(dsi_pll_res->pll_base, MMSS_DSI_PHY_PLL_PLL_VCOTAIL_EN, 0x02); __dsi_pll_disable(dsi_pll_res->pll_base); /* Disable PLL1 to avoid current leakage while toggling MDSS GDSC */ if (dsi_pll_res->pll_1_base) __dsi_pll_disable(dsi_pll_res->pll_1_base); mdss_pll_resource_enable(dsi_pll_res, false); dsi_pll_res->pll_on = false; Loading Loading @@ -779,6 +798,8 @@ int pll_20nm_vco_set_rate(struct dsi_pll_vco_clk *vco, unsigned long rate) udelay(1000); /* memory barrier */ wmb(); if (dsi_pll_res->pll_1_base) __dsi_pll_disable(dsi_pll_res->pll_1_base); return 0; } Loading
drivers/clk/qcom/mdss/mdss-dsi-pll-20nm.c +62 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ #include <linux/delay.h> #include <linux/clk/msm-clk-provider.h> #include <linux/clk/msm-clk.h> #include <linux/workqueue.h> #include <linux/clk/msm-clock-generic.h> #include <dt-bindings/clock/msm-clocks-8994.h> Loading Loading @@ -47,6 +48,8 @@ static int vco_set_rate_20nm(struct clk *c, unsigned long rate) return rc; } pr_debug("Cancel pending pll off work\n"); cancel_work_sync(&dsi_pll_res->pll_off); rc = pll_20nm_vco_set_rate(vco, rate); mdss_pll_resource_enable(dsi_pll_res, false); Loading Loading @@ -453,10 +456,58 @@ static struct clk_lookup mdss_dsi_pllcc_8994[] = { CLK_LIST(shadow_dsi_vco_clk_8994), }; static void dsi_pll_off_work(struct work_struct *work) { struct mdss_pll_resources *pll_res; if (!work) { pr_err("pll_resource is invalid\n"); return; } pr_debug("Starting PLL off Worker%s\n", __func__); pll_res = container_of(work, struct mdss_pll_resources, pll_off); mdss_pll_resource_enable(pll_res, true); __dsi_pll_disable(pll_res->pll_base); if (pll_res->pll_1_base) __dsi_pll_disable(pll_res->pll_1_base); mdss_pll_resource_enable(pll_res, false); } static int dsi_pll_regulator_notifier_call(struct notifier_block *self, unsigned long event, void *data) { struct mdss_pll_resources *pll_res; if (!self) { pr_err("pll_resource is invalid\n"); goto error; } pll_res = container_of(self, struct mdss_pll_resources, gdsc_cb); if (event & REGULATOR_EVENT_ENABLE) { pr_debug("Regulator ON event. Scheduling pll off worker\n"); schedule_work(&pll_res->pll_off); } if (event & REGULATOR_EVENT_DISABLE) pr_debug("Regulator OFF event.\n"); error: return NOTIFY_OK; } int dsi_pll_clock_register_20nm(struct platform_device *pdev, struct mdss_pll_resources *pll_res) { int rc; struct dss_vreg *pll_reg; if (!pdev || !pdev->dev.of_node) { pr_err("Invalid input parameters\n"); Loading Loading @@ -513,12 +564,23 @@ int dsi_pll_clock_register_20nm(struct platform_device *pdev, shadow_byte_clk_src_ops.prepare = dsi_pll_div_prepare; 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); 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"); } } else { pr_err("Invalid target ID\n"); rc = -EINVAL; Loading
drivers/clk/qcom/mdss/mdss-dsi-pll.h +1 −0 Original line number Diff line number Diff line Loading @@ -99,6 +99,7 @@ int hr_oclk3_get_div(struct div_clk *clk); int ndiv_set_div(struct div_clk *clk, int div); int shadow_ndiv_set_div(struct div_clk *clk, int div); int ndiv_get_div(struct div_clk *clk); void __dsi_pll_disable(void __iomem *pll_base); int set_mdss_pixel_mux_sel(struct mux_clk *clk, int sel); int get_mdss_pixel_mux_sel(struct mux_clk *clk); Loading
drivers/clk/qcom/mdss/mdss-pll-util.c +34 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,40 @@ int mdss_pll_util_resource_init(struct platform_device *pdev, return rc; } /** * mdss_pll_get_mp_by_reg_name() -- Find power module by regulator name *@pll_res: Pointer to the PLL resource *@name: Regulator name as specified in the pll dtsi * * This is a helper function to retrieve the regulator information * for each pll resource. */ struct dss_vreg *mdss_pll_get_mp_by_reg_name(struct mdss_pll_resources *pll_res , char *name) { struct dss_vreg *regulator = NULL; int i; if ((pll_res == NULL) || (pll_res->mp.vreg_config == NULL)) { pr_err("%s Invalid PLL resource\n", __func__); goto error; } regulator = pll_res->mp.vreg_config; for (i = 0; i < pll_res->mp.num_vreg; i++) { if (!strcmp(name, regulator->vreg_name)) { pr_debug("Found regulator match for %s\n", name); break; } regulator++; } error: return regulator; } void mdss_pll_util_resource_deinit(struct platform_device *pdev, struct mdss_pll_resources *pll_res) { Loading
drivers/clk/qcom/mdss/mdss-pll.c +22 −0 Original line number Diff line number Diff line Loading @@ -249,6 +249,26 @@ static int mdss_pll_probe(struct platform_device *pdev) goto res_parse_error; } /* * DSI PLL 1 is leaking current whenever MDSS GDSC is toggled. Need to * map PLL1 registers along with the PLl0 so that we can manually turn * off PLL1. */ if (pll_res->pll_interface_type == MDSS_DSI_PLL_20NM) { struct resource *pll_1_base_reg; pll_1_base_reg = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll_1_base"); if (pll_1_base_reg) { pll_res->pll_1_base = ioremap(pll_1_base_reg->start, resource_size(pll_1_base_reg)); if (!pll_res->pll_1_base) pr_err("Unable to remap pll 1 base resources\n"); } else { pr_err("Unable to get the pll 1 base resource\n"); } } phy_base_reg = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_base"); if (!phy_base_reg) { Loading Loading @@ -303,6 +323,8 @@ static int mdss_pll_probe(struct platform_device *pdev) if (pll_res->phy_base) iounmap(pll_res->phy_base); phy_io_error: if (pll_res->pll_1_base) iounmap(pll_res->pll_1_base); mdss_pll_resource_release(pdev, pll_res); res_parse_error: iounmap(pll_res->pll_base); Loading