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
