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