]>
Commit | Line | Data |
---|---|---|
a245fecb HS |
1 | /* |
2 | * Copyright (c) 2014 MundoReader S.L. | |
3 | * Author: Heiko Stuebner <heiko@sntech.de> | |
4 | * | |
5 | * based on | |
6 | * | |
7 | * samsung/clk.h | |
8 | * Copyright (c) 2013 Samsung Electronics Co., Ltd. | |
9 | * Copyright (c) 2013 Linaro Ltd. | |
10 | * Author: Thomas Abraham <thomas.ab@samsung.com> | |
11 | * | |
12 | * This program is free software; you can redistribute it and/or modify | |
13 | * it under the terms of the GNU General Public License as published by | |
14 | * the Free Software Foundation; either version 2 of the License, or | |
15 | * (at your option) any later version. | |
16 | * | |
17 | * This program is distributed in the hope that it will be useful, | |
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 | * GNU General Public License for more details. | |
21 | */ | |
22 | ||
23 | #ifndef CLK_ROCKCHIP_CLK_H | |
24 | #define CLK_ROCKCHIP_CLK_H | |
25 | ||
26 | #include <linux/io.h> | |
f684ff8b SB |
27 | |
28 | struct clk; | |
a245fecb HS |
29 | |
30 | #define HIWORD_UPDATE(val, mask, shift) \ | |
31 | ((val) << (shift) | (mask) << ((shift) + 16)) | |
32 | ||
33 | /* register positions shared by RK2928, RK3066 and RK3188 */ | |
2d7884a7 | 34 | #define RK2928_PLL_CON(x) ((x) * 0x4) |
a245fecb | 35 | #define RK2928_MODE_CON 0x40 |
2d7884a7 HS |
36 | #define RK2928_CLKSEL_CON(x) ((x) * 0x4 + 0x44) |
37 | #define RK2928_CLKGATE_CON(x) ((x) * 0x4 + 0xd0) | |
a245fecb HS |
38 | #define RK2928_GLB_SRST_FST 0x100 |
39 | #define RK2928_GLB_SRST_SND 0x104 | |
2d7884a7 | 40 | #define RK2928_SOFTRST_CON(x) ((x) * 0x4 + 0x110) |
a245fecb HS |
41 | #define RK2928_MISC_CON 0x134 |
42 | ||
b9e4ba54 HS |
43 | #define RK3288_PLL_CON(x) RK2928_PLL_CON(x) |
44 | #define RK3288_MODE_CON 0x50 | |
2d7884a7 HS |
45 | #define RK3288_CLKSEL_CON(x) ((x) * 0x4 + 0x60) |
46 | #define RK3288_CLKGATE_CON(x) ((x) * 0x4 + 0x160) | |
b9e4ba54 HS |
47 | #define RK3288_GLB_SRST_FST 0x1b0 |
48 | #define RK3288_GLB_SRST_SND 0x1b4 | |
2d7884a7 | 49 | #define RK3288_SOFTRST_CON(x) ((x) * 0x4 + 0x1b8) |
b9e4ba54 | 50 | #define RK3288_MISC_CON 0x1e8 |
89bf26cb AS |
51 | #define RK3288_SDMMC_CON0 0x200 |
52 | #define RK3288_SDMMC_CON1 0x204 | |
53 | #define RK3288_SDIO0_CON0 0x208 | |
54 | #define RK3288_SDIO0_CON1 0x20c | |
55 | #define RK3288_SDIO1_CON0 0x210 | |
56 | #define RK3288_SDIO1_CON1 0x214 | |
57 | #define RK3288_EMMC_CON0 0x218 | |
58 | #define RK3288_EMMC_CON1 0x21c | |
b9e4ba54 | 59 | |
3536c97a HS |
60 | #define RK3368_PLL_CON(x) RK2928_PLL_CON(x) |
61 | #define RK3368_CLKSEL_CON(x) ((x) * 0x4 + 0x100) | |
62 | #define RK3368_CLKGATE_CON(x) ((x) * 0x4 + 0x200) | |
63 | #define RK3368_GLB_SRST_FST 0x280 | |
64 | #define RK3368_GLB_SRST_SND 0x284 | |
65 | #define RK3368_SOFTRST_CON(x) ((x) * 0x4 + 0x300) | |
66 | #define RK3368_MISC_CON 0x380 | |
67 | #define RK3368_SDMMC_CON0 0x400 | |
68 | #define RK3368_SDMMC_CON1 0x404 | |
69 | #define RK3368_SDIO0_CON0 0x408 | |
70 | #define RK3368_SDIO0_CON1 0x40c | |
71 | #define RK3368_SDIO1_CON0 0x410 | |
72 | #define RK3368_SDIO1_CON1 0x414 | |
73 | #define RK3368_EMMC_CON0 0x418 | |
74 | #define RK3368_EMMC_CON1 0x41c | |
75 | ||
90c59025 HS |
76 | enum rockchip_pll_type { |
77 | pll_rk3066, | |
78 | }; | |
79 | ||
80 | #define RK3066_PLL_RATE(_rate, _nr, _nf, _no) \ | |
81 | { \ | |
82 | .rate = _rate##U, \ | |
83 | .nr = _nr, \ | |
84 | .nf = _nf, \ | |
85 | .no = _no, \ | |
2bbfe001 | 86 | .nb = ((_nf) < 2) ? 1 : (_nf) >> 1, \ |
90c59025 HS |
87 | } |
88 | ||
2bbfe001 | 89 | #define RK3066_PLL_RATE_NB(_rate, _nr, _nf, _no, _nb) \ |
49ed9ee4 KY |
90 | { \ |
91 | .rate = _rate##U, \ | |
92 | .nr = _nr, \ | |
93 | .nf = _nf, \ | |
94 | .no = _no, \ | |
2bbfe001 | 95 | .nb = _nb, \ |
49ed9ee4 KY |
96 | } |
97 | ||
90c59025 HS |
98 | struct rockchip_pll_rate_table { |
99 | unsigned long rate; | |
100 | unsigned int nr; | |
101 | unsigned int nf; | |
102 | unsigned int no; | |
2bbfe001 | 103 | unsigned int nb; |
90c59025 HS |
104 | }; |
105 | ||
106 | /** | |
107 | * struct rockchip_pll_clock: information about pll clock | |
108 | * @id: platform specific id of the clock. | |
109 | * @name: name of this pll clock. | |
110 | * @parent_name: name of the parent clock. | |
111 | * @flags: optional flags for basic clock. | |
112 | * @con_offset: offset of the register for configuring the PLL. | |
113 | * @mode_offset: offset of the register for configuring the PLL-mode. | |
114 | * @mode_shift: offset inside the mode-register for the mode of this pll. | |
115 | * @lock_shift: offset inside the lock register for the lock status. | |
116 | * @type: Type of PLL to be registered. | |
4f8a7c54 | 117 | * @pll_flags: hardware-specific flags |
90c59025 | 118 | * @rate_table: Table of usable pll rates |
0bb66d3b HS |
119 | * |
120 | * Flags: | |
121 | * ROCKCHIP_PLL_SYNC_RATE - check rate parameters to match against the | |
122 | * rate_table parameters and ajust them if necessary. | |
90c59025 HS |
123 | */ |
124 | struct rockchip_pll_clock { | |
125 | unsigned int id; | |
126 | const char *name; | |
4a1caed3 | 127 | const char *const *parent_names; |
90c59025 HS |
128 | u8 num_parents; |
129 | unsigned long flags; | |
130 | int con_offset; | |
131 | int mode_offset; | |
132 | int mode_shift; | |
133 | int lock_shift; | |
134 | enum rockchip_pll_type type; | |
4f8a7c54 | 135 | u8 pll_flags; |
90c59025 HS |
136 | struct rockchip_pll_rate_table *rate_table; |
137 | }; | |
138 | ||
0bb66d3b HS |
139 | #define ROCKCHIP_PLL_SYNC_RATE BIT(0) |
140 | ||
90c59025 | 141 | #define PLL(_type, _id, _name, _pnames, _flags, _con, _mode, _mshift, \ |
4f8a7c54 | 142 | _lshift, _pflags, _rtable) \ |
90c59025 HS |
143 | { \ |
144 | .id = _id, \ | |
145 | .type = _type, \ | |
146 | .name = _name, \ | |
147 | .parent_names = _pnames, \ | |
148 | .num_parents = ARRAY_SIZE(_pnames), \ | |
149 | .flags = CLK_GET_RATE_NOCACHE | _flags, \ | |
150 | .con_offset = _con, \ | |
151 | .mode_offset = _mode, \ | |
152 | .mode_shift = _mshift, \ | |
153 | .lock_shift = _lshift, \ | |
4f8a7c54 | 154 | .pll_flags = _pflags, \ |
90c59025 HS |
155 | .rate_table = _rtable, \ |
156 | } | |
157 | ||
158 | struct clk *rockchip_clk_register_pll(enum rockchip_pll_type pll_type, | |
4a1caed3 UKK |
159 | const char *name, const char *const *parent_names, |
160 | u8 num_parents, void __iomem *base, int con_offset, | |
161 | int grf_lock_offset, int lock_shift, int reg_mode, | |
162 | int mode_shift, struct rockchip_pll_rate_table *rate_table, | |
4f8a7c54 | 163 | u8 clk_pll_flags, spinlock_t *lock); |
90c59025 | 164 | |
f6fba5f6 HS |
165 | struct rockchip_cpuclk_clksel { |
166 | int reg; | |
167 | u32 val; | |
168 | }; | |
169 | ||
170 | #define ROCKCHIP_CPUCLK_NUM_DIVIDERS 2 | |
171 | struct rockchip_cpuclk_rate_table { | |
172 | unsigned long prate; | |
173 | struct rockchip_cpuclk_clksel divs[ROCKCHIP_CPUCLK_NUM_DIVIDERS]; | |
174 | }; | |
175 | ||
176 | /** | |
177 | * struct rockchip_cpuclk_reg_data: describes register offsets and masks of the cpuclock | |
178 | * @core_reg: register offset of the core settings register | |
179 | * @div_core_shift: core divider offset used to divide the pll value | |
180 | * @div_core_mask: core divider mask | |
181 | * @mux_core_shift: offset of the core multiplexer | |
182 | */ | |
183 | struct rockchip_cpuclk_reg_data { | |
184 | int core_reg; | |
185 | u8 div_core_shift; | |
186 | u32 div_core_mask; | |
187 | int mux_core_reg; | |
188 | u8 mux_core_shift; | |
189 | }; | |
190 | ||
191 | struct clk *rockchip_clk_register_cpuclk(const char *name, | |
4a1caed3 | 192 | const char *const *parent_names, u8 num_parents, |
f6fba5f6 HS |
193 | const struct rockchip_cpuclk_reg_data *reg_data, |
194 | const struct rockchip_cpuclk_rate_table *rates, | |
195 | int nrates, void __iomem *reg_base, spinlock_t *lock); | |
196 | ||
89bf26cb | 197 | struct clk *rockchip_clk_register_mmc(const char *name, |
4a1caed3 | 198 | const char *const *parent_names, u8 num_parents, |
89bf26cb AS |
199 | void __iomem *reg, int shift); |
200 | ||
8a76f443 HS |
201 | #define ROCKCHIP_INVERTER_HIWORD_MASK BIT(0) |
202 | ||
203 | struct clk *rockchip_clk_register_inverter(const char *name, | |
204 | const char *const *parent_names, u8 num_parents, | |
205 | void __iomem *reg, int shift, int flags, | |
206 | spinlock_t *lock); | |
207 | ||
4a1caed3 | 208 | #define PNAME(x) static const char *const x[] __initconst |
a245fecb HS |
209 | |
210 | enum rockchip_clk_branch_type { | |
211 | branch_composite, | |
212 | branch_mux, | |
213 | branch_divider, | |
214 | branch_fraction_divider, | |
215 | branch_gate, | |
89bf26cb | 216 | branch_mmc, |
8a76f443 | 217 | branch_inverter, |
a245fecb HS |
218 | }; |
219 | ||
220 | struct rockchip_clk_branch { | |
221 | unsigned int id; | |
222 | enum rockchip_clk_branch_type branch_type; | |
223 | const char *name; | |
4a1caed3 | 224 | const char *const *parent_names; |
a245fecb HS |
225 | u8 num_parents; |
226 | unsigned long flags; | |
227 | int muxdiv_offset; | |
228 | u8 mux_shift; | |
229 | u8 mux_width; | |
230 | u8 mux_flags; | |
231 | u8 div_shift; | |
232 | u8 div_width; | |
233 | u8 div_flags; | |
234 | struct clk_div_table *div_table; | |
235 | int gate_offset; | |
236 | u8 gate_shift; | |
237 | u8 gate_flags; | |
238 | }; | |
239 | ||
240 | #define COMPOSITE(_id, cname, pnames, f, mo, ms, mw, mf, ds, dw,\ | |
241 | df, go, gs, gf) \ | |
242 | { \ | |
243 | .id = _id, \ | |
244 | .branch_type = branch_composite, \ | |
245 | .name = cname, \ | |
246 | .parent_names = pnames, \ | |
247 | .num_parents = ARRAY_SIZE(pnames), \ | |
248 | .flags = f, \ | |
249 | .muxdiv_offset = mo, \ | |
250 | .mux_shift = ms, \ | |
251 | .mux_width = mw, \ | |
252 | .mux_flags = mf, \ | |
253 | .div_shift = ds, \ | |
254 | .div_width = dw, \ | |
255 | .div_flags = df, \ | |
256 | .gate_offset = go, \ | |
257 | .gate_shift = gs, \ | |
258 | .gate_flags = gf, \ | |
259 | } | |
260 | ||
261 | #define COMPOSITE_NOMUX(_id, cname, pname, f, mo, ds, dw, df, \ | |
262 | go, gs, gf) \ | |
263 | { \ | |
264 | .id = _id, \ | |
265 | .branch_type = branch_composite, \ | |
266 | .name = cname, \ | |
267 | .parent_names = (const char *[]){ pname }, \ | |
268 | .num_parents = 1, \ | |
269 | .flags = f, \ | |
270 | .muxdiv_offset = mo, \ | |
271 | .div_shift = ds, \ | |
272 | .div_width = dw, \ | |
273 | .div_flags = df, \ | |
274 | .gate_offset = go, \ | |
275 | .gate_shift = gs, \ | |
276 | .gate_flags = gf, \ | |
277 | } | |
278 | ||
279 | #define COMPOSITE_NOMUX_DIVTBL(_id, cname, pname, f, mo, ds, dw,\ | |
280 | df, dt, go, gs, gf) \ | |
281 | { \ | |
282 | .id = _id, \ | |
283 | .branch_type = branch_composite, \ | |
284 | .name = cname, \ | |
285 | .parent_names = (const char *[]){ pname }, \ | |
286 | .num_parents = 1, \ | |
287 | .flags = f, \ | |
288 | .muxdiv_offset = mo, \ | |
289 | .div_shift = ds, \ | |
290 | .div_width = dw, \ | |
291 | .div_flags = df, \ | |
292 | .div_table = dt, \ | |
293 | .gate_offset = go, \ | |
294 | .gate_shift = gs, \ | |
295 | .gate_flags = gf, \ | |
296 | } | |
297 | ||
298 | #define COMPOSITE_NODIV(_id, cname, pnames, f, mo, ms, mw, mf, \ | |
299 | go, gs, gf) \ | |
300 | { \ | |
301 | .id = _id, \ | |
302 | .branch_type = branch_composite, \ | |
303 | .name = cname, \ | |
304 | .parent_names = pnames, \ | |
305 | .num_parents = ARRAY_SIZE(pnames), \ | |
306 | .flags = f, \ | |
307 | .muxdiv_offset = mo, \ | |
308 | .mux_shift = ms, \ | |
309 | .mux_width = mw, \ | |
310 | .mux_flags = mf, \ | |
311 | .gate_offset = go, \ | |
312 | .gate_shift = gs, \ | |
313 | .gate_flags = gf, \ | |
314 | } | |
315 | ||
316 | #define COMPOSITE_NOGATE(_id, cname, pnames, f, mo, ms, mw, mf, \ | |
317 | ds, dw, df) \ | |
318 | { \ | |
319 | .id = _id, \ | |
320 | .branch_type = branch_composite, \ | |
321 | .name = cname, \ | |
322 | .parent_names = pnames, \ | |
323 | .num_parents = ARRAY_SIZE(pnames), \ | |
324 | .flags = f, \ | |
325 | .muxdiv_offset = mo, \ | |
326 | .mux_shift = ms, \ | |
327 | .mux_width = mw, \ | |
328 | .mux_flags = mf, \ | |
329 | .div_shift = ds, \ | |
330 | .div_width = dw, \ | |
331 | .div_flags = df, \ | |
332 | .gate_offset = -1, \ | |
333 | } | |
334 | ||
6f085072 HS |
335 | #define COMPOSITE_NOGATE_DIVTBL(_id, cname, pnames, f, mo, ms, \ |
336 | mw, mf, ds, dw, df, dt) \ | |
337 | { \ | |
338 | .id = _id, \ | |
339 | .branch_type = branch_composite, \ | |
340 | .name = cname, \ | |
341 | .parent_names = pnames, \ | |
342 | .num_parents = ARRAY_SIZE(pnames), \ | |
343 | .flags = f, \ | |
344 | .muxdiv_offset = mo, \ | |
345 | .mux_shift = ms, \ | |
346 | .mux_width = mw, \ | |
347 | .mux_flags = mf, \ | |
348 | .div_shift = ds, \ | |
349 | .div_width = dw, \ | |
350 | .div_flags = df, \ | |
351 | .div_table = dt, \ | |
352 | .gate_offset = -1, \ | |
353 | } | |
354 | ||
a245fecb HS |
355 | #define COMPOSITE_FRAC(_id, cname, pname, f, mo, df, go, gs, gf)\ |
356 | { \ | |
357 | .id = _id, \ | |
358 | .branch_type = branch_fraction_divider, \ | |
359 | .name = cname, \ | |
360 | .parent_names = (const char *[]){ pname }, \ | |
361 | .num_parents = 1, \ | |
362 | .flags = f, \ | |
363 | .muxdiv_offset = mo, \ | |
364 | .div_shift = 16, \ | |
365 | .div_width = 16, \ | |
366 | .div_flags = df, \ | |
367 | .gate_offset = go, \ | |
368 | .gate_shift = gs, \ | |
369 | .gate_flags = gf, \ | |
370 | } | |
371 | ||
372 | #define MUX(_id, cname, pnames, f, o, s, w, mf) \ | |
373 | { \ | |
374 | .id = _id, \ | |
375 | .branch_type = branch_mux, \ | |
376 | .name = cname, \ | |
377 | .parent_names = pnames, \ | |
378 | .num_parents = ARRAY_SIZE(pnames), \ | |
379 | .flags = f, \ | |
380 | .muxdiv_offset = o, \ | |
381 | .mux_shift = s, \ | |
382 | .mux_width = w, \ | |
383 | .mux_flags = mf, \ | |
384 | .gate_offset = -1, \ | |
385 | } | |
386 | ||
387 | #define DIV(_id, cname, pname, f, o, s, w, df) \ | |
388 | { \ | |
389 | .id = _id, \ | |
390 | .branch_type = branch_divider, \ | |
391 | .name = cname, \ | |
392 | .parent_names = (const char *[]){ pname }, \ | |
393 | .num_parents = 1, \ | |
394 | .flags = f, \ | |
395 | .muxdiv_offset = o, \ | |
396 | .div_shift = s, \ | |
397 | .div_width = w, \ | |
398 | .div_flags = df, \ | |
399 | .gate_offset = -1, \ | |
400 | } | |
401 | ||
402 | #define DIVTBL(_id, cname, pname, f, o, s, w, df, dt) \ | |
403 | { \ | |
404 | .id = _id, \ | |
405 | .branch_type = branch_divider, \ | |
406 | .name = cname, \ | |
407 | .parent_names = (const char *[]){ pname }, \ | |
408 | .num_parents = 1, \ | |
409 | .flags = f, \ | |
410 | .muxdiv_offset = o, \ | |
411 | .div_shift = s, \ | |
412 | .div_width = w, \ | |
413 | .div_flags = df, \ | |
414 | .div_table = dt, \ | |
415 | } | |
416 | ||
417 | #define GATE(_id, cname, pname, f, o, b, gf) \ | |
418 | { \ | |
419 | .id = _id, \ | |
420 | .branch_type = branch_gate, \ | |
421 | .name = cname, \ | |
422 | .parent_names = (const char *[]){ pname }, \ | |
423 | .num_parents = 1, \ | |
424 | .flags = f, \ | |
425 | .gate_offset = o, \ | |
426 | .gate_shift = b, \ | |
427 | .gate_flags = gf, \ | |
428 | } | |
429 | ||
89bf26cb AS |
430 | #define MMC(_id, cname, pname, offset, shift) \ |
431 | { \ | |
432 | .id = _id, \ | |
433 | .branch_type = branch_mmc, \ | |
434 | .name = cname, \ | |
435 | .parent_names = (const char *[]){ pname }, \ | |
436 | .num_parents = 1, \ | |
437 | .muxdiv_offset = offset, \ | |
438 | .div_shift = shift, \ | |
439 | } | |
a245fecb | 440 | |
8a76f443 HS |
441 | #define INVERTER(_id, cname, pname, io, is, if) \ |
442 | { \ | |
443 | .id = _id, \ | |
444 | .branch_type = branch_inverter, \ | |
445 | .name = cname, \ | |
446 | .parent_names = (const char *[]){ pname }, \ | |
447 | .num_parents = 1, \ | |
448 | .muxdiv_offset = io, \ | |
449 | .div_shift = is, \ | |
450 | .div_flags = if, \ | |
451 | } | |
452 | ||
a245fecb HS |
453 | void rockchip_clk_init(struct device_node *np, void __iomem *base, |
454 | unsigned long nr_clks); | |
90c59025 | 455 | struct regmap *rockchip_clk_get_grf(void); |
a245fecb HS |
456 | void rockchip_clk_add_lookup(struct clk *clk, unsigned int id); |
457 | void rockchip_clk_register_branches(struct rockchip_clk_branch *clk_list, | |
458 | unsigned int nr_clk); | |
90c59025 HS |
459 | void rockchip_clk_register_plls(struct rockchip_pll_clock *pll_list, |
460 | unsigned int nr_pll, int grf_lock_offset); | |
f6fba5f6 | 461 | void rockchip_clk_register_armclk(unsigned int lookup_id, const char *name, |
4a1caed3 | 462 | const char *const *parent_names, u8 num_parents, |
f6fba5f6 HS |
463 | const struct rockchip_cpuclk_reg_data *reg_data, |
464 | const struct rockchip_cpuclk_rate_table *rates, | |
465 | int nrates); | |
692d8328 | 466 | void rockchip_clk_protect_critical(const char *const clocks[], int nclocks); |
6f1294b5 | 467 | void rockchip_register_restart_notifier(unsigned int reg); |
a245fecb | 468 | |
85fa0c7f HS |
469 | #define ROCKCHIP_SOFTRST_HIWORD_MASK BIT(0) |
470 | ||
471 | #ifdef CONFIG_RESET_CONTROLLER | |
472 | void rockchip_register_softrst(struct device_node *np, | |
473 | unsigned int num_regs, | |
474 | void __iomem *base, u8 flags); | |
475 | #else | |
476 | static inline void rockchip_register_softrst(struct device_node *np, | |
477 | unsigned int num_regs, | |
478 | void __iomem *base, u8 flags) | |
479 | { | |
480 | } | |
481 | #endif | |
482 | ||
a245fecb | 483 | #endif |