]> git.sur5r.net Git - u-boot/blob - drivers/clk/clk_zynqmp.c
mtd: spi: Correct parameters for s25fs512s flash
[u-boot] / drivers / clk / clk_zynqmp.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * ZynqMP clock driver
4  *
5  * Copyright (C) 2016 Xilinx, Inc.
6  */
7
8 #include <common.h>
9 #include <linux/bitops.h>
10 #include <clk-uclass.h>
11 #include <clk.h>
12 #include <asm/arch/sys_proto.h>
13 #include <dm.h>
14
15 static const resource_size_t zynqmp_crf_apb_clkc_base = 0xfd1a0020;
16 static const resource_size_t zynqmp_crl_apb_clkc_base = 0xff5e0020;
17
18 /* Full power domain clocks */
19 #define CRF_APB_APLL_CTRL               (zynqmp_crf_apb_clkc_base + 0x00)
20 #define CRF_APB_DPLL_CTRL               (zynqmp_crf_apb_clkc_base + 0x0c)
21 #define CRF_APB_VPLL_CTRL               (zynqmp_crf_apb_clkc_base + 0x18)
22 #define CRF_APB_PLL_STATUS              (zynqmp_crf_apb_clkc_base + 0x24)
23 #define CRF_APB_APLL_TO_LPD_CTRL        (zynqmp_crf_apb_clkc_base + 0x28)
24 #define CRF_APB_DPLL_TO_LPD_CTRL        (zynqmp_crf_apb_clkc_base + 0x2c)
25 #define CRF_APB_VPLL_TO_LPD_CTRL        (zynqmp_crf_apb_clkc_base + 0x30)
26 /* Peripheral clocks */
27 #define CRF_APB_ACPU_CTRL               (zynqmp_crf_apb_clkc_base + 0x40)
28 #define CRF_APB_DBG_TRACE_CTRL          (zynqmp_crf_apb_clkc_base + 0x44)
29 #define CRF_APB_DBG_FPD_CTRL            (zynqmp_crf_apb_clkc_base + 0x48)
30 #define CRF_APB_DP_VIDEO_REF_CTRL       (zynqmp_crf_apb_clkc_base + 0x50)
31 #define CRF_APB_DP_AUDIO_REF_CTRL       (zynqmp_crf_apb_clkc_base + 0x54)
32 #define CRF_APB_DP_STC_REF_CTRL         (zynqmp_crf_apb_clkc_base + 0x5c)
33 #define CRF_APB_DDR_CTRL                (zynqmp_crf_apb_clkc_base + 0x60)
34 #define CRF_APB_GPU_REF_CTRL            (zynqmp_crf_apb_clkc_base + 0x64)
35 #define CRF_APB_SATA_REF_CTRL           (zynqmp_crf_apb_clkc_base + 0x80)
36 #define CRF_APB_PCIE_REF_CTRL           (zynqmp_crf_apb_clkc_base + 0x94)
37 #define CRF_APB_GDMA_REF_CTRL           (zynqmp_crf_apb_clkc_base + 0x98)
38 #define CRF_APB_DPDMA_REF_CTRL          (zynqmp_crf_apb_clkc_base + 0x9c)
39 #define CRF_APB_TOPSW_MAIN_CTRL         (zynqmp_crf_apb_clkc_base + 0xa0)
40 #define CRF_APB_TOPSW_LSBUS_CTRL        (zynqmp_crf_apb_clkc_base + 0xa4)
41 #define CRF_APB_GTGREF0_REF_CTRL        (zynqmp_crf_apb_clkc_base + 0xa8)
42 #define CRF_APB_DBG_TSTMP_CTRL          (zynqmp_crf_apb_clkc_base + 0xd8)
43
44 /* Low power domain clocks */
45 #define CRL_APB_IOPLL_CTRL              (zynqmp_crl_apb_clkc_base + 0x00)
46 #define CRL_APB_RPLL_CTRL               (zynqmp_crl_apb_clkc_base + 0x10)
47 #define CRL_APB_PLL_STATUS              (zynqmp_crl_apb_clkc_base + 0x20)
48 #define CRL_APB_IOPLL_TO_FPD_CTRL       (zynqmp_crl_apb_clkc_base + 0x24)
49 #define CRL_APB_RPLL_TO_FPD_CTRL        (zynqmp_crl_apb_clkc_base + 0x28)
50 /* Peripheral clocks */
51 #define CRL_APB_USB3_DUAL_REF_CTRL      (zynqmp_crl_apb_clkc_base + 0x2c)
52 #define CRL_APB_GEM0_REF_CTRL           (zynqmp_crl_apb_clkc_base + 0x30)
53 #define CRL_APB_GEM1_REF_CTRL           (zynqmp_crl_apb_clkc_base + 0x34)
54 #define CRL_APB_GEM2_REF_CTRL           (zynqmp_crl_apb_clkc_base + 0x38)
55 #define CRL_APB_GEM3_REF_CTRL           (zynqmp_crl_apb_clkc_base + 0x3c)
56 #define CRL_APB_USB0_BUS_REF_CTRL       (zynqmp_crl_apb_clkc_base + 0x40)
57 #define CRL_APB_USB1_BUS_REF_CTRL       (zynqmp_crl_apb_clkc_base + 0x44)
58 #define CRL_APB_QSPI_REF_CTRL           (zynqmp_crl_apb_clkc_base + 0x48)
59 #define CRL_APB_SDIO0_REF_CTRL          (zynqmp_crl_apb_clkc_base + 0x4c)
60 #define CRL_APB_SDIO1_REF_CTRL          (zynqmp_crl_apb_clkc_base + 0x50)
61 #define CRL_APB_UART0_REF_CTRL          (zynqmp_crl_apb_clkc_base + 0x54)
62 #define CRL_APB_UART1_REF_CTRL          (zynqmp_crl_apb_clkc_base + 0x58)
63 #define CRL_APB_SPI0_REF_CTRL           (zynqmp_crl_apb_clkc_base + 0x5c)
64 #define CRL_APB_SPI1_REF_CTRL           (zynqmp_crl_apb_clkc_base + 0x60)
65 #define CRL_APB_CAN0_REF_CTRL           (zynqmp_crl_apb_clkc_base + 0x64)
66 #define CRL_APB_CAN1_REF_CTRL           (zynqmp_crl_apb_clkc_base + 0x68)
67 #define CRL_APB_CPU_R5_CTRL             (zynqmp_crl_apb_clkc_base + 0x70)
68 #define CRL_APB_IOU_SWITCH_CTRL         (zynqmp_crl_apb_clkc_base + 0x7c)
69 #define CRL_APB_CSU_PLL_CTRL            (zynqmp_crl_apb_clkc_base + 0x80)
70 #define CRL_APB_PCAP_CTRL               (zynqmp_crl_apb_clkc_base + 0x84)
71 #define CRL_APB_LPD_SWITCH_CTRL         (zynqmp_crl_apb_clkc_base + 0x88)
72 #define CRL_APB_LPD_LSBUS_CTRL          (zynqmp_crl_apb_clkc_base + 0x8c)
73 #define CRL_APB_DBG_LPD_CTRL            (zynqmp_crl_apb_clkc_base + 0x90)
74 #define CRL_APB_NAND_REF_CTRL           (zynqmp_crl_apb_clkc_base + 0x94)
75 #define CRL_APB_ADMA_REF_CTRL           (zynqmp_crl_apb_clkc_base + 0x98)
76 #define CRL_APB_PL0_REF_CTRL            (zynqmp_crl_apb_clkc_base + 0xa0)
77 #define CRL_APB_PL1_REF_CTRL            (zynqmp_crl_apb_clkc_base + 0xa4)
78 #define CRL_APB_PL2_REF_CTRL            (zynqmp_crl_apb_clkc_base + 0xa8)
79 #define CRL_APB_PL3_REF_CTRL            (zynqmp_crl_apb_clkc_base + 0xac)
80 #define CRL_APB_PL0_THR_CNT             (zynqmp_crl_apb_clkc_base + 0xb4)
81 #define CRL_APB_PL1_THR_CNT             (zynqmp_crl_apb_clkc_base + 0xbc)
82 #define CRL_APB_PL2_THR_CNT             (zynqmp_crl_apb_clkc_base + 0xc4)
83 #define CRL_APB_PL3_THR_CNT             (zynqmp_crl_apb_clkc_base + 0xdc)
84 #define CRL_APB_GEM_TSU_REF_CTRL        (zynqmp_crl_apb_clkc_base + 0xe0)
85 #define CRL_APB_DLL_REF_CTRL            (zynqmp_crl_apb_clkc_base + 0xe4)
86 #define CRL_APB_AMS_REF_CTRL            (zynqmp_crl_apb_clkc_base + 0xe8)
87 #define CRL_APB_I2C0_REF_CTRL           (zynqmp_crl_apb_clkc_base + 0x100)
88 #define CRL_APB_I2C1_REF_CTRL           (zynqmp_crl_apb_clkc_base + 0x104)
89 #define CRL_APB_TIMESTAMP_REF_CTRL      (zynqmp_crl_apb_clkc_base + 0x108)
90
91 #define ZYNQ_CLK_MAXDIV         0x3f
92 #define CLK_CTRL_DIV1_SHIFT     16
93 #define CLK_CTRL_DIV1_MASK      (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV1_SHIFT)
94 #define CLK_CTRL_DIV0_SHIFT     8
95 #define CLK_CTRL_DIV0_MASK      (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV0_SHIFT)
96 #define CLK_CTRL_SRCSEL_SHIFT   0
97 #define CLK_CTRL_SRCSEL_MASK    (0x3 << CLK_CTRL_SRCSEL_SHIFT)
98 #define PLLCTRL_FBDIV_MASK      0x7f00
99 #define PLLCTRL_FBDIV_SHIFT     8
100 #define PLLCTRL_RESET_MASK      1
101 #define PLLCTRL_RESET_SHIFT     0
102 #define PLLCTRL_BYPASS_MASK     0x8
103 #define PLLCTRL_BYPASS_SHFT     3
104 #define PLLCTRL_POST_SRC_SHFT   24
105 #define PLLCTRL_POST_SRC_MASK   (0x7 << PLLCTRL_POST_SRC_SHFT)
106
107
108 #define NUM_MIO_PINS    77
109
110 enum zynqmp_clk {
111         iopll, rpll,
112         apll, dpll, vpll,
113         iopll_to_fpd, rpll_to_fpd, apll_to_lpd, dpll_to_lpd, vpll_to_lpd,
114         acpu, acpu_half,
115         dbg_fpd, dbg_lpd, dbg_trace, dbg_tstmp,
116         dp_video_ref, dp_audio_ref,
117         dp_stc_ref, gdma_ref, dpdma_ref,
118         ddr_ref, sata_ref, pcie_ref,
119         gpu_ref, gpu_pp0_ref, gpu_pp1_ref,
120         topsw_main, topsw_lsbus,
121         gtgref0_ref,
122         lpd_switch, lpd_lsbus,
123         usb0_bus_ref, usb1_bus_ref, usb3_dual_ref, usb0, usb1,
124         cpu_r5, cpu_r5_core,
125         csu_spb, csu_pll, pcap,
126         iou_switch,
127         gem_tsu_ref, gem_tsu,
128         gem0_ref, gem1_ref, gem2_ref, gem3_ref,
129         gem0_rx, gem1_rx, gem2_rx, gem3_rx,
130         qspi_ref,
131         sdio0_ref, sdio1_ref,
132         uart0_ref, uart1_ref,
133         spi0_ref, spi1_ref,
134         nand_ref,
135         i2c0_ref, i2c1_ref, can0_ref, can1_ref, can0, can1,
136         dll_ref,
137         adma_ref,
138         timestamp_ref,
139         ams_ref,
140         pl0, pl1, pl2, pl3,
141         wdt,
142         clk_max,
143 };
144
145 static const char * const clk_names[clk_max] = {
146         "iopll", "rpll", "apll", "dpll",
147         "vpll", "iopll_to_fpd", "rpll_to_fpd",
148         "apll_to_lpd", "dpll_to_lpd", "vpll_to_lpd",
149         "acpu", "acpu_half", "dbf_fpd", "dbf_lpd",
150         "dbg_trace", "dbg_tstmp", "dp_video_ref",
151         "dp_audio_ref", "dp_stc_ref", "gdma_ref",
152         "dpdma_ref", "ddr_ref", "sata_ref", "pcie_ref",
153         "gpu_ref", "gpu_pp0_ref", "gpu_pp1_ref",
154         "topsw_main", "topsw_lsbus", "gtgref0_ref",
155         "lpd_switch", "lpd_lsbus", "usb0_bus_ref",
156         "usb1_bus_ref", "usb3_dual_ref", "usb0",
157         "usb1", "cpu_r5", "cpu_r5_core", "csu_spb",
158         "csu_pll", "pcap", "iou_switch", "gem_tsu_ref",
159         "gem_tsu", "gem0_ref", "gem1_ref", "gem2_ref",
160         "gem3_ref", "gem0_tx", "gem1_tx", "gem2_tx",
161         "gem3_tx", "qspi_ref", "sdio0_ref", "sdio1_ref",
162         "uart0_ref", "uart1_ref", "spi0_ref",
163         "spi1_ref", "nand_ref", "i2c0_ref", "i2c1_ref",
164         "can0_ref", "can1_ref", "can0", "can1",
165         "dll_ref", "adma_ref", "timestamp_ref",
166         "ams_ref", "pl0", "pl1", "pl2", "pl3", "wdt"
167 };
168
169 struct zynqmp_clk_priv {
170         unsigned long ps_clk_freq;
171         unsigned long video_clk;
172         unsigned long pss_alt_ref_clk;
173         unsigned long gt_crx_ref_clk;
174         unsigned long aux_ref_clk;
175 };
176
177 static u32 zynqmp_clk_get_register(enum zynqmp_clk id)
178 {
179         switch (id) {
180         case iopll:
181                 return CRL_APB_IOPLL_CTRL;
182         case rpll:
183                 return CRL_APB_RPLL_CTRL;
184         case apll:
185                 return CRF_APB_APLL_CTRL;
186         case dpll:
187                 return CRF_APB_DPLL_CTRL;
188         case vpll:
189                 return CRF_APB_VPLL_CTRL;
190         case acpu:
191                 return CRF_APB_ACPU_CTRL;
192         case ddr_ref:
193                 return CRF_APB_DDR_CTRL;
194         case qspi_ref:
195                 return CRL_APB_QSPI_REF_CTRL;
196         case gem0_ref:
197                 return CRL_APB_GEM0_REF_CTRL;
198         case gem1_ref:
199                 return CRL_APB_GEM1_REF_CTRL;
200         case gem2_ref:
201                 return CRL_APB_GEM2_REF_CTRL;
202         case gem3_ref:
203                 return CRL_APB_GEM3_REF_CTRL;
204         case uart0_ref:
205                 return CRL_APB_UART0_REF_CTRL;
206         case uart1_ref:
207                 return CRL_APB_UART1_REF_CTRL;
208         case sdio0_ref:
209                 return CRL_APB_SDIO0_REF_CTRL;
210         case sdio1_ref:
211                 return CRL_APB_SDIO1_REF_CTRL;
212         case spi0_ref:
213                 return CRL_APB_SPI0_REF_CTRL;
214         case spi1_ref:
215                 return CRL_APB_SPI1_REF_CTRL;
216         case nand_ref:
217                 return CRL_APB_NAND_REF_CTRL;
218         case i2c0_ref:
219                 return CRL_APB_I2C0_REF_CTRL;
220         case i2c1_ref:
221                 return CRL_APB_I2C1_REF_CTRL;
222         case can0_ref:
223                 return CRL_APB_CAN0_REF_CTRL;
224         case can1_ref:
225                 return CRL_APB_CAN1_REF_CTRL;
226         case pl0:
227                 return CRL_APB_PL0_REF_CTRL;
228         case pl1:
229                 return CRL_APB_PL1_REF_CTRL;
230         case pl2:
231                 return CRL_APB_PL2_REF_CTRL;
232         case pl3:
233                 return CRL_APB_PL3_REF_CTRL;
234         case wdt:
235                 return CRF_APB_TOPSW_LSBUS_CTRL;
236         case iopll_to_fpd:
237                 return CRL_APB_IOPLL_TO_FPD_CTRL;
238         default:
239                 debug("Invalid clk id%d\n", id);
240         }
241         return 0;
242 }
243
244 static enum zynqmp_clk zynqmp_clk_get_cpu_pll(u32 clk_ctrl)
245 {
246         u32 srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >>
247                       CLK_CTRL_SRCSEL_SHIFT;
248
249         switch (srcsel) {
250         case 2:
251                 return dpll;
252         case 3:
253                 return vpll;
254         case 0 ... 1:
255         default:
256                 return apll;
257         }
258 }
259
260 static enum zynqmp_clk zynqmp_clk_get_ddr_pll(u32 clk_ctrl)
261 {
262         u32 srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >>
263                       CLK_CTRL_SRCSEL_SHIFT;
264
265         switch (srcsel) {
266         case 1:
267                 return vpll;
268         case 0:
269         default:
270                 return dpll;
271         }
272 }
273
274 static enum zynqmp_clk zynqmp_clk_get_peripheral_pll(u32 clk_ctrl)
275 {
276         u32 srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >>
277                       CLK_CTRL_SRCSEL_SHIFT;
278
279         switch (srcsel) {
280         case 2:
281                 return rpll;
282         case 3:
283                 return dpll;
284         case 0 ... 1:
285         default:
286                 return iopll;
287         }
288 }
289
290 static enum zynqmp_clk zynqmp_clk_get_wdt_pll(u32 clk_ctrl)
291 {
292         u32 srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >>
293                       CLK_CTRL_SRCSEL_SHIFT;
294
295         switch (srcsel) {
296         case 2:
297                 return iopll_to_fpd;
298         case 3:
299                 return dpll;
300         case 0 ... 1:
301         default:
302                 return apll;
303         }
304 }
305
306 static ulong zynqmp_clk_get_pll_src(ulong clk_ctrl,
307                                     struct zynqmp_clk_priv *priv,
308                                     bool is_pre_src)
309 {
310         u32 src_sel;
311
312         if (is_pre_src)
313                 src_sel = (clk_ctrl & PLLCTRL_POST_SRC_MASK) >>
314                            PLLCTRL_POST_SRC_SHFT;
315         else
316                 src_sel = (clk_ctrl & PLLCTRL_POST_SRC_MASK) >>
317                            PLLCTRL_POST_SRC_SHFT;
318
319         switch (src_sel) {
320         case 4:
321                 return priv->video_clk;
322         case 5:
323                 return priv->pss_alt_ref_clk;
324         case 6:
325                 return priv->aux_ref_clk;
326         case 7:
327                 return priv->gt_crx_ref_clk;
328         case 0 ... 3:
329         default:
330         return priv->ps_clk_freq;
331         }
332 }
333
334 static ulong zynqmp_clk_get_pll_rate(struct zynqmp_clk_priv *priv,
335                                      enum zynqmp_clk id)
336 {
337         u32 clk_ctrl, reset, mul;
338         ulong freq;
339         int ret;
340
341         ret = zynqmp_mmio_read(zynqmp_clk_get_register(id), &clk_ctrl);
342         if (ret) {
343                 printf("%s mio read fail\n", __func__);
344                 return -EIO;
345         }
346
347         if (clk_ctrl & PLLCTRL_BYPASS_MASK)
348                 freq = zynqmp_clk_get_pll_src(clk_ctrl, priv, 0);
349         else
350                 freq = zynqmp_clk_get_pll_src(clk_ctrl, priv, 1);
351
352         reset = (clk_ctrl & PLLCTRL_RESET_MASK) >> PLLCTRL_RESET_SHIFT;
353         if (reset && !(clk_ctrl & PLLCTRL_BYPASS_MASK))
354                 return 0;
355
356         mul = (clk_ctrl & PLLCTRL_FBDIV_MASK) >> PLLCTRL_FBDIV_SHIFT;
357
358         freq *= mul;
359
360         if (clk_ctrl & (1 << 16))
361                 freq /= 2;
362
363         return freq;
364 }
365
366 static ulong zynqmp_clk_get_cpu_rate(struct zynqmp_clk_priv *priv,
367                                      enum zynqmp_clk id)
368 {
369         u32 clk_ctrl, div;
370         enum zynqmp_clk pll;
371         int ret;
372         unsigned long pllrate;
373
374         ret = zynqmp_mmio_read(CRF_APB_ACPU_CTRL, &clk_ctrl);
375         if (ret) {
376                 printf("%s mio read fail\n", __func__);
377                 return -EIO;
378         }
379
380         div = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
381
382         pll = zynqmp_clk_get_cpu_pll(clk_ctrl);
383         pllrate = zynqmp_clk_get_pll_rate(priv, pll);
384         if (IS_ERR_VALUE(pllrate))
385                 return pllrate;
386
387         return DIV_ROUND_CLOSEST(pllrate, div);
388 }
389
390 static ulong zynqmp_clk_get_ddr_rate(struct zynqmp_clk_priv *priv)
391 {
392         u32 clk_ctrl, div;
393         enum zynqmp_clk pll;
394         int ret;
395         ulong pllrate;
396
397         ret = zynqmp_mmio_read(CRF_APB_DDR_CTRL, &clk_ctrl);
398         if (ret) {
399                 printf("%s mio read fail\n", __func__);
400                 return -EIO;
401         }
402
403         div = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
404
405         pll = zynqmp_clk_get_ddr_pll(clk_ctrl);
406         pllrate = zynqmp_clk_get_pll_rate(priv, pll);
407         if (IS_ERR_VALUE(pllrate))
408                 return pllrate;
409
410         return DIV_ROUND_CLOSEST(pllrate, div);
411 }
412
413 static ulong zynqmp_clk_get_peripheral_rate(struct zynqmp_clk_priv *priv,
414                                           enum zynqmp_clk id, bool two_divs)
415 {
416         enum zynqmp_clk pll;
417         u32 clk_ctrl, div0;
418         u32 div1 = 1;
419         int ret;
420         ulong pllrate;
421
422         ret = zynqmp_mmio_read(zynqmp_clk_get_register(id), &clk_ctrl);
423         if (ret) {
424                 printf("%s mio read fail\n", __func__);
425                 return -EIO;
426         }
427
428         div0 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
429         if (!div0)
430                 div0 = 1;
431
432         if (two_divs) {
433                 div1 = (clk_ctrl & CLK_CTRL_DIV1_MASK) >> CLK_CTRL_DIV1_SHIFT;
434                 if (!div1)
435                         div1 = 1;
436         }
437
438         pll = zynqmp_clk_get_peripheral_pll(clk_ctrl);
439         pllrate = zynqmp_clk_get_pll_rate(priv, pll);
440         if (IS_ERR_VALUE(pllrate))
441                 return pllrate;
442
443         return
444                 DIV_ROUND_CLOSEST(
445                         DIV_ROUND_CLOSEST(pllrate, div0), div1);
446 }
447
448 static ulong zynqmp_clk_get_wdt_rate(struct zynqmp_clk_priv *priv,
449                                      enum zynqmp_clk id, bool two_divs)
450 {
451         enum zynqmp_clk pll;
452         u32 clk_ctrl, div0;
453         u32 div1 = 1;
454         int ret;
455         ulong pllrate;
456
457         ret = zynqmp_mmio_read(zynqmp_clk_get_register(id), &clk_ctrl);
458         if (ret) {
459                 printf("%d %s mio read fail\n", __LINE__, __func__);
460                 return -EIO;
461         }
462
463         div0 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
464         if (!div0)
465                 div0 = 1;
466
467         pll = zynqmp_clk_get_wdt_pll(clk_ctrl);
468         if (two_divs) {
469                 ret = zynqmp_mmio_read(zynqmp_clk_get_register(pll), &clk_ctrl);
470                 if (ret) {
471                         printf("%d %s mio read fail\n", __LINE__, __func__);
472                         return -EIO;
473                 }
474                 div1 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
475                 if (!div1)
476                         div1 = 1;
477         }
478
479         if (pll == iopll_to_fpd)
480                 pll = iopll;
481
482         pllrate = zynqmp_clk_get_pll_rate(priv, pll);
483         if (IS_ERR_VALUE(pllrate))
484                 return pllrate;
485
486         return
487                 DIV_ROUND_CLOSEST(
488                         DIV_ROUND_CLOSEST(pllrate, div0), div1);
489 }
490
491 static unsigned long zynqmp_clk_calc_peripheral_two_divs(ulong rate,
492                                                        ulong pll_rate,
493                                                        u32 *div0, u32 *div1)
494 {
495         long new_err, best_err = (long)(~0UL >> 1);
496         ulong new_rate, best_rate = 0;
497         u32 d0, d1;
498
499         for (d0 = 1; d0 <= ZYNQ_CLK_MAXDIV; d0++) {
500                 for (d1 = 1; d1 <= ZYNQ_CLK_MAXDIV >> 1; d1++) {
501                         new_rate = DIV_ROUND_CLOSEST(
502                                         DIV_ROUND_CLOSEST(pll_rate, d0), d1);
503                         new_err = abs(new_rate - rate);
504
505                         if (new_err < best_err) {
506                                 *div0 = d0;
507                                 *div1 = d1;
508                                 best_err = new_err;
509                                 best_rate = new_rate;
510                         }
511                 }
512         }
513
514         return best_rate;
515 }
516
517 static ulong zynqmp_clk_set_peripheral_rate(struct zynqmp_clk_priv *priv,
518                                           enum zynqmp_clk id, ulong rate,
519                                           bool two_divs)
520 {
521         enum zynqmp_clk pll;
522         u32 clk_ctrl, div0 = 0, div1 = 0;
523         ulong pll_rate, new_rate;
524         u32 reg;
525         int ret;
526         u32 mask;
527
528         reg = zynqmp_clk_get_register(id);
529         ret = zynqmp_mmio_read(reg, &clk_ctrl);
530         if (ret) {
531                 printf("%s mio read fail\n", __func__);
532                 return -EIO;
533         }
534
535         pll = zynqmp_clk_get_peripheral_pll(clk_ctrl);
536         pll_rate = zynqmp_clk_get_pll_rate(priv, pll);
537         if (IS_ERR_VALUE(pll_rate))
538                 return pll_rate;
539
540         clk_ctrl &= ~CLK_CTRL_DIV0_MASK;
541         if (two_divs) {
542                 clk_ctrl &= ~CLK_CTRL_DIV1_MASK;
543                 new_rate = zynqmp_clk_calc_peripheral_two_divs(rate, pll_rate,
544                                 &div0, &div1);
545                 clk_ctrl |= div1 << CLK_CTRL_DIV1_SHIFT;
546         } else {
547                 div0 = DIV_ROUND_CLOSEST(pll_rate, rate);
548                 if (div0 > ZYNQ_CLK_MAXDIV)
549                         div0 = ZYNQ_CLK_MAXDIV;
550                 new_rate = DIV_ROUND_CLOSEST(rate, div0);
551         }
552         clk_ctrl |= div0 << CLK_CTRL_DIV0_SHIFT;
553
554         mask = (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV0_SHIFT) |
555                (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV1_SHIFT);
556
557         ret = zynqmp_mmio_write(reg, mask, clk_ctrl);
558         if (ret) {
559                 printf("%s mio write fail\n", __func__);
560                 return -EIO;
561         }
562
563         return new_rate;
564 }
565
566 static ulong zynqmp_clk_get_rate(struct clk *clk)
567 {
568         struct zynqmp_clk_priv *priv = dev_get_priv(clk->dev);
569         enum zynqmp_clk id = clk->id;
570         bool two_divs = false;
571
572         switch (id) {
573         case iopll ... vpll:
574                 return zynqmp_clk_get_pll_rate(priv, id);
575         case acpu:
576                 return zynqmp_clk_get_cpu_rate(priv, id);
577         case ddr_ref:
578                 return zynqmp_clk_get_ddr_rate(priv);
579         case gem0_ref ... gem3_ref:
580         case qspi_ref ... can1_ref:
581         case pl0 ... pl3:
582                 two_divs = true;
583                 return zynqmp_clk_get_peripheral_rate(priv, id, two_divs);
584         case wdt:
585                 two_divs = true;
586                 return zynqmp_clk_get_wdt_rate(priv, id, two_divs);
587         default:
588                 return -ENXIO;
589         }
590 }
591
592 static ulong zynqmp_clk_set_rate(struct clk *clk, ulong rate)
593 {
594         struct zynqmp_clk_priv *priv = dev_get_priv(clk->dev);
595         enum zynqmp_clk id = clk->id;
596         bool two_divs = true;
597
598         switch (id) {
599         case gem0_ref ... gem3_ref:
600         case qspi_ref ... can1_ref:
601                 return zynqmp_clk_set_peripheral_rate(priv, id,
602                                                       rate, two_divs);
603         default:
604                 return -ENXIO;
605         }
606 }
607
608 int soc_clk_dump(void)
609 {
610         struct udevice *dev;
611         int i, ret;
612
613         ret = uclass_get_device_by_driver(UCLASS_CLK,
614                 DM_GET_DRIVER(zynqmp_clk), &dev);
615         if (ret)
616                 return ret;
617
618         printf("clk\t\tfrequency\n");
619         for (i = 0; i < clk_max; i++) {
620                 const char *name = clk_names[i];
621                 if (name) {
622                         struct clk clk;
623                         unsigned long rate;
624
625                         clk.id = i;
626                         ret = clk_request(dev, &clk);
627                         if (ret < 0)
628                                 return ret;
629
630                         rate = clk_get_rate(&clk);
631
632                         clk_free(&clk);
633
634                         if ((rate == (unsigned long)-ENOSYS) ||
635                             (rate == (unsigned long)-ENXIO) ||
636                             (rate == (unsigned long)-EIO))
637                                 printf("%10s%20s\n", name, "unknown");
638                         else
639                                 printf("%10s%20lu\n", name, rate);
640                 }
641         }
642
643         return 0;
644 }
645
646 static int zynqmp_get_freq_by_name(char *name, struct udevice *dev, ulong *freq)
647 {
648         struct clk clk;
649         int ret;
650
651         ret = clk_get_by_name(dev, name, &clk);
652         if (ret < 0) {
653                 dev_err(dev, "failed to get %s\n", name);
654                 return ret;
655         }
656
657         *freq = clk_get_rate(&clk);
658         if (IS_ERR_VALUE(*freq)) {
659                 dev_err(dev, "failed to get rate %s\n", name);
660                 return -EINVAL;
661         }
662
663         return 0;
664 }
665 static int zynqmp_clk_probe(struct udevice *dev)
666 {
667         int ret;
668         struct zynqmp_clk_priv *priv = dev_get_priv(dev);
669
670         debug("%s\n", __func__);
671         ret = zynqmp_get_freq_by_name("pss_ref_clk", dev, &priv->ps_clk_freq);
672         if (ret < 0)
673                 return -EINVAL;
674
675         ret = zynqmp_get_freq_by_name("video_clk", dev, &priv->video_clk);
676         if (ret < 0)
677                 return -EINVAL;
678
679         ret = zynqmp_get_freq_by_name("pss_alt_ref_clk", dev,
680                                       &priv->pss_alt_ref_clk);
681         if (ret < 0)
682                 return -EINVAL;
683
684         ret = zynqmp_get_freq_by_name("aux_ref_clk", dev, &priv->aux_ref_clk);
685         if (ret < 0)
686                 return -EINVAL;
687
688         ret = zynqmp_get_freq_by_name("gt_crx_ref_clk", dev,
689                                       &priv->gt_crx_ref_clk);
690         if (ret < 0)
691                 return -EINVAL;
692
693         return 0;
694 }
695
696 static struct clk_ops zynqmp_clk_ops = {
697         .set_rate = zynqmp_clk_set_rate,
698         .get_rate = zynqmp_clk_get_rate,
699 };
700
701 static const struct udevice_id zynqmp_clk_ids[] = {
702         { .compatible = "xlnx,zynqmp-clk" },
703         { .compatible = "xlnx,zynqmp-clkc" },
704         { }
705 };
706
707 U_BOOT_DRIVER(zynqmp_clk) = {
708         .name = "zynqmp-clk",
709         .id = UCLASS_CLK,
710         .of_match = zynqmp_clk_ids,
711         .probe = zynqmp_clk_probe,
712         .ops = &zynqmp_clk_ops,
713         .priv_auto_alloc_size = sizeof(struct zynqmp_clk_priv),
714 };