1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2019 Axiado Corporation 5 * All rights reserved. 6 * Copyright (c) 2021 Jessica Clarke <jrtc27@FreeBSD.org> 7 * 8 * This software was developed in part by Kristof Provost under contract for 9 * Axiado Corporation. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 #include <sys/cdefs.h> 34 __FBSDID("$FreeBSD$"); 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/bus.h> 39 #include <sys/kernel.h> 40 #include <sys/lock.h> 41 #include <sys/module.h> 42 #include <sys/mutex.h> 43 #include <sys/rman.h> 44 45 #include <machine/bus.h> 46 #include <machine/cpu.h> 47 48 #include <dev/extres/clk/clk.h> 49 #include <dev/extres/clk/clk_fixed.h> 50 #include <dev/extres/clk/clk_gate.h> 51 52 #include <dev/ofw/ofw_bus.h> 53 #include <dev/ofw/ofw_bus_subr.h> 54 #include <dev/ofw/openfirm.h> 55 56 #include "clkdev_if.h" 57 #include "hwreset_if.h" 58 59 static struct resource_spec prci_spec[] = { 60 { SYS_RES_MEMORY, 0, RF_ACTIVE }, 61 RESOURCE_SPEC_END 62 }; 63 64 struct prci_softc { 65 device_t dev; 66 67 struct mtx mtx; 68 69 struct clkdom *clkdom; 70 struct resource *res; 71 bus_space_tag_t bst; 72 bus_space_handle_t bsh; 73 74 int nresets; 75 }; 76 77 struct prci_clk_pll_sc { 78 struct prci_softc *parent_sc; 79 uint32_t reg; 80 }; 81 82 struct prci_clk_div_sc { 83 struct prci_softc *parent_sc; 84 uint32_t reg; 85 uint32_t bias; 86 }; 87 88 #define PRCI_LOCK(sc) mtx_lock(&(sc)->mtx) 89 #define PRCI_UNLOCK(sc) mtx_unlock(&(sc)->mtx) 90 #define PRCI_ASSERT_LOCKED(sc) mtx_assert(&(sc)->mtx, MA_OWNED); 91 #define PRCI_ASSERT_UNLOCKED(sc) mtx_assert(&(sc)->mtx, MA_NOTOWNED); 92 93 #define PRCI_PLL_DIVR_MASK 0x3f 94 #define PRCI_PLL_DIVR_SHIFT 0 95 #define PRCI_PLL_DIVF_MASK 0x7fc0 96 #define PRCI_PLL_DIVF_SHIFT 6 97 #define PRCI_PLL_DIVQ_MASK 0x38000 98 #define PRCI_PLL_DIVQ_SHIFT 15 99 100 /* Called devicesresetreg on the FU540 */ 101 #define PRCI_DEVICES_RESET_N 0x28 102 103 #define PRCI_READ(_sc, _reg) \ 104 bus_space_read_4((_sc)->bst, (_sc)->bsh, (_reg)) 105 #define PRCI_WRITE(_sc, _reg, _val) \ 106 bus_space_write_4((_sc)->bst, (_sc)->bsh, (_reg), (_val)) 107 108 struct prci_pll_def { 109 uint32_t id; 110 const char *name; 111 uint32_t reg; 112 }; 113 114 #define PLL(_id, _name, _base) \ 115 { \ 116 .id = (_id), \ 117 .name = (_name), \ 118 .reg = (_base), \ 119 } 120 121 #define PLL_END PLL(0, NULL, 0) 122 123 struct prci_div_def { 124 uint32_t id; 125 const char *name; 126 const char *parent_name; 127 uint32_t reg; 128 uint32_t bias; 129 }; 130 131 #define DIV(_id, _name, _parent_name, _base, _bias) \ 132 { \ 133 .id = (_id), \ 134 .name = (_name), \ 135 .parent_name = (_parent_name), \ 136 .reg = (_base), \ 137 .bias = (_bias), \ 138 } 139 140 #define DIV_END DIV(0, NULL, NULL, 0, 0) 141 142 struct prci_gate_def { 143 uint32_t id; 144 const char *name; 145 const char *parent_name; 146 uint32_t reg; 147 }; 148 149 #define GATE(_id, _name, _parent_name, _base) \ 150 { \ 151 .id = (_id), \ 152 .name = (_name), \ 153 .parent_name = (_parent_name), \ 154 .reg = (_base), \ 155 } 156 157 #define GATE_END GATE(0, NULL, NULL, 0) 158 159 struct prci_config { 160 struct prci_pll_def *pll_clks; 161 struct prci_div_def *div_clks; 162 struct prci_gate_def *gate_clks; 163 struct clk_fixed_def *tlclk_def; 164 int nresets; 165 }; 166 167 /* FU540 clock numbers */ 168 #define FU540_PRCI_CORECLK 0 169 #define FU540_PRCI_DDRCLK 1 170 #define FU540_PRCI_GEMGXLCLK 2 171 #define FU540_PRCI_TLCLK 3 172 173 /* FU540 registers */ 174 #define FU540_PRCI_COREPLL_CFG0 0x4 175 #define FU540_PRCI_DDRPLL_CFG0 0xC 176 #define FU540_PRCI_GEMGXLPLL_CFG0 0x1C 177 178 /* FU540 PLL clocks */ 179 static struct prci_pll_def fu540_pll_clks[] = { 180 PLL(FU540_PRCI_CORECLK, "coreclk", FU540_PRCI_COREPLL_CFG0), 181 PLL(FU540_PRCI_DDRCLK, "ddrclk", FU540_PRCI_DDRPLL_CFG0), 182 PLL(FU540_PRCI_GEMGXLCLK, "gemgxlclk", FU540_PRCI_GEMGXLPLL_CFG0), 183 PLL_END 184 }; 185 186 /* FU540 fixed divisor clock TLCLK. */ 187 static struct clk_fixed_def fu540_tlclk_def = { 188 .clkdef.id = FU540_PRCI_TLCLK, 189 .clkdef.name = "tlclk", 190 .clkdef.parent_names = (const char *[]){"coreclk"}, 191 .clkdef.parent_cnt = 1, 192 .clkdef.flags = CLK_NODE_STATIC_STRINGS, 193 .mult = 1, 194 .div = 2, 195 }; 196 197 /* FU540 config */ 198 struct prci_config fu540_prci_config = { 199 .pll_clks = fu540_pll_clks, 200 .tlclk_def = &fu540_tlclk_def, 201 .nresets = 6, 202 }; 203 204 /* FU740 clock numbers */ 205 #define FU740_PRCI_CORECLK 0 206 #define FU740_PRCI_DDRCLK 1 207 #define FU740_PRCI_GEMGXLCLK 2 208 #define FU740_PRCI_DVFSCORECLK 3 209 #define FU740_PRCI_HFPCLK 4 210 #define FU740_PRCI_CLTXCLK 5 211 #define FU740_PRCI_TLCLK 6 212 #define FU740_PRCI_PCLK 7 213 #define FU740_PRCI_PCIEAUXCLK 8 214 215 /* FU740 registers */ 216 #define FU740_PRCI_COREPLL_CFG0 0x4 217 #define FU740_PRCI_DDRPLL_CFG0 0xC 218 #define FU740_PRCI_PCIEAUX_GATE 0x14 219 #define FU740_PRCI_GEMGXLPLL_CFG0 0x1C 220 #define FU740_PRCI_DVFSCOREPLL_CFG0 0x38 221 #define FU740_PRCI_HFPCLKPLL_CFG0 0x50 222 #define FU740_PRCI_CLTXPLL_CFG0 0x30 223 #define FU740_PRCI_HFPCLK_DIV 0x5C 224 225 /* FU740 PLL clocks */ 226 static struct prci_pll_def fu740_pll_clks[] = { 227 PLL(FU740_PRCI_CORECLK, "coreclk", FU740_PRCI_COREPLL_CFG0), 228 PLL(FU740_PRCI_DDRCLK, "ddrclk", FU740_PRCI_DDRPLL_CFG0), 229 PLL(FU740_PRCI_GEMGXLCLK, "gemgxlclk", FU740_PRCI_GEMGXLPLL_CFG0), 230 PLL(FU740_PRCI_DVFSCORECLK, "dvfscoreclk", FU740_PRCI_DVFSCOREPLL_CFG0), 231 PLL(FU740_PRCI_HFPCLK, "hfpclk", FU740_PRCI_HFPCLKPLL_CFG0), 232 PLL(FU740_PRCI_CLTXCLK, "cltxclk", FU740_PRCI_CLTXPLL_CFG0), 233 PLL_END 234 }; 235 236 /* FU740 divisor clocks */ 237 static struct prci_div_def fu740_div_clks[] = { 238 DIV(FU740_PRCI_PCLK, "pclk", "hfpclk", FU740_PRCI_HFPCLK_DIV, 2), 239 DIV_END 240 }; 241 242 /* FU740 gated clocks */ 243 static struct prci_gate_def fu740_gate_clks[] = { 244 GATE(FU740_PRCI_PCIEAUXCLK, "pcieauxclk", "hfclk", FU740_PRCI_PCIEAUX_GATE), 245 GATE_END 246 }; 247 248 /* FU740 fixed divisor clock TLCLK. */ 249 static struct clk_fixed_def fu740_tlclk_def = { 250 .clkdef.id = FU740_PRCI_TLCLK, 251 .clkdef.name = "tlclk", 252 .clkdef.parent_names = (const char *[]){"coreclk"}, 253 .clkdef.parent_cnt = 1, 254 .clkdef.flags = CLK_NODE_STATIC_STRINGS, 255 .mult = 1, 256 .div = 2, 257 }; 258 259 /* FU740 config */ 260 struct prci_config fu740_prci_config = { 261 .pll_clks = fu740_pll_clks, 262 .div_clks = fu740_div_clks, 263 .gate_clks = fu740_gate_clks, 264 .tlclk_def = &fu740_tlclk_def, 265 .nresets = 7, 266 }; 267 268 static struct ofw_compat_data compat_data[] = { 269 { "sifive,aloeprci0", (uintptr_t)&fu540_prci_config }, 270 { "sifive,ux00prci0", (uintptr_t)&fu540_prci_config }, 271 { "sifive,fu540-c000-prci", (uintptr_t)&fu540_prci_config }, 272 { "sifive,fu740-c000-prci", (uintptr_t)&fu740_prci_config }, 273 { NULL, 0 }, 274 }; 275 276 static int 277 prci_clk_pll_init(struct clknode *clk, device_t dev) 278 { 279 280 clknode_init_parent_idx(clk, 0); 281 282 return (0); 283 } 284 285 static int 286 prci_clk_pll_recalc(struct clknode *clk, uint64_t *freq) 287 { 288 struct prci_clk_pll_sc *sc; 289 struct clknode *parent_clk; 290 uint32_t val; 291 uint64_t refclk, divf, divq, divr; 292 int err; 293 294 KASSERT(freq != NULL, ("freq cannot be NULL")); 295 296 sc = clknode_get_softc(clk); 297 298 PRCI_LOCK(sc->parent_sc); 299 300 /* Get refclock frequency. */ 301 parent_clk = clknode_get_parent(clk); 302 err = clknode_get_freq(parent_clk, &refclk); 303 if (err) { 304 device_printf(sc->parent_sc->dev, 305 "Failed to get refclk frequency\n"); 306 PRCI_UNLOCK(sc->parent_sc); 307 return (err); 308 } 309 310 /* Calculate the PLL output */ 311 val = PRCI_READ(sc->parent_sc, sc->reg); 312 313 divf = (val & PRCI_PLL_DIVF_MASK) >> PRCI_PLL_DIVF_SHIFT; 314 divq = (val & PRCI_PLL_DIVQ_MASK) >> PRCI_PLL_DIVQ_SHIFT; 315 divr = (val & PRCI_PLL_DIVR_MASK) >> PRCI_PLL_DIVR_SHIFT; 316 317 *freq = refclk / (divr + 1) * (2 * (divf + 1)) / (1 << divq); 318 319 PRCI_UNLOCK(sc->parent_sc); 320 321 return (0); 322 } 323 324 static clknode_method_t prci_clk_pll_clknode_methods[] = { 325 CLKNODEMETHOD(clknode_init, prci_clk_pll_init), 326 CLKNODEMETHOD(clknode_recalc_freq, prci_clk_pll_recalc), 327 CLKNODEMETHOD_END 328 }; 329 330 DEFINE_CLASS_1(prci_clk_pll_clknode, prci_clk_pll_clknode_class, 331 prci_clk_pll_clknode_methods, sizeof(struct prci_clk_pll_sc), 332 clknode_class); 333 334 static int 335 prci_clk_div_init(struct clknode *clk, device_t dev) 336 { 337 338 clknode_init_parent_idx(clk, 0); 339 340 return (0); 341 } 342 343 static int 344 prci_clk_div_recalc(struct clknode *clk, uint64_t *freq) 345 { 346 struct prci_clk_div_sc *sc; 347 struct clknode *parent_clk; 348 uint32_t div; 349 uint64_t refclk; 350 int err; 351 352 KASSERT(freq != NULL, ("freq cannot be NULL")); 353 354 sc = clknode_get_softc(clk); 355 356 PRCI_LOCK(sc->parent_sc); 357 358 /* Get refclock frequency. */ 359 parent_clk = clknode_get_parent(clk); 360 err = clknode_get_freq(parent_clk, &refclk); 361 if (err) { 362 device_printf(sc->parent_sc->dev, 363 "Failed to get refclk frequency\n"); 364 PRCI_UNLOCK(sc->parent_sc); 365 return (err); 366 } 367 368 /* Calculate the divisor output */ 369 div = PRCI_READ(sc->parent_sc, sc->reg); 370 371 *freq = refclk / (div + sc->bias); 372 373 PRCI_UNLOCK(sc->parent_sc); 374 375 return (0); 376 } 377 378 static clknode_method_t prci_clk_div_clknode_methods[] = { 379 CLKNODEMETHOD(clknode_init, prci_clk_div_init), 380 CLKNODEMETHOD(clknode_recalc_freq, prci_clk_div_recalc), 381 CLKNODEMETHOD_END 382 }; 383 384 DEFINE_CLASS_1(prci_clk_div_clknode, prci_clk_div_clknode_class, 385 prci_clk_div_clknode_methods, sizeof(struct prci_clk_div_sc), 386 clknode_class); 387 388 static int 389 prci_probe(device_t dev) 390 { 391 392 if (!ofw_bus_status_okay(dev)) 393 return (ENXIO); 394 395 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 396 return (ENXIO); 397 398 device_set_desc(dev, "SiFive Power Reset Clocking Interrupt"); 399 400 return (BUS_PROBE_DEFAULT); 401 } 402 403 static void 404 prci_pll_register(struct prci_softc *parent_sc, struct clknode_init_def *clkdef, 405 uint32_t reg) 406 { 407 struct clknode *clk; 408 struct prci_clk_pll_sc *sc; 409 410 clk = clknode_create(parent_sc->clkdom, &prci_clk_pll_clknode_class, 411 clkdef); 412 if (clk == NULL) 413 panic("Failed to create clknode"); 414 415 sc = clknode_get_softc(clk); 416 sc->parent_sc = parent_sc; 417 sc->reg = reg; 418 419 clknode_register(parent_sc->clkdom, clk); 420 } 421 422 static void 423 prci_div_register(struct prci_softc *parent_sc, struct clknode_init_def *clkdef, 424 uint32_t reg, uint32_t bias) 425 { 426 struct clknode *clk; 427 struct prci_clk_div_sc *sc; 428 429 clk = clknode_create(parent_sc->clkdom, &prci_clk_div_clknode_class, 430 clkdef); 431 if (clk == NULL) 432 panic("Failed to create clknode"); 433 434 sc = clknode_get_softc(clk); 435 sc->parent_sc = parent_sc; 436 sc->reg = reg; 437 sc->bias = bias; 438 439 clknode_register(parent_sc->clkdom, clk); 440 } 441 442 static int 443 prci_attach(device_t dev) 444 { 445 struct clknode_init_def clkdef, clkdef_div; 446 struct clk_gate_def clkdef_gate; 447 struct prci_softc *sc; 448 clk_t clk_parent; 449 phandle_t node; 450 int i, ncells, error; 451 struct prci_config *cfg; 452 struct prci_pll_def *pll_clk; 453 struct prci_div_def *div_clk; 454 struct prci_gate_def *gate_clk; 455 456 sc = device_get_softc(dev); 457 sc->dev = dev; 458 459 cfg = (struct prci_config *)ofw_bus_search_compatible(dev, 460 compat_data)->ocd_data; 461 462 mtx_init(&sc->mtx, device_get_nameunit(sc->dev), NULL, MTX_DEF); 463 464 error = bus_alloc_resources(dev, prci_spec, &sc->res); 465 if (error) { 466 device_printf(dev, "Couldn't allocate resources\n"); 467 goto fail; 468 } 469 sc->bst = rman_get_bustag(sc->res); 470 sc->bsh = rman_get_bushandle(sc->res); 471 472 node = ofw_bus_get_node(dev); 473 error = ofw_bus_parse_xref_list_get_length(node, "clocks", 474 "#clock-cells", &ncells); 475 if (error != 0 || ncells < 1) { 476 device_printf(dev, "couldn't find parent clock\n"); 477 goto fail; 478 } 479 480 bzero(&clkdef, sizeof(clkdef)); 481 clkdef.parent_names = mallocarray(ncells, sizeof(char *), M_OFWPROP, 482 M_WAITOK); 483 for (i = 0; i < ncells; i++) { 484 error = clk_get_by_ofw_index(dev, 0, i, &clk_parent); 485 if (error != 0) { 486 device_printf(dev, "cannot get clock %d\n", error); 487 goto fail1; 488 } 489 clkdef.parent_names[i] = clk_get_name(clk_parent); 490 if (bootverbose) 491 device_printf(dev, "clk parent: %s\n", 492 clkdef.parent_names[i]); 493 clk_release(clk_parent); 494 } 495 clkdef.parent_cnt = ncells; 496 497 sc->clkdom = clkdom_create(dev); 498 if (sc->clkdom == NULL) { 499 device_printf(dev, "Couldn't create clock domain\n"); 500 goto fail; 501 } 502 503 /* We can't free a clkdom, so from now on we cannot fail. */ 504 for (pll_clk = cfg->pll_clks; pll_clk->name; pll_clk++) { 505 clkdef.id = pll_clk->id; 506 clkdef.name = pll_clk->name; 507 prci_pll_register(sc, &clkdef, pll_clk->reg); 508 } 509 510 if (cfg->div_clks != NULL) { 511 bzero(&clkdef_div, sizeof(clkdef_div)); 512 for (div_clk = cfg->div_clks; div_clk->name; div_clk++) { 513 clkdef_div.id = div_clk->id; 514 clkdef_div.name = div_clk->name; 515 clkdef_div.parent_names = &div_clk->parent_name; 516 clkdef_div.parent_cnt = 1; 517 prci_div_register(sc, &clkdef_div, div_clk->reg, 518 div_clk->bias); 519 } 520 } 521 522 if (cfg->gate_clks != NULL) { 523 bzero(&clkdef_gate, sizeof(clkdef_gate)); 524 for (gate_clk = cfg->gate_clks; gate_clk->name; gate_clk++) { 525 clkdef_gate.clkdef.id = gate_clk->id; 526 clkdef_gate.clkdef.name = gate_clk->name; 527 clkdef_gate.clkdef.parent_names = &gate_clk->parent_name; 528 clkdef_gate.clkdef.parent_cnt = 1; 529 clkdef_gate.offset = gate_clk->reg; 530 clkdef_gate.shift = 0; 531 clkdef_gate.mask = 1; 532 clkdef_gate.on_value = 1; 533 clkdef_gate.off_value = 0; 534 error = clknode_gate_register(sc->clkdom, 535 &clkdef_gate); 536 if (error != 0) { 537 device_printf(dev, 538 "Couldn't create gated clock %s: %d\n", 539 gate_clk->name, error); 540 goto fail; 541 } 542 } 543 } 544 545 /* 546 * Register the fixed clock "tlclk". 547 * 548 * If an older device tree is being used, tlclk may appear as its own 549 * entity in the device tree, under soc/tlclk. If this is the case it 550 * will be registered automatically by the fixed_clk driver, and the 551 * version we register here will be an unreferenced duplicate. 552 */ 553 clknode_fixed_register(sc->clkdom, cfg->tlclk_def); 554 555 error = clkdom_finit(sc->clkdom); 556 if (error) 557 panic("Couldn't finalise clock domain"); 558 559 sc->nresets = cfg->nresets; 560 561 return (0); 562 563 fail1: 564 free(clkdef.parent_names, M_OFWPROP); 565 566 fail: 567 bus_release_resources(dev, prci_spec, &sc->res); 568 mtx_destroy(&sc->mtx); 569 return (error); 570 } 571 572 static int 573 prci_write_4(device_t dev, bus_addr_t addr, uint32_t val) 574 { 575 struct prci_softc *sc; 576 577 sc = device_get_softc(dev); 578 579 PRCI_WRITE(sc, addr, val); 580 581 return (0); 582 } 583 584 static int 585 prci_read_4(device_t dev, bus_addr_t addr, uint32_t *val) 586 { 587 struct prci_softc *sc; 588 589 sc = device_get_softc(dev); 590 591 *val = PRCI_READ(sc, addr); 592 593 return (0); 594 } 595 596 static int 597 prci_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set) 598 { 599 struct prci_softc *sc; 600 uint32_t reg; 601 602 sc = device_get_softc(dev); 603 604 reg = PRCI_READ(sc, addr); 605 reg &= ~clr; 606 reg |= set; 607 PRCI_WRITE(sc, addr, reg); 608 609 return (0); 610 } 611 612 static void 613 prci_device_lock(device_t dev) 614 { 615 struct prci_softc *sc; 616 617 sc = device_get_softc(dev); 618 PRCI_LOCK(sc); 619 } 620 621 static void 622 prci_device_unlock(device_t dev) 623 { 624 struct prci_softc *sc; 625 626 sc = device_get_softc(dev); 627 PRCI_UNLOCK(sc); 628 } 629 630 static int 631 prci_reset_assert(device_t dev, intptr_t id, bool reset) 632 { 633 struct prci_softc *sc; 634 uint32_t reg; 635 636 sc = device_get_softc(dev); 637 638 if (id >= sc->nresets) 639 return (ENXIO); 640 641 PRCI_LOCK(sc); 642 reg = PRCI_READ(sc, PRCI_DEVICES_RESET_N); 643 if (reset) 644 reg &= ~(1u << id); 645 else 646 reg |= (1u << id); 647 PRCI_WRITE(sc, PRCI_DEVICES_RESET_N, reg); 648 PRCI_UNLOCK(sc); 649 650 return (0); 651 } 652 653 static int 654 prci_reset_is_asserted(device_t dev, intptr_t id, bool *reset) 655 { 656 struct prci_softc *sc; 657 uint32_t reg; 658 659 sc = device_get_softc(dev); 660 661 if (id >= sc->nresets) 662 return (ENXIO); 663 664 PRCI_LOCK(sc); 665 reg = PRCI_READ(sc, PRCI_DEVICES_RESET_N); 666 *reset = (reg & (1u << id)) == 0; 667 PRCI_UNLOCK(sc); 668 669 return (0); 670 } 671 672 static device_method_t prci_methods[] = { 673 DEVMETHOD(device_probe, prci_probe), 674 DEVMETHOD(device_attach, prci_attach), 675 676 /* clkdev interface */ 677 DEVMETHOD(clkdev_write_4, prci_write_4), 678 DEVMETHOD(clkdev_read_4, prci_read_4), 679 DEVMETHOD(clkdev_modify_4, prci_modify_4), 680 DEVMETHOD(clkdev_device_lock, prci_device_lock), 681 DEVMETHOD(clkdev_device_unlock, prci_device_unlock), 682 683 /* Reset interface */ 684 DEVMETHOD(hwreset_assert, prci_reset_assert), 685 DEVMETHOD(hwreset_is_asserted, prci_reset_is_asserted), 686 687 DEVMETHOD_END 688 }; 689 690 static driver_t prci_driver = { 691 "sifive_prci", 692 prci_methods, 693 sizeof(struct prci_softc) 694 }; 695 696 /* 697 * hfclk and rtcclk appear later in the device tree than prci, so we must 698 * attach late. 699 */ 700 EARLY_DRIVER_MODULE(sifive_prci, simplebus, prci_driver, 0, 0, 701 BUS_PASS_BUS + BUS_PASS_ORDER_LATE); 702