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