diff options
Diffstat (limited to 'drivers/clk/qcom/clk-alpha-pll.c')
-rw-r--r-- | drivers/clk/qcom/clk-alpha-pll.c | 455 |
1 files changed, 422 insertions, 33 deletions
diff --git a/drivers/clk/qcom/clk-alpha-pll.c b/drivers/clk/qcom/clk-alpha-pll.c index 05898d2a8b22..cec0afea8e44 100644 --- a/drivers/clk/qcom/clk-alpha-pll.c +++ b/drivers/clk/qcom/clk-alpha-pll.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2015, 2018, The Linux Foundation. All rights reserved. - * Copyright (c) 2021, 2023, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2021, 2023-2024, Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/kernel.h> @@ -40,7 +40,8 @@ #define PLL_USER_CTL(p) ((p)->offset + (p)->regs[PLL_OFF_USER_CTL]) # define PLL_POST_DIV_SHIFT 8 -# define PLL_POST_DIV_MASK(p) GENMASK((p)->width, 0) +# define PLL_POST_DIV_MASK(p) GENMASK((p)->width ? (p)->width - 1 : 3, 0) +# define PLL_ALPHA_MSB BIT(15) # define PLL_ALPHA_EN BIT(24) # define PLL_ALPHA_MODE BIT(25) # define PLL_VCO_SHIFT 20 @@ -52,10 +53,12 @@ #define PLL_CONFIG_CTL(p) ((p)->offset + (p)->regs[PLL_OFF_CONFIG_CTL]) #define PLL_CONFIG_CTL_U(p) ((p)->offset + (p)->regs[PLL_OFF_CONFIG_CTL_U]) #define PLL_CONFIG_CTL_U1(p) ((p)->offset + (p)->regs[PLL_OFF_CONFIG_CTL_U1]) +#define PLL_CONFIG_CTL_U2(p) ((p)->offset + (p)->regs[PLL_OFF_CONFIG_CTL_U2]) #define PLL_TEST_CTL(p) ((p)->offset + (p)->regs[PLL_OFF_TEST_CTL]) #define PLL_TEST_CTL_U(p) ((p)->offset + (p)->regs[PLL_OFF_TEST_CTL_U]) #define PLL_TEST_CTL_U1(p) ((p)->offset + (p)->regs[PLL_OFF_TEST_CTL_U1]) #define PLL_TEST_CTL_U2(p) ((p)->offset + (p)->regs[PLL_OFF_TEST_CTL_U2]) +#define PLL_TEST_CTL_U3(p) ((p)->offset + (p)->regs[PLL_OFF_TEST_CTL_U3]) #define PLL_STATUS(p) ((p)->offset + (p)->regs[PLL_OFF_STATUS]) #define PLL_OPMODE(p) ((p)->offset + (p)->regs[PLL_OFF_OPMODE]) #define PLL_FRAC(p) ((p)->offset + (p)->regs[PLL_OFF_FRAC]) @@ -82,6 +85,29 @@ const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = { [PLL_OFF_TEST_CTL_U] = 0x20, [PLL_OFF_STATUS] = 0x24, }, + [CLK_ALPHA_PLL_TYPE_HUAYRA_APSS] = { + [PLL_OFF_L_VAL] = 0x08, + [PLL_OFF_ALPHA_VAL] = 0x10, + [PLL_OFF_USER_CTL] = 0x18, + [PLL_OFF_CONFIG_CTL] = 0x20, + [PLL_OFF_CONFIG_CTL_U] = 0x24, + [PLL_OFF_STATUS] = 0x28, + [PLL_OFF_TEST_CTL] = 0x30, + [PLL_OFF_TEST_CTL_U] = 0x34, + }, + [CLK_ALPHA_PLL_TYPE_HUAYRA_2290] = { + [PLL_OFF_L_VAL] = 0x04, + [PLL_OFF_ALPHA_VAL] = 0x08, + [PLL_OFF_USER_CTL] = 0x0c, + [PLL_OFF_CONFIG_CTL] = 0x10, + [PLL_OFF_CONFIG_CTL_U] = 0x14, + [PLL_OFF_CONFIG_CTL_U1] = 0x18, + [PLL_OFF_TEST_CTL] = 0x1c, + [PLL_OFF_TEST_CTL_U] = 0x20, + [PLL_OFF_TEST_CTL_U1] = 0x24, + [PLL_OFF_OPMODE] = 0x28, + [PLL_OFF_STATUS] = 0x38, + }, [CLK_ALPHA_PLL_TYPE_BRAMMO] = { [PLL_OFF_L_VAL] = 0x04, [PLL_OFF_ALPHA_VAL] = 0x08, @@ -172,6 +198,37 @@ const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = { [PLL_OFF_TEST_CTL_U1] = 0x34, [PLL_OFF_TEST_CTL_U2] = 0x38, }, + [CLK_ALPHA_PLL_TYPE_PONGO_ELU] = { + [PLL_OFF_OPMODE] = 0x04, + [PLL_OFF_STATE] = 0x08, + [PLL_OFF_STATUS] = 0x0c, + [PLL_OFF_L_VAL] = 0x10, + [PLL_OFF_USER_CTL] = 0x14, + [PLL_OFF_USER_CTL_U] = 0x18, + [PLL_OFF_CONFIG_CTL] = 0x1c, + [PLL_OFF_CONFIG_CTL_U] = 0x20, + [PLL_OFF_CONFIG_CTL_U1] = 0x24, + [PLL_OFF_CONFIG_CTL_U2] = 0x28, + [PLL_OFF_TEST_CTL] = 0x2c, + [PLL_OFF_TEST_CTL_U] = 0x30, + [PLL_OFF_TEST_CTL_U1] = 0x34, + [PLL_OFF_TEST_CTL_U2] = 0x38, + [PLL_OFF_TEST_CTL_U3] = 0x3c, + }, + [CLK_ALPHA_PLL_TYPE_TAYCAN_ELU] = { + [PLL_OFF_OPMODE] = 0x04, + [PLL_OFF_STATE] = 0x08, + [PLL_OFF_STATUS] = 0x0c, + [PLL_OFF_L_VAL] = 0x10, + [PLL_OFF_ALPHA_VAL] = 0x14, + [PLL_OFF_USER_CTL] = 0x18, + [PLL_OFF_USER_CTL_U] = 0x1c, + [PLL_OFF_CONFIG_CTL] = 0x20, + [PLL_OFF_CONFIG_CTL_U] = 0x24, + [PLL_OFF_CONFIG_CTL_U1] = 0x28, + [PLL_OFF_TEST_CTL] = 0x2c, + [PLL_OFF_TEST_CTL_U] = 0x30, + }, [CLK_ALPHA_PLL_TYPE_RIVIAN_EVO] = { [PLL_OFF_OPMODE] = 0x04, [PLL_OFF_STATUS] = 0x0c, @@ -212,10 +269,9 @@ const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = { [PLL_OFF_USER_CTL] = 0x18, [PLL_OFF_USER_CTL_U] = 0x1c, [PLL_OFF_CONFIG_CTL] = 0x20, - [PLL_OFF_CONFIG_CTL_U] = 0xff, + [PLL_OFF_STATUS] = 0x28, [PLL_OFF_TEST_CTL] = 0x30, [PLL_OFF_TEST_CTL_U] = 0x34, - [PLL_OFF_STATUS] = 0x28, }, [CLK_ALPHA_PLL_TYPE_STROMER_PLUS] = { [PLL_OFF_L_VAL] = 0x04, @@ -228,6 +284,32 @@ const u8 clk_alpha_pll_regs[][PLL_OFF_MAX_REGS] = { [PLL_OFF_ALPHA_VAL] = 0x24, [PLL_OFF_ALPHA_VAL_U] = 0x28, }, + [CLK_ALPHA_PLL_TYPE_ZONDA_OLE] = { + [PLL_OFF_L_VAL] = 0x04, + [PLL_OFF_ALPHA_VAL] = 0x08, + [PLL_OFF_USER_CTL] = 0x0c, + [PLL_OFF_USER_CTL_U] = 0x10, + [PLL_OFF_CONFIG_CTL] = 0x14, + [PLL_OFF_CONFIG_CTL_U] = 0x18, + [PLL_OFF_CONFIG_CTL_U1] = 0x1c, + [PLL_OFF_CONFIG_CTL_U2] = 0x20, + [PLL_OFF_TEST_CTL] = 0x24, + [PLL_OFF_TEST_CTL_U] = 0x28, + [PLL_OFF_TEST_CTL_U1] = 0x2c, + [PLL_OFF_OPMODE] = 0x30, + [PLL_OFF_STATUS] = 0x3c, + }, + [CLK_ALPHA_PLL_TYPE_NSS_HUAYRA] = { + [PLL_OFF_L_VAL] = 0x04, + [PLL_OFF_ALPHA_VAL] = 0x08, + [PLL_OFF_TEST_CTL] = 0x0c, + [PLL_OFF_TEST_CTL_U] = 0x10, + [PLL_OFF_USER_CTL] = 0x14, + [PLL_OFF_CONFIG_CTL] = 0x18, + [PLL_OFF_CONFIG_CTL_U] = 0x1c, + [PLL_OFF_STATUS] = 0x20, + }, + }; EXPORT_SYMBOL_GPL(clk_alpha_pll_regs); @@ -273,6 +355,12 @@ EXPORT_SYMBOL_GPL(clk_alpha_pll_regs); #define LUCID_EVO_PLL_CAL_L_VAL_SHIFT 16 #define LUCID_OLE_PLL_RINGOSC_CAL_L_VAL_SHIFT 24 +/* PONGO ELU PLL specific setting and offsets */ +#define PONGO_PLL_OUT_MASK GENMASK(1, 0) +#define PONGO_PLL_L_VAL_MASK GENMASK(11, 0) +#define PONGO_XO_PRESENT BIT(10) +#define PONGO_CLOCK_SELECT BIT(12) + /* ZONDA PLL specific */ #define ZONDA_PLL_OUT_MASK 0xf #define ZONDA_STAY_IN_CFA BIT(16) @@ -302,7 +390,8 @@ static int wait_for_pll(struct clk_alpha_pll *pll, u32 mask, bool inverse, if (ret) return ret; - for (count = 200; count > 0; count--) { + /* Pongo PLLs using a 32KHz reference can take upwards of 1500us to lock. */ + for (count = 1500; count > 0; count--) { ret = regmap_read(pll->clkr.regmap, PLL_MODE(pll), &val); if (ret) return ret; @@ -382,6 +471,8 @@ void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, mask |= config->pre_div_mask; mask |= config->post_div_mask; mask |= config->vco_mask; + mask |= config->alpha_en_mask; + mask |= config->alpha_mode_mask; regmap_update_bits(regmap, PLL_USER_CTL(pll), mask, val); @@ -618,14 +709,19 @@ clk_alpha_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); u32 alpha_width = pll_alpha_width(pll); - regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l); + if (regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l)) + return 0; + + if (regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &ctl)) + return 0; - regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &ctl); if (ctl & PLL_ALPHA_EN) { - regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL(pll), &low); + if (regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL(pll), &low)) + return 0; if (alpha_width > 32) { - regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL_U(pll), - &high); + if (regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL_U(pll), + &high)) + return 0; a = (u64)high << 32 | low; } else { a = low & GENMASK(alpha_width - 1, 0); @@ -763,6 +859,40 @@ static long clk_alpha_pll_round_rate(struct clk_hw *hw, unsigned long rate, return clamp(rate, min_freq, max_freq); } +void clk_huayra_2290_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, + const struct alpha_pll_config *config) +{ + u32 val; + + clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL(pll), config->config_ctl_val); + clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL_U(pll), config->config_ctl_hi_val); + clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL_U1(pll), config->config_ctl_hi1_val); + clk_alpha_pll_write_config(regmap, PLL_TEST_CTL(pll), config->test_ctl_val); + clk_alpha_pll_write_config(regmap, PLL_TEST_CTL_U(pll), config->test_ctl_hi_val); + clk_alpha_pll_write_config(regmap, PLL_TEST_CTL_U1(pll), config->test_ctl_hi1_val); + clk_alpha_pll_write_config(regmap, PLL_L_VAL(pll), config->l); + clk_alpha_pll_write_config(regmap, PLL_ALPHA_VAL(pll), config->alpha); + clk_alpha_pll_write_config(regmap, PLL_USER_CTL(pll), config->user_ctl_val); + + /* Set PLL_BYPASSNL */ + regmap_update_bits(regmap, PLL_MODE(pll), PLL_BYPASSNL, PLL_BYPASSNL); + regmap_read(regmap, PLL_MODE(pll), &val); + + /* Wait 5 us between setting BYPASS and deasserting reset */ + udelay(5); + + /* Take PLL out from reset state */ + regmap_update_bits(regmap, PLL_MODE(pll), PLL_RESET_N, PLL_RESET_N); + regmap_read(regmap, PLL_MODE(pll), &val); + + /* Wait 50us for PLL_LOCK_DET bit to go high */ + usleep_range(50, 55); + + /* Enable PLL output */ + regmap_update_bits(regmap, PLL_MODE(pll), PLL_OUTCTRL, PLL_OUTCTRL); +} +EXPORT_SYMBOL_GPL(clk_huayra_2290_pll_configure); + static unsigned long alpha_huayra_pll_calc_rate(u64 prate, u32 l, u32 a) { @@ -817,8 +947,11 @@ alpha_pll_huayra_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); u32 l, alpha = 0, ctl, alpha_m, alpha_n; - regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l); - regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &ctl); + if (regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l)) + return 0; + + if (regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &ctl)) + return 0; if (ctl & PLL_ALPHA_EN) { regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL(pll), &alpha); @@ -1012,8 +1145,11 @@ clk_trion_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); u32 l, frac, alpha_width = pll_alpha_width(pll); - regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l); - regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL(pll), &frac); + if (regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l)) + return 0; + + if (regmap_read(pll->clkr.regmap, PLL_ALPHA_VAL(pll), &frac)) + return 0; return alpha_pll_calc_rate(parent_rate, l, frac, alpha_width); } @@ -1071,7 +1207,8 @@ clk_alpha_pll_postdiv_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) struct clk_alpha_pll_postdiv *pll = to_clk_alpha_pll_postdiv(hw); u32 ctl; - regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &ctl); + if (regmap_read(pll->clkr.regmap, PLL_USER_CTL(pll), &ctl)) + return 0; ctl >>= PLL_POST_DIV_SHIFT; ctl &= PLL_POST_DIV_MASK(pll); @@ -1287,8 +1424,11 @@ static unsigned long alpha_pll_fabia_recalc_rate(struct clk_hw *hw, struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); u32 l, frac, alpha_width = pll_alpha_width(pll); - regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l); - regmap_read(pll->clkr.regmap, PLL_FRAC(pll), &frac); + if (regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l)) + return 0; + + if (regmap_read(pll->clkr.regmap, PLL_FRAC(pll), &frac)) + return 0; return alpha_pll_calc_rate(parent_rate, l, frac, alpha_width); } @@ -1438,7 +1578,8 @@ clk_trion_pll_postdiv_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) struct regmap *regmap = pll->clkr.regmap; u32 i, div = 1, val; - regmap_read(regmap, PLL_USER_CTL(pll), &val); + if (regmap_read(regmap, PLL_USER_CTL(pll), &val)) + return 0; val >>= pll->post_div_shift; val &= PLL_POST_DIV_MASK(pll); @@ -1480,8 +1621,8 @@ clk_trion_pll_postdiv_set_rate(struct clk_hw *hw, unsigned long rate, } return regmap_update_bits(regmap, PLL_USER_CTL(pll), - PLL_POST_DIV_MASK(pll) << PLL_POST_DIV_SHIFT, - val << PLL_POST_DIV_SHIFT); + PLL_POST_DIV_MASK(pll) << pll->post_div_shift, + val << pll->post_div_shift); } const struct clk_ops clk_alpha_pll_postdiv_trion_ops = { @@ -1640,7 +1781,7 @@ static int __alpha_pll_trion_set_rate(struct clk_hw *hw, unsigned long rate, if (ret < 0) return ret; - regmap_write(pll->clkr.regmap, PLL_L_VAL(pll), l); + regmap_update_bits(pll->clkr.regmap, PLL_L_VAL(pll), LUCID_EVO_PLL_L_VAL_MASK, l); regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL(pll), a); /* Latch the PLL input */ @@ -1759,6 +1900,58 @@ const struct clk_ops clk_alpha_pll_agera_ops = { }; EXPORT_SYMBOL_GPL(clk_alpha_pll_agera_ops); +/** + * clk_lucid_5lpe_pll_configure - configure the lucid 5lpe pll + * + * @pll: clk alpha pll + * @regmap: register map + * @config: configuration to apply for pll + */ +void clk_lucid_5lpe_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, + const struct alpha_pll_config *config) +{ + /* + * If the bootloader left the PLL enabled it's likely that there are + * RCGs that will lock up if we disable the PLL below. + */ + if (trion_pll_is_enabled(pll, regmap)) { + pr_debug("Lucid 5LPE PLL is already enabled, skipping configuration\n"); + return; + } + + clk_alpha_pll_write_config(regmap, PLL_L_VAL(pll), config->l); + regmap_write(regmap, PLL_CAL_L_VAL(pll), TRION_PLL_CAL_VAL); + clk_alpha_pll_write_config(regmap, PLL_ALPHA_VAL(pll), config->alpha); + clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL(pll), + config->config_ctl_val); + clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL_U(pll), + config->config_ctl_hi_val); + clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL_U1(pll), + config->config_ctl_hi1_val); + clk_alpha_pll_write_config(regmap, PLL_USER_CTL(pll), + config->user_ctl_val); + clk_alpha_pll_write_config(regmap, PLL_USER_CTL_U(pll), + config->user_ctl_hi_val); + clk_alpha_pll_write_config(regmap, PLL_USER_CTL_U1(pll), + config->user_ctl_hi1_val); + clk_alpha_pll_write_config(regmap, PLL_TEST_CTL(pll), + config->test_ctl_val); + clk_alpha_pll_write_config(regmap, PLL_TEST_CTL_U(pll), + config->test_ctl_hi_val); + clk_alpha_pll_write_config(regmap, PLL_TEST_CTL_U1(pll), + config->test_ctl_hi1_val); + + /* Disable PLL output */ + regmap_update_bits(regmap, PLL_MODE(pll), PLL_OUTCTRL, 0); + + /* Set operation mode to OFF */ + regmap_write(regmap, PLL_OPMODE(pll), PLL_STANDBY); + + /* Place the PLL in STANDBY mode */ + regmap_update_bits(regmap, PLL_MODE(pll), PLL_RESET_N, PLL_RESET_N); +} +EXPORT_SYMBOL_GPL(clk_lucid_5lpe_pll_configure); + static int alpha_pll_lucid_5lpe_enable(struct clk_hw *hw) { struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); @@ -1778,9 +1971,8 @@ static int alpha_pll_lucid_5lpe_enable(struct clk_hw *hw) } /* Check if PLL is already enabled, return if enabled */ - ret = trion_pll_is_enabled(pll, pll->clkr.regmap); - if (ret < 0) - return ret; + if (trion_pll_is_enabled(pll, pll->clkr.regmap)) + return 0; ret = regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), PLL_RESET_N, PLL_RESET_N); if (ret) @@ -2045,6 +2237,16 @@ static void clk_zonda_pll_disable(struct clk_hw *hw) regmap_write(regmap, PLL_OPMODE(pll), 0x0); } +static void zonda_pll_adjust_l_val(unsigned long rate, unsigned long prate, u32 *l) +{ + u64 remainder, quotient; + + quotient = rate; + remainder = do_div(quotient, prate); + + *l = rate + (u32)(remainder * 2 >= prate); +} + static int clk_zonda_pll_set_rate(struct clk_hw *hw, unsigned long rate, unsigned long prate) { @@ -2061,9 +2263,15 @@ static int clk_zonda_pll_set_rate(struct clk_hw *hw, unsigned long rate, if (ret < 0) return ret; + if (a & PLL_ALPHA_MSB) + zonda_pll_adjust_l_val(rate, prate, &l); + regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL(pll), a); regmap_write(pll->clkr.regmap, PLL_L_VAL(pll), l); + if (!clk_hw_is_enabled(hw)) + return 0; + /* Wait before polling for the frequency latch */ udelay(5); @@ -2098,6 +2306,15 @@ void clk_lucid_evo_pll_configure(struct clk_alpha_pll *pll, struct regmap *regma { u32 lval = config->l; + /* + * If the bootloader left the PLL enabled it's likely that there are + * RCGs that will lock up if we disable the PLL below. + */ + if (trion_pll_is_enabled(pll, regmap)) { + pr_debug("Lucid Evo PLL is already enabled, skipping configuration\n"); + return; + } + lval |= TRION_PLL_CAL_VAL << LUCID_EVO_PLL_CAL_L_VAL_SHIFT; clk_alpha_pll_write_config(regmap, PLL_L_VAL(pll), lval); clk_alpha_pll_write_config(regmap, PLL_ALPHA_VAL(pll), config->alpha); @@ -2168,13 +2385,8 @@ static int alpha_pll_lucid_evo_enable(struct clk_hw *hw) } /* Check if PLL is already enabled */ - ret = trion_pll_is_enabled(pll, regmap); - if (ret < 0) { - return ret; - } else if (ret) { - pr_warn("%s PLL is already enabled\n", clk_hw_get_name(&pll->clkr.hw)); + if (trion_pll_is_enabled(pll, regmap)) return 0; - } ret = regmap_update_bits(regmap, PLL_MODE(pll), PLL_RESET_N, PLL_RESET_N); if (ret) @@ -2288,9 +2500,12 @@ static unsigned long alpha_pll_lucid_evo_recalc_rate(struct clk_hw *hw, struct regmap *regmap = pll->clkr.regmap; u32 l, frac; - regmap_read(regmap, PLL_L_VAL(pll), &l); + if (regmap_read(regmap, PLL_L_VAL(pll), &l)) + return 0; l &= LUCID_EVO_PLL_L_VAL_MASK; - regmap_read(regmap, PLL_ALPHA_VAL(pll), &frac); + + if (regmap_read(regmap, PLL_ALPHA_VAL(pll), &frac)) + return 0; return alpha_pll_calc_rate(parent_rate, l, frac, pll_alpha_width(pll)); } @@ -2339,6 +2554,144 @@ const struct clk_ops clk_alpha_pll_reset_lucid_evo_ops = { }; EXPORT_SYMBOL_GPL(clk_alpha_pll_reset_lucid_evo_ops); +static int alpha_pll_pongo_elu_prepare(struct clk_hw *hw) +{ + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + struct regmap *regmap = pll->clkr.regmap; + int ret; + + /* Enable PLL intially to one-time calibrate against XO. */ + regmap_write(regmap, PLL_OPMODE(pll), PLL_RUN); + regmap_update_bits(regmap, PLL_MODE(pll), PLL_RESET_N, PLL_RESET_N); + regmap_update_bits(regmap, PLL_MODE(pll), PONGO_XO_PRESENT, PONGO_XO_PRESENT); + + /* Set regmap for wait_for_pll() */ + pll->clkr.regmap = regmap; + ret = wait_for_pll_enable_lock(pll); + if (ret) { + /* Reverse calibration - disable PLL output */ + regmap_update_bits(regmap, PLL_MODE(pll), PLL_OUTCTRL, 0); + return ret; + } + + /* Disable PLL after one-time calibration. */ + regmap_write(regmap, PLL_OPMODE(pll), PLL_STANDBY); + + /* Select internally generated clock. */ + regmap_update_bits(regmap, PLL_MODE(pll), PONGO_CLOCK_SELECT, + PONGO_CLOCK_SELECT); + + return 0; +} + +static int alpha_pll_pongo_elu_enable(struct clk_hw *hw) +{ + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + struct regmap *regmap = pll->clkr.regmap; + int ret; + + /* Check if PLL is already enabled */ + if (trion_pll_is_enabled(pll, regmap)) + return 0; + + ret = regmap_update_bits(regmap, PLL_MODE(pll), PLL_RESET_N, PLL_RESET_N); + if (ret) + return ret; + + /* Set operation mode to RUN */ + regmap_write(regmap, PLL_OPMODE(pll), PLL_RUN); + + ret = wait_for_pll_enable_lock(pll); + if (ret) + return ret; + + /* Enable the global PLL outputs */ + ret = regmap_update_bits(regmap, PLL_MODE(pll), PLL_OUTCTRL, PLL_OUTCTRL); + if (ret) + return ret; + + /* Ensure that the write above goes through before returning. */ + mb(); + + return ret; +} + +static void alpha_pll_pongo_elu_disable(struct clk_hw *hw) +{ + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + struct regmap *regmap = pll->clkr.regmap; + int ret; + + /* Disable the global PLL output */ + ret = regmap_update_bits(regmap, PLL_MODE(pll), PLL_OUTCTRL, 0); + if (ret) + return; + + /* Place the PLL mode in STANDBY */ + regmap_write(regmap, PLL_OPMODE(pll), PLL_STANDBY); +} + +static unsigned long alpha_pll_pongo_elu_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); + struct regmap *regmap = pll->clkr.regmap; + u32 l; + + if (regmap_read(regmap, PLL_L_VAL(pll), &l)) + return 0; + + l &= PONGO_PLL_L_VAL_MASK; + + return alpha_pll_calc_rate(parent_rate, l, 0, pll_alpha_width(pll)); +} + +const struct clk_ops clk_alpha_pll_pongo_elu_ops = { + .prepare = alpha_pll_pongo_elu_prepare, + .enable = alpha_pll_pongo_elu_enable, + .disable = alpha_pll_pongo_elu_disable, + .recalc_rate = alpha_pll_pongo_elu_recalc_rate, +}; +EXPORT_SYMBOL_GPL(clk_alpha_pll_pongo_elu_ops); + +void clk_pongo_elu_pll_configure(struct clk_alpha_pll *pll, + struct regmap *regmap, + const struct alpha_pll_config *config) +{ + u32 val; + + regmap_update_bits(regmap, PLL_USER_CTL(pll), PONGO_PLL_OUT_MASK, + PONGO_PLL_OUT_MASK); + + if (trion_pll_is_enabled(pll, regmap)) + return; + + if (regmap_read(regmap, PLL_L_VAL(pll), &val)) + return; + val &= PONGO_PLL_L_VAL_MASK; + if (val) + return; + + clk_alpha_pll_write_config(regmap, PLL_L_VAL(pll), config->l); + clk_alpha_pll_write_config(regmap, PLL_ALPHA_VAL(pll), config->alpha); + clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL(pll), config->config_ctl_val); + clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL_U(pll), config->config_ctl_hi_val); + clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL_U1(pll), config->config_ctl_hi1_val); + clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL_U2(pll), config->config_ctl_hi2_val); + clk_alpha_pll_write_config(regmap, PLL_USER_CTL(pll), + config->user_ctl_val | PONGO_PLL_OUT_MASK); + clk_alpha_pll_write_config(regmap, PLL_USER_CTL_U(pll), config->user_ctl_hi_val); + clk_alpha_pll_write_config(regmap, PLL_TEST_CTL(pll), config->test_ctl_val); + clk_alpha_pll_write_config(regmap, PLL_TEST_CTL_U(pll), config->test_ctl_hi_val); + clk_alpha_pll_write_config(regmap, PLL_TEST_CTL_U1(pll), config->test_ctl_hi1_val); + clk_alpha_pll_write_config(regmap, PLL_TEST_CTL_U2(pll), config->test_ctl_hi2_val); + clk_alpha_pll_write_config(regmap, PLL_TEST_CTL_U3(pll), config->test_ctl_hi3_val); + + /* Disable PLL output */ + regmap_update_bits(regmap, PLL_MODE(pll), PLL_OUTCTRL, 0); +} +EXPORT_SYMBOL_GPL(clk_pongo_elu_pll_configure); + void clk_rivian_evo_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, const struct alpha_pll_config *config) { @@ -2365,7 +2718,8 @@ static unsigned long clk_rivian_evo_pll_recalc_rate(struct clk_hw *hw, struct clk_alpha_pll *pll = to_clk_alpha_pll(hw); u32 l; - regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l); + if (regmap_read(pll->clkr.regmap, PLL_L_VAL(pll), &l)) + return 0; return parent_rate * l; } @@ -2474,6 +2828,8 @@ static int clk_alpha_pll_stromer_set_rate(struct clk_hw *hw, unsigned long rate, rate = alpha_pll_round_rate(rate, prate, &l, &a, ALPHA_REG_BITWIDTH); regmap_write(pll->clkr.regmap, PLL_L_VAL(pll), l); + + a <<= ALPHA_REG_BITWIDTH - ALPHA_BITWIDTH; regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL(pll), a); regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL_U(pll), a >> ALPHA_BITWIDTH); @@ -2538,6 +2894,9 @@ static int clk_alpha_pll_stromer_plus_set_rate(struct clk_hw *hw, regmap_write(pll->clkr.regmap, PLL_ALPHA_VAL_U(pll), a >> ALPHA_BITWIDTH); + regmap_update_bits(pll->clkr.regmap, PLL_USER_CTL(pll), + PLL_ALPHA_EN, PLL_ALPHA_EN); + regmap_write(pll->clkr.regmap, PLL_MODE(pll), PLL_BYPASSNL); /* Wait five micro seconds or more */ @@ -2571,3 +2930,33 @@ const struct clk_ops clk_alpha_pll_stromer_plus_ops = { .set_rate = clk_alpha_pll_stromer_plus_set_rate, }; EXPORT_SYMBOL_GPL(clk_alpha_pll_stromer_plus_ops); + +void clk_regera_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap, + const struct alpha_pll_config *config) +{ + clk_alpha_pll_write_config(regmap, PLL_L_VAL(pll), config->l); + clk_alpha_pll_write_config(regmap, PLL_ALPHA_VAL(pll), config->alpha); + clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL(pll), config->config_ctl_val); + clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL_U(pll), config->config_ctl_hi_val); + clk_alpha_pll_write_config(regmap, PLL_CONFIG_CTL_U1(pll), config->config_ctl_hi1_val); + clk_alpha_pll_write_config(regmap, PLL_USER_CTL(pll), config->user_ctl_val); + clk_alpha_pll_write_config(regmap, PLL_USER_CTL_U(pll), config->user_ctl_hi_val); + clk_alpha_pll_write_config(regmap, PLL_USER_CTL_U1(pll), config->user_ctl_hi1_val); + clk_alpha_pll_write_config(regmap, PLL_TEST_CTL(pll), config->test_ctl_val); + clk_alpha_pll_write_config(regmap, PLL_TEST_CTL_U(pll), config->test_ctl_hi_val); + clk_alpha_pll_write_config(regmap, PLL_TEST_CTL_U1(pll), config->test_ctl_hi1_val); + + /* Set operation mode to STANDBY */ + regmap_write(regmap, PLL_OPMODE(pll), PLL_STANDBY); +} +EXPORT_SYMBOL_GPL(clk_regera_pll_configure); + +const struct clk_ops clk_alpha_pll_regera_ops = { + .enable = clk_zonda_pll_enable, + .disable = clk_zonda_pll_disable, + .is_enabled = clk_alpha_pll_is_enabled, + .recalc_rate = clk_trion_pll_recalc_rate, + .round_rate = clk_alpha_pll_round_rate, + .set_rate = clk_zonda_pll_set_rate, +}; +EXPORT_SYMBOL_GPL(clk_alpha_pll_regera_ops); |