blob: 97f3b999d7c8b510328bdc54bfd56a0b9d5b8d12 [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +05302/*
3 * ZynqMP clock driver
4 *
5 * Copyright (C) 2016 Xilinx, Inc.
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +05306 */
7
Simon Glass0f2af882020-05-10 11:40:05 -06008#include <log.h>
Simon Glass9bc15642020-02-03 07:36:16 -07009#include <malloc.h>
10#include <dm/device_compat.h>
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +053011#include <linux/bitops.h>
12#include <clk-uclass.h>
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +053013#include <clk.h>
Michal Simeka7acb532023-06-23 14:51:57 +020014#include <zynqmp_firmware.h>
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +053015#include <asm/arch/sys_proto.h>
Simon Glass11c89f32017-05-17 17:18:03 -060016#include <dm.h>
Simon Glassd66c5f72020-02-03 07:36:15 -070017#include <linux/err.h>
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +053018
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +053019static const resource_size_t zynqmp_crf_apb_clkc_base = 0xfd1a0020;
20static const resource_size_t zynqmp_crl_apb_clkc_base = 0xff5e0020;
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +053021
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +053022/* Full power domain clocks */
23#define CRF_APB_APLL_CTRL (zynqmp_crf_apb_clkc_base + 0x00)
24#define CRF_APB_DPLL_CTRL (zynqmp_crf_apb_clkc_base + 0x0c)
25#define CRF_APB_VPLL_CTRL (zynqmp_crf_apb_clkc_base + 0x18)
26#define CRF_APB_PLL_STATUS (zynqmp_crf_apb_clkc_base + 0x24)
27#define CRF_APB_APLL_TO_LPD_CTRL (zynqmp_crf_apb_clkc_base + 0x28)
28#define CRF_APB_DPLL_TO_LPD_CTRL (zynqmp_crf_apb_clkc_base + 0x2c)
29#define CRF_APB_VPLL_TO_LPD_CTRL (zynqmp_crf_apb_clkc_base + 0x30)
30/* Peripheral clocks */
31#define CRF_APB_ACPU_CTRL (zynqmp_crf_apb_clkc_base + 0x40)
32#define CRF_APB_DBG_TRACE_CTRL (zynqmp_crf_apb_clkc_base + 0x44)
33#define CRF_APB_DBG_FPD_CTRL (zynqmp_crf_apb_clkc_base + 0x48)
34#define CRF_APB_DP_VIDEO_REF_CTRL (zynqmp_crf_apb_clkc_base + 0x50)
35#define CRF_APB_DP_AUDIO_REF_CTRL (zynqmp_crf_apb_clkc_base + 0x54)
36#define CRF_APB_DP_STC_REF_CTRL (zynqmp_crf_apb_clkc_base + 0x5c)
37#define CRF_APB_DDR_CTRL (zynqmp_crf_apb_clkc_base + 0x60)
38#define CRF_APB_GPU_REF_CTRL (zynqmp_crf_apb_clkc_base + 0x64)
39#define CRF_APB_SATA_REF_CTRL (zynqmp_crf_apb_clkc_base + 0x80)
40#define CRF_APB_PCIE_REF_CTRL (zynqmp_crf_apb_clkc_base + 0x94)
41#define CRF_APB_GDMA_REF_CTRL (zynqmp_crf_apb_clkc_base + 0x98)
42#define CRF_APB_DPDMA_REF_CTRL (zynqmp_crf_apb_clkc_base + 0x9c)
43#define CRF_APB_TOPSW_MAIN_CTRL (zynqmp_crf_apb_clkc_base + 0xa0)
44#define CRF_APB_TOPSW_LSBUS_CTRL (zynqmp_crf_apb_clkc_base + 0xa4)
45#define CRF_APB_GTGREF0_REF_CTRL (zynqmp_crf_apb_clkc_base + 0xa8)
46#define CRF_APB_DBG_TSTMP_CTRL (zynqmp_crf_apb_clkc_base + 0xd8)
47
48/* Low power domain clocks */
49#define CRL_APB_IOPLL_CTRL (zynqmp_crl_apb_clkc_base + 0x00)
50#define CRL_APB_RPLL_CTRL (zynqmp_crl_apb_clkc_base + 0x10)
51#define CRL_APB_PLL_STATUS (zynqmp_crl_apb_clkc_base + 0x20)
52#define CRL_APB_IOPLL_TO_FPD_CTRL (zynqmp_crl_apb_clkc_base + 0x24)
53#define CRL_APB_RPLL_TO_FPD_CTRL (zynqmp_crl_apb_clkc_base + 0x28)
54/* Peripheral clocks */
55#define CRL_APB_USB3_DUAL_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x2c)
56#define CRL_APB_GEM0_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x30)
57#define CRL_APB_GEM1_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x34)
58#define CRL_APB_GEM2_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x38)
59#define CRL_APB_GEM3_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x3c)
60#define CRL_APB_USB0_BUS_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x40)
61#define CRL_APB_USB1_BUS_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x44)
62#define CRL_APB_QSPI_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x48)
63#define CRL_APB_SDIO0_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x4c)
64#define CRL_APB_SDIO1_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x50)
65#define CRL_APB_UART0_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x54)
66#define CRL_APB_UART1_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x58)
67#define CRL_APB_SPI0_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x5c)
68#define CRL_APB_SPI1_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x60)
69#define CRL_APB_CAN0_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x64)
70#define CRL_APB_CAN1_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x68)
71#define CRL_APB_CPU_R5_CTRL (zynqmp_crl_apb_clkc_base + 0x70)
72#define CRL_APB_IOU_SWITCH_CTRL (zynqmp_crl_apb_clkc_base + 0x7c)
73#define CRL_APB_CSU_PLL_CTRL (zynqmp_crl_apb_clkc_base + 0x80)
74#define CRL_APB_PCAP_CTRL (zynqmp_crl_apb_clkc_base + 0x84)
75#define CRL_APB_LPD_SWITCH_CTRL (zynqmp_crl_apb_clkc_base + 0x88)
76#define CRL_APB_LPD_LSBUS_CTRL (zynqmp_crl_apb_clkc_base + 0x8c)
77#define CRL_APB_DBG_LPD_CTRL (zynqmp_crl_apb_clkc_base + 0x90)
78#define CRL_APB_NAND_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x94)
79#define CRL_APB_ADMA_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x98)
80#define CRL_APB_PL0_REF_CTRL (zynqmp_crl_apb_clkc_base + 0xa0)
81#define CRL_APB_PL1_REF_CTRL (zynqmp_crl_apb_clkc_base + 0xa4)
82#define CRL_APB_PL2_REF_CTRL (zynqmp_crl_apb_clkc_base + 0xa8)
83#define CRL_APB_PL3_REF_CTRL (zynqmp_crl_apb_clkc_base + 0xac)
84#define CRL_APB_PL0_THR_CNT (zynqmp_crl_apb_clkc_base + 0xb4)
85#define CRL_APB_PL1_THR_CNT (zynqmp_crl_apb_clkc_base + 0xbc)
86#define CRL_APB_PL2_THR_CNT (zynqmp_crl_apb_clkc_base + 0xc4)
87#define CRL_APB_PL3_THR_CNT (zynqmp_crl_apb_clkc_base + 0xdc)
88#define CRL_APB_GEM_TSU_REF_CTRL (zynqmp_crl_apb_clkc_base + 0xe0)
89#define CRL_APB_DLL_REF_CTRL (zynqmp_crl_apb_clkc_base + 0xe4)
90#define CRL_APB_AMS_REF_CTRL (zynqmp_crl_apb_clkc_base + 0xe8)
91#define CRL_APB_I2C0_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x100)
92#define CRL_APB_I2C1_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x104)
93#define CRL_APB_TIMESTAMP_REF_CTRL (zynqmp_crl_apb_clkc_base + 0x108)
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +053094
95#define ZYNQ_CLK_MAXDIV 0x3f
96#define CLK_CTRL_DIV1_SHIFT 16
97#define CLK_CTRL_DIV1_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV1_SHIFT)
98#define CLK_CTRL_DIV0_SHIFT 8
99#define CLK_CTRL_DIV0_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV0_SHIFT)
T Karthik Reddy97ab47d2021-02-24 23:44:46 -0700100#define CLK_CTRL_SRCSEL_MASK 0x7
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530101#define PLLCTRL_FBDIV_MASK 0x7f00
102#define PLLCTRL_FBDIV_SHIFT 8
103#define PLLCTRL_RESET_MASK 1
104#define PLLCTRL_RESET_SHIFT 0
105#define PLLCTRL_BYPASS_MASK 0x8
106#define PLLCTRL_BYPASS_SHFT 3
107#define PLLCTRL_POST_SRC_SHFT 24
108#define PLLCTRL_POST_SRC_MASK (0x7 << PLLCTRL_POST_SRC_SHFT)
Vipul Kumar488f0e72018-06-27 10:44:45 +0530109#define PLLCTRL_PRE_SRC_SHFT 20
110#define PLLCTRL_PRE_SRC_MASK (0x7 << PLLCTRL_PRE_SRC_SHFT)
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530111
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530112#define NUM_MIO_PINS 77
113
114enum zynqmp_clk {
115 iopll, rpll,
116 apll, dpll, vpll,
117 iopll_to_fpd, rpll_to_fpd, apll_to_lpd, dpll_to_lpd, vpll_to_lpd,
118 acpu, acpu_half,
119 dbg_fpd, dbg_lpd, dbg_trace, dbg_tstmp,
120 dp_video_ref, dp_audio_ref,
121 dp_stc_ref, gdma_ref, dpdma_ref,
122 ddr_ref, sata_ref, pcie_ref,
123 gpu_ref, gpu_pp0_ref, gpu_pp1_ref,
124 topsw_main, topsw_lsbus,
125 gtgref0_ref,
126 lpd_switch, lpd_lsbus,
127 usb0_bus_ref, usb1_bus_ref, usb3_dual_ref, usb0, usb1,
128 cpu_r5, cpu_r5_core,
129 csu_spb, csu_pll, pcap,
130 iou_switch,
131 gem_tsu_ref, gem_tsu,
T Karthik Reddy97ab47d2021-02-24 23:44:46 -0700132 gem0_tx, gem1_tx, gem2_tx, gem3_tx,
Michal Simek544f4482021-10-29 13:13:38 +0200133 gem0_rx, gem1_rx, gem2_rx, gem3_rx,
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530134 qspi_ref,
135 sdio0_ref, sdio1_ref,
136 uart0_ref, uart1_ref,
137 spi0_ref, spi1_ref,
138 nand_ref,
139 i2c0_ref, i2c1_ref, can0_ref, can1_ref, can0, can1,
140 dll_ref,
141 adma_ref,
142 timestamp_ref,
143 ams_ref,
144 pl0, pl1, pl2, pl3,
145 wdt,
Michal Simek544f4482021-10-29 13:13:38 +0200146 gem0_ref = 104,
147 gem1_ref, gem2_ref, gem3_ref,
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530148 clk_max,
149};
150
151static const char * const clk_names[clk_max] = {
152 "iopll", "rpll", "apll", "dpll",
153 "vpll", "iopll_to_fpd", "rpll_to_fpd",
154 "apll_to_lpd", "dpll_to_lpd", "vpll_to_lpd",
T Karthik Reddy97ab47d2021-02-24 23:44:46 -0700155 "acpu", "acpu_half", "dbg_fpd", "dbg_lpd",
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530156 "dbg_trace", "dbg_tstmp", "dp_video_ref",
157 "dp_audio_ref", "dp_stc_ref", "gdma_ref",
158 "dpdma_ref", "ddr_ref", "sata_ref", "pcie_ref",
159 "gpu_ref", "gpu_pp0_ref", "gpu_pp1_ref",
160 "topsw_main", "topsw_lsbus", "gtgref0_ref",
161 "lpd_switch", "lpd_lsbus", "usb0_bus_ref",
162 "usb1_bus_ref", "usb3_dual_ref", "usb0",
163 "usb1", "cpu_r5", "cpu_r5_core", "csu_spb",
164 "csu_pll", "pcap", "iou_switch", "gem_tsu_ref",
Michal Simek544f4482021-10-29 13:13:38 +0200165 "gem_tsu", "gem0_tx", "gem1_tx", "gem2_tx",
166 "gem3_tx", "gem0_rx", "gem1_rx", "gem2_rx",
167 "gem3_rx", "qspi_ref", "sdio0_ref", "sdio1_ref",
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530168 "uart0_ref", "uart1_ref", "spi0_ref",
169 "spi1_ref", "nand_ref", "i2c0_ref", "i2c1_ref",
170 "can0_ref", "can1_ref", "can0", "can1",
171 "dll_ref", "adma_ref", "timestamp_ref",
Michal Simek544f4482021-10-29 13:13:38 +0200172 "ams_ref", "pl0", "pl1", "pl2", "pl3", "wdt",
173 NULL, NULL, NULL, NULL,
174 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
175 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
176 NULL, NULL, NULL, NULL, "gem0_ref", "gem1_ref", "gem2_ref", "gem3_ref",
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530177};
178
T Karthik Reddy97ab47d2021-02-24 23:44:46 -0700179static const u32 pll_src[][4] = {
180 {apll, 0xff, dpll, vpll}, /* acpu */
181 {dpll, vpll, 0xff, 0xff}, /* ddr_ref */
182 {rpll, iopll, 0xff, 0xff}, /* dll_ref */
183 {iopll, 0xff, rpll, dpll_to_lpd}, /* gem_tsu_ref */
184 {iopll, 0xff, rpll, dpll}, /* peripheral */
185 {apll, 0xff, iopll_to_fpd, dpll}, /* wdt */
186 {iopll_to_fpd, 0xff, dpll, apll}, /* dbg_fpd */
187 {iopll, 0xff, rpll, dpll_to_lpd}, /* timestamp_ref */
188 {iopll_to_fpd, 0xff, apll, dpll}, /* sata_ref */
189 {iopll_to_fpd, 0xff, rpll_to_fpd, dpll},/* pcie_ref */
190 {iopll_to_fpd, 0xff, vpll, dpll}, /* gpu_ref */
191 {apll, 0xff, vpll, dpll}, /* topsw_main_ref */
192 {rpll, 0xff, iopll, dpll_to_lpd}, /* cpu_r5_ref */
193};
194
195enum zynqmp_clk_pll_src {
196 ACPU_CLK_SRC = 0,
197 DDR_CLK_SRC,
198 DLL_CLK_SRC,
199 GEM_TSU_CLK_SRC,
200 PERI_CLK_SRC,
201 WDT_CLK_SRC,
202 DBG_FPD_CLK_SRC,
203 TIMESTAMP_CLK_SRC,
204 SATA_CLK_SRC,
205 PCIE_CLK_SRC,
206 GPU_CLK_SRC,
207 TOPSW_MAIN_CLK_SRC,
208 CPU_R5_CLK_SRC
209};
210
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530211struct zynqmp_clk_priv {
212 unsigned long ps_clk_freq;
213 unsigned long video_clk;
214 unsigned long pss_alt_ref_clk;
215 unsigned long gt_crx_ref_clk;
216 unsigned long aux_ref_clk;
217};
218
219static u32 zynqmp_clk_get_register(enum zynqmp_clk id)
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530220{
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530221 switch (id) {
222 case iopll:
223 return CRL_APB_IOPLL_CTRL;
224 case rpll:
225 return CRL_APB_RPLL_CTRL;
226 case apll:
227 return CRF_APB_APLL_CTRL;
228 case dpll:
229 return CRF_APB_DPLL_CTRL;
230 case vpll:
231 return CRF_APB_VPLL_CTRL;
232 case acpu:
233 return CRF_APB_ACPU_CTRL;
T Karthik Reddy97ab47d2021-02-24 23:44:46 -0700234 case dbg_fpd:
235 return CRF_APB_DBG_FPD_CTRL;
236 case dbg_trace:
237 return CRF_APB_DBG_TRACE_CTRL;
238 case dbg_tstmp:
239 return CRF_APB_DBG_TSTMP_CTRL;
Michal Simekacff4c82022-03-29 13:13:56 +0200240 case dp_video_ref:
241 return CRF_APB_DP_VIDEO_REF_CTRL;
242 case dp_audio_ref:
243 return CRF_APB_DP_AUDIO_REF_CTRL;
244 case dp_stc_ref:
245 return CRF_APB_DP_STC_REF_CTRL;
T Karthik Reddy97ab47d2021-02-24 23:44:46 -0700246 case gpu_ref ... gpu_pp1_ref:
247 return CRF_APB_GPU_REF_CTRL;
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530248 case ddr_ref:
249 return CRF_APB_DDR_CTRL;
T Karthik Reddy97ab47d2021-02-24 23:44:46 -0700250 case sata_ref:
251 return CRF_APB_SATA_REF_CTRL;
252 case pcie_ref:
253 return CRF_APB_PCIE_REF_CTRL;
254 case gdma_ref:
255 return CRF_APB_GDMA_REF_CTRL;
256 case dpdma_ref:
257 return CRF_APB_DPDMA_REF_CTRL;
258 case topsw_main:
259 return CRF_APB_TOPSW_MAIN_CTRL;
260 case topsw_lsbus:
261 return CRF_APB_TOPSW_LSBUS_CTRL;
262 case lpd_switch:
263 return CRL_APB_LPD_SWITCH_CTRL;
264 case lpd_lsbus:
265 return CRL_APB_LPD_LSBUS_CTRL;
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530266 case qspi_ref:
267 return CRL_APB_QSPI_REF_CTRL;
T Karthik Reddy2aa360e2021-02-03 03:10:45 -0700268 case usb3_dual_ref:
269 return CRL_APB_USB3_DUAL_REF_CTRL;
T Karthik Reddy97ab47d2021-02-24 23:44:46 -0700270 case gem_tsu_ref:
Ashok Reddy Soma0a08f442023-07-20 01:28:59 -0600271 case gem_tsu:
T Karthik Reddy97ab47d2021-02-24 23:44:46 -0700272 return CRL_APB_GEM_TSU_REF_CTRL;
Michal Simek544f4482021-10-29 13:13:38 +0200273 case gem0_tx:
Ashok Reddy Soma0a08f442023-07-20 01:28:59 -0600274 case gem0_rx:
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530275 case gem0_ref:
276 return CRL_APB_GEM0_REF_CTRL;
Michal Simek544f4482021-10-29 13:13:38 +0200277 case gem1_tx:
Ashok Reddy Soma0a08f442023-07-20 01:28:59 -0600278 case gem1_rx:
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530279 case gem1_ref:
280 return CRL_APB_GEM1_REF_CTRL;
Michal Simek544f4482021-10-29 13:13:38 +0200281 case gem2_tx:
Ashok Reddy Soma0a08f442023-07-20 01:28:59 -0600282 case gem2_rx:
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530283 case gem2_ref:
284 return CRL_APB_GEM2_REF_CTRL;
Michal Simek544f4482021-10-29 13:13:38 +0200285 case gem3_tx:
Ashok Reddy Soma0a08f442023-07-20 01:28:59 -0600286 case gem3_rx:
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530287 case gem3_ref:
288 return CRL_APB_GEM3_REF_CTRL;
T Karthik Reddy2aa360e2021-02-03 03:10:45 -0700289 case usb0_bus_ref:
290 return CRL_APB_USB0_BUS_REF_CTRL;
291 case usb1_bus_ref:
292 return CRL_APB_USB1_BUS_REF_CTRL;
T Karthik Reddy97ab47d2021-02-24 23:44:46 -0700293 case cpu_r5:
294 return CRL_APB_CPU_R5_CTRL;
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530295 case uart0_ref:
296 return CRL_APB_UART0_REF_CTRL;
297 case uart1_ref:
298 return CRL_APB_UART1_REF_CTRL;
299 case sdio0_ref:
300 return CRL_APB_SDIO0_REF_CTRL;
301 case sdio1_ref:
302 return CRL_APB_SDIO1_REF_CTRL;
303 case spi0_ref:
304 return CRL_APB_SPI0_REF_CTRL;
305 case spi1_ref:
306 return CRL_APB_SPI1_REF_CTRL;
307 case nand_ref:
308 return CRL_APB_NAND_REF_CTRL;
309 case i2c0_ref:
310 return CRL_APB_I2C0_REF_CTRL;
311 case i2c1_ref:
312 return CRL_APB_I2C1_REF_CTRL;
313 case can0_ref:
314 return CRL_APB_CAN0_REF_CTRL;
315 case can1_ref:
316 return CRL_APB_CAN1_REF_CTRL;
T Karthik Reddy97ab47d2021-02-24 23:44:46 -0700317 case dll_ref:
318 return CRL_APB_DLL_REF_CTRL;
319 case adma_ref:
320 return CRL_APB_ADMA_REF_CTRL;
321 case timestamp_ref:
322 return CRL_APB_TIMESTAMP_REF_CTRL;
323 case ams_ref:
324 return CRL_APB_AMS_REF_CTRL;
Vipul Kumarc35e5f62018-03-07 14:52:44 +0530325 case pl0:
326 return CRL_APB_PL0_REF_CTRL;
327 case pl1:
328 return CRL_APB_PL1_REF_CTRL;
329 case pl2:
330 return CRL_APB_PL2_REF_CTRL;
331 case pl3:
332 return CRL_APB_PL3_REF_CTRL;
333 case wdt:
334 return CRF_APB_TOPSW_LSBUS_CTRL;
335 case iopll_to_fpd:
336 return CRL_APB_IOPLL_TO_FPD_CTRL;
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530337 default:
338 debug("Invalid clk id%d\n", id);
339 }
340 return 0;
341}
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530342
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530343static ulong zynqmp_clk_get_pll_src(ulong clk_ctrl,
344 struct zynqmp_clk_priv *priv,
345 bool is_pre_src)
346{
347 u32 src_sel;
348
349 if (is_pre_src)
Vipul Kumar488f0e72018-06-27 10:44:45 +0530350 src_sel = (clk_ctrl & PLLCTRL_PRE_SRC_MASK) >>
351 PLLCTRL_PRE_SRC_SHFT;
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530352 else
353 src_sel = (clk_ctrl & PLLCTRL_POST_SRC_MASK) >>
354 PLLCTRL_POST_SRC_SHFT;
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530355
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530356 switch (src_sel) {
357 case 4:
358 return priv->video_clk;
359 case 5:
360 return priv->pss_alt_ref_clk;
361 case 6:
362 return priv->aux_ref_clk;
363 case 7:
364 return priv->gt_crx_ref_clk;
365 case 0 ... 3:
366 default:
367 return priv->ps_clk_freq;
368 }
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530369}
370
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530371static ulong zynqmp_clk_get_pll_rate(struct zynqmp_clk_priv *priv,
372 enum zynqmp_clk id)
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530373{
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530374 u32 clk_ctrl, reset, mul;
375 ulong freq;
376 int ret;
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530377
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530378 ret = zynqmp_mmio_read(zynqmp_clk_get_register(id), &clk_ctrl);
Siva Durga Prasad Paladugubcfc0862017-04-13 16:59:38 +0530379 if (ret) {
380 printf("%s mio read fail\n", __func__);
381 return -EIO;
382 }
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530383
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530384 if (clk_ctrl & PLLCTRL_BYPASS_MASK)
385 freq = zynqmp_clk_get_pll_src(clk_ctrl, priv, 0);
386 else
387 freq = zynqmp_clk_get_pll_src(clk_ctrl, priv, 1);
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530388
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530389 reset = (clk_ctrl & PLLCTRL_RESET_MASK) >> PLLCTRL_RESET_SHIFT;
390 if (reset && !(clk_ctrl & PLLCTRL_BYPASS_MASK))
391 return 0;
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530392
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530393 mul = (clk_ctrl & PLLCTRL_FBDIV_MASK) >> PLLCTRL_FBDIV_SHIFT;
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530394
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530395 freq *= mul;
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530396
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530397 if (clk_ctrl & (1 << 16))
398 freq /= 2;
399
400 return freq;
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530401}
402
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530403static ulong zynqmp_clk_get_cpu_rate(struct zynqmp_clk_priv *priv,
404 enum zynqmp_clk id)
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530405{
T Karthik Reddy97ab47d2021-02-24 23:44:46 -0700406 u32 clk_ctrl, div, srcsel;
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530407 enum zynqmp_clk pll;
408 int ret;
Siva Durga Prasad Paladugubcfc0862017-04-13 16:59:38 +0530409 unsigned long pllrate;
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530410
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530411 ret = zynqmp_mmio_read(CRF_APB_ACPU_CTRL, &clk_ctrl);
Siva Durga Prasad Paladugubcfc0862017-04-13 16:59:38 +0530412 if (ret) {
413 printf("%s mio read fail\n", __func__);
414 return -EIO;
415 }
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530416
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530417 div = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530418
T Karthik Reddy97ab47d2021-02-24 23:44:46 -0700419 srcsel = clk_ctrl & CLK_CTRL_SRCSEL_MASK;
420 pll = pll_src[ACPU_CLK_SRC][srcsel];
Siva Durga Prasad Paladugubcfc0862017-04-13 16:59:38 +0530421 pllrate = zynqmp_clk_get_pll_rate(priv, pll);
422 if (IS_ERR_VALUE(pllrate))
423 return pllrate;
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530424
Siva Durga Prasad Paladugubcfc0862017-04-13 16:59:38 +0530425 return DIV_ROUND_CLOSEST(pllrate, div);
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530426}
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530427
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530428static ulong zynqmp_clk_get_ddr_rate(struct zynqmp_clk_priv *priv)
429{
T Karthik Reddy97ab47d2021-02-24 23:44:46 -0700430 u32 clk_ctrl, div, srcsel;
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530431 enum zynqmp_clk pll;
432 int ret;
Siva Durga Prasad Paladugubcfc0862017-04-13 16:59:38 +0530433 ulong pllrate;
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530434
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530435 ret = zynqmp_mmio_read(CRF_APB_DDR_CTRL, &clk_ctrl);
Siva Durga Prasad Paladugubcfc0862017-04-13 16:59:38 +0530436 if (ret) {
437 printf("%s mio read fail\n", __func__);
438 return -EIO;
439 }
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530440
441 div = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
442
T Karthik Reddy97ab47d2021-02-24 23:44:46 -0700443 srcsel = clk_ctrl & CLK_CTRL_SRCSEL_MASK;
444 pll = pll_src[DDR_CLK_SRC][srcsel];
Siva Durga Prasad Paladugubcfc0862017-04-13 16:59:38 +0530445 pllrate = zynqmp_clk_get_pll_rate(priv, pll);
446 if (IS_ERR_VALUE(pllrate))
447 return pllrate;
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530448
Siva Durga Prasad Paladugubcfc0862017-04-13 16:59:38 +0530449 return DIV_ROUND_CLOSEST(pllrate, div);
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530450}
451
T Karthik Reddy97ab47d2021-02-24 23:44:46 -0700452static ulong zynqmp_clk_get_dll_rate(struct zynqmp_clk_priv *priv)
453{
454 u32 clk_ctrl, srcsel;
455 enum zynqmp_clk pll;
456 ulong pllrate;
457 int ret;
458
459 ret = zynqmp_mmio_read(CRL_APB_DLL_REF_CTRL, &clk_ctrl);
460 if (ret) {
461 printf("%s mio read fail\n", __func__);
462 return -EIO;
463 }
464
465 srcsel = clk_ctrl & CLK_CTRL_SRCSEL_MASK;
466 pll = pll_src[DLL_CLK_SRC][srcsel];
467 pllrate = zynqmp_clk_get_pll_rate(priv, pll);
468 if (IS_ERR_VALUE(pllrate))
469 return pllrate;
470
471 return pllrate;
472}
473
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530474static ulong zynqmp_clk_get_peripheral_rate(struct zynqmp_clk_priv *priv,
T Karthik Reddy97ab47d2021-02-24 23:44:46 -0700475 enum zynqmp_clk id, bool two_divs)
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530476{
477 enum zynqmp_clk pll;
T Karthik Reddy97ab47d2021-02-24 23:44:46 -0700478 u32 clk_ctrl, div0, srcsel;
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530479 u32 div1 = 1;
480 int ret;
Siva Durga Prasad Paladugubcfc0862017-04-13 16:59:38 +0530481 ulong pllrate;
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530482
483 ret = zynqmp_mmio_read(zynqmp_clk_get_register(id), &clk_ctrl);
Siva Durga Prasad Paladugubcfc0862017-04-13 16:59:38 +0530484 if (ret) {
485 printf("%s mio read fail\n", __func__);
486 return -EIO;
487 }
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530488
489 div0 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
490 if (!div0)
491 div0 = 1;
492
493 if (two_divs) {
494 div1 = (clk_ctrl & CLK_CTRL_DIV1_MASK) >> CLK_CTRL_DIV1_SHIFT;
495 if (!div1)
496 div1 = 1;
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530497 }
T Karthik Reddy97ab47d2021-02-24 23:44:46 -0700498 srcsel = clk_ctrl & CLK_CTRL_SRCSEL_MASK;
499
500 if (id == gem_tsu_ref)
501 pll = pll_src[GEM_TSU_CLK_SRC][srcsel];
502 else
503 pll = pll_src[PERI_CLK_SRC][srcsel];
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530504
Siva Durga Prasad Paladugubcfc0862017-04-13 16:59:38 +0530505 pllrate = zynqmp_clk_get_pll_rate(priv, pll);
506 if (IS_ERR_VALUE(pllrate))
507 return pllrate;
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530508
509 return
510 DIV_ROUND_CLOSEST(
Siva Durga Prasad Paladugubcfc0862017-04-13 16:59:38 +0530511 DIV_ROUND_CLOSEST(pllrate, div0), div1);
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530512}
513
T Karthik Reddy97ab47d2021-02-24 23:44:46 -0700514static ulong zynqmp_clk_get_crf_crl_rate(struct zynqmp_clk_priv *priv,
515 enum zynqmp_clk id, bool two_divs)
Vipul Kumarc35e5f62018-03-07 14:52:44 +0530516{
517 enum zynqmp_clk pll;
T Karthik Reddy97ab47d2021-02-24 23:44:46 -0700518 u32 clk_ctrl, div0, srcsel;
Vipul Kumarc35e5f62018-03-07 14:52:44 +0530519 u32 div1 = 1;
520 int ret;
521 ulong pllrate;
522
523 ret = zynqmp_mmio_read(zynqmp_clk_get_register(id), &clk_ctrl);
524 if (ret) {
525 printf("%d %s mio read fail\n", __LINE__, __func__);
526 return -EIO;
527 }
528
529 div0 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
530 if (!div0)
531 div0 = 1;
T Karthik Reddy97ab47d2021-02-24 23:44:46 -0700532 srcsel = clk_ctrl & CLK_CTRL_SRCSEL_MASK;
Vipul Kumarc35e5f62018-03-07 14:52:44 +0530533
T Karthik Reddy97ab47d2021-02-24 23:44:46 -0700534 switch (id) {
535 case wdt:
536 case dbg_trace:
537 case topsw_lsbus:
538 pll = pll_src[WDT_CLK_SRC][srcsel];
539 break;
540 case dbg_fpd:
541 case dbg_tstmp:
542 pll = pll_src[DBG_FPD_CLK_SRC][srcsel];
543 break;
544 case timestamp_ref:
545 pll = pll_src[TIMESTAMP_CLK_SRC][srcsel];
546 break;
547 case sata_ref:
548 pll = pll_src[SATA_CLK_SRC][srcsel];
549 break;
550 case pcie_ref:
551 pll = pll_src[PCIE_CLK_SRC][srcsel];
552 break;
553 case gpu_ref ... gpu_pp1_ref:
554 pll = pll_src[GPU_CLK_SRC][srcsel];
555 break;
556 case gdma_ref:
557 case dpdma_ref:
558 case topsw_main:
559 pll = pll_src[TOPSW_MAIN_CLK_SRC][srcsel];
560 break;
561 case cpu_r5:
562 case ams_ref:
563 case adma_ref:
564 case lpd_lsbus:
565 case lpd_switch:
566 pll = pll_src[CPU_R5_CLK_SRC][srcsel];
567 break;
568 default:
569 return -ENXIO;
570 }
Vipul Kumarc35e5f62018-03-07 14:52:44 +0530571 if (two_divs) {
572 ret = zynqmp_mmio_read(zynqmp_clk_get_register(pll), &clk_ctrl);
573 if (ret) {
574 printf("%d %s mio read fail\n", __LINE__, __func__);
575 return -EIO;
576 }
577 div1 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT;
578 if (!div1)
579 div1 = 1;
580 }
581
582 if (pll == iopll_to_fpd)
583 pll = iopll;
584
585 pllrate = zynqmp_clk_get_pll_rate(priv, pll);
586 if (IS_ERR_VALUE(pllrate))
587 return pllrate;
588
589 return
590 DIV_ROUND_CLOSEST(
591 DIV_ROUND_CLOSEST(pllrate, div0), div1);
592}
593
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530594static unsigned long zynqmp_clk_calc_peripheral_two_divs(ulong rate,
595 ulong pll_rate,
596 u32 *div0, u32 *div1)
597{
598 long new_err, best_err = (long)(~0UL >> 1);
599 ulong new_rate, best_rate = 0;
600 u32 d0, d1;
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530601
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530602 for (d0 = 1; d0 <= ZYNQ_CLK_MAXDIV; d0++) {
603 for (d1 = 1; d1 <= ZYNQ_CLK_MAXDIV >> 1; d1++) {
604 new_rate = DIV_ROUND_CLOSEST(
605 DIV_ROUND_CLOSEST(pll_rate, d0), d1);
606 new_err = abs(new_rate - rate);
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530607
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530608 if (new_err < best_err) {
609 *div0 = d0;
610 *div1 = d1;
611 best_err = new_err;
612 best_rate = new_rate;
613 }
614 }
615 }
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530616
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530617 return best_rate;
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530618}
619
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530620static ulong zynqmp_clk_set_peripheral_rate(struct zynqmp_clk_priv *priv,
621 enum zynqmp_clk id, ulong rate,
622 bool two_divs)
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530623{
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530624 enum zynqmp_clk pll;
625 u32 clk_ctrl, div0 = 0, div1 = 0;
626 ulong pll_rate, new_rate;
T Karthik Reddy97ab47d2021-02-24 23:44:46 -0700627 u32 reg, srcsel;
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530628 int ret;
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530629 u32 mask;
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530630
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530631 reg = zynqmp_clk_get_register(id);
632 ret = zynqmp_mmio_read(reg, &clk_ctrl);
Siva Durga Prasad Paladugubcfc0862017-04-13 16:59:38 +0530633 if (ret) {
634 printf("%s mio read fail\n", __func__);
635 return -EIO;
636 }
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530637
T Karthik Reddy97ab47d2021-02-24 23:44:46 -0700638 srcsel = clk_ctrl & CLK_CTRL_SRCSEL_MASK;
639 pll = pll_src[PERI_CLK_SRC][srcsel];
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530640 pll_rate = zynqmp_clk_get_pll_rate(priv, pll);
Siva Durga Prasad Paladugubcfc0862017-04-13 16:59:38 +0530641 if (IS_ERR_VALUE(pll_rate))
642 return pll_rate;
643
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530644 clk_ctrl &= ~CLK_CTRL_DIV0_MASK;
645 if (two_divs) {
646 clk_ctrl &= ~CLK_CTRL_DIV1_MASK;
647 new_rate = zynqmp_clk_calc_peripheral_two_divs(rate, pll_rate,
648 &div0, &div1);
649 clk_ctrl |= div1 << CLK_CTRL_DIV1_SHIFT;
650 } else {
651 div0 = DIV_ROUND_CLOSEST(pll_rate, rate);
652 if (div0 > ZYNQ_CLK_MAXDIV)
653 div0 = ZYNQ_CLK_MAXDIV;
654 new_rate = DIV_ROUND_CLOSEST(rate, div0);
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530655 }
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530656 clk_ctrl |= div0 << CLK_CTRL_DIV0_SHIFT;
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530657
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530658 mask = (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV0_SHIFT) |
659 (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV1_SHIFT);
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530660
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530661 ret = zynqmp_mmio_write(reg, mask, clk_ctrl);
Siva Durga Prasad Paladugubcfc0862017-04-13 16:59:38 +0530662 if (ret) {
663 printf("%s mio write fail\n", __func__);
664 return -EIO;
665 }
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530666
667 return new_rate;
668}
669
670static ulong zynqmp_clk_get_rate(struct clk *clk)
671{
672 struct zynqmp_clk_priv *priv = dev_get_priv(clk->dev);
673 enum zynqmp_clk id = clk->id;
674 bool two_divs = false;
675
676 switch (id) {
677 case iopll ... vpll:
678 return zynqmp_clk_get_pll_rate(priv, id);
679 case acpu:
680 return zynqmp_clk_get_cpu_rate(priv, id);
681 case ddr_ref:
682 return zynqmp_clk_get_ddr_rate(priv);
T Karthik Reddy97ab47d2021-02-24 23:44:46 -0700683 case dll_ref:
684 return zynqmp_clk_get_dll_rate(priv);
685 case gem_tsu_ref:
Michal Simekacff4c82022-03-29 13:13:56 +0200686 case dp_video_ref ... dp_stc_ref:
T Karthik Reddy97ab47d2021-02-24 23:44:46 -0700687 case pl0 ... pl3:
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530688 case gem0_ref ... gem3_ref:
Michal Simek544f4482021-10-29 13:13:38 +0200689 case gem0_tx ... gem3_tx:
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530690 case qspi_ref ... can1_ref:
T Karthik Reddy97ab47d2021-02-24 23:44:46 -0700691 case usb0_bus_ref ... usb3_dual_ref:
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530692 two_divs = true;
693 return zynqmp_clk_get_peripheral_rate(priv, id, two_divs);
Vipul Kumarc35e5f62018-03-07 14:52:44 +0530694 case wdt:
T Karthik Reddy97ab47d2021-02-24 23:44:46 -0700695 case topsw_lsbus:
696 case sata_ref ... gpu_pp1_ref:
Vipul Kumarc35e5f62018-03-07 14:52:44 +0530697 two_divs = true;
Algapally Santosh Sagar9a990932023-05-19 17:08:15 +0530698 fallthrough;
T Karthik Reddy97ab47d2021-02-24 23:44:46 -0700699 case cpu_r5:
700 case dbg_fpd:
701 case ams_ref:
702 case adma_ref:
703 case lpd_lsbus:
704 case dbg_trace:
705 case dbg_tstmp:
706 case lpd_switch:
707 case topsw_main:
708 case timestamp_ref:
709 case gdma_ref ... dpdma_ref:
710 return zynqmp_clk_get_crf_crl_rate(priv, id, two_divs);
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530711 default:
712 return -ENXIO;
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530713 }
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530714}
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530715
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530716static ulong zynqmp_clk_set_rate(struct clk *clk, ulong rate)
717{
718 struct zynqmp_clk_priv *priv = dev_get_priv(clk->dev);
719 enum zynqmp_clk id = clk->id;
720 bool two_divs = true;
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530721
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530722 switch (id) {
723 case gem0_ref ... gem3_ref:
Michal Simek544f4482021-10-29 13:13:38 +0200724 case gem0_tx ... gem3_tx:
Ashok Reddy Soma025964b2023-07-19 02:49:12 -0600725 case gem0_rx ... gem3_rx:
726 case gem_tsu:
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530727 case qspi_ref ... can1_ref:
Michal Simek66a38922021-10-29 13:13:37 +0200728 case usb0_bus_ref ... usb3_dual_ref:
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530729 return zynqmp_clk_set_peripheral_rate(priv, id,
730 rate, two_divs);
731 default:
732 return -ENXIO;
733 }
734}
735
Igor Prusov1a3427b2023-11-09 13:55:15 +0300736#if IS_ENABLED(CONFIG_CMD_CLK)
737static void zynqmp_clk_dump(struct udevice *dev)
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530738{
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530739 int i, ret;
740
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530741 printf("clk\t\tfrequency\n");
742 for (i = 0; i < clk_max; i++) {
743 const char *name = clk_names[i];
744 if (name) {
745 struct clk clk;
746 unsigned long rate;
747
748 clk.id = i;
749 ret = clk_request(dev, &clk);
Igor Prusov1a3427b2023-11-09 13:55:15 +0300750 if (ret < 0) {
751 printf("%s clk_request() failed: %d\n",
752 __func__, ret);
753 break;
754 }
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530755
756 rate = clk_get_rate(&clk);
757
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530758 if ((rate == (unsigned long)-ENOSYS) ||
Siva Durga Prasad Paladugubcfc0862017-04-13 16:59:38 +0530759 (rate == (unsigned long)-ENXIO) ||
760 (rate == (unsigned long)-EIO))
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530761 printf("%10s%20s\n", name, "unknown");
762 else
763 printf("%10s%20lu\n", name, rate);
764 }
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530765 }
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530766}
Igor Prusov1a3427b2023-11-09 13:55:15 +0300767#endif
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530768
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530769static int zynqmp_get_freq_by_name(char *name, struct udevice *dev, ulong *freq)
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530770{
771 struct clk clk;
772 int ret;
773
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530774 ret = clk_get_by_name(dev, name, &clk);
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530775 if (ret < 0) {
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530776 dev_err(dev, "failed to get %s\n", name);
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530777 return ret;
778 }
779
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530780 *freq = clk_get_rate(&clk);
781 if (IS_ERR_VALUE(*freq)) {
782 dev_err(dev, "failed to get rate %s\n", name);
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530783 return -EINVAL;
784 }
785
786 return 0;
787}
Siva Durga Prasad Paladuguf0471e92017-02-03 23:56:49 +0530788static int zynqmp_clk_probe(struct udevice *dev)
789{
790 int ret;
791 struct zynqmp_clk_priv *priv = dev_get_priv(dev);
792
793 debug("%s\n", __func__);
794 ret = zynqmp_get_freq_by_name("pss_ref_clk", dev, &priv->ps_clk_freq);
795 if (ret < 0)
796 return -EINVAL;
797
798 ret = zynqmp_get_freq_by_name("video_clk", dev, &priv->video_clk);
799 if (ret < 0)
800 return -EINVAL;
801
802 ret = zynqmp_get_freq_by_name("pss_alt_ref_clk", dev,
803 &priv->pss_alt_ref_clk);
804 if (ret < 0)
805 return -EINVAL;
806
807 ret = zynqmp_get_freq_by_name("aux_ref_clk", dev, &priv->aux_ref_clk);
808 if (ret < 0)
809 return -EINVAL;
810
811 ret = zynqmp_get_freq_by_name("gt_crx_ref_clk", dev,
812 &priv->gt_crx_ref_clk);
813 if (ret < 0)
814 return -EINVAL;
815
816 return 0;
817}
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530818
T Karthik Reddy2aa360e2021-02-03 03:10:45 -0700819static int zynqmp_clk_enable(struct clk *clk)
820{
821 enum zynqmp_clk id = clk->id;
822 u32 reg, clk_ctrl, clkact_shift, mask;
823 int ret;
824
825 reg = zynqmp_clk_get_register(id);
826 debug("%s, clk_id:%x, clk_base:0x%x\n", __func__, id, reg);
827
828 switch (id) {
829 case usb0_bus_ref ... usb1:
830 clkact_shift = 25;
831 mask = 0x1;
832 break;
Michal Simek544f4482021-10-29 13:13:38 +0200833 case gem0_tx ... gem3_tx:
T Karthik Reddy2aa360e2021-02-03 03:10:45 -0700834 case gem0_ref ... gem3_ref:
835 clkact_shift = 25;
836 mask = 0x3;
837 break;
838 case qspi_ref ... can1_ref:
Michal Simek97790fb2021-07-01 19:01:42 +0200839 case lpd_lsbus:
Venkatesh Yadav Abbarapu0d84dcd2023-12-04 14:15:15 +0530840 case topsw_lsbus:
T Karthik Reddy2aa360e2021-02-03 03:10:45 -0700841 clkact_shift = 24;
842 mask = 0x1;
843 break;
844 default:
845 return -ENXIO;
846 }
847
848 ret = zynqmp_mmio_read(reg, &clk_ctrl);
849 if (ret) {
850 printf("%s mio read fail\n", __func__);
851 return -EIO;
852 }
853
854 clk_ctrl |= (mask << clkact_shift);
855 ret = zynqmp_mmio_write(reg, mask << clkact_shift, clk_ctrl);
856 if (ret) {
857 printf("%s mio write fail\n", __func__);
858 return -EIO;
859 }
860
861 return ret;
862}
863
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530864static struct clk_ops zynqmp_clk_ops = {
865 .set_rate = zynqmp_clk_set_rate,
866 .get_rate = zynqmp_clk_get_rate,
T Karthik Reddy2aa360e2021-02-03 03:10:45 -0700867 .enable = zynqmp_clk_enable,
Igor Prusov1a3427b2023-11-09 13:55:15 +0300868#if IS_ENABLED(CONFIG_CMD_CLK)
869 .dump = zynqmp_clk_dump,
870#endif
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530871};
872
873static const struct udevice_id zynqmp_clk_ids[] = {
Michal Simekd260ac72018-02-21 13:59:21 +0100874 { .compatible = "xlnx,zynqmp-clk" },
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530875 { }
876};
877
878U_BOOT_DRIVER(zynqmp_clk) = {
Michal Simek33093082020-01-07 08:50:34 +0100879 .name = "zynqmp_clk",
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530880 .id = UCLASS_CLK,
881 .of_match = zynqmp_clk_ids,
882 .probe = zynqmp_clk_probe,
883 .ops = &zynqmp_clk_ops,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700884 .priv_auto = sizeof(struct zynqmp_clk_priv),
Siva Durga Prasad Paladugu468b55f2016-11-15 16:15:41 +0530885};