|
@@ -32,7 +32,10 @@
|
|
|
# define PLL_VOTE_FSM_ENA BIT(20)
|
|
|
# define PLL_FSM_ENA BIT(20)
|
|
|
# define PLL_VOTE_FSM_RESET BIT(21)
|
|
|
+# define PLL_UPDATE BIT(22)
|
|
|
+# define PLL_UPDATE_BYPASS BIT(23)
|
|
|
# define PLL_OFFLINE_ACK BIT(28)
|
|
|
+# define ALPHA_PLL_ACK_LATCH BIT(29)
|
|
|
# define PLL_ACTIVE_FLAG BIT(30)
|
|
|
# define PLL_LOCK_DET BIT(31)
|
|
|
|
|
@@ -130,6 +133,15 @@ static int wait_for_pll(struct clk_alpha_pll *pll, u32 mask, bool inverse,
|
|
|
#define wait_for_pll_offline(pll) \
|
|
|
wait_for_pll(pll, PLL_OFFLINE_ACK, 0, "offline")
|
|
|
|
|
|
+#define wait_for_pll_update(pll) \
|
|
|
+ wait_for_pll(pll, PLL_UPDATE, 1, "update")
|
|
|
+
|
|
|
+#define wait_for_pll_update_ack_set(pll) \
|
|
|
+ wait_for_pll(pll, ALPHA_PLL_ACK_LATCH, 0, "update_ack_set")
|
|
|
+
|
|
|
+#define wait_for_pll_update_ack_clear(pll) \
|
|
|
+ wait_for_pll(pll, ALPHA_PLL_ACK_LATCH, 1, "update_ack_clear")
|
|
|
+
|
|
|
void clk_alpha_pll_configure(struct clk_alpha_pll *pll, struct regmap *regmap,
|
|
|
const struct alpha_pll_config *config)
|
|
|
{
|
|
@@ -402,8 +414,57 @@ clk_alpha_pll_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
|
|
|
return alpha_pll_calc_rate(prate, l, a, alpha_width);
|
|
|
}
|
|
|
|
|
|
-static int clk_alpha_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
|
|
- unsigned long prate)
|
|
|
+static int clk_alpha_pll_update_latch(struct clk_alpha_pll *pll,
|
|
|
+ int (*is_enabled)(struct clk_hw *))
|
|
|
+{
|
|
|
+ int ret;
|
|
|
+ u32 mode;
|
|
|
+
|
|
|
+ if (!is_enabled(&pll->clkr.hw) ||
|
|
|
+ !(pll->flags & SUPPORTS_DYNAMIC_UPDATE))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ regmap_read(pll->clkr.regmap, PLL_MODE(pll), &mode);
|
|
|
+
|
|
|
+ /* Latch the input to the PLL */
|
|
|
+ regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), PLL_UPDATE,
|
|
|
+ PLL_UPDATE);
|
|
|
+
|
|
|
+ /* Wait for 2 reference cycle before checking ACK bit */
|
|
|
+ udelay(1);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * PLL will latch the new L, Alpha and freq control word.
|
|
|
+ * PLL will respond by raising PLL_ACK_LATCH output when new programming
|
|
|
+ * has been latched in and PLL is being updated. When
|
|
|
+ * UPDATE_LOGIC_BYPASS bit is not set, PLL_UPDATE will be cleared
|
|
|
+ * automatically by hardware when PLL_ACK_LATCH is asserted by PLL.
|
|
|
+ */
|
|
|
+ if (mode & PLL_UPDATE_BYPASS) {
|
|
|
+ ret = wait_for_pll_update_ack_set(pll);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ regmap_update_bits(pll->clkr.regmap, PLL_MODE(pll), PLL_UPDATE, 0);
|
|
|
+ } else {
|
|
|
+ ret = wait_for_pll_update(pll);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ ret = wait_for_pll_update_ack_clear(pll);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ /* Wait for PLL output to stabilize */
|
|
|
+ udelay(10);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int __clk_alpha_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
|
|
+ unsigned long prate,
|
|
|
+ int (*is_enabled)(struct clk_hw *))
|
|
|
{
|
|
|
struct clk_alpha_pll *pll = to_clk_alpha_pll(hw);
|
|
|
const struct pll_vco *vco;
|
|
@@ -434,7 +495,21 @@ static int clk_alpha_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
|
|
regmap_update_bits(pll->clkr.regmap, PLL_USER_CTL(pll),
|
|
|
PLL_ALPHA_EN, PLL_ALPHA_EN);
|
|
|
|
|
|
- return 0;
|
|
|
+ return clk_alpha_pll_update_latch(pll, is_enabled);
|
|
|
+}
|
|
|
+
|
|
|
+static int clk_alpha_pll_set_rate(struct clk_hw *hw, unsigned long rate,
|
|
|
+ unsigned long prate)
|
|
|
+{
|
|
|
+ return __clk_alpha_pll_set_rate(hw, rate, prate,
|
|
|
+ clk_alpha_pll_is_enabled);
|
|
|
+}
|
|
|
+
|
|
|
+static int clk_alpha_pll_hwfsm_set_rate(struct clk_hw *hw, unsigned long rate,
|
|
|
+ unsigned long prate)
|
|
|
+{
|
|
|
+ return __clk_alpha_pll_set_rate(hw, rate, prate,
|
|
|
+ clk_alpha_pll_hwfsm_is_enabled);
|
|
|
}
|
|
|
|
|
|
static long clk_alpha_pll_round_rate(struct clk_hw *hw, unsigned long rate,
|
|
@@ -471,7 +546,7 @@ const struct clk_ops clk_alpha_pll_hwfsm_ops = {
|
|
|
.is_enabled = clk_alpha_pll_hwfsm_is_enabled,
|
|
|
.recalc_rate = clk_alpha_pll_recalc_rate,
|
|
|
.round_rate = clk_alpha_pll_round_rate,
|
|
|
- .set_rate = clk_alpha_pll_set_rate,
|
|
|
+ .set_rate = clk_alpha_pll_hwfsm_set_rate,
|
|
|
};
|
|
|
EXPORT_SYMBOL_GPL(clk_alpha_pll_hwfsm_ops);
|
|
|
|