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