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