]>
Commit | Line | Data |
---|---|---|
912af842 JB |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * (C) Copyright 2018 - Beniamino Galvani <[email protected]> | |
4 | * (C) Copyright 2018 - BayLibre, SAS | |
5 | * Author: Neil Armstrong <[email protected]> | |
6 | */ | |
7 | ||
8 | #include <common.h> | |
f7ae49fc | 9 | #include <log.h> |
912af842 JB |
10 | #include <asm/arch/clock-g12a.h> |
11 | #include <asm/io.h> | |
12 | #include <clk-uclass.h> | |
13 | #include <dm.h> | |
14 | #include <regmap.h> | |
15 | #include <syscon.h> | |
16 | #include <div64.h> | |
17 | #include <dt-bindings/clock/g12a-clkc.h> | |
c05ed00a | 18 | #include <linux/delay.h> |
61b29b82 | 19 | #include <linux/err.h> |
a0513b40 | 20 | #include <linux/kernel.h> |
912af842 JB |
21 | #include "clk_meson.h" |
22 | ||
a0513b40 NA |
23 | /* This driver support only basic clock tree operations : |
24 | * - Can calculate clock frequency on a limited tree | |
25 | * - Can Read muxes and basic dividers (0-based only) | |
26 | * - Can enable/disable gates with limited propagation | |
27 | * - Can reparent without propagation, only on muxes | |
28 | * - Can set rates without reparenting | |
29 | * This driver is adapted to what is actually supported by U-Boot | |
30 | */ | |
31 | ||
32 | /* Only the clocks ids we don't want to expose, such as the internal muxes | |
33 | * and dividers of composite clocks, will remain defined here. | |
34 | */ | |
35 | #define CLKID_MPEG_SEL 8 | |
36 | #define CLKID_MPEG_DIV 9 | |
37 | #define CLKID_SD_EMMC_A_CLK0_SEL 63 | |
38 | #define CLKID_SD_EMMC_A_CLK0_DIV 64 | |
39 | #define CLKID_SD_EMMC_B_CLK0_SEL 65 | |
40 | #define CLKID_SD_EMMC_B_CLK0_DIV 66 | |
41 | #define CLKID_SD_EMMC_C_CLK0_SEL 67 | |
42 | #define CLKID_SD_EMMC_C_CLK0_DIV 68 | |
43 | #define CLKID_MPLL0_DIV 69 | |
44 | #define CLKID_MPLL1_DIV 70 | |
45 | #define CLKID_MPLL2_DIV 71 | |
46 | #define CLKID_MPLL3_DIV 72 | |
47 | #define CLKID_MPLL_PREDIV 73 | |
48 | #define CLKID_FCLK_DIV2_DIV 75 | |
49 | #define CLKID_FCLK_DIV3_DIV 76 | |
50 | #define CLKID_FCLK_DIV4_DIV 77 | |
51 | #define CLKID_FCLK_DIV5_DIV 78 | |
52 | #define CLKID_FCLK_DIV7_DIV 79 | |
53 | #define CLKID_FCLK_DIV2P5_DIV 100 | |
54 | #define CLKID_FIXED_PLL_DCO 101 | |
55 | #define CLKID_SYS_PLL_DCO 102 | |
56 | #define CLKID_GP0_PLL_DCO 103 | |
57 | #define CLKID_HIFI_PLL_DCO 104 | |
58 | #define CLKID_VPU_0_DIV 111 | |
59 | #define CLKID_VPU_1_DIV 114 | |
60 | #define CLKID_VAPB_0_DIV 118 | |
61 | #define CLKID_VAPB_1_DIV 121 | |
62 | #define CLKID_HDMI_PLL_DCO 125 | |
63 | #define CLKID_HDMI_PLL_OD 126 | |
64 | #define CLKID_HDMI_PLL_OD2 127 | |
65 | #define CLKID_VID_PLL_SEL 130 | |
66 | #define CLKID_VID_PLL_DIV 131 | |
67 | #define CLKID_VCLK_SEL 132 | |
68 | #define CLKID_VCLK2_SEL 133 | |
69 | #define CLKID_VCLK_INPUT 134 | |
70 | #define CLKID_VCLK2_INPUT 135 | |
71 | #define CLKID_VCLK_DIV 136 | |
72 | #define CLKID_VCLK2_DIV 137 | |
73 | #define CLKID_VCLK_DIV2_EN 140 | |
74 | #define CLKID_VCLK_DIV4_EN 141 | |
75 | #define CLKID_VCLK_DIV6_EN 142 | |
76 | #define CLKID_VCLK_DIV12_EN 143 | |
77 | #define CLKID_VCLK2_DIV2_EN 144 | |
78 | #define CLKID_VCLK2_DIV4_EN 145 | |
79 | #define CLKID_VCLK2_DIV6_EN 146 | |
80 | #define CLKID_VCLK2_DIV12_EN 147 | |
81 | #define CLKID_CTS_ENCI_SEL 158 | |
82 | #define CLKID_CTS_ENCP_SEL 159 | |
83 | #define CLKID_CTS_VDAC_SEL 160 | |
84 | #define CLKID_HDMI_TX_SEL 161 | |
85 | #define CLKID_HDMI_SEL 166 | |
86 | #define CLKID_HDMI_DIV 167 | |
87 | #define CLKID_MALI_0_DIV 170 | |
88 | #define CLKID_MALI_1_DIV 173 | |
89 | ||
90 | #define CLKID_XTAL 0x10000000 | |
91 | ||
912af842 JB |
92 | #define XTAL_RATE 24000000 |
93 | ||
94 | struct meson_clk { | |
95 | struct regmap *map; | |
96 | }; | |
97 | ||
a0513b40 NA |
98 | static ulong meson_div_get_rate(struct clk *clk, unsigned long id); |
99 | static ulong meson_div_set_rate(struct clk *clk, unsigned long id, ulong rate, | |
100 | ulong current_rate); | |
101 | static ulong meson_mux_set_parent(struct clk *clk, unsigned long id, | |
102 | unsigned long parent_id); | |
103 | static ulong meson_mux_get_rate(struct clk *clk, unsigned long id); | |
08e09c26 NA |
104 | static ulong meson_clk_set_rate_by_id(struct clk *clk, unsigned long id, |
105 | ulong rate, ulong current_rate); | |
a0513b40 | 106 | static ulong meson_mux_get_parent(struct clk *clk, unsigned long id); |
912af842 JB |
107 | static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id); |
108 | ||
109 | #define NUM_CLKS 178 | |
110 | ||
111 | static struct meson_gate gates[NUM_CLKS] = { | |
112 | /* Everything Else (EE) domain gates */ | |
113 | MESON_GATE(CLKID_SPICC0, HHI_GCLK_MPEG0, 8), | |
114 | MESON_GATE(CLKID_I2C, HHI_GCLK_MPEG0, 9), | |
115 | MESON_GATE(CLKID_UART0, HHI_GCLK_MPEG0, 13), | |
116 | MESON_GATE(CLKID_SPICC1, HHI_GCLK_MPEG0, 14), | |
75dcc2d4 | 117 | MESON_GATE(CLKID_SD_EMMC_A, HHI_GCLK_MPEG0, 4), |
912af842 JB |
118 | MESON_GATE(CLKID_SD_EMMC_B, HHI_GCLK_MPEG0, 25), |
119 | MESON_GATE(CLKID_SD_EMMC_C, HHI_GCLK_MPEG0, 26), | |
120 | MESON_GATE(CLKID_ETH, HHI_GCLK_MPEG1, 3), | |
121 | MESON_GATE(CLKID_UART1, HHI_GCLK_MPEG1, 16), | |
08e09c26 | 122 | MESON_GATE(CLKID_USB, HHI_GCLK_MPEG1, 25), |
a0513b40 | 123 | MESON_GATE(CLKID_HTX_PCLK, HHI_GCLK_MPEG2, 4), |
08e09c26 | 124 | MESON_GATE(CLKID_USB1_DDR_BRIDGE, HHI_GCLK_MPEG2, 8), |
a0513b40 | 125 | MESON_GATE(CLKID_VPU_INTR, HHI_GCLK_MPEG2, 25), |
912af842 JB |
126 | |
127 | /* Peripheral Gates */ | |
a0513b40 NA |
128 | MESON_GATE(CLKID_FCLK_DIV2, HHI_FIX_PLL_CNTL1, 24), |
129 | MESON_GATE(CLKID_FCLK_DIV3, HHI_FIX_PLL_CNTL1, 20), | |
130 | MESON_GATE(CLKID_FCLK_DIV4, HHI_FIX_PLL_CNTL1, 21), | |
131 | MESON_GATE(CLKID_FCLK_DIV5, HHI_FIX_PLL_CNTL1, 22), | |
132 | MESON_GATE(CLKID_FCLK_DIV7, HHI_FIX_PLL_CNTL1, 23), | |
75dcc2d4 | 133 | MESON_GATE(CLKID_SD_EMMC_A_CLK0, HHI_SD_EMMC_CLK_CNTL, 7), |
912af842 JB |
134 | MESON_GATE(CLKID_SD_EMMC_B_CLK0, HHI_SD_EMMC_CLK_CNTL, 23), |
135 | MESON_GATE(CLKID_SD_EMMC_C_CLK0, HHI_NAND_CLK_CNTL, 7), | |
a0513b40 NA |
136 | MESON_GATE(CLKID_VPU_0, HHI_VPU_CLK_CNTL, 8), |
137 | MESON_GATE(CLKID_VPU_1, HHI_VPU_CLK_CNTL, 24), | |
138 | MESON_GATE(CLKID_VAPB_0, HHI_VAPBCLK_CNTL, 8), | |
139 | MESON_GATE(CLKID_VAPB_1, HHI_VAPBCLK_CNTL, 24), | |
140 | MESON_GATE(CLKID_VAPB, HHI_VAPBCLK_CNTL, 30), | |
141 | MESON_GATE(CLKID_HDMI, HHI_HDMI_CLK_CNTL, 8), | |
912af842 JB |
142 | }; |
143 | ||
a0513b40 | 144 | static int meson_set_gate_by_id(struct clk *clk, unsigned long id, bool on) |
912af842 JB |
145 | { |
146 | struct meson_clk *priv = dev_get_priv(clk->dev); | |
147 | struct meson_gate *gate; | |
148 | ||
a0513b40 NA |
149 | debug("%s: %sabling %ld\n", __func__, on ? "en" : "dis", id); |
150 | ||
151 | /* Propagate through muxes */ | |
152 | switch (id) { | |
153 | case CLKID_VPU: | |
154 | return meson_set_gate_by_id(clk, | |
155 | meson_mux_get_parent(clk, CLKID_VPU), on); | |
156 | case CLKID_VAPB_SEL: | |
157 | return meson_set_gate_by_id(clk, | |
158 | meson_mux_get_parent(clk, CLKID_VAPB_SEL), on); | |
159 | } | |
160 | ||
161 | if (id >= ARRAY_SIZE(gates)) | |
912af842 JB |
162 | return -ENOENT; |
163 | ||
a0513b40 | 164 | gate = &gates[id]; |
912af842 JB |
165 | |
166 | if (gate->reg == 0) | |
167 | return 0; | |
168 | ||
a0513b40 NA |
169 | debug("%s: really %sabling %ld\n", __func__, on ? "en" : "dis", id); |
170 | ||
912af842 JB |
171 | regmap_update_bits(priv->map, gate->reg, |
172 | BIT(gate->bit), on ? BIT(gate->bit) : 0); | |
173 | ||
a0513b40 NA |
174 | /* Propagate to next gate(s) */ |
175 | switch (id) { | |
176 | case CLKID_VAPB: | |
177 | return meson_set_gate_by_id(clk, CLKID_VAPB_SEL, on); | |
178 | case CLKID_VAPB_0: | |
179 | return meson_set_gate_by_id(clk, | |
180 | meson_mux_get_parent(clk, CLKID_VAPB_0_SEL), on); | |
181 | case CLKID_VAPB_1: | |
182 | return meson_set_gate_by_id(clk, | |
183 | meson_mux_get_parent(clk, CLKID_VAPB_0_SEL), on); | |
184 | case CLKID_VPU_0: | |
185 | return meson_set_gate_by_id(clk, | |
186 | meson_mux_get_parent(clk, CLKID_VPU_0_SEL), on); | |
187 | case CLKID_VPU_1: | |
188 | return meson_set_gate_by_id(clk, | |
189 | meson_mux_get_parent(clk, CLKID_VPU_1_SEL), on); | |
190 | } | |
191 | ||
912af842 JB |
192 | return 0; |
193 | } | |
194 | ||
195 | static int meson_clk_enable(struct clk *clk) | |
196 | { | |
a0513b40 | 197 | return meson_set_gate_by_id(clk, clk->id, true); |
912af842 JB |
198 | } |
199 | ||
200 | static int meson_clk_disable(struct clk *clk) | |
201 | { | |
a0513b40 NA |
202 | return meson_set_gate_by_id(clk, clk->id, false); |
203 | } | |
204 | ||
205 | static struct parm meson_vpu_0_div_parm = { | |
206 | HHI_VPU_CLK_CNTL, 0, 7, | |
207 | }; | |
208 | ||
209 | int meson_vpu_0_div_parent = CLKID_VPU_0_SEL; | |
210 | ||
211 | static struct parm meson_vpu_1_div_parm = { | |
212 | HHI_VPU_CLK_CNTL, 16, 7, | |
213 | }; | |
214 | ||
215 | int meson_vpu_1_div_parent = CLKID_VPU_1_SEL; | |
216 | ||
217 | static struct parm meson_vapb_0_div_parm = { | |
218 | HHI_VAPBCLK_CNTL, 0, 7, | |
219 | }; | |
220 | ||
221 | int meson_vapb_0_div_parent = CLKID_VAPB_0_SEL; | |
222 | ||
223 | static struct parm meson_vapb_1_div_parm = { | |
224 | HHI_VAPBCLK_CNTL, 16, 7, | |
225 | }; | |
226 | ||
227 | int meson_vapb_1_div_parent = CLKID_VAPB_1_SEL; | |
228 | ||
229 | static struct parm meson_hdmi_div_parm = { | |
230 | HHI_HDMI_CLK_CNTL, 0, 7, | |
231 | }; | |
232 | ||
233 | int meson_hdmi_div_parent = CLKID_HDMI_SEL; | |
234 | ||
235 | static ulong meson_div_get_rate(struct clk *clk, unsigned long id) | |
236 | { | |
237 | struct meson_clk *priv = dev_get_priv(clk->dev); | |
238 | unsigned int rate, parent_rate; | |
239 | struct parm *parm; | |
240 | int parent; | |
241 | uint reg; | |
242 | ||
243 | switch (id) { | |
244 | case CLKID_VPU_0_DIV: | |
245 | parm = &meson_vpu_0_div_parm; | |
246 | parent = meson_vpu_0_div_parent; | |
247 | break; | |
248 | case CLKID_VPU_1_DIV: | |
249 | parm = &meson_vpu_1_div_parm; | |
250 | parent = meson_vpu_1_div_parent; | |
251 | break; | |
252 | case CLKID_VAPB_0_DIV: | |
253 | parm = &meson_vapb_0_div_parm; | |
254 | parent = meson_vapb_0_div_parent; | |
255 | break; | |
256 | case CLKID_VAPB_1_DIV: | |
257 | parm = &meson_vapb_1_div_parm; | |
258 | parent = meson_vapb_1_div_parent; | |
259 | break; | |
260 | case CLKID_HDMI_DIV: | |
261 | parm = &meson_hdmi_div_parm; | |
262 | parent = meson_hdmi_div_parent; | |
263 | break; | |
264 | default: | |
265 | return -ENOENT; | |
266 | } | |
267 | ||
268 | regmap_read(priv->map, parm->reg_off, ®); | |
269 | reg = PARM_GET(parm->width, parm->shift, reg); | |
270 | ||
271 | debug("%s: div of %ld is %d\n", __func__, id, reg + 1); | |
272 | ||
273 | parent_rate = meson_clk_get_rate_by_id(clk, parent); | |
274 | if (IS_ERR_VALUE(parent_rate)) | |
275 | return parent_rate; | |
276 | ||
277 | debug("%s: parent rate of %ld is %d\n", __func__, id, parent_rate); | |
278 | ||
279 | rate = parent_rate / (reg + 1); | |
280 | ||
281 | debug("%s: rate of %ld is %d\n", __func__, id, rate); | |
282 | ||
283 | return rate; | |
284 | } | |
285 | ||
286 | static ulong meson_div_set_rate(struct clk *clk, unsigned long id, ulong rate, | |
287 | ulong current_rate) | |
288 | { | |
289 | struct meson_clk *priv = dev_get_priv(clk->dev); | |
290 | unsigned int new_div = -EINVAL; | |
291 | unsigned long parent_rate; | |
292 | struct parm *parm; | |
293 | int parent; | |
294 | int ret; | |
295 | ||
296 | if (current_rate == rate) | |
297 | return 0; | |
298 | ||
299 | debug("%s: setting rate of %ld from %ld to %ld\n", | |
300 | __func__, id, current_rate, rate); | |
301 | ||
302 | switch (id) { | |
303 | case CLKID_VPU_0_DIV: | |
304 | parm = &meson_vpu_0_div_parm; | |
305 | parent = meson_vpu_0_div_parent; | |
306 | break; | |
307 | case CLKID_VPU_1_DIV: | |
308 | parm = &meson_vpu_1_div_parm; | |
309 | parent = meson_vpu_1_div_parent; | |
310 | break; | |
311 | case CLKID_VAPB_0_DIV: | |
312 | parm = &meson_vapb_0_div_parm; | |
313 | parent = meson_vapb_0_div_parent; | |
314 | break; | |
315 | case CLKID_VAPB_1_DIV: | |
316 | parm = &meson_vapb_1_div_parm; | |
317 | parent = meson_vapb_1_div_parent; | |
318 | break; | |
319 | case CLKID_HDMI_DIV: | |
320 | parm = &meson_hdmi_div_parm; | |
321 | parent = meson_hdmi_div_parent; | |
322 | break; | |
323 | default: | |
324 | return -ENOENT; | |
325 | } | |
326 | ||
327 | parent_rate = meson_clk_get_rate_by_id(clk, parent); | |
328 | if (IS_ERR_VALUE(parent_rate)) | |
329 | return parent_rate; | |
330 | ||
331 | debug("%s: parent rate of %ld is %ld\n", __func__, id, parent_rate); | |
332 | ||
333 | /* If can't divide, set parent instead */ | |
334 | if (!parent_rate || rate > parent_rate) | |
335 | return meson_clk_set_rate_by_id(clk, parent, rate, | |
336 | current_rate); | |
337 | ||
338 | new_div = DIV_ROUND_CLOSEST(parent_rate, rate); | |
339 | ||
340 | debug("%s: new div of %ld is %d\n", __func__, id, new_div); | |
341 | ||
342 | /* If overflow, try to set parent rate and retry */ | |
343 | if (!new_div || new_div > (1 << parm->width)) { | |
344 | ret = meson_clk_set_rate_by_id(clk, parent, rate, current_rate); | |
345 | if (IS_ERR_VALUE(ret)) | |
346 | return ret; | |
347 | ||
348 | parent_rate = meson_clk_get_rate_by_id(clk, parent); | |
349 | if (IS_ERR_VALUE(parent_rate)) | |
350 | return parent_rate; | |
351 | ||
352 | new_div = DIV_ROUND_CLOSEST(parent_rate, rate); | |
353 | ||
354 | debug("%s: new new div of %ld is %d\n", __func__, id, new_div); | |
355 | ||
356 | if (!new_div || new_div > (1 << parm->width)) | |
357 | return -EINVAL; | |
358 | } | |
359 | ||
360 | debug("%s: setting div of %ld to %d\n", __func__, id, new_div); | |
361 | ||
362 | regmap_update_bits(priv->map, parm->reg_off, | |
363 | SETPMASK(parm->width, parm->shift), | |
364 | (new_div - 1) << parm->shift); | |
365 | ||
366 | debug("%s: new rate of %ld is %ld\n", | |
367 | __func__, id, meson_div_get_rate(clk, id)); | |
368 | ||
369 | return 0; | |
370 | } | |
371 | ||
372 | static struct parm meson_vpu_mux_parm = { | |
373 | HHI_VPU_CLK_CNTL, 31, 1, | |
374 | }; | |
375 | ||
376 | int meson_vpu_mux_parents[] = { | |
377 | CLKID_VPU_0, | |
378 | CLKID_VPU_1, | |
379 | }; | |
380 | ||
381 | static struct parm meson_vpu_0_mux_parm = { | |
382 | HHI_VPU_CLK_CNTL, 9, 3, | |
383 | }; | |
384 | ||
385 | static struct parm meson_vpu_1_mux_parm = { | |
386 | HHI_VPU_CLK_CNTL, 25, 3, | |
387 | }; | |
388 | ||
389 | static int meson_vpu_0_1_mux_parents[] = { | |
390 | CLKID_FCLK_DIV3, | |
391 | CLKID_FCLK_DIV4, | |
392 | CLKID_FCLK_DIV5, | |
393 | CLKID_FCLK_DIV7, | |
394 | -ENOENT, | |
395 | -ENOENT, | |
396 | -ENOENT, | |
397 | -ENOENT, | |
398 | }; | |
399 | ||
400 | static struct parm meson_vapb_sel_mux_parm = { | |
401 | HHI_VAPBCLK_CNTL, 31, 1, | |
402 | }; | |
403 | ||
404 | int meson_vapb_sel_mux_parents[] = { | |
405 | CLKID_VAPB_0, | |
406 | CLKID_VAPB_1, | |
407 | }; | |
408 | ||
409 | static struct parm meson_vapb_0_mux_parm = { | |
410 | HHI_VAPBCLK_CNTL, 9, 2, | |
411 | }; | |
412 | ||
413 | static struct parm meson_vapb_1_mux_parm = { | |
414 | HHI_VAPBCLK_CNTL, 25, 2, | |
415 | }; | |
416 | ||
417 | static int meson_vapb_0_1_mux_parents[] = { | |
418 | CLKID_FCLK_DIV4, | |
419 | CLKID_FCLK_DIV3, | |
420 | CLKID_FCLK_DIV5, | |
421 | CLKID_FCLK_DIV7, | |
422 | }; | |
423 | ||
424 | static struct parm meson_hdmi_mux_parm = { | |
425 | HHI_HDMI_CLK_CNTL, 9, 2, | |
426 | }; | |
427 | ||
428 | static int meson_hdmi_mux_parents[] = { | |
429 | CLKID_XTAL, | |
430 | CLKID_FCLK_DIV4, | |
431 | CLKID_FCLK_DIV3, | |
432 | CLKID_FCLK_DIV5, | |
433 | }; | |
434 | ||
435 | static ulong meson_mux_get_parent(struct clk *clk, unsigned long id) | |
436 | { | |
437 | struct meson_clk *priv = dev_get_priv(clk->dev); | |
438 | struct parm *parm; | |
439 | int *parents; | |
440 | uint reg; | |
441 | ||
442 | switch (id) { | |
443 | case CLKID_VPU: | |
444 | parm = &meson_vpu_mux_parm; | |
445 | parents = meson_vpu_mux_parents; | |
446 | break; | |
447 | case CLKID_VPU_0_SEL: | |
448 | parm = &meson_vpu_0_mux_parm; | |
449 | parents = meson_vpu_0_1_mux_parents; | |
450 | break; | |
451 | case CLKID_VPU_1_SEL: | |
452 | parm = &meson_vpu_1_mux_parm; | |
453 | parents = meson_vpu_0_1_mux_parents; | |
454 | break; | |
455 | case CLKID_VAPB_SEL: | |
456 | parm = &meson_vapb_sel_mux_parm; | |
457 | parents = meson_vapb_sel_mux_parents; | |
458 | break; | |
459 | case CLKID_VAPB_0_SEL: | |
460 | parm = &meson_vapb_0_mux_parm; | |
461 | parents = meson_vapb_0_1_mux_parents; | |
462 | break; | |
463 | case CLKID_VAPB_1_SEL: | |
464 | parm = &meson_vapb_1_mux_parm; | |
465 | parents = meson_vapb_0_1_mux_parents; | |
466 | break; | |
467 | case CLKID_HDMI_SEL: | |
468 | parm = &meson_hdmi_mux_parm; | |
469 | parents = meson_hdmi_mux_parents; | |
470 | break; | |
471 | default: | |
472 | return -ENOENT; | |
473 | } | |
474 | ||
475 | regmap_read(priv->map, parm->reg_off, ®); | |
476 | reg = PARM_GET(parm->width, parm->shift, reg); | |
477 | ||
478 | debug("%s: parent of %ld is %d (%d)\n", | |
479 | __func__, id, parents[reg], reg); | |
480 | ||
481 | return parents[reg]; | |
482 | } | |
483 | ||
484 | static ulong meson_mux_set_parent(struct clk *clk, unsigned long id, | |
485 | unsigned long parent_id) | |
486 | { | |
487 | unsigned long cur_parent = meson_mux_get_parent(clk, id); | |
488 | struct meson_clk *priv = dev_get_priv(clk->dev); | |
489 | unsigned int new_index = -EINVAL; | |
490 | struct parm *parm; | |
491 | int *parents; | |
492 | int i; | |
493 | ||
494 | if (IS_ERR_VALUE(cur_parent)) | |
495 | return cur_parent; | |
496 | ||
497 | debug("%s: setting parent of %ld from %ld to %ld\n", | |
498 | __func__, id, cur_parent, parent_id); | |
499 | ||
500 | if (cur_parent == parent_id) | |
501 | return 0; | |
502 | ||
503 | switch (id) { | |
504 | case CLKID_VPU: | |
505 | parm = &meson_vpu_mux_parm; | |
506 | parents = meson_vpu_mux_parents; | |
507 | break; | |
508 | case CLKID_VPU_0_SEL: | |
509 | parm = &meson_vpu_0_mux_parm; | |
510 | parents = meson_vpu_0_1_mux_parents; | |
511 | break; | |
512 | case CLKID_VPU_1_SEL: | |
513 | parm = &meson_vpu_1_mux_parm; | |
514 | parents = meson_vpu_0_1_mux_parents; | |
515 | break; | |
516 | case CLKID_VAPB_SEL: | |
517 | parm = &meson_vapb_sel_mux_parm; | |
518 | parents = meson_vapb_sel_mux_parents; | |
519 | break; | |
520 | case CLKID_VAPB_0_SEL: | |
521 | parm = &meson_vapb_0_mux_parm; | |
522 | parents = meson_vapb_0_1_mux_parents; | |
523 | break; | |
524 | case CLKID_VAPB_1_SEL: | |
525 | parm = &meson_vapb_1_mux_parm; | |
526 | parents = meson_vapb_0_1_mux_parents; | |
527 | break; | |
528 | case CLKID_HDMI_SEL: | |
529 | parm = &meson_hdmi_mux_parm; | |
530 | parents = meson_hdmi_mux_parents; | |
531 | break; | |
532 | default: | |
533 | /* Not a mux */ | |
534 | return -ENOENT; | |
535 | } | |
536 | ||
537 | for (i = 0 ; i < (1 << parm->width) ; ++i) { | |
538 | if (parents[i] == parent_id) | |
539 | new_index = i; | |
540 | } | |
541 | ||
542 | if (IS_ERR_VALUE(new_index)) | |
543 | return new_index; | |
544 | ||
545 | debug("%s: new index of %ld is %d\n", __func__, id, new_index); | |
546 | ||
547 | regmap_update_bits(priv->map, parm->reg_off, | |
548 | SETPMASK(parm->width, parm->shift), | |
549 | new_index << parm->shift); | |
550 | ||
551 | debug("%s: new parent of %ld is %ld\n", | |
552 | __func__, id, meson_mux_get_parent(clk, id)); | |
553 | ||
554 | return 0; | |
555 | } | |
556 | ||
557 | static ulong meson_mux_get_rate(struct clk *clk, unsigned long id) | |
558 | { | |
559 | int parent = meson_mux_get_parent(clk, id); | |
560 | ||
561 | if (IS_ERR_VALUE(parent)) | |
562 | return parent; | |
563 | ||
564 | return meson_clk_get_rate_by_id(clk, parent); | |
912af842 JB |
565 | } |
566 | ||
567 | static unsigned long meson_clk81_get_rate(struct clk *clk) | |
568 | { | |
569 | struct meson_clk *priv = dev_get_priv(clk->dev); | |
570 | unsigned long parent_rate; | |
571 | uint reg; | |
572 | int parents[] = { | |
a0513b40 | 573 | CLKID_XTAL, |
912af842 JB |
574 | -1, |
575 | CLKID_FCLK_DIV7, | |
576 | CLKID_MPLL1, | |
577 | CLKID_MPLL2, | |
578 | CLKID_FCLK_DIV4, | |
579 | CLKID_FCLK_DIV3, | |
580 | CLKID_FCLK_DIV5 | |
581 | }; | |
582 | ||
583 | /* mux */ | |
584 | regmap_read(priv->map, HHI_MPEG_CLK_CNTL, ®); | |
585 | reg = (reg >> 12) & 7; | |
586 | ||
587 | switch (reg) { | |
912af842 JB |
588 | case 1: |
589 | return -ENOENT; | |
590 | default: | |
591 | parent_rate = meson_clk_get_rate_by_id(clk, parents[reg]); | |
592 | } | |
593 | ||
594 | /* divider */ | |
595 | regmap_read(priv->map, HHI_MPEG_CLK_CNTL, ®); | |
596 | reg = reg & ((1 << 7) - 1); | |
597 | ||
598 | return parent_rate / reg; | |
599 | } | |
600 | ||
601 | static long mpll_rate_from_params(unsigned long parent_rate, | |
602 | unsigned long sdm, | |
603 | unsigned long n2) | |
604 | { | |
605 | unsigned long divisor = (SDM_DEN * n2) + sdm; | |
606 | ||
607 | if (n2 < N2_MIN) | |
608 | return -EINVAL; | |
609 | ||
610 | return DIV_ROUND_UP_ULL((u64)parent_rate * SDM_DEN, divisor); | |
611 | } | |
612 | ||
613 | static struct parm meson_mpll0_parm[2] = { | |
614 | {HHI_MPLL_CNTL1, 0, 14}, /* psdm */ | |
615 | {HHI_MPLL_CNTL1, 20, 9}, /* pn2 */ | |
616 | }; | |
617 | ||
618 | static struct parm meson_mpll1_parm[2] = { | |
619 | {HHI_MPLL_CNTL3, 0, 14}, /* psdm */ | |
620 | {HHI_MPLL_CNTL3, 20, 9}, /* pn2 */ | |
621 | }; | |
622 | ||
623 | static struct parm meson_mpll2_parm[2] = { | |
624 | {HHI_MPLL_CNTL5, 0, 14}, /* psdm */ | |
625 | {HHI_MPLL_CNTL5, 20, 9}, /* pn2 */ | |
626 | }; | |
627 | ||
628 | /* | |
629 | * MultiPhase Locked Loops are outputs from a PLL with additional frequency | |
630 | * scaling capabilities. MPLL rates are calculated as: | |
631 | * | |
632 | * f(N2_integer, SDM_IN ) = 2.0G/(N2_integer + SDM_IN/16384) | |
633 | */ | |
634 | static ulong meson_mpll_get_rate(struct clk *clk, unsigned long id) | |
635 | { | |
636 | struct meson_clk *priv = dev_get_priv(clk->dev); | |
637 | struct parm *psdm, *pn2; | |
638 | unsigned long sdm, n2; | |
639 | unsigned long parent_rate; | |
640 | uint reg; | |
641 | ||
642 | switch (id) { | |
643 | case CLKID_MPLL0: | |
644 | psdm = &meson_mpll0_parm[0]; | |
645 | pn2 = &meson_mpll0_parm[1]; | |
646 | break; | |
647 | case CLKID_MPLL1: | |
648 | psdm = &meson_mpll1_parm[0]; | |
649 | pn2 = &meson_mpll1_parm[1]; | |
650 | break; | |
651 | case CLKID_MPLL2: | |
652 | psdm = &meson_mpll2_parm[0]; | |
653 | pn2 = &meson_mpll2_parm[1]; | |
654 | break; | |
655 | default: | |
656 | return -ENOENT; | |
657 | } | |
658 | ||
659 | parent_rate = meson_clk_get_rate_by_id(clk, CLKID_FIXED_PLL); | |
660 | if (IS_ERR_VALUE(parent_rate)) | |
661 | return parent_rate; | |
662 | ||
663 | regmap_read(priv->map, psdm->reg_off, ®); | |
664 | sdm = PARM_GET(psdm->width, psdm->shift, reg); | |
665 | ||
666 | regmap_read(priv->map, pn2->reg_off, ®); | |
667 | n2 = PARM_GET(pn2->width, pn2->shift, reg); | |
668 | ||
669 | return mpll_rate_from_params(parent_rate, sdm, n2); | |
670 | } | |
671 | ||
a0513b40 NA |
672 | static struct parm meson_fixed_pll_parm[4] = { |
673 | {HHI_FIX_PLL_CNTL0, 0, 9}, /* pm */ | |
912af842 JB |
674 | {HHI_FIX_PLL_CNTL0, 10, 5}, /* pn */ |
675 | {HHI_FIX_PLL_CNTL0, 16, 2}, /* pod */ | |
a0513b40 | 676 | {HHI_FIX_PLL_CNTL1, 0, 17}, /* pfrac */ |
912af842 JB |
677 | }; |
678 | ||
679 | static struct parm meson_sys_pll_parm[3] = { | |
a0513b40 | 680 | {HHI_SYS_PLL_CNTL0, 0, 9}, /* pm */ |
912af842 | 681 | {HHI_SYS_PLL_CNTL0, 10, 5}, /* pn */ |
a0513b40 | 682 | {HHI_SYS_PLL_CNTL0, 16, 3}, /* pod */ |
912af842 JB |
683 | }; |
684 | ||
685 | static ulong meson_pll_get_rate(struct clk *clk, unsigned long id) | |
686 | { | |
687 | struct meson_clk *priv = dev_get_priv(clk->dev); | |
a0513b40 | 688 | struct parm *pm, *pn, *pod, *pfrac = NULL; |
912af842 | 689 | unsigned long parent_rate_mhz = XTAL_RATE / 1000000; |
a0513b40 NA |
690 | u16 n, m, od, frac; |
691 | ulong rate; | |
912af842 JB |
692 | uint reg; |
693 | ||
694 | /* | |
695 | * FIXME: Between the unit conversion and the missing frac, we know | |
696 | * rate will be slightly off ... | |
697 | */ | |
698 | ||
699 | switch (id) { | |
700 | case CLKID_FIXED_PLL: | |
701 | pm = &meson_fixed_pll_parm[0]; | |
702 | pn = &meson_fixed_pll_parm[1]; | |
703 | pod = &meson_fixed_pll_parm[2]; | |
a0513b40 | 704 | pfrac = &meson_fixed_pll_parm[3]; |
912af842 JB |
705 | break; |
706 | case CLKID_SYS_PLL: | |
707 | pm = &meson_sys_pll_parm[0]; | |
708 | pn = &meson_sys_pll_parm[1]; | |
709 | pod = &meson_sys_pll_parm[2]; | |
710 | break; | |
711 | default: | |
712 | return -ENOENT; | |
713 | } | |
714 | ||
715 | regmap_read(priv->map, pn->reg_off, ®); | |
716 | n = PARM_GET(pn->width, pn->shift, reg); | |
717 | ||
718 | regmap_read(priv->map, pm->reg_off, ®); | |
719 | m = PARM_GET(pm->width, pm->shift, reg); | |
720 | ||
721 | regmap_read(priv->map, pod->reg_off, ®); | |
722 | od = PARM_GET(pod->width, pod->shift, reg); | |
723 | ||
a0513b40 NA |
724 | rate = parent_rate_mhz * m; |
725 | ||
726 | if (pfrac) { | |
727 | ulong frac_rate; | |
728 | ||
729 | regmap_read(priv->map, pfrac->reg_off, ®); | |
730 | frac = PARM_GET(pfrac->width - 1, pfrac->shift, reg); | |
731 | ||
732 | frac_rate = DIV_ROUND_UP_ULL((u64)parent_rate_mhz * frac, | |
733 | 1 << (pfrac->width - 2)); | |
734 | ||
735 | if (frac & BIT(pfrac->width - 1)) | |
736 | rate -= frac_rate; | |
737 | else | |
738 | rate += frac_rate; | |
739 | } | |
740 | ||
741 | return (DIV_ROUND_UP_ULL(rate, n) >> od) * 1000000; | |
912af842 JB |
742 | } |
743 | ||
08e09c26 NA |
744 | static struct parm meson_pcie_pll_parm[3] = { |
745 | {HHI_PCIE_PLL_CNTL0, 0, 8}, /* pm */ | |
746 | {HHI_PCIE_PLL_CNTL0, 10, 5}, /* pn */ | |
747 | {HHI_PCIE_PLL_CNTL0, 16, 5}, /* pod */ | |
748 | }; | |
749 | ||
750 | static ulong meson_pcie_pll_get_rate(struct clk *clk) | |
751 | { | |
752 | struct meson_clk *priv = dev_get_priv(clk->dev); | |
753 | struct parm *pm, *pn, *pod; | |
754 | unsigned long parent_rate_mhz = XTAL_RATE / 1000000; | |
755 | u16 n, m, od; | |
756 | uint reg; | |
757 | ||
758 | pm = &meson_pcie_pll_parm[0]; | |
759 | pn = &meson_pcie_pll_parm[1]; | |
760 | pod = &meson_pcie_pll_parm[2]; | |
761 | ||
762 | regmap_read(priv->map, pn->reg_off, ®); | |
763 | n = PARM_GET(pn->width, pn->shift, reg); | |
764 | ||
765 | regmap_read(priv->map, pm->reg_off, ®); | |
766 | m = PARM_GET(pm->width, pm->shift, reg); | |
767 | ||
768 | regmap_read(priv->map, pod->reg_off, ®); | |
769 | od = PARM_GET(pod->width, pod->shift, reg); | |
770 | ||
771 | return ((parent_rate_mhz * m / n) / 2 / od / 2) * 1000000; | |
772 | } | |
773 | ||
912af842 JB |
774 | static ulong meson_clk_get_rate_by_id(struct clk *clk, unsigned long id) |
775 | { | |
776 | ulong rate; | |
777 | ||
778 | switch (id) { | |
a0513b40 NA |
779 | case CLKID_XTAL: |
780 | rate = XTAL_RATE; | |
781 | break; | |
912af842 JB |
782 | case CLKID_FIXED_PLL: |
783 | case CLKID_SYS_PLL: | |
784 | rate = meson_pll_get_rate(clk, id); | |
785 | break; | |
786 | case CLKID_FCLK_DIV2: | |
787 | rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 2; | |
788 | break; | |
789 | case CLKID_FCLK_DIV3: | |
790 | rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 3; | |
791 | break; | |
792 | case CLKID_FCLK_DIV4: | |
793 | rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 4; | |
794 | break; | |
795 | case CLKID_FCLK_DIV5: | |
796 | rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 5; | |
797 | break; | |
798 | case CLKID_FCLK_DIV7: | |
799 | rate = meson_pll_get_rate(clk, CLKID_FIXED_PLL) / 7; | |
800 | break; | |
801 | case CLKID_MPLL0: | |
802 | case CLKID_MPLL1: | |
803 | case CLKID_MPLL2: | |
804 | rate = meson_mpll_get_rate(clk, id); | |
805 | break; | |
806 | case CLKID_CLK81: | |
807 | rate = meson_clk81_get_rate(clk); | |
808 | break; | |
08e09c26 NA |
809 | case CLKID_PCIE_PLL: |
810 | rate = meson_pcie_pll_get_rate(clk); | |
87a8f967 | 811 | break; |
a0513b40 NA |
812 | case CLKID_VPU_0: |
813 | rate = meson_div_get_rate(clk, CLKID_VPU_0_DIV); | |
814 | break; | |
815 | case CLKID_VPU_1: | |
816 | rate = meson_div_get_rate(clk, CLKID_VPU_1_DIV); | |
817 | break; | |
818 | case CLKID_VAPB: | |
819 | rate = meson_mux_get_rate(clk, CLKID_VAPB_SEL); | |
820 | break; | |
821 | case CLKID_VAPB_0: | |
822 | rate = meson_div_get_rate(clk, CLKID_VAPB_0_DIV); | |
823 | break; | |
824 | case CLKID_VAPB_1: | |
825 | rate = meson_div_get_rate(clk, CLKID_VAPB_1_DIV); | |
826 | break; | |
827 | case CLKID_HDMI: | |
828 | rate = meson_div_get_rate(clk, CLKID_HDMI_DIV); | |
829 | break; | |
830 | case CLKID_VPU_0_DIV: | |
831 | case CLKID_VPU_1_DIV: | |
832 | case CLKID_VAPB_0_DIV: | |
833 | case CLKID_VAPB_1_DIV: | |
834 | case CLKID_HDMI_DIV: | |
835 | rate = meson_div_get_rate(clk, id); | |
836 | break; | |
837 | case CLKID_VPU: | |
838 | case CLKID_VPU_0_SEL: | |
839 | case CLKID_VPU_1_SEL: | |
840 | case CLKID_VAPB_SEL: | |
841 | case CLKID_VAPB_0_SEL: | |
842 | case CLKID_VAPB_1_SEL: | |
843 | case CLKID_HDMI_SEL: | |
844 | rate = meson_mux_get_rate(clk, id); | |
08e09c26 | 845 | break; |
912af842 JB |
846 | default: |
847 | if (gates[id].reg != 0) { | |
848 | /* a clock gate */ | |
849 | rate = meson_clk81_get_rate(clk); | |
850 | break; | |
851 | } | |
852 | return -ENOENT; | |
853 | } | |
854 | ||
855 | debug("clock %lu has rate %lu\n", id, rate); | |
856 | return rate; | |
857 | } | |
858 | ||
859 | static ulong meson_clk_get_rate(struct clk *clk) | |
860 | { | |
861 | return meson_clk_get_rate_by_id(clk, clk->id); | |
862 | } | |
863 | ||
08e09c26 NA |
864 | static ulong meson_pcie_pll_set_rate(struct clk *clk, ulong rate) |
865 | { | |
866 | struct meson_clk *priv = dev_get_priv(clk->dev); | |
867 | ||
868 | regmap_write(priv->map, HHI_PCIE_PLL_CNTL0, 0x20090496); | |
869 | regmap_write(priv->map, HHI_PCIE_PLL_CNTL0, 0x30090496); | |
870 | regmap_write(priv->map, HHI_PCIE_PLL_CNTL1, 0x00000000); | |
871 | regmap_write(priv->map, HHI_PCIE_PLL_CNTL2, 0x00001100); | |
872 | regmap_write(priv->map, HHI_PCIE_PLL_CNTL3, 0x10058e00); | |
873 | regmap_write(priv->map, HHI_PCIE_PLL_CNTL4, 0x000100c0); | |
874 | regmap_write(priv->map, HHI_PCIE_PLL_CNTL5, 0x68000048); | |
875 | regmap_write(priv->map, HHI_PCIE_PLL_CNTL5, 0x68000068); | |
876 | udelay(20); | |
877 | regmap_write(priv->map, HHI_PCIE_PLL_CNTL4, 0x008100c0); | |
878 | udelay(10); | |
879 | regmap_write(priv->map, HHI_PCIE_PLL_CNTL0, 0x34090496); | |
880 | regmap_write(priv->map, HHI_PCIE_PLL_CNTL0, 0x14090496); | |
881 | udelay(10); | |
882 | regmap_write(priv->map, HHI_PCIE_PLL_CNTL2, 0x00001000); | |
883 | regmap_update_bits(priv->map, HHI_PCIE_PLL_CNTL0, | |
884 | 0x1f << 16, 9 << 16); | |
885 | ||
886 | return 100000000; | |
887 | } | |
888 | ||
a0513b40 NA |
889 | static int meson_clk_set_parent(struct clk *clk, struct clk *parent) |
890 | { | |
891 | return meson_mux_set_parent(clk, clk->id, parent->id); | |
892 | } | |
893 | ||
08e09c26 NA |
894 | static ulong meson_clk_set_rate_by_id(struct clk *clk, unsigned long id, |
895 | ulong rate, ulong current_rate) | |
896 | { | |
897 | if (current_rate == rate) | |
898 | return 0; | |
899 | ||
900 | switch (id) { | |
901 | /* Fixed clocks */ | |
a0513b40 NA |
902 | case CLKID_FIXED_PLL: |
903 | case CLKID_SYS_PLL: | |
904 | case CLKID_FCLK_DIV2: | |
905 | case CLKID_FCLK_DIV3: | |
906 | case CLKID_FCLK_DIV4: | |
907 | case CLKID_FCLK_DIV5: | |
908 | case CLKID_FCLK_DIV7: | |
909 | case CLKID_MPLL0: | |
910 | case CLKID_MPLL1: | |
911 | case CLKID_MPLL2: | |
912 | case CLKID_CLK81: | |
913 | if (current_rate != rate) | |
914 | return -EINVAL; | |
08e09c26 NA |
915 | case CLKID_PCIE_PLL: |
916 | return meson_pcie_pll_set_rate(clk, rate); | |
917 | ||
a0513b40 NA |
918 | return 0; |
919 | case CLKID_VPU: | |
920 | return meson_clk_set_rate_by_id(clk, | |
921 | meson_mux_get_parent(clk, CLKID_VPU), rate, | |
922 | current_rate); | |
923 | case CLKID_VAPB: | |
924 | case CLKID_VAPB_SEL: | |
925 | return meson_clk_set_rate_by_id(clk, | |
926 | meson_mux_get_parent(clk, CLKID_VAPB_SEL), | |
927 | rate, current_rate); | |
928 | case CLKID_VPU_0: | |
929 | return meson_div_set_rate(clk, CLKID_VPU_0_DIV, rate, | |
930 | current_rate); | |
931 | case CLKID_VPU_1: | |
932 | return meson_div_set_rate(clk, CLKID_VPU_1_DIV, rate, | |
933 | current_rate); | |
934 | case CLKID_VAPB_0: | |
935 | return meson_div_set_rate(clk, CLKID_VAPB_0_DIV, rate, | |
936 | current_rate); | |
937 | case CLKID_VAPB_1: | |
938 | return meson_div_set_rate(clk, CLKID_VAPB_1_DIV, rate, | |
939 | current_rate); | |
940 | case CLKID_VPU_0_DIV: | |
941 | case CLKID_VPU_1_DIV: | |
942 | case CLKID_VAPB_0_DIV: | |
943 | case CLKID_VAPB_1_DIV: | |
944 | case CLKID_HDMI_DIV: | |
945 | return meson_div_set_rate(clk, id, rate, current_rate); | |
946 | case CLKID_HDMI: | |
947 | return meson_clk_set_rate_by_id(clk, CLKID_HDMI_DIV, | |
948 | rate, current_rate); | |
08e09c26 NA |
949 | default: |
950 | return -ENOENT; | |
951 | } | |
952 | ||
953 | return -EINVAL; | |
954 | } | |
955 | ||
08e09c26 NA |
956 | static ulong meson_clk_set_rate(struct clk *clk, ulong rate) |
957 | { | |
958 | ulong current_rate = meson_clk_get_rate_by_id(clk, clk->id); | |
959 | int ret; | |
960 | ||
961 | if (IS_ERR_VALUE(current_rate)) | |
962 | return current_rate; | |
963 | ||
964 | debug("%s: setting rate of %ld from %ld to %ld\n", | |
965 | __func__, clk->id, current_rate, rate); | |
966 | ||
967 | ret = meson_clk_set_rate_by_id(clk, clk->id, rate, current_rate); | |
968 | if (IS_ERR_VALUE(ret)) | |
969 | return ret; | |
970 | ||
971 | debug("clock %lu has new rate %lu\n", clk->id, | |
972 | meson_clk_get_rate_by_id(clk, clk->id)); | |
973 | ||
974 | return 0; | |
975 | } | |
976 | ||
912af842 JB |
977 | static int meson_clk_probe(struct udevice *dev) |
978 | { | |
979 | struct meson_clk *priv = dev_get_priv(dev); | |
980 | ||
981 | priv->map = syscon_node_to_regmap(dev_get_parent(dev)->node); | |
982 | if (IS_ERR(priv->map)) | |
983 | return PTR_ERR(priv->map); | |
984 | ||
b3d69aa5 JB |
985 | /* |
986 | * Depending on the boot src, the state of the MMC clock might | |
987 | * be different. Reset it to make sure we won't get stuck | |
988 | */ | |
989 | regmap_write(priv->map, HHI_NAND_CLK_CNTL, 0); | |
990 | regmap_write(priv->map, HHI_SD_EMMC_CLK_CNTL, 0); | |
991 | ||
912af842 JB |
992 | debug("meson-clk-g12a: probed\n"); |
993 | ||
994 | return 0; | |
995 | } | |
996 | ||
997 | static struct clk_ops meson_clk_ops = { | |
998 | .disable = meson_clk_disable, | |
999 | .enable = meson_clk_enable, | |
1000 | .get_rate = meson_clk_get_rate, | |
a0513b40 | 1001 | .set_parent = meson_clk_set_parent, |
08e09c26 | 1002 | .set_rate = meson_clk_set_rate, |
912af842 JB |
1003 | }; |
1004 | ||
1005 | static const struct udevice_id meson_clk_ids[] = { | |
1006 | { .compatible = "amlogic,g12a-clkc" }, | |
d0e8c4ad | 1007 | { .compatible = "amlogic,g12b-clkc" }, |
2168a52e | 1008 | { .compatible = "amlogic,sm1-clkc" }, |
912af842 JB |
1009 | { } |
1010 | }; | |
1011 | ||
1012 | U_BOOT_DRIVER(meson_clk_g12a) = { | |
1013 | .name = "meson_clk_g12a", | |
1014 | .id = UCLASS_CLK, | |
1015 | .of_match = meson_clk_ids, | |
1016 | .priv_auto_alloc_size = sizeof(struct meson_clk), | |
1017 | .ops = &meson_clk_ops, | |
1018 | .probe = meson_clk_probe, | |
1019 | }; |