CLK: ARC: HSDK: prepare for multiple clock maps support
[platform/kernel/u-boot.git] / drivers / clk / clk-hsdk-cgu.c
1 /*
2  * Synopsys HSDK SDP CGU clock driver
3  *
4  * Copyright (C) 2017 Synopsys
5  * Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
6  *
7  * This file is licensed under the terms of the GNU General Public
8  * License version 2. This program is licensed "as is" without any
9  * warranty of any kind, whether express or implied.
10  */
11
12 #include <common.h>
13 #include <clk-uclass.h>
14 #include <div64.h>
15 #include <dm.h>
16 #include <linux/io.h>
17
18 /*
19  * Synopsys ARC HSDK clock tree.
20  *
21  *   ------------------
22  *   | 33.33 MHz xtal |
23  *   ------------------
24  *            |
25  *            |   -----------
26  *            |-->| ARC PLL |
27  *            |   -----------
28  *            |        |
29  *            |        |-->|CGU_ARC_IDIV|----------->
30  *            |        |-->|CREG_CORE_IF_DIV|------->
31  *            |
32  *            |   --------------
33  *            |-->| SYSTEM PLL |
34  *            |   --------------
35  *            |        |
36  *            |        |-->|CGU_SYS_IDIV_APB|------->
37  *            |        |-->|CGU_SYS_IDIV_AXI|------->
38  *            |        |-->|CGU_SYS_IDIV_*|--------->
39  *            |        |-->|CGU_SYS_IDIV_EBI_REF|--->
40  *            |
41  *            |   --------------
42  *            |-->| TUNNEL PLL |
43  *            |   --------------
44  *            |        |
45  *            |        |-->|CGU_TUN_IDIV_TUN|----------->
46  *            |        |-->|CGU_TUN_IDIV_ROM|----------->
47  *            |        |-->|CGU_TUN_IDIV_PWM|----------->
48  *            |
49  *            |   -----------
50  *            |-->| DDR PLL |
51  *                -----------
52  *                     |
53  *                     |---------------------------->
54  *
55  *   ------------------
56  *   | 27.00 MHz xtal |
57  *   ------------------
58  *            |
59  *            |   ------------
60  *            |-->| HDMI PLL |
61  *                ------------
62  *                     |
63  *                     |-->|CGU_HDMI_IDIV_APB|------>
64  */
65
66 #define CGU_ARC_IDIV            0x080
67 #define CGU_TUN_IDIV_TUN        0x380
68 #define CGU_TUN_IDIV_ROM        0x390
69 #define CGU_TUN_IDIV_PWM        0x3A0
70 #define CGU_TUN_IDIV_TIMER      0x3B0
71 #define CGU_HDMI_IDIV_APB       0x480
72 #define CGU_SYS_IDIV_APB        0x180
73 #define CGU_SYS_IDIV_AXI        0x190
74 #define CGU_SYS_IDIV_ETH        0x1A0
75 #define CGU_SYS_IDIV_USB        0x1B0
76 #define CGU_SYS_IDIV_SDIO       0x1C0
77 #define CGU_SYS_IDIV_HDMI       0x1D0
78 #define CGU_SYS_IDIV_GFX_CORE   0x1E0
79 #define CGU_SYS_IDIV_GFX_DMA    0x1F0
80 #define CGU_SYS_IDIV_GFX_CFG    0x200
81 #define CGU_SYS_IDIV_DMAC_CORE  0x210
82 #define CGU_SYS_IDIV_DMAC_CFG   0x220
83 #define CGU_SYS_IDIV_SDIO_REF   0x230
84 #define CGU_SYS_IDIV_SPI_REF    0x240
85 #define CGU_SYS_IDIV_I2C_REF    0x250
86 #define CGU_SYS_IDIV_UART_REF   0x260
87 #define CGU_SYS_IDIV_EBI_REF    0x270
88
89 #define CGU_IDIV_MASK           0xFF /* All idiv have 8 significant bits */
90
91 #define CGU_ARC_PLL             0x0
92 #define CGU_SYS_PLL             0x10
93 #define CGU_DDR_PLL             0x20
94 #define CGU_TUN_PLL             0x30
95 #define CGU_HDMI_PLL            0x40
96
97 #define CGU_PLL_CTRL            0x000 /* ARC PLL control register */
98 #define CGU_PLL_STATUS          0x004 /* ARC PLL status register */
99 #define CGU_PLL_FMEAS           0x008 /* ARC PLL frequency measurement register */
100 #define CGU_PLL_MON             0x00C /* ARC PLL monitor register */
101
102 #define CGU_PLL_CTRL_ODIV_SHIFT         2
103 #define CGU_PLL_CTRL_IDIV_SHIFT         4
104 #define CGU_PLL_CTRL_FBDIV_SHIFT        9
105 #define CGU_PLL_CTRL_BAND_SHIFT         20
106
107 #define CGU_PLL_CTRL_ODIV_MASK          GENMASK(3, CGU_PLL_CTRL_ODIV_SHIFT)
108 #define CGU_PLL_CTRL_IDIV_MASK          GENMASK(8, CGU_PLL_CTRL_IDIV_SHIFT)
109 #define CGU_PLL_CTRL_FBDIV_MASK         GENMASK(15, CGU_PLL_CTRL_FBDIV_SHIFT)
110
111 #define CGU_PLL_CTRL_PD                 BIT(0)
112 #define CGU_PLL_CTRL_BYPASS             BIT(1)
113
114 #define CGU_PLL_STATUS_LOCK             BIT(0)
115 #define CGU_PLL_STATUS_ERR              BIT(1)
116
117 #define HSDK_PLL_MAX_LOCK_TIME          100 /* 100 us */
118
119 #define CREG_CORE_IF_DIV                0x000 /* ARC CORE interface divider */
120 #define CORE_IF_CLK_THRESHOLD_HZ        500000000
121 #define CREG_CORE_IF_CLK_DIV_1          0x0
122 #define CREG_CORE_IF_CLK_DIV_2          0x1
123
124 #define MIN_PLL_RATE                    100000000 /* 100 MHz */
125 #define PARENT_RATE_33                  33333333 /* fixed clock - xtal */
126 #define PARENT_RATE_27                  27000000 /* fixed clock - xtal */
127 #define CGU_MAX_CLOCKS                  27
128
129 #define MAX_FREQ_VARIATIONS             6
130
131 struct hsdk_idiv_cfg {
132         const u32 oft;
133         const u8  val[MAX_FREQ_VARIATIONS];
134 };
135
136 struct hsdk_div_full_cfg {
137         const u32 clk_rate[MAX_FREQ_VARIATIONS];
138         const u32 pll_rate[MAX_FREQ_VARIATIONS];
139         const struct hsdk_idiv_cfg idiv[];
140 };
141
142 static const struct hsdk_div_full_cfg tun_clk_cfg = {
143         { 25000000,  50000000,  75000000,  100000000, 125000000, 150000000 },
144         { 600000000, 600000000, 600000000, 600000000, 750000000, 600000000 }, {
145         { CGU_TUN_IDIV_TUN,     { 24,   12,     8,      6,      6,      4 } },
146         { CGU_TUN_IDIV_ROM,     { 4,    4,      4,      4,      5,      4 } },
147         { CGU_TUN_IDIV_PWM,     { 8,    8,      8,      8,      10,     8 } },
148         { CGU_TUN_IDIV_TIMER,   { 12,   12,     12,     12,     15,     12 } },
149         { /* last one */ }
150         }
151 };
152
153 static const struct hsdk_div_full_cfg axi_clk_cfg = {
154         { 200000000,    400000000,      600000000,      800000000 },
155         { 800000000,    800000000,      600000000,      800000000 }, {
156         { CGU_SYS_IDIV_APB,      { 4,   4,      3,      4 } },  /* APB */
157         { CGU_SYS_IDIV_AXI,      { 4,   2,      1,      1 } },  /* AXI */
158         { CGU_SYS_IDIV_ETH,      { 2,   2,      2,      2 } },  /* ETH */
159         { CGU_SYS_IDIV_USB,      { 2,   2,      2,      2 } },  /* USB */
160         { CGU_SYS_IDIV_SDIO,     { 2,   2,      2,      2 } },  /* SDIO */
161         { CGU_SYS_IDIV_HDMI,     { 2,   2,      2,      2 } },  /* HDMI */
162         { CGU_SYS_IDIV_GFX_CORE, { 1,   1,      1,      1 } },  /* GPU-CORE */
163         { CGU_SYS_IDIV_GFX_DMA,  { 2,   2,      2,      2 } },  /* GPU-DMA */
164         { CGU_SYS_IDIV_GFX_CFG,  { 4,   4,      3,      4 } },  /* GPU-CFG */
165         { CGU_SYS_IDIV_DMAC_CORE,{ 2,   2,      2,      2 } },  /* DMAC-CORE */
166         { CGU_SYS_IDIV_DMAC_CFG, { 4,   4,      3,      4 } },  /* DMAC-CFG */
167         { CGU_SYS_IDIV_SDIO_REF, { 8,   8,      6,      8 } },  /* SDIO-REF */
168         { CGU_SYS_IDIV_SPI_REF,  { 24,  24,     18,     24 } }, /* SPI-REF */
169         { CGU_SYS_IDIV_I2C_REF,  { 4,   4,      3,      4 } },  /* I2C-REF */
170         { CGU_SYS_IDIV_UART_REF, { 24,  24,     18,     24 } }, /* UART-REF */
171         { CGU_SYS_IDIV_EBI_REF,  { 16,  16,     12,     16 } }, /* EBI-REF */
172         { /* last one */ }
173         }
174 };
175
176 struct hsdk_pll_cfg {
177         const u32 rate;
178         const u8  idiv;
179         const u8  fbdiv;
180         const u8  odiv;
181         const u8  band;
182 };
183
184 static const struct hsdk_pll_cfg asdt_pll_cfg[] = {
185         { 100000000,  0, 11, 3, 0 },
186         { 125000000,  0, 14, 3, 0 },
187         { 133000000,  0, 15, 3, 0 },
188         { 150000000,  0, 17, 3, 0 },
189         { 200000000,  1, 47, 3, 0 },
190         { 233000000,  1, 27, 2, 0 },
191         { 300000000,  1, 35, 2, 0 },
192         { 333000000,  1, 39, 2, 0 },
193         { 400000000,  1, 47, 2, 0 },
194         { 500000000,  0, 14, 1, 0 },
195         { 600000000,  0, 17, 1, 0 },
196         { 700000000,  0, 20, 1, 0 },
197         { 750000000,  1, 44, 1, 0 },
198         { 800000000,  0, 23, 1, 0 },
199         { 900000000,  1, 26, 0, 0 },
200         { 1000000000, 1, 29, 0, 0 },
201         { 1100000000, 1, 32, 0, 0 },
202         { 1200000000, 1, 35, 0, 0 },
203         { 1300000000, 1, 38, 0, 0 },
204         { 1400000000, 1, 41, 0, 0 },
205         { 1500000000, 1, 44, 0, 0 },
206         { 1600000000, 1, 47, 0, 0 },
207         {}
208 };
209
210 static const struct hsdk_pll_cfg hdmi_pll_cfg[] = {
211         { 297000000,  0, 21, 2, 0 },
212         { 540000000,  0, 19, 1, 0 },
213         { 594000000,  0, 21, 1, 0 },
214         {}
215 };
216
217 struct hsdk_cgu_domain {
218         /* PLLs registers */
219         void __iomem *pll_regs;
220         /* PLLs special registers */
221         void __iomem *spec_regs;
222         /* PLLs devdata */
223         const struct hsdk_pll_devdata *pll;
224
225         /* Dividers registers */
226         void __iomem *idiv_regs;
227 };
228
229 struct hsdk_cgu_clk {
230         const struct cgu_clk_map *map;
231         /* CGU block register */
232         void __iomem *cgu_regs;
233         /* CREG block register */
234         void __iomem *creg_regs;
235
236         /* The domain we are working with */
237         struct hsdk_cgu_domain curr_domain;
238 };
239
240 struct hsdk_pll_devdata {
241         const u32 parent_rate;
242         const struct hsdk_pll_cfg *const pll_cfg;
243         const int (*const update_rate)(struct hsdk_cgu_clk *clk,
244                                        unsigned long rate,
245                                        const struct hsdk_pll_cfg *cfg);
246 };
247
248 static int hsdk_pll_core_update_rate(struct hsdk_cgu_clk *, unsigned long,
249                                      const struct hsdk_pll_cfg *);
250 static int hsdk_pll_comm_update_rate(struct hsdk_cgu_clk *, unsigned long,
251                                      const struct hsdk_pll_cfg *);
252
253 static const struct hsdk_pll_devdata core_pll_dat = {
254         .parent_rate = PARENT_RATE_33,
255         .pll_cfg = asdt_pll_cfg,
256         .update_rate = hsdk_pll_core_update_rate,
257 };
258
259 static const struct hsdk_pll_devdata sdt_pll_dat = {
260         .parent_rate = PARENT_RATE_33,
261         .pll_cfg = asdt_pll_cfg,
262         .update_rate = hsdk_pll_comm_update_rate,
263 };
264
265 static const struct hsdk_pll_devdata hdmi_pll_dat = {
266         .parent_rate = PARENT_RATE_27,
267         .pll_cfg = hdmi_pll_cfg,
268         .update_rate = hsdk_pll_comm_update_rate,
269 };
270
271 static ulong idiv_set(struct clk *, ulong);
272 static ulong cpu_clk_set(struct clk *, ulong);
273 static ulong axi_clk_set(struct clk *, ulong);
274 static ulong tun_clk_set(struct clk *, ulong);
275 static ulong idiv_get(struct clk *);
276 static int idiv_off(struct clk *);
277 static ulong pll_set(struct clk *, ulong);
278 static ulong pll_get(struct clk *);
279
280 struct cgu_clk_map {
281         const u32 cgu_pll_oft;
282         const u32 cgu_div_oft;
283         const struct hsdk_pll_devdata *const pll_devdata;
284         const ulong (*const get_rate)(struct clk *clk);
285         const ulong (*const set_rate)(struct clk *clk, ulong rate);
286         const int (*const disable)(struct clk *clk);
287 };
288
289 static const struct cgu_clk_map clock_map[] = {
290         { CGU_ARC_PLL, 0, &core_pll_dat, pll_get, pll_set, NULL },
291         { CGU_ARC_PLL, CGU_ARC_IDIV, &core_pll_dat, idiv_get, cpu_clk_set, idiv_off },
292         { CGU_DDR_PLL, 0, &sdt_pll_dat, pll_get, pll_set, NULL },
293         { CGU_SYS_PLL, 0, &sdt_pll_dat, pll_get, pll_set, NULL },
294         { CGU_SYS_PLL, CGU_SYS_IDIV_APB, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
295         { CGU_SYS_PLL, CGU_SYS_IDIV_AXI, &sdt_pll_dat, idiv_get, axi_clk_set, idiv_off },
296         { CGU_SYS_PLL, CGU_SYS_IDIV_ETH, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
297         { CGU_SYS_PLL, CGU_SYS_IDIV_USB, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
298         { CGU_SYS_PLL, CGU_SYS_IDIV_SDIO, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
299         { CGU_SYS_PLL, CGU_SYS_IDIV_HDMI, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
300         { CGU_SYS_PLL, CGU_SYS_IDIV_GFX_CORE, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
301         { CGU_SYS_PLL, CGU_SYS_IDIV_GFX_DMA, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
302         { CGU_SYS_PLL, CGU_SYS_IDIV_GFX_CFG, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
303         { CGU_SYS_PLL, CGU_SYS_IDIV_DMAC_CORE, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
304         { CGU_SYS_PLL, CGU_SYS_IDIV_DMAC_CFG, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
305         { CGU_SYS_PLL, CGU_SYS_IDIV_SDIO_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
306         { CGU_SYS_PLL, CGU_SYS_IDIV_SPI_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
307         { CGU_SYS_PLL, CGU_SYS_IDIV_I2C_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
308         { CGU_SYS_PLL, CGU_SYS_IDIV_UART_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
309         { CGU_SYS_PLL, CGU_SYS_IDIV_EBI_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
310         { CGU_TUN_PLL, 0, &sdt_pll_dat, pll_get, pll_set, NULL },
311         { CGU_TUN_PLL, CGU_TUN_IDIV_TUN, &sdt_pll_dat, idiv_get, tun_clk_set, idiv_off },
312         { CGU_TUN_PLL, CGU_TUN_IDIV_ROM, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
313         { CGU_TUN_PLL, CGU_TUN_IDIV_PWM, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
314         { CGU_TUN_PLL, CGU_TUN_IDIV_TIMER, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
315         { CGU_HDMI_PLL, 0, &hdmi_pll_dat, pll_get, pll_set, NULL },
316         { CGU_HDMI_PLL, CGU_HDMI_IDIV_APB, &hdmi_pll_dat, idiv_get, idiv_set, idiv_off }
317 };
318
319 static inline void hsdk_idiv_write(struct hsdk_cgu_clk *clk, u32 val)
320 {
321         iowrite32(val, clk->curr_domain.idiv_regs);
322 }
323
324 static inline u32 hsdk_idiv_read(struct hsdk_cgu_clk *clk)
325 {
326         return ioread32(clk->curr_domain.idiv_regs);
327 }
328
329 static inline void hsdk_pll_write(struct hsdk_cgu_clk *clk, u32 reg, u32 val)
330 {
331         iowrite32(val, clk->curr_domain.pll_regs + reg);
332 }
333
334 static inline u32 hsdk_pll_read(struct hsdk_cgu_clk *clk, u32 reg)
335 {
336         return ioread32(clk->curr_domain.pll_regs + reg);
337 }
338
339 static inline void hsdk_pll_spcwrite(struct hsdk_cgu_clk *clk, u32 reg, u32 val)
340 {
341         iowrite32(val, clk->curr_domain.spec_regs + reg);
342 }
343
344 static inline u32 hsdk_pll_spcread(struct hsdk_cgu_clk *clk, u32 reg)
345 {
346         return ioread32(clk->curr_domain.spec_regs + reg);
347 }
348
349 static inline void hsdk_pll_set_cfg(struct hsdk_cgu_clk *clk,
350                                     const struct hsdk_pll_cfg *cfg)
351 {
352         u32 val = 0;
353
354         /* Powerdown and Bypass bits should be cleared */
355         val |= (u32)cfg->idiv << CGU_PLL_CTRL_IDIV_SHIFT;
356         val |= (u32)cfg->fbdiv << CGU_PLL_CTRL_FBDIV_SHIFT;
357         val |= (u32)cfg->odiv << CGU_PLL_CTRL_ODIV_SHIFT;
358         val |= (u32)cfg->band << CGU_PLL_CTRL_BAND_SHIFT;
359
360         pr_debug("write configurarion: %#x\n", val);
361
362         hsdk_pll_write(clk, CGU_PLL_CTRL, val);
363 }
364
365 static inline bool hsdk_pll_is_locked(struct hsdk_cgu_clk *clk)
366 {
367         return !!(hsdk_pll_read(clk, CGU_PLL_STATUS) & CGU_PLL_STATUS_LOCK);
368 }
369
370 static inline bool hsdk_pll_is_err(struct hsdk_cgu_clk *clk)
371 {
372         return !!(hsdk_pll_read(clk, CGU_PLL_STATUS) & CGU_PLL_STATUS_ERR);
373 }
374
375 static ulong pll_get(struct clk *sclk)
376 {
377         u32 val;
378         u64 rate;
379         u32 idiv, fbdiv, odiv;
380         struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
381         u32 parent_rate = clk->curr_domain.pll->parent_rate;
382
383         val = hsdk_pll_read(clk, CGU_PLL_CTRL);
384
385         pr_debug("current configurarion: %#x\n", val);
386
387         /* Check if PLL is bypassed */
388         if (val & CGU_PLL_CTRL_BYPASS)
389                 return parent_rate;
390
391         /* Check if PLL is disabled */
392         if (val & CGU_PLL_CTRL_PD)
393                 return 0;
394
395         /* input divider = reg.idiv + 1 */
396         idiv = 1 + ((val & CGU_PLL_CTRL_IDIV_MASK) >> CGU_PLL_CTRL_IDIV_SHIFT);
397         /* fb divider = 2*(reg.fbdiv + 1) */
398         fbdiv = 2 * (1 + ((val & CGU_PLL_CTRL_FBDIV_MASK) >> CGU_PLL_CTRL_FBDIV_SHIFT));
399         /* output divider = 2^(reg.odiv) */
400         odiv = 1 << ((val & CGU_PLL_CTRL_ODIV_MASK) >> CGU_PLL_CTRL_ODIV_SHIFT);
401
402         rate = (u64)parent_rate * fbdiv;
403         do_div(rate, idiv * odiv);
404
405         return rate;
406 }
407
408 static unsigned long hsdk_pll_round_rate(struct clk *sclk, unsigned long rate)
409 {
410         int i;
411         unsigned long best_rate;
412         struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
413         const struct hsdk_pll_cfg *pll_cfg = clk->curr_domain.pll->pll_cfg;
414
415         if (pll_cfg[0].rate == 0)
416                 return -EINVAL;
417
418         best_rate = pll_cfg[0].rate;
419
420         for (i = 1; pll_cfg[i].rate != 0; i++) {
421                 if (abs(rate - pll_cfg[i].rate) < abs(rate - best_rate))
422                         best_rate = pll_cfg[i].rate;
423         }
424
425         pr_debug("chosen best rate: %lu\n", best_rate);
426
427         return best_rate;
428 }
429
430 static int hsdk_pll_comm_update_rate(struct hsdk_cgu_clk *clk,
431                                      unsigned long rate,
432                                      const struct hsdk_pll_cfg *cfg)
433 {
434         hsdk_pll_set_cfg(clk, cfg);
435
436         /*
437          * Wait until CGU relocks and check error status.
438          * If after timeout CGU is unlocked yet return error.
439          */
440         udelay(HSDK_PLL_MAX_LOCK_TIME);
441         if (!hsdk_pll_is_locked(clk))
442                 return -ETIMEDOUT;
443
444         if (hsdk_pll_is_err(clk))
445                 return -EINVAL;
446
447         return 0;
448 }
449
450 static int hsdk_pll_core_update_rate(struct hsdk_cgu_clk *clk,
451                                      unsigned long rate,
452                                      const struct hsdk_pll_cfg *cfg)
453 {
454         /*
455          * When core clock exceeds 500MHz, the divider for the interface
456          * clock must be programmed to div-by-2.
457          */
458         if (rate > CORE_IF_CLK_THRESHOLD_HZ)
459                 hsdk_pll_spcwrite(clk, CREG_CORE_IF_DIV, CREG_CORE_IF_CLK_DIV_2);
460
461         hsdk_pll_set_cfg(clk, cfg);
462
463         /*
464          * Wait until CGU relocks and check error status.
465          * If after timeout CGU is unlocked yet return error.
466          */
467         udelay(HSDK_PLL_MAX_LOCK_TIME);
468         if (!hsdk_pll_is_locked(clk))
469                 return -ETIMEDOUT;
470
471         if (hsdk_pll_is_err(clk))
472                 return -EINVAL;
473
474         /*
475          * Program divider to div-by-1 if we succesfuly set core clock below
476          * 500MHz threshold.
477          */
478         if (rate <= CORE_IF_CLK_THRESHOLD_HZ)
479                 hsdk_pll_spcwrite(clk, CREG_CORE_IF_DIV, CREG_CORE_IF_CLK_DIV_1);
480
481         return 0;
482 }
483
484 static ulong pll_set(struct clk *sclk, ulong rate)
485 {
486         int i;
487         unsigned long best_rate;
488         struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
489         const struct hsdk_pll_devdata *pll = clk->curr_domain.pll;
490         const struct hsdk_pll_cfg *pll_cfg = pll->pll_cfg;
491
492         best_rate = hsdk_pll_round_rate(sclk, rate);
493
494         for (i = 0; pll_cfg[i].rate != 0; i++)
495                 if (pll_cfg[i].rate == best_rate)
496                         return pll->update_rate(clk, best_rate, &pll_cfg[i]);
497
498         pr_err("invalid rate=%ld Hz, parent_rate=%d Hz\n", best_rate,
499                pll->parent_rate);
500
501         return -EINVAL;
502 }
503
504 static int idiv_off(struct clk *sclk)
505 {
506         struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
507
508         hsdk_idiv_write(clk, 0);
509
510         return 0;
511 }
512
513 static ulong idiv_get(struct clk *sclk)
514 {
515         struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
516         ulong parent_rate = pll_get(sclk);
517         u32 div_factor = hsdk_idiv_read(clk);
518
519         div_factor &= CGU_IDIV_MASK;
520
521         pr_debug("current configurarion: %#x (%d)\n", div_factor, div_factor);
522
523         if (div_factor == 0)
524                 return 0;
525
526         return parent_rate / div_factor;
527 }
528
529 /* Special behavior: wen we set this clock we set both idiv and pll */
530 static ulong cpu_clk_set(struct clk *sclk, ulong rate)
531 {
532         ulong ret;
533
534         ret = pll_set(sclk, rate);
535         idiv_set(sclk, rate);
536
537         return ret;
538 }
539
540 /*
541  * Special behavior:
542  * when we set these clocks we set both PLL and all idiv dividers related to
543  * this PLL domain.
544  */
545 static ulong common_div_clk_set(struct clk *sclk, ulong rate,
546                                 const struct hsdk_div_full_cfg *cfg)
547 {
548         struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
549         ulong pll_rate;
550         int i, freq_idx = -1;
551         ulong ret = 0;
552
553         pll_rate = pll_get(sclk);
554
555         for (i = 0; i < MAX_FREQ_VARIATIONS; i++) {
556                 /* unused freq variations are filled with 0 */
557                 if (!cfg->clk_rate[i])
558                         break;
559
560                 if (cfg->clk_rate[i] == rate) {
561                         freq_idx = i;
562                         break;
563                 }
564         }
565
566         if (freq_idx < 0) {
567                 pr_err("clk: invalid rate=%ld Hz\n", rate);
568                 return -EINVAL;
569         }
570
571         /* configure PLL before dividers */
572         if (cfg->pll_rate[freq_idx] < pll_rate)
573                 ret = pll_set(sclk, cfg->pll_rate[freq_idx]);
574
575         /* configure SYS dividers */
576         for (i = 0; cfg->idiv[i].oft != 0; i++) {
577                 clk->curr_domain.idiv_regs = clk->cgu_regs + cfg->idiv[i].oft;
578                 hsdk_idiv_write(clk, cfg->idiv[i].val[freq_idx]);
579         }
580
581         /* configure PLL after dividers */
582         if (cfg->pll_rate[freq_idx] >= pll_rate)
583                 ret = pll_set(sclk, cfg->pll_rate[freq_idx]);
584
585         return ret;
586 }
587
588 static ulong axi_clk_set(struct clk *sclk, ulong rate)
589 {
590         return common_div_clk_set(sclk, rate, &axi_clk_cfg);
591 }
592
593 static ulong tun_clk_set(struct clk *sclk, ulong rate)
594 {
595         return common_div_clk_set(sclk, rate, &tun_clk_cfg);
596 }
597
598 static ulong idiv_set(struct clk *sclk, ulong rate)
599 {
600         struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
601         ulong parent_rate = pll_get(sclk);
602         u32 div_factor;
603
604         div_factor = parent_rate / rate;
605         if (abs(rate - parent_rate / (div_factor + 1)) <=
606             abs(rate - parent_rate / div_factor)) {
607                 div_factor += 1;
608         }
609
610         if (div_factor & ~CGU_IDIV_MASK) {
611                 pr_err("invalid rate=%ld Hz, parent_rate=%ld Hz, div=%d: max divider valie is%d\n",
612                        rate, parent_rate, div_factor, CGU_IDIV_MASK);
613
614                 div_factor = CGU_IDIV_MASK;
615         }
616
617         if (div_factor == 0) {
618                 pr_err("invalid rate=%ld Hz, parent_rate=%ld Hz, div=%d: min divider valie is 1\n",
619                        rate, parent_rate, div_factor);
620
621                 div_factor = 1;
622         }
623
624         hsdk_idiv_write(clk, div_factor);
625
626         return 0;
627 }
628
629 static int hsdk_prepare_clock_tree_branch(struct clk *sclk)
630 {
631         struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
632
633         if (sclk->id >= CGU_MAX_CLOCKS)
634                 return -EINVAL;
635
636         /* clocks missing in current map have their entry zeroed */
637         if (!clk->map[sclk->id].pll_devdata)
638                 return -EINVAL;
639
640         clk->curr_domain.pll = clk->map[sclk->id].pll_devdata;
641         clk->curr_domain.pll_regs = clk->cgu_regs + clk->map[sclk->id].cgu_pll_oft;
642         clk->curr_domain.spec_regs = clk->creg_regs;
643         clk->curr_domain.idiv_regs = clk->cgu_regs + clk->map[sclk->id].cgu_div_oft;
644
645         return 0;
646 }
647
648 static ulong hsdk_cgu_get_rate(struct clk *sclk)
649 {
650         struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
651
652         if (hsdk_prepare_clock_tree_branch(sclk))
653                 return -EINVAL;
654
655         return clk->map[sclk->id].get_rate(sclk);
656 }
657
658 static ulong hsdk_cgu_set_rate(struct clk *sclk, ulong rate)
659 {
660         struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
661
662         if (hsdk_prepare_clock_tree_branch(sclk))
663                 return -EINVAL;
664
665         return clk->map[sclk->id].set_rate(sclk, rate);
666 }
667
668 static int hsdk_cgu_disable(struct clk *sclk)
669 {
670         struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
671
672         if (hsdk_prepare_clock_tree_branch(sclk))
673                 return -EINVAL;
674
675         if (clk->map[sclk->id].disable)
676                 return clk->map[sclk->id].disable(sclk);
677
678         return -ENOTSUPP;
679 }
680
681 static const struct clk_ops hsdk_cgu_ops = {
682         .set_rate = hsdk_cgu_set_rate,
683         .get_rate = hsdk_cgu_get_rate,
684         .disable = hsdk_cgu_disable,
685 };
686
687 static int hsdk_cgu_clk_probe(struct udevice *dev)
688 {
689         struct hsdk_cgu_clk *hsdk_clk = dev_get_priv(dev);
690
691         BUILD_BUG_ON(ARRAY_SIZE(clock_map) != CGU_MAX_CLOCKS);
692
693         hsdk_clk->map = clock_map;
694
695         hsdk_clk->cgu_regs = (void __iomem *)devfdt_get_addr_index(dev, 0);
696         if (!hsdk_clk->cgu_regs)
697                 return -EINVAL;
698
699         hsdk_clk->creg_regs = (void __iomem *)devfdt_get_addr_index(dev, 1);
700         if (!hsdk_clk->creg_regs)
701                 return -EINVAL;
702
703         return 0;
704 }
705
706 static const struct udevice_id hsdk_cgu_clk_id[] = {
707         { .compatible = "snps,hsdk-cgu-clock" },
708         { }
709 };
710
711 U_BOOT_DRIVER(hsdk_cgu_clk) = {
712         .name = "hsdk-cgu-clk",
713         .id = UCLASS_CLK,
714         .of_match = hsdk_cgu_clk_id,
715         .probe = hsdk_cgu_clk_probe,
716         .priv_auto_alloc_size = sizeof(struct hsdk_cgu_clk),
717         .ops = &hsdk_cgu_ops,
718 };