1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // Copyright (c) 2018, The Linux Foundation. All rights reserved. |
3 | |
4 | #include <linux/kernel.h> |
5 | #include <linux/export.h> |
6 | #include <linux/regmap.h> |
7 | #include <linux/delay.h> |
8 | #include <linux/err.h> |
9 | #include <linux/clk-provider.h> |
10 | #include <linux/spinlock.h> |
11 | |
12 | #include "clk-regmap.h" |
13 | #include "clk-hfpll.h" |
14 | |
15 | #define PLL_OUTCTRL BIT(0) |
16 | #define PLL_BYPASSNL BIT(1) |
17 | #define PLL_RESET_N BIT(2) |
18 | |
19 | /* Initialize a HFPLL at a given rate and enable it. */ |
20 | static void __clk_hfpll_init_once(struct clk_hw *hw) |
21 | { |
22 | struct clk_hfpll *h = to_clk_hfpll(hw); |
23 | struct hfpll_data const *hd = h->d; |
24 | struct regmap *regmap = h->clkr.regmap; |
25 | |
26 | if (likely(h->init_done)) |
27 | return; |
28 | |
29 | /* Configure PLL parameters for integer mode. */ |
30 | if (hd->config_val) |
31 | regmap_write(map: regmap, reg: hd->config_reg, val: hd->config_val); |
32 | regmap_write(map: regmap, reg: hd->m_reg, val: 0); |
33 | regmap_write(map: regmap, reg: hd->n_reg, val: 1); |
34 | |
35 | if (hd->user_reg) { |
36 | u32 regval = hd->user_val; |
37 | unsigned long rate; |
38 | |
39 | rate = clk_hw_get_rate(hw); |
40 | |
41 | /* Pick the right VCO. */ |
42 | if (hd->user_vco_mask && rate > hd->low_vco_max_rate) |
43 | regval |= hd->user_vco_mask; |
44 | regmap_write(map: regmap, reg: hd->user_reg, val: regval); |
45 | } |
46 | |
47 | /* Write L_VAL from conf if it exist */ |
48 | if (hd->l_val) |
49 | regmap_write(map: regmap, reg: hd->l_reg, val: hd->l_val); |
50 | |
51 | if (hd->droop_reg) |
52 | regmap_write(map: regmap, reg: hd->droop_reg, val: hd->droop_val); |
53 | |
54 | h->init_done = true; |
55 | } |
56 | |
57 | static void __clk_hfpll_enable(struct clk_hw *hw) |
58 | { |
59 | struct clk_hfpll *h = to_clk_hfpll(hw); |
60 | struct hfpll_data const *hd = h->d; |
61 | struct regmap *regmap = h->clkr.regmap; |
62 | u32 val; |
63 | |
64 | __clk_hfpll_init_once(hw); |
65 | |
66 | /* Disable PLL bypass mode. */ |
67 | regmap_update_bits(map: regmap, reg: hd->mode_reg, PLL_BYPASSNL, PLL_BYPASSNL); |
68 | |
69 | /* |
70 | * H/W requires a 5us delay between disabling the bypass and |
71 | * de-asserting the reset. Delay 10us just to be safe. |
72 | */ |
73 | udelay(10); |
74 | |
75 | /* De-assert active-low PLL reset. */ |
76 | regmap_update_bits(map: regmap, reg: hd->mode_reg, PLL_RESET_N, PLL_RESET_N); |
77 | |
78 | /* Wait for PLL to lock. */ |
79 | if (hd->status_reg) |
80 | /* |
81 | * Busy wait. Should never timeout, we add a timeout to |
82 | * prevent any sort of stall. |
83 | */ |
84 | regmap_read_poll_timeout(regmap, hd->status_reg, val, |
85 | !(val & BIT(hd->lock_bit)), 0, |
86 | 100 * USEC_PER_MSEC); |
87 | else |
88 | udelay(60); |
89 | |
90 | /* Enable PLL output. */ |
91 | regmap_update_bits(map: regmap, reg: hd->mode_reg, PLL_OUTCTRL, PLL_OUTCTRL); |
92 | } |
93 | |
94 | /* Enable an already-configured HFPLL. */ |
95 | static int clk_hfpll_enable(struct clk_hw *hw) |
96 | { |
97 | unsigned long flags; |
98 | struct clk_hfpll *h = to_clk_hfpll(hw); |
99 | struct hfpll_data const *hd = h->d; |
100 | struct regmap *regmap = h->clkr.regmap; |
101 | u32 mode; |
102 | |
103 | spin_lock_irqsave(&h->lock, flags); |
104 | regmap_read(map: regmap, reg: hd->mode_reg, val: &mode); |
105 | if (!(mode & (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL))) |
106 | __clk_hfpll_enable(hw); |
107 | spin_unlock_irqrestore(lock: &h->lock, flags); |
108 | |
109 | return 0; |
110 | } |
111 | |
112 | static void __clk_hfpll_disable(struct clk_hfpll *h) |
113 | { |
114 | struct hfpll_data const *hd = h->d; |
115 | struct regmap *regmap = h->clkr.regmap; |
116 | |
117 | /* |
118 | * Disable the PLL output, disable test mode, enable the bypass mode, |
119 | * and assert the reset. |
120 | */ |
121 | regmap_update_bits(map: regmap, reg: hd->mode_reg, |
122 | PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL, val: 0); |
123 | } |
124 | |
125 | static void clk_hfpll_disable(struct clk_hw *hw) |
126 | { |
127 | struct clk_hfpll *h = to_clk_hfpll(hw); |
128 | unsigned long flags; |
129 | |
130 | spin_lock_irqsave(&h->lock, flags); |
131 | __clk_hfpll_disable(h); |
132 | spin_unlock_irqrestore(lock: &h->lock, flags); |
133 | } |
134 | |
135 | static int clk_hfpll_determine_rate(struct clk_hw *hw, struct clk_rate_request *req) |
136 | { |
137 | struct clk_hfpll *h = to_clk_hfpll(hw); |
138 | struct hfpll_data const *hd = h->d; |
139 | unsigned long rrate; |
140 | |
141 | req->rate = clamp(req->rate, hd->min_rate, hd->max_rate); |
142 | |
143 | rrate = DIV_ROUND_UP(req->rate, req->best_parent_rate) * req->best_parent_rate; |
144 | if (rrate > hd->max_rate) |
145 | rrate -= req->best_parent_rate; |
146 | |
147 | req->rate = rrate; |
148 | return 0; |
149 | } |
150 | |
151 | /* |
152 | * For optimization reasons, assumes no downstream clocks are actively using |
153 | * it. |
154 | */ |
155 | static int clk_hfpll_set_rate(struct clk_hw *hw, unsigned long rate, |
156 | unsigned long parent_rate) |
157 | { |
158 | struct clk_hfpll *h = to_clk_hfpll(hw); |
159 | struct hfpll_data const *hd = h->d; |
160 | struct regmap *regmap = h->clkr.regmap; |
161 | unsigned long flags; |
162 | u32 l_val, val; |
163 | bool enabled; |
164 | |
165 | l_val = rate / parent_rate; |
166 | |
167 | spin_lock_irqsave(&h->lock, flags); |
168 | |
169 | enabled = __clk_is_enabled(clk: hw->clk); |
170 | if (enabled) |
171 | __clk_hfpll_disable(h); |
172 | |
173 | /* Pick the right VCO. */ |
174 | if (hd->user_reg && hd->user_vco_mask) { |
175 | regmap_read(map: regmap, reg: hd->user_reg, val: &val); |
176 | if (rate <= hd->low_vco_max_rate) |
177 | val &= ~hd->user_vco_mask; |
178 | else |
179 | val |= hd->user_vco_mask; |
180 | regmap_write(map: regmap, reg: hd->user_reg, val); |
181 | } |
182 | |
183 | regmap_write(map: regmap, reg: hd->l_reg, val: l_val); |
184 | |
185 | if (enabled) |
186 | __clk_hfpll_enable(hw); |
187 | |
188 | spin_unlock_irqrestore(lock: &h->lock, flags); |
189 | |
190 | return 0; |
191 | } |
192 | |
193 | static unsigned long clk_hfpll_recalc_rate(struct clk_hw *hw, |
194 | unsigned long parent_rate) |
195 | { |
196 | struct clk_hfpll *h = to_clk_hfpll(hw); |
197 | struct hfpll_data const *hd = h->d; |
198 | struct regmap *regmap = h->clkr.regmap; |
199 | u32 l_val; |
200 | |
201 | regmap_read(map: regmap, reg: hd->l_reg, val: &l_val); |
202 | |
203 | return l_val * parent_rate; |
204 | } |
205 | |
206 | static int clk_hfpll_init(struct clk_hw *hw) |
207 | { |
208 | struct clk_hfpll *h = to_clk_hfpll(hw); |
209 | struct hfpll_data const *hd = h->d; |
210 | struct regmap *regmap = h->clkr.regmap; |
211 | u32 mode, status; |
212 | |
213 | regmap_read(map: regmap, reg: hd->mode_reg, val: &mode); |
214 | if (mode != (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL)) { |
215 | __clk_hfpll_init_once(hw); |
216 | return 0; |
217 | } |
218 | |
219 | if (hd->status_reg) { |
220 | regmap_read(map: regmap, reg: hd->status_reg, val: &status); |
221 | if (!(status & BIT(hd->lock_bit))) { |
222 | WARN(1, "HFPLL %s is ON, but not locked!\n" , |
223 | __clk_get_name(hw->clk)); |
224 | clk_hfpll_disable(hw); |
225 | __clk_hfpll_init_once(hw); |
226 | } |
227 | } |
228 | |
229 | return 0; |
230 | } |
231 | |
232 | static int hfpll_is_enabled(struct clk_hw *hw) |
233 | { |
234 | struct clk_hfpll *h = to_clk_hfpll(hw); |
235 | struct hfpll_data const *hd = h->d; |
236 | struct regmap *regmap = h->clkr.regmap; |
237 | u32 mode; |
238 | |
239 | regmap_read(map: regmap, reg: hd->mode_reg, val: &mode); |
240 | mode &= 0x7; |
241 | return mode == (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL); |
242 | } |
243 | |
244 | const struct clk_ops clk_ops_hfpll = { |
245 | .enable = clk_hfpll_enable, |
246 | .disable = clk_hfpll_disable, |
247 | .is_enabled = hfpll_is_enabled, |
248 | .determine_rate = clk_hfpll_determine_rate, |
249 | .set_rate = clk_hfpll_set_rate, |
250 | .recalc_rate = clk_hfpll_recalc_rate, |
251 | .init = clk_hfpll_init, |
252 | }; |
253 | EXPORT_SYMBOL_GPL(clk_ops_hfpll); |
254 | |