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