1 /* 2 * Copyright (C) 2017 Weidmüller Interface GmbH & Co. KG 3 * Stefan Herbrechtsmeier <stefan.herbrechtsmeier@weidmueller.com> 4 * 5 * Copyright (C) 2013 Soren Brinkmann <soren.brinkmann@xilinx.com> 6 * Copyright (C) 2013 Xilinx, Inc. All rights reserved. 7 * 8 * SPDX-License-Identifier: GPL-2.0+ 9 */ 10 11 #include <common.h> 12 #include <clk-uclass.h> 13 #include <dm.h> 14 #include <dm/lists.h> 15 #include <errno.h> 16 #include <asm/io.h> 17 #include <asm/arch/clk.h> 18 #include <asm/arch/hardware.h> 19 #include <asm/arch/sys_proto.h> 20 21 /* Register bitfield defines */ 22 #define PLLCTRL_FBDIV_MASK 0x7f000 23 #define PLLCTRL_FBDIV_SHIFT 12 24 #define PLLCTRL_BPFORCE_MASK (1 << 4) 25 #define PLLCTRL_PWRDWN_MASK 2 26 #define PLLCTRL_PWRDWN_SHIFT 1 27 #define PLLCTRL_RESET_MASK 1 28 #define PLLCTRL_RESET_SHIFT 0 29 30 #define ZYNQ_CLK_MAXDIV 0x3f 31 #define CLK_CTRL_DIV1_SHIFT 20 32 #define CLK_CTRL_DIV1_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV1_SHIFT) 33 #define CLK_CTRL_DIV0_SHIFT 8 34 #define CLK_CTRL_DIV0_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV0_SHIFT) 35 #define CLK_CTRL_SRCSEL_SHIFT 4 36 #define CLK_CTRL_SRCSEL_MASK (0x3 << CLK_CTRL_SRCSEL_SHIFT) 37 38 #define CLK_CTRL_DIV2X_SHIFT 26 39 #define CLK_CTRL_DIV2X_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV2X_SHIFT) 40 #define CLK_CTRL_DIV3X_SHIFT 20 41 #define CLK_CTRL_DIV3X_MASK (ZYNQ_CLK_MAXDIV << CLK_CTRL_DIV3X_SHIFT) 42 43 DECLARE_GLOBAL_DATA_PTR; 44 45 #ifndef CONFIG_SPL_BUILD 46 enum zynq_clk_rclk {mio_clk, emio_clk}; 47 #endif 48 49 struct zynq_clk_priv { 50 ulong ps_clk_freq; 51 #ifndef CONFIG_SPL_BUILD 52 struct clk gem_emio_clk[2]; 53 #endif 54 }; 55 56 static void *zynq_clk_get_register(enum zynq_clk id) 57 { 58 switch (id) { 59 case armpll_clk: 60 return &slcr_base->arm_pll_ctrl; 61 case ddrpll_clk: 62 return &slcr_base->ddr_pll_ctrl; 63 case iopll_clk: 64 return &slcr_base->io_pll_ctrl; 65 case lqspi_clk: 66 return &slcr_base->lqspi_clk_ctrl; 67 case smc_clk: 68 return &slcr_base->smc_clk_ctrl; 69 case pcap_clk: 70 return &slcr_base->pcap_clk_ctrl; 71 case sdio0_clk ... sdio1_clk: 72 return &slcr_base->sdio_clk_ctrl; 73 case uart0_clk ... uart1_clk: 74 return &slcr_base->uart_clk_ctrl; 75 case spi0_clk ... spi1_clk: 76 return &slcr_base->spi_clk_ctrl; 77 #ifndef CONFIG_SPL_BUILD 78 case dci_clk: 79 return &slcr_base->dci_clk_ctrl; 80 case gem0_clk: 81 return &slcr_base->gem0_clk_ctrl; 82 case gem1_clk: 83 return &slcr_base->gem1_clk_ctrl; 84 case fclk0_clk: 85 return &slcr_base->fpga0_clk_ctrl; 86 case fclk1_clk: 87 return &slcr_base->fpga1_clk_ctrl; 88 case fclk2_clk: 89 return &slcr_base->fpga2_clk_ctrl; 90 case fclk3_clk: 91 return &slcr_base->fpga3_clk_ctrl; 92 case can0_clk ... can1_clk: 93 return &slcr_base->can_clk_ctrl; 94 case dbg_trc_clk ... dbg_apb_clk: 95 /* fall through */ 96 #endif 97 default: 98 return &slcr_base->dbg_clk_ctrl; 99 } 100 } 101 102 static enum zynq_clk zynq_clk_get_cpu_pll(u32 clk_ctrl) 103 { 104 u32 srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >> CLK_CTRL_SRCSEL_SHIFT; 105 106 switch (srcsel) { 107 case 2: 108 return ddrpll_clk; 109 case 3: 110 return iopll_clk; 111 case 0 ... 1: 112 default: 113 return armpll_clk; 114 } 115 } 116 117 static enum zynq_clk zynq_clk_get_peripheral_pll(u32 clk_ctrl) 118 { 119 u32 srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >> CLK_CTRL_SRCSEL_SHIFT; 120 121 switch (srcsel) { 122 case 2: 123 return armpll_clk; 124 case 3: 125 return ddrpll_clk; 126 case 0 ... 1: 127 default: 128 return iopll_clk; 129 } 130 } 131 132 static ulong zynq_clk_get_pll_rate(struct zynq_clk_priv *priv, enum zynq_clk id) 133 { 134 u32 clk_ctrl, reset, pwrdwn, mul, bypass; 135 136 clk_ctrl = readl(zynq_clk_get_register(id)); 137 138 reset = (clk_ctrl & PLLCTRL_RESET_MASK) >> PLLCTRL_RESET_SHIFT; 139 pwrdwn = (clk_ctrl & PLLCTRL_PWRDWN_MASK) >> PLLCTRL_PWRDWN_SHIFT; 140 if (reset || pwrdwn) 141 return 0; 142 143 bypass = clk_ctrl & PLLCTRL_BPFORCE_MASK; 144 if (bypass) 145 mul = 1; 146 else 147 mul = (clk_ctrl & PLLCTRL_FBDIV_MASK) >> PLLCTRL_FBDIV_SHIFT; 148 149 return priv->ps_clk_freq * mul; 150 } 151 152 #ifndef CONFIG_SPL_BUILD 153 static enum zynq_clk_rclk zynq_clk_get_gem_rclk(enum zynq_clk id) 154 { 155 u32 clk_ctrl, srcsel; 156 157 if (id == gem0_clk) 158 clk_ctrl = readl(&slcr_base->gem0_rclk_ctrl); 159 else 160 clk_ctrl = readl(&slcr_base->gem1_rclk_ctrl); 161 162 srcsel = (clk_ctrl & CLK_CTRL_SRCSEL_MASK) >> CLK_CTRL_SRCSEL_SHIFT; 163 if (srcsel) 164 return emio_clk; 165 else 166 return mio_clk; 167 } 168 #endif 169 170 static ulong zynq_clk_get_cpu_rate(struct zynq_clk_priv *priv, enum zynq_clk id) 171 { 172 u32 clk_621, clk_ctrl, div; 173 enum zynq_clk pll; 174 175 clk_ctrl = readl(&slcr_base->arm_clk_ctrl); 176 177 div = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT; 178 179 switch (id) { 180 case cpu_1x_clk: 181 div *= 2; 182 /* fall through */ 183 case cpu_2x_clk: 184 clk_621 = readl(&slcr_base->clk_621_true) & 1; 185 div *= 2 + clk_621; 186 break; 187 case cpu_3or2x_clk: 188 div *= 2; 189 /* fall through */ 190 case cpu_6or4x_clk: 191 break; 192 default: 193 return 0; 194 } 195 196 pll = zynq_clk_get_cpu_pll(clk_ctrl); 197 198 return DIV_ROUND_CLOSEST(zynq_clk_get_pll_rate(priv, pll), div); 199 } 200 201 #ifndef CONFIG_SPL_BUILD 202 static ulong zynq_clk_get_ddr2x_rate(struct zynq_clk_priv *priv) 203 { 204 u32 clk_ctrl, div; 205 206 clk_ctrl = readl(&slcr_base->ddr_clk_ctrl); 207 208 div = (clk_ctrl & CLK_CTRL_DIV2X_MASK) >> CLK_CTRL_DIV2X_SHIFT; 209 210 return DIV_ROUND_CLOSEST(zynq_clk_get_pll_rate(priv, ddrpll_clk), div); 211 } 212 #endif 213 214 static ulong zynq_clk_get_ddr3x_rate(struct zynq_clk_priv *priv) 215 { 216 u32 clk_ctrl, div; 217 218 clk_ctrl = readl(&slcr_base->ddr_clk_ctrl); 219 220 div = (clk_ctrl & CLK_CTRL_DIV3X_MASK) >> CLK_CTRL_DIV3X_SHIFT; 221 222 return DIV_ROUND_CLOSEST(zynq_clk_get_pll_rate(priv, ddrpll_clk), div); 223 } 224 225 #ifndef CONFIG_SPL_BUILD 226 static ulong zynq_clk_get_dci_rate(struct zynq_clk_priv *priv) 227 { 228 u32 clk_ctrl, div0, div1; 229 230 clk_ctrl = readl(&slcr_base->dci_clk_ctrl); 231 232 div0 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT; 233 div1 = (clk_ctrl & CLK_CTRL_DIV1_MASK) >> CLK_CTRL_DIV1_SHIFT; 234 235 return DIV_ROUND_CLOSEST(DIV_ROUND_CLOSEST( 236 zynq_clk_get_pll_rate(priv, ddrpll_clk), div0), div1); 237 } 238 #endif 239 240 static ulong zynq_clk_get_peripheral_rate(struct zynq_clk_priv *priv, 241 enum zynq_clk id, bool two_divs) 242 { 243 enum zynq_clk pll; 244 u32 clk_ctrl, div0; 245 u32 div1 = 1; 246 247 clk_ctrl = readl(zynq_clk_get_register(id)); 248 249 div0 = (clk_ctrl & CLK_CTRL_DIV0_MASK) >> CLK_CTRL_DIV0_SHIFT; 250 if (!div0) 251 div0 = 1; 252 253 #ifndef CONFIG_SPL_BUILD 254 if (two_divs) { 255 div1 = (clk_ctrl & CLK_CTRL_DIV1_MASK) >> CLK_CTRL_DIV1_SHIFT; 256 if (!div1) 257 div1 = 1; 258 } 259 #endif 260 261 pll = zynq_clk_get_peripheral_pll(clk_ctrl); 262 263 return 264 DIV_ROUND_CLOSEST( 265 DIV_ROUND_CLOSEST( 266 zynq_clk_get_pll_rate(priv, pll), div0), 267 div1); 268 } 269 270 #ifndef CONFIG_SPL_BUILD 271 static ulong zynq_clk_get_gem_rate(struct zynq_clk_priv *priv, enum zynq_clk id) 272 { 273 struct clk *parent; 274 275 if (zynq_clk_get_gem_rclk(id) == mio_clk) 276 return zynq_clk_get_peripheral_rate(priv, id, true); 277 278 parent = &priv->gem_emio_clk[id - gem0_clk]; 279 if (parent->dev) 280 return clk_get_rate(parent); 281 282 debug("%s: gem%d emio rx clock source unknown\n", __func__, 283 id - gem0_clk); 284 285 return -ENOSYS; 286 } 287 288 static unsigned long zynq_clk_calc_peripheral_two_divs(ulong rate, 289 ulong pll_rate, 290 u32 *div0, u32 *div1) 291 { 292 long new_err, best_err = (long)(~0UL >> 1); 293 ulong new_rate, best_rate = 0; 294 u32 d0, d1; 295 296 for (d0 = 1; d0 <= ZYNQ_CLK_MAXDIV; d0++) { 297 for (d1 = 1; d1 <= ZYNQ_CLK_MAXDIV >> 1; d1++) { 298 new_rate = DIV_ROUND_CLOSEST( 299 DIV_ROUND_CLOSEST(pll_rate, d0), d1); 300 new_err = abs(new_rate - rate); 301 302 if (new_err < best_err) { 303 *div0 = d0; 304 *div1 = d1; 305 best_err = new_err; 306 best_rate = new_rate; 307 } 308 } 309 } 310 311 return best_rate; 312 } 313 314 static ulong zynq_clk_set_peripheral_rate(struct zynq_clk_priv *priv, 315 enum zynq_clk id, ulong rate, 316 bool two_divs) 317 { 318 enum zynq_clk pll; 319 u32 clk_ctrl, div0 = 0, div1 = 0; 320 ulong pll_rate, new_rate; 321 u32 *reg; 322 323 reg = zynq_clk_get_register(id); 324 clk_ctrl = readl(reg); 325 326 pll = zynq_clk_get_peripheral_pll(clk_ctrl); 327 pll_rate = zynq_clk_get_pll_rate(priv, pll); 328 clk_ctrl &= ~CLK_CTRL_DIV0_MASK; 329 if (two_divs) { 330 clk_ctrl &= ~CLK_CTRL_DIV1_MASK; 331 new_rate = zynq_clk_calc_peripheral_two_divs(rate, pll_rate, 332 &div0, &div1); 333 clk_ctrl |= div1 << CLK_CTRL_DIV1_SHIFT; 334 } else { 335 div0 = DIV_ROUND_CLOSEST(pll_rate, rate); 336 if (div0 > ZYNQ_CLK_MAXDIV) 337 div0 = ZYNQ_CLK_MAXDIV; 338 new_rate = DIV_ROUND_CLOSEST(rate, div0); 339 } 340 clk_ctrl |= div0 << CLK_CTRL_DIV0_SHIFT; 341 342 zynq_slcr_unlock(); 343 writel(clk_ctrl, reg); 344 zynq_slcr_lock(); 345 346 return new_rate; 347 } 348 349 static ulong zynq_clk_set_gem_rate(struct zynq_clk_priv *priv, enum zynq_clk id, 350 ulong rate) 351 { 352 struct clk *parent; 353 354 if (zynq_clk_get_gem_rclk(id) == mio_clk) 355 return zynq_clk_set_peripheral_rate(priv, id, rate, true); 356 357 parent = &priv->gem_emio_clk[id - gem0_clk]; 358 if (parent->dev) 359 return clk_set_rate(parent, rate); 360 361 debug("%s: gem%d emio rx clock source unknown\n", __func__, 362 id - gem0_clk); 363 364 return -ENOSYS; 365 } 366 #endif 367 368 #ifndef CONFIG_SPL_BUILD 369 static ulong zynq_clk_get_rate(struct clk *clk) 370 { 371 struct zynq_clk_priv *priv = dev_get_priv(clk->dev); 372 enum zynq_clk id = clk->id; 373 bool two_divs = false; 374 375 switch (id) { 376 case armpll_clk ... iopll_clk: 377 return zynq_clk_get_pll_rate(priv, id); 378 case cpu_6or4x_clk ... cpu_1x_clk: 379 return zynq_clk_get_cpu_rate(priv, id); 380 case ddr2x_clk: 381 return zynq_clk_get_ddr2x_rate(priv); 382 case ddr3x_clk: 383 return zynq_clk_get_ddr3x_rate(priv); 384 case dci_clk: 385 return zynq_clk_get_dci_rate(priv); 386 case gem0_clk ... gem1_clk: 387 return zynq_clk_get_gem_rate(priv, id); 388 case fclk0_clk ... can1_clk: 389 two_divs = true; 390 /* fall through */ 391 case dbg_trc_clk ... dbg_apb_clk: 392 case lqspi_clk ... pcap_clk: 393 case sdio0_clk ... spi1_clk: 394 return zynq_clk_get_peripheral_rate(priv, id, two_divs); 395 case dma_clk: 396 return zynq_clk_get_cpu_rate(priv, cpu_2x_clk); 397 case usb0_aper_clk ... smc_aper_clk: 398 return zynq_clk_get_cpu_rate(priv, cpu_1x_clk); 399 default: 400 return -ENXIO; 401 } 402 } 403 404 static ulong zynq_clk_set_rate(struct clk *clk, ulong rate) 405 { 406 struct zynq_clk_priv *priv = dev_get_priv(clk->dev); 407 enum zynq_clk id = clk->id; 408 bool two_divs = false; 409 410 switch (id) { 411 case gem0_clk ... gem1_clk: 412 return zynq_clk_set_gem_rate(priv, id, rate); 413 case fclk0_clk ... can1_clk: 414 two_divs = true; 415 /* fall through */ 416 case lqspi_clk ... pcap_clk: 417 case sdio0_clk ... spi1_clk: 418 case dbg_trc_clk ... dbg_apb_clk: 419 return zynq_clk_set_peripheral_rate(priv, id, rate, two_divs); 420 default: 421 return -ENXIO; 422 } 423 } 424 #else 425 static ulong zynq_clk_get_rate(struct clk *clk) 426 { 427 struct zynq_clk_priv *priv = dev_get_priv(clk->dev); 428 enum zynq_clk id = clk->id; 429 430 switch (id) { 431 case cpu_6or4x_clk ... cpu_1x_clk: 432 return zynq_clk_get_cpu_rate(priv, id); 433 case ddr3x_clk: 434 return zynq_clk_get_ddr3x_rate(priv); 435 case lqspi_clk ... pcap_clk: 436 case sdio0_clk ... spi1_clk: 437 return zynq_clk_get_peripheral_rate(priv, id, 0); 438 default: 439 return -ENXIO; 440 } 441 } 442 #endif 443 444 static struct clk_ops zynq_clk_ops = { 445 .get_rate = zynq_clk_get_rate, 446 #ifndef CONFIG_SPL_BUILD 447 .set_rate = zynq_clk_set_rate, 448 #endif 449 }; 450 451 static int zynq_clk_probe(struct udevice *dev) 452 { 453 struct zynq_clk_priv *priv = dev_get_priv(dev); 454 #ifndef CONFIG_SPL_BUILD 455 unsigned int i; 456 char name[16]; 457 int ret; 458 459 for (i = 0; i < 2; i++) { 460 sprintf(name, "gem%d_emio_clk", i); 461 ret = clk_get_by_name(dev, name, &priv->gem_emio_clk[i]); 462 if (ret < 0 && ret != -FDT_ERR_NOTFOUND) { 463 dev_err(dev, "failed to get %s clock\n", name); 464 return ret; 465 } 466 } 467 #endif 468 469 priv->ps_clk_freq = fdtdec_get_uint(gd->fdt_blob, dev->of_offset, 470 "ps-clk-frequency", 33333333UL); 471 472 return 0; 473 } 474 475 static const struct udevice_id zynq_clk_ids[] = { 476 { .compatible = "xlnx,ps7-clkc"}, 477 {} 478 }; 479 480 U_BOOT_DRIVER(zynq_clk) = { 481 .name = "zynq_clk", 482 .id = UCLASS_CLK, 483 .of_match = zynq_clk_ids, 484 .flags = DM_FLAG_PRE_RELOC, 485 .ops = &zynq_clk_ops, 486 .priv_auto_alloc_size = sizeof(struct zynq_clk_priv), 487 .probe = zynq_clk_probe, 488 }; 489