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