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