1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2013 Thomas Skibo 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 /* 30 * Zynq-700 SLCR driver. Provides hooks for cpu_reset and PL control stuff. 31 * In the future, maybe MIO control, clock control, etc. could go here. 32 * 33 * Reference: Zynq-7000 All Programmable SoC Technical Reference Manual. 34 * (v1.4) November 16, 2012. Xilinx doc UG585. 35 */ 36 37 #include <sys/cdefs.h> 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/conf.h> 41 #include <sys/kernel.h> 42 #include <sys/module.h> 43 #include <sys/lock.h> 44 #include <sys/mutex.h> 45 #include <sys/resource.h> 46 #include <sys/sysctl.h> 47 #include <sys/rman.h> 48 49 #include <machine/bus.h> 50 #include <machine/resource.h> 51 #include <machine/stdarg.h> 52 53 #include <dev/ofw/ofw_bus.h> 54 #include <dev/ofw/ofw_bus_subr.h> 55 56 #include <arm/xilinx/zy7_slcr.h> 57 58 struct zy7_slcr_softc { 59 device_t dev; 60 struct mtx sc_mtx; 61 struct resource *mem_res; 62 }; 63 64 static struct zy7_slcr_softc *zy7_slcr_softc_p; 65 extern void (*zynq7_cpu_reset); 66 67 #define ZSLCR_LOCK(sc) mtx_lock(&(sc)->sc_mtx) 68 #define ZSLCR_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) 69 #define ZSLCR_LOCK_INIT(sc) \ 70 mtx_init(&(sc)->sc_mtx, device_get_nameunit((sc)->dev), \ 71 "zy7_slcr", MTX_DEF) 72 #define ZSLCR_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx); 73 74 #define RD4(sc, off) (bus_read_4((sc)->mem_res, (off))) 75 #define WR4(sc, off, val) (bus_write_4((sc)->mem_res, (off), (val))) 76 77 #define ZYNQ_DEFAULT_PS_CLK_FREQUENCY 33333333 /* 33.3 Mhz */ 78 79 SYSCTL_NODE(_hw, OID_AUTO, zynq, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 80 "Xilinx Zynq-7000"); 81 82 static char zynq_bootmode[64]; 83 SYSCTL_STRING(_hw_zynq, OID_AUTO, bootmode, CTLFLAG_RD, zynq_bootmode, 0, 84 "Zynq boot mode"); 85 86 static char zynq_pssid[100]; 87 SYSCTL_STRING(_hw_zynq, OID_AUTO, pssid, CTLFLAG_RD, zynq_pssid, 0, 88 "Zynq PSS IDCODE"); 89 90 static uint32_t zynq_reboot_status; 91 SYSCTL_INT(_hw_zynq, OID_AUTO, reboot_status, CTLFLAG_RD, &zynq_reboot_status, 92 0, "Zynq REBOOT_STATUS register"); 93 94 static int ps_clk_frequency; 95 SYSCTL_INT(_hw_zynq, OID_AUTO, ps_clk_frequency, CTLFLAG_RD, &ps_clk_frequency, 96 0, "Zynq PS_CLK Frequency"); 97 98 static int io_pll_frequency; 99 SYSCTL_INT(_hw_zynq, OID_AUTO, io_pll_frequency, CTLFLAG_RD, &io_pll_frequency, 100 0, "Zynq IO PLL Frequency"); 101 102 static int arm_pll_frequency; 103 SYSCTL_INT(_hw_zynq, OID_AUTO, arm_pll_frequency, CTLFLAG_RD, 104 &arm_pll_frequency, 0, "Zynq ARM PLL Frequency"); 105 106 static int ddr_pll_frequency; 107 SYSCTL_INT(_hw_zynq, OID_AUTO, ddr_pll_frequency, CTLFLAG_RD, 108 &ddr_pll_frequency, 0, "Zynq DDR PLL Frequency"); 109 110 static void 111 zy7_slcr_unlock(struct zy7_slcr_softc *sc) 112 { 113 114 /* Unlock SLCR with magic number. */ 115 WR4(sc, ZY7_SLCR_UNLOCK, ZY7_SLCR_UNLOCK_MAGIC); 116 } 117 118 static void 119 zy7_slcr_lock(struct zy7_slcr_softc *sc) 120 { 121 122 /* Lock SLCR with magic number. */ 123 WR4(sc, ZY7_SLCR_LOCK, ZY7_SLCR_LOCK_MAGIC); 124 } 125 126 static void 127 zy7_slcr_cpu_reset(void) 128 { 129 struct zy7_slcr_softc *sc = zy7_slcr_softc_p; 130 131 /* Unlock SLCR registers. */ 132 zy7_slcr_unlock(sc); 133 134 /* This has something to do with a work-around so the fsbl will load 135 * the bitstream after soft-reboot. It's very important. 136 */ 137 WR4(sc, ZY7_SLCR_REBOOT_STAT, 138 RD4(sc, ZY7_SLCR_REBOOT_STAT) & 0xf0ffffff); 139 140 /* Soft reset */ 141 WR4(sc, ZY7_SLCR_PSS_RST_CTRL, ZY7_SLCR_PSS_RST_CTRL_SOFT_RESET); 142 143 for (;;) 144 ; 145 } 146 147 /* Assert PL resets and disable level shifters in preparation of programming 148 * the PL (FPGA) section. Called from zy7_devcfg.c. 149 */ 150 void 151 zy7_slcr_preload_pl(void) 152 { 153 struct zy7_slcr_softc *sc = zy7_slcr_softc_p; 154 155 if (!sc) 156 return; 157 158 ZSLCR_LOCK(sc); 159 160 /* Unlock SLCR registers. */ 161 zy7_slcr_unlock(sc); 162 163 /* Assert top level output resets. */ 164 WR4(sc, ZY7_SLCR_FPGA_RST_CTRL, ZY7_SLCR_FPGA_RST_CTRL_RST_ALL); 165 166 /* Disable all level shifters. */ 167 WR4(sc, ZY7_SLCR_LVL_SHFTR_EN, 0); 168 169 /* Lock SLCR registers. */ 170 zy7_slcr_lock(sc); 171 172 ZSLCR_UNLOCK(sc); 173 } 174 175 /* After PL configuration, enable level shifters and deassert top-level 176 * PL resets. Called from zy7_devcfg.c. Optionally, the level shifters 177 * can be left disabled but that's rare of an FPGA application. That option 178 * is controlled by a sysctl in the devcfg driver. 179 */ 180 void 181 zy7_slcr_postload_pl(int en_level_shifters) 182 { 183 struct zy7_slcr_softc *sc = zy7_slcr_softc_p; 184 185 if (!sc) 186 return; 187 188 ZSLCR_LOCK(sc); 189 190 /* Unlock SLCR registers. */ 191 zy7_slcr_unlock(sc); 192 193 if (en_level_shifters) 194 /* Enable level shifters. */ 195 WR4(sc, ZY7_SLCR_LVL_SHFTR_EN, ZY7_SLCR_LVL_SHFTR_EN_ALL); 196 197 /* Deassert top level output resets. */ 198 WR4(sc, ZY7_SLCR_FPGA_RST_CTRL, 0); 199 200 /* Lock SLCR registers. */ 201 zy7_slcr_lock(sc); 202 203 ZSLCR_UNLOCK(sc); 204 } 205 206 /* Override cgem_set_refclk() in gigabit ethernet driver 207 * (sys/dev/cadence/if_cgem.c). This function is called to 208 * request a change in the gem's reference clock speed. 209 */ 210 int 211 cgem_set_ref_clk(int unit, int frequency) 212 { 213 struct zy7_slcr_softc *sc = zy7_slcr_softc_p; 214 int div0, div1; 215 216 if (!sc) 217 return (-1); 218 219 /* Find suitable divisor pairs. Round result to nearest khz 220 * to test for match. 221 */ 222 for (div1 = 1; div1 <= ZY7_SLCR_GEM_CLK_CTRL_DIVISOR1_MAX; div1++) { 223 div0 = (io_pll_frequency + div1 * frequency / 2) / 224 div1 / frequency; 225 if (div0 > 0 && div0 <= ZY7_SLCR_GEM_CLK_CTRL_DIVISOR_MAX && 226 ((io_pll_frequency / div0 / div1) + 500) / 1000 == 227 (frequency + 500) / 1000) 228 break; 229 } 230 231 if (div1 > ZY7_SLCR_GEM_CLK_CTRL_DIVISOR1_MAX) 232 return (-1); 233 234 ZSLCR_LOCK(sc); 235 236 /* Unlock SLCR registers. */ 237 zy7_slcr_unlock(sc); 238 239 /* Modify GEM reference clock. */ 240 WR4(sc, unit ? ZY7_SLCR_GEM1_CLK_CTRL : ZY7_SLCR_GEM0_CLK_CTRL, 241 (div1 << ZY7_SLCR_GEM_CLK_CTRL_DIVISOR1_SHIFT) | 242 (div0 << ZY7_SLCR_GEM_CLK_CTRL_DIVISOR_SHIFT) | 243 ZY7_SLCR_GEM_CLK_CTRL_SRCSEL_IO_PLL | 244 ZY7_SLCR_GEM_CLK_CTRL_CLKACT); 245 246 /* Lock SLCR registers. */ 247 zy7_slcr_lock(sc); 248 249 ZSLCR_UNLOCK(sc); 250 251 return (0); 252 } 253 254 /* 255 * PL clocks management function 256 */ 257 int 258 zy7_pl_fclk_set_source(int unit, int source) 259 { 260 struct zy7_slcr_softc *sc = zy7_slcr_softc_p; 261 uint32_t reg; 262 263 if (!sc) 264 return (-1); 265 266 ZSLCR_LOCK(sc); 267 268 /* Unlock SLCR registers. */ 269 zy7_slcr_unlock(sc); 270 271 /* Modify FPGAx source. */ 272 reg = RD4(sc, ZY7_SLCR_FPGA_CLK_CTRL(unit)); 273 reg &= ~(ZY7_SLCR_FPGA_CLK_CTRL_SRCSEL_MASK); 274 reg |= (source << ZY7_SLCR_FPGA_CLK_CTRL_SRCSEL_SHIFT); 275 WR4(sc, ZY7_SLCR_FPGA_CLK_CTRL(unit), reg); 276 277 /* Lock SLCR registers. */ 278 zy7_slcr_lock(sc); 279 280 ZSLCR_UNLOCK(sc); 281 282 return (0); 283 } 284 285 int 286 zy7_pl_fclk_get_source(int unit) 287 { 288 struct zy7_slcr_softc *sc = zy7_slcr_softc_p; 289 uint32_t reg; 290 int source; 291 292 if (!sc) 293 return (-1); 294 295 ZSLCR_LOCK(sc); 296 297 /* Modify GEM reference clock. */ 298 reg = RD4(sc, ZY7_SLCR_FPGA_CLK_CTRL(unit)); 299 source = (reg & ZY7_SLCR_FPGA_CLK_CTRL_SRCSEL_MASK) >> 300 ZY7_SLCR_FPGA_CLK_CTRL_SRCSEL_SHIFT; 301 302 /* ZY7_PL_FCLK_SRC_IO is actually b0x */ 303 if ((source & 2) == 0) 304 source = ZY7_PL_FCLK_SRC_IO; 305 306 ZSLCR_UNLOCK(sc); 307 308 return (source); 309 } 310 311 int 312 zy7_pl_fclk_set_freq(int unit, int frequency) 313 { 314 struct zy7_slcr_softc *sc = zy7_slcr_softc_p; 315 int div0, div1; 316 int base_frequency; 317 uint32_t reg; 318 int source; 319 320 if (!sc) 321 return (-1); 322 323 source = zy7_pl_fclk_get_source(unit); 324 switch (source) { 325 case ZY7_PL_FCLK_SRC_IO: 326 base_frequency = io_pll_frequency; 327 break; 328 329 case ZY7_PL_FCLK_SRC_ARM: 330 base_frequency = arm_pll_frequency; 331 break; 332 333 case ZY7_PL_FCLK_SRC_DDR: 334 base_frequency = ddr_pll_frequency; 335 break; 336 337 default: 338 return (-1); 339 } 340 341 /* Find suitable divisor pairs. Round result to nearest khz 342 * to test for match. 343 */ 344 for (div1 = 1; div1 <= ZY7_SLCR_FPGA_CLK_CTRL_DIVISOR_MAX; div1++) { 345 div0 = (base_frequency + div1 * frequency / 2) / 346 div1 / frequency; 347 if (div0 > 0 && div0 <= ZY7_SLCR_FPGA_CLK_CTRL_DIVISOR_MAX && 348 ((base_frequency / div0 / div1) + 500) / 1000 == 349 (frequency + 500) / 1000) 350 break; 351 } 352 353 if (div1 > ZY7_SLCR_FPGA_CLK_CTRL_DIVISOR_MAX) 354 return (-1); 355 356 ZSLCR_LOCK(sc); 357 358 /* Unlock SLCR registers. */ 359 zy7_slcr_unlock(sc); 360 361 /* Modify FPGAx reference clock. */ 362 reg = RD4(sc, ZY7_SLCR_FPGA_CLK_CTRL(unit)); 363 reg &= ~(ZY7_SLCR_FPGA_CLK_CTRL_DIVISOR1_MASK | 364 ZY7_SLCR_FPGA_CLK_CTRL_DIVISOR0_MASK); 365 reg |= (div1 << ZY7_SLCR_FPGA_CLK_CTRL_DIVISOR1_SHIFT) | 366 (div0 << ZY7_SLCR_FPGA_CLK_CTRL_DIVISOR0_SHIFT); 367 WR4(sc, ZY7_SLCR_FPGA_CLK_CTRL(unit), reg); 368 369 /* Lock SLCR registers. */ 370 zy7_slcr_lock(sc); 371 372 ZSLCR_UNLOCK(sc); 373 374 return (base_frequency / div0 / div1); 375 } 376 377 int 378 zy7_pl_fclk_get_freq(int unit) 379 { 380 struct zy7_slcr_softc *sc = zy7_slcr_softc_p; 381 int div0, div1; 382 int base_frequency; 383 int frequency; 384 uint32_t reg; 385 int source; 386 387 if (!sc) 388 return (-1); 389 390 source = zy7_pl_fclk_get_source(unit); 391 switch (source) { 392 case ZY7_PL_FCLK_SRC_IO: 393 base_frequency = io_pll_frequency; 394 break; 395 396 case ZY7_PL_FCLK_SRC_ARM: 397 base_frequency = arm_pll_frequency; 398 break; 399 400 case ZY7_PL_FCLK_SRC_DDR: 401 base_frequency = ddr_pll_frequency; 402 break; 403 404 default: 405 return (-1); 406 } 407 408 ZSLCR_LOCK(sc); 409 410 /* Modify FPGAx reference clock. */ 411 reg = RD4(sc, ZY7_SLCR_FPGA_CLK_CTRL(unit)); 412 div1 = (reg & ZY7_SLCR_FPGA_CLK_CTRL_DIVISOR1_MASK) >> 413 ZY7_SLCR_FPGA_CLK_CTRL_DIVISOR1_SHIFT; 414 div0 = (reg & ZY7_SLCR_FPGA_CLK_CTRL_DIVISOR0_MASK) >> 415 ZY7_SLCR_FPGA_CLK_CTRL_DIVISOR0_SHIFT; 416 417 ZSLCR_UNLOCK(sc); 418 419 if (div0 == 0) 420 div0 = 1; 421 422 if (div1 == 0) 423 div1 = 1; 424 425 frequency = (base_frequency / div0 / div1); 426 /* Round to KHz */ 427 frequency = (frequency + 500) / 1000; 428 frequency = frequency * 1000; 429 430 return (frequency); 431 } 432 433 int 434 zy7_pl_fclk_enable(int unit) 435 { 436 struct zy7_slcr_softc *sc = zy7_slcr_softc_p; 437 438 if (!sc) 439 return (-1); 440 441 ZSLCR_LOCK(sc); 442 443 /* Unlock SLCR registers. */ 444 zy7_slcr_unlock(sc); 445 446 WR4(sc, ZY7_SLCR_FPGA_THR_CTRL(unit), 0); 447 WR4(sc, ZY7_SLCR_FPGA_THR_CNT(unit), 0); 448 449 /* Lock SLCR registers. */ 450 zy7_slcr_lock(sc); 451 452 ZSLCR_UNLOCK(sc); 453 454 return (0); 455 } 456 457 int 458 zy7_pl_fclk_disable(int unit) 459 { 460 struct zy7_slcr_softc *sc = zy7_slcr_softc_p; 461 462 if (!sc) 463 return (-1); 464 465 ZSLCR_LOCK(sc); 466 467 /* Unlock SLCR registers. */ 468 zy7_slcr_unlock(sc); 469 470 WR4(sc, ZY7_SLCR_FPGA_THR_CTRL(unit), 0); 471 WR4(sc, ZY7_SLCR_FPGA_THR_CNT(unit), 1); 472 473 /* Lock SLCR registers. */ 474 zy7_slcr_lock(sc); 475 476 ZSLCR_UNLOCK(sc); 477 478 return (0); 479 } 480 481 int 482 zy7_pl_fclk_enabled(int unit) 483 { 484 struct zy7_slcr_softc *sc = zy7_slcr_softc_p; 485 uint32_t reg; 486 487 if (!sc) 488 return (-1); 489 490 ZSLCR_LOCK(sc); 491 reg = RD4(sc, ZY7_SLCR_FPGA_THR_CNT(unit)); 492 ZSLCR_UNLOCK(sc); 493 494 return !(reg & 1); 495 } 496 497 int 498 zy7_pl_level_shifters_enabled(void) 499 { 500 struct zy7_slcr_softc *sc = zy7_slcr_softc_p; 501 502 uint32_t reg; 503 504 if (!sc) 505 return (-1); 506 507 ZSLCR_LOCK(sc); 508 reg = RD4(sc, ZY7_SLCR_LVL_SHFTR_EN); 509 ZSLCR_UNLOCK(sc); 510 511 return (reg == ZY7_SLCR_LVL_SHFTR_EN_ALL); 512 } 513 514 void 515 zy7_pl_level_shifters_enable(void) 516 { 517 struct zy7_slcr_softc *sc = zy7_slcr_softc_p; 518 519 if (!sc) 520 return; 521 522 ZSLCR_LOCK(sc); 523 zy7_slcr_unlock(sc); 524 WR4(sc, ZY7_SLCR_LVL_SHFTR_EN, ZY7_SLCR_LVL_SHFTR_EN_ALL); 525 zy7_slcr_lock(sc); 526 ZSLCR_UNLOCK(sc); 527 } 528 529 void 530 zy7_pl_level_shifters_disable(void) 531 { 532 struct zy7_slcr_softc *sc = zy7_slcr_softc_p; 533 534 if (!sc) 535 return; 536 537 ZSLCR_LOCK(sc); 538 zy7_slcr_unlock(sc); 539 WR4(sc, ZY7_SLCR_LVL_SHFTR_EN, 0); 540 zy7_slcr_lock(sc); 541 ZSLCR_UNLOCK(sc); 542 } 543 544 static int 545 zy7_slcr_probe(device_t dev) 546 { 547 548 if (!ofw_bus_status_okay(dev)) 549 return (ENXIO); 550 551 if (!ofw_bus_is_compatible(dev, "xlnx,zy7_slcr")) 552 return (ENXIO); 553 554 device_set_desc(dev, "Zynq-7000 slcr block"); 555 return (0); 556 } 557 558 static int 559 zy7_slcr_attach(device_t dev) 560 { 561 struct zy7_slcr_softc *sc = device_get_softc(dev); 562 int rid; 563 phandle_t node; 564 pcell_t cell; 565 uint32_t bootmode; 566 uint32_t pss_idcode; 567 uint32_t arm_pll_ctrl; 568 uint32_t ddr_pll_ctrl; 569 uint32_t io_pll_ctrl; 570 static char *bootdev_names[] = { 571 "JTAG", "Quad-SPI", "NOR", "(3?)", 572 "NAND", "SD Card", "(6?)", "(7?)" 573 }; 574 575 /* Allow only one attach. */ 576 if (zy7_slcr_softc_p != NULL) 577 return (ENXIO); 578 579 sc->dev = dev; 580 581 ZSLCR_LOCK_INIT(sc); 582 583 /* Get memory resource. */ 584 rid = 0; 585 sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 586 RF_ACTIVE); 587 if (sc->mem_res == NULL) { 588 device_printf(dev, "could not allocate memory resources.\n"); 589 return (ENOMEM); 590 } 591 592 /* Hook up cpu_reset. */ 593 zy7_slcr_softc_p = sc; 594 zynq7_cpu_reset = zy7_slcr_cpu_reset; 595 596 /* Read info and set sysctls. */ 597 bootmode = RD4(sc, ZY7_SLCR_BOOT_MODE); 598 snprintf(zynq_bootmode, sizeof(zynq_bootmode), 599 "0x%x: boot device: %s", bootmode, 600 bootdev_names[bootmode & ZY7_SLCR_BOOT_MODE_BOOTDEV_MASK]); 601 602 pss_idcode = RD4(sc, ZY7_SLCR_PSS_IDCODE); 603 snprintf(zynq_pssid, sizeof(zynq_pssid), 604 "0x%x: manufacturer: 0x%x device: 0x%x " 605 "family: 0x%x sub-family: 0x%x rev: 0x%x", 606 pss_idcode, 607 (pss_idcode & ZY7_SLCR_PSS_IDCODE_MNFR_ID_MASK) >> 608 ZY7_SLCR_PSS_IDCODE_MNFR_ID_SHIFT, 609 (pss_idcode & ZY7_SLCR_PSS_IDCODE_DEVICE_MASK) >> 610 ZY7_SLCR_PSS_IDCODE_DEVICE_SHIFT, 611 (pss_idcode & ZY7_SLCR_PSS_IDCODE_FAMILY_MASK) >> 612 ZY7_SLCR_PSS_IDCODE_FAMILY_SHIFT, 613 (pss_idcode & ZY7_SLCR_PSS_IDCODE_SUB_FAMILY_MASK) >> 614 ZY7_SLCR_PSS_IDCODE_SUB_FAMILY_SHIFT, 615 (pss_idcode & ZY7_SLCR_PSS_IDCODE_REVISION_MASK) >> 616 ZY7_SLCR_PSS_IDCODE_REVISION_SHIFT); 617 618 zynq_reboot_status = RD4(sc, ZY7_SLCR_REBOOT_STAT); 619 620 /* Derive PLL frequencies from PS_CLK. */ 621 node = ofw_bus_get_node(dev); 622 if (OF_getencprop(node, "clock-frequency", &cell, sizeof(cell)) > 0) 623 ps_clk_frequency = cell; 624 else 625 ps_clk_frequency = ZYNQ_DEFAULT_PS_CLK_FREQUENCY; 626 627 arm_pll_ctrl = RD4(sc, ZY7_SLCR_ARM_PLL_CTRL); 628 ddr_pll_ctrl = RD4(sc, ZY7_SLCR_DDR_PLL_CTRL); 629 io_pll_ctrl = RD4(sc, ZY7_SLCR_IO_PLL_CTRL); 630 631 /* Determine ARM PLL frequency. */ 632 if (((arm_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_QUAL) == 0 && 633 (arm_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_FORCE) != 0) || 634 ((arm_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_QUAL) != 0 && 635 (bootmode & ZY7_SLCR_BOOT_MODE_PLL_BYPASS) != 0)) 636 /* PLL is bypassed. */ 637 arm_pll_frequency = ps_clk_frequency; 638 else 639 arm_pll_frequency = ps_clk_frequency * 640 ((arm_pll_ctrl & ZY7_SLCR_PLL_CTRL_FDIV_MASK) >> 641 ZY7_SLCR_PLL_CTRL_FDIV_SHIFT); 642 643 /* Determine DDR PLL frequency. */ 644 if (((ddr_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_QUAL) == 0 && 645 (ddr_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_FORCE) != 0) || 646 ((ddr_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_QUAL) != 0 && 647 (bootmode & ZY7_SLCR_BOOT_MODE_PLL_BYPASS) != 0)) 648 /* PLL is bypassed. */ 649 ddr_pll_frequency = ps_clk_frequency; 650 else 651 ddr_pll_frequency = ps_clk_frequency * 652 ((ddr_pll_ctrl & ZY7_SLCR_PLL_CTRL_FDIV_MASK) >> 653 ZY7_SLCR_PLL_CTRL_FDIV_SHIFT); 654 655 /* Determine IO PLL frequency. */ 656 if (((io_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_QUAL) == 0 && 657 (io_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_FORCE) != 0) || 658 ((io_pll_ctrl & ZY7_SLCR_PLL_CTRL_BYPASS_QUAL) != 0 && 659 (bootmode & ZY7_SLCR_BOOT_MODE_PLL_BYPASS) != 0)) 660 /* PLL is bypassed. */ 661 io_pll_frequency = ps_clk_frequency; 662 else 663 io_pll_frequency = ps_clk_frequency * 664 ((io_pll_ctrl & ZY7_SLCR_PLL_CTRL_FDIV_MASK) >> 665 ZY7_SLCR_PLL_CTRL_FDIV_SHIFT); 666 667 /* Lock SLCR registers. */ 668 zy7_slcr_lock(sc); 669 670 return (0); 671 } 672 673 static int 674 zy7_slcr_detach(device_t dev) 675 { 676 struct zy7_slcr_softc *sc = device_get_softc(dev); 677 678 bus_generic_detach(dev); 679 680 /* Release memory resource. */ 681 if (sc->mem_res != NULL) 682 bus_release_resource(dev, SYS_RES_MEMORY, 683 rman_get_rid(sc->mem_res), sc->mem_res); 684 685 zy7_slcr_softc_p = NULL; 686 zynq7_cpu_reset = NULL; 687 688 ZSLCR_LOCK_DESTROY(sc); 689 690 return (0); 691 } 692 693 static device_method_t zy7_slcr_methods[] = { 694 /* device_if */ 695 DEVMETHOD(device_probe, zy7_slcr_probe), 696 DEVMETHOD(device_attach, zy7_slcr_attach), 697 DEVMETHOD(device_detach, zy7_slcr_detach), 698 699 DEVMETHOD_END 700 }; 701 702 static driver_t zy7_slcr_driver = { 703 "zy7_slcr", 704 zy7_slcr_methods, 705 sizeof(struct zy7_slcr_softc), 706 }; 707 708 DRIVER_MODULE(zy7_slcr, simplebus, zy7_slcr_driver, 0, 0); 709 MODULE_VERSION(zy7_slcr, 1); 710