Add a reusable helper to configure and vote for Alpha PLLs
controlled by the GCC vote FSM. Per-PLL register offsets
support targets with different PLL layouts.

Signed-off-by: Abhilash V <[email protected]>
---
 drivers/clk/qcom/clock-qcom.c | 48 +++++++++++++++++++++++++++++++++++
 drivers/clk/qcom/clock-qcom.h | 24 ++++++++++++++++++
 2 files changed, 72 insertions(+)

diff --git a/drivers/clk/qcom/clock-qcom.c b/drivers/clk/qcom/clock-qcom.c
index 6b46d9db744..30127c1fffe 100644
--- a/drivers/clk/qcom/clock-qcom.c
+++ b/drivers/clk/qcom/clock-qcom.c
@@ -59,6 +59,54 @@ void clk_enable_gpll0(phys_addr_t base, const struct 
pll_vote_clk *gpll0)
                ;
 }
 
+#define PLL_MODE_ACTIVE_FLAG   BIT(30)
+#define PLL_MODE_BIAS_COUNT    GENMASK(19, 14)
+#define PLL_MODE_LOCK_COUNT    GENMASK(13, 8)
+#define PLL_MODE_VOTE_FSM_ENA  BIT(20)
+
+#define PLL_MODE_BIAS_COUNT_VAL        (0x6 << 14)
+#define PLL_MODE_LOCK_COUNT_VAL        (0x0 << 8)
+
+#define PLL_LOCK_TIMEOUT_US    200
+
+void clk_configure_enable_pll(phys_addr_t base, const struct pll_config *pll)
+{
+       u32 mode = readl(base + pll->mode_reg);
+       unsigned int count;
+
+       if ((mode & PLL_MODE_VOTE_FSM_ENA) &&
+           (readl(base + pll->ena_vote) & pll->vote_bit) == pll->vote_bit &&
+           (mode & PLL_MODE_ACTIVE_FLAG))
+               return;
+
+       writel(0, base + pll->mode_reg);
+       writel(pll->user_ctl_u, base + pll->mode_reg + pll->user_ctl_u_offset);
+       writel(pll->config_ctl, base + pll->mode_reg + pll->config_ctl_offset);
+       writel(pll->test_ctl, base + pll->mode_reg + pll->test_ctl_offset);
+       writel(pll->test_ctl_u, base + pll->mode_reg + pll->test_ctl_u_offset);
+       writel(pll->user_ctl, base + pll->mode_reg + pll->user_ctl_offset);
+       writel(pll->l_val, base + pll->mode_reg + pll->l_val_offset);
+       writel(pll->alpha_val, base + pll->mode_reg + pll->alpha_val_offset);
+       writel(pll->alpha_val_u, base + pll->mode_reg + 
pll->alpha_val_u_offset);
+
+       mode &= ~(PLL_MODE_BIAS_COUNT | PLL_MODE_LOCK_COUNT);
+       mode |= PLL_MODE_BIAS_COUNT_VAL | PLL_MODE_LOCK_COUNT_VAL |
+               PLL_MODE_VOTE_FSM_ENA;
+       writel(mode, base + pll->mode_reg);
+
+       setbits_le32(base + pll->ena_vote, pll->vote_bit);
+
+       for (count = 0; count < PLL_LOCK_TIMEOUT_US; count++) {
+               if (readl(base + pll->mode_reg) & PLL_MODE_ACTIVE_FLAG)
+                       return;
+               udelay(1);
+       }
+
+       WARN(count == PLL_LOCK_TIMEOUT_US,
+            "PLL @ %#llx [%#010x] never locked\n",
+            base + pll->mode_reg, readl(base + pll->mode_reg));
+}
+
 #define BRANCH_ON_VAL (0)
 #define BRANCH_NOC_FSM_ON_VAL BIT(29)
 #define BRANCH_CHECK_MASK GENMASK(31, 28)
diff --git a/drivers/clk/qcom/clock-qcom.h b/drivers/clk/qcom/clock-qcom.h
index 9899cd28aad..47930ae9d5e 100644
--- a/drivers/clk/qcom/clock-qcom.h
+++ b/drivers/clk/qcom/clock-qcom.h
@@ -36,6 +36,29 @@ struct pll_vote_clk {
        int vote_bit;
 };
 
+/* Configuration for an FSM-voteable Alpha PLL. */
+struct pll_config {
+       uintptr_t mode_reg;
+       uintptr_t ena_vote;
+       u32 vote_bit;
+       u32 l_val;
+       u32 alpha_val;
+       u32 alpha_val_u;
+       u32 user_ctl;
+       u32 user_ctl_u;
+       u32 config_ctl;
+       u32 test_ctl;
+       u32 test_ctl_u;
+       u32 l_val_offset;
+       u32 alpha_val_offset;
+       u32 alpha_val_u_offset;
+       u32 test_ctl_offset;
+       u32 test_ctl_u_offset;
+       u32 user_ctl_offset;
+       u32 user_ctl_u_offset;
+       u32 config_ctl_offset;
+};
+
 struct vote_clk {
        uintptr_t cbcr_reg;
        uintptr_t ena_vote;
@@ -107,6 +130,7 @@ struct msm_clk_priv {
 
 int qcom_cc_bind(struct udevice *parent);
 void clk_enable_gpll0(phys_addr_t base, const struct pll_vote_clk *gpll0);
+void clk_configure_enable_pll(phys_addr_t base, const struct pll_config *pll);
 void clk_bcr_update(phys_addr_t apps_cmd_rgcr);
 void clk_enable_cbc(phys_addr_t cbcr);
 void clk_enable_vote_clk(phys_addr_t base, const struct vote_clk *vclk);
-- 
2.34.1

Reply via email to