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