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