1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 2006-2008, Juniper Networks, Inc. 5 * Copyright (c) 2008 Semihalf, Rafal Czubak 6 * Copyright (c) 2009 The FreeBSD Foundation 7 * All rights reserved. 8 * 9 * Portions of this software were developed by Semihalf 10 * under sponsorship from the FreeBSD Foundation. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. The name of the author may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include "opt_platform.h" 37 38 #include <sys/cdefs.h> 39 __FBSDID("$FreeBSD$"); 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 #include <sys/ktr.h> 44 #include <sys/kernel.h> 45 #include <sys/malloc.h> 46 #include <sys/module.h> 47 #include <sys/bus.h> 48 #include <sys/rman.h> 49 #include <machine/bus.h> 50 51 #include <vm/vm.h> 52 #include <vm/pmap.h> 53 54 #include <dev/fdt/fdt_common.h> 55 #include <dev/ofw/ofw_bus.h> 56 #include <dev/ofw/ofw_bus_subr.h> 57 58 #include <powerpc/mpc85xx/mpc85xx.h> 59 60 #include "ofw_bus_if.h" 61 #include "lbc.h" 62 63 #ifdef DEBUG 64 #define debugf(fmt, args...) do { printf("%s(): ", __func__); \ 65 printf(fmt,##args); } while (0) 66 #else 67 #define debugf(fmt, args...) 68 #endif 69 70 static MALLOC_DEFINE(M_LBC, "localbus", "localbus devices information"); 71 72 static int lbc_probe(device_t); 73 static int lbc_attach(device_t); 74 static int lbc_shutdown(device_t); 75 static int lbc_activate_resource(device_t bus __unused, device_t child __unused, 76 int type, int rid __unused, struct resource *r); 77 static int lbc_deactivate_resource(device_t bus __unused, 78 device_t child __unused, int type __unused, int rid __unused, 79 struct resource *r); 80 static struct resource *lbc_alloc_resource(device_t, device_t, int, int *, 81 rman_res_t, rman_res_t, rman_res_t, u_int); 82 static int lbc_print_child(device_t, device_t); 83 static int lbc_release_resource(device_t, device_t, int, int, 84 struct resource *); 85 static const struct ofw_bus_devinfo *lbc_get_devinfo(device_t, device_t); 86 87 /* 88 * Bus interface definition 89 */ 90 static device_method_t lbc_methods[] = { 91 /* Device interface */ 92 DEVMETHOD(device_probe, lbc_probe), 93 DEVMETHOD(device_attach, lbc_attach), 94 DEVMETHOD(device_shutdown, lbc_shutdown), 95 96 /* Bus interface */ 97 DEVMETHOD(bus_print_child, lbc_print_child), 98 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 99 DEVMETHOD(bus_teardown_intr, NULL), 100 101 DEVMETHOD(bus_alloc_resource, lbc_alloc_resource), 102 DEVMETHOD(bus_release_resource, lbc_release_resource), 103 DEVMETHOD(bus_activate_resource, lbc_activate_resource), 104 DEVMETHOD(bus_deactivate_resource, lbc_deactivate_resource), 105 106 /* OFW bus interface */ 107 DEVMETHOD(ofw_bus_get_devinfo, lbc_get_devinfo), 108 DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 109 DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 110 DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 111 DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 112 DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 113 { 0, 0 } 114 }; 115 116 static driver_t lbc_driver = { 117 "lbc", 118 lbc_methods, 119 sizeof(struct lbc_softc) 120 }; 121 122 devclass_t lbc_devclass; 123 124 EARLY_DRIVER_MODULE(lbc, ofwbus, lbc_driver, lbc_devclass, 125 0, 0, BUS_PASS_BUS); 126 127 /* 128 * Calculate address mask used by OR(n) registers. Use memory region size to 129 * determine mask value. The size must be a power of two and within the range 130 * of 32KB - 4GB. Otherwise error code is returned. Value representing 131 * 4GB size can be passed as 0xffffffff. 132 */ 133 static uint32_t 134 lbc_address_mask(uint32_t size) 135 { 136 int n = 15; 137 138 if (size == ~0) 139 return (0); 140 141 while (n < 32) { 142 if (size == (1U << n)) 143 break; 144 n++; 145 } 146 147 if (n == 32) 148 return (EINVAL); 149 150 return (0xffff8000 << (n - 15)); 151 } 152 153 static void 154 lbc_banks_unmap(struct lbc_softc *sc) 155 { 156 int r; 157 158 r = 0; 159 while (r < LBC_DEV_MAX) { 160 if (sc->sc_range[r].size == 0) 161 return; 162 163 pmap_unmapdev(sc->sc_range[r].kva, sc->sc_range[r].size); 164 law_disable(OCP85XX_TGTIF_LBC, sc->sc_range[r].addr, 165 sc->sc_range[r].size); 166 r++; 167 } 168 } 169 170 static int 171 lbc_banks_map(struct lbc_softc *sc) 172 { 173 vm_paddr_t end, start; 174 vm_size_t size; 175 u_int i, r, ranges, s; 176 int error; 177 178 bzero(sc->sc_range, sizeof(sc->sc_range)); 179 180 /* 181 * Determine number of discontiguous address ranges to program. 182 */ 183 ranges = 0; 184 for (i = 0; i < LBC_DEV_MAX; i++) { 185 size = sc->sc_banks[i].size; 186 if (size == 0) 187 continue; 188 189 start = sc->sc_banks[i].addr; 190 for (r = 0; r < ranges; r++) { 191 /* Avoid wrap-around bugs. */ 192 end = sc->sc_range[r].addr - 1 + sc->sc_range[r].size; 193 if (start > 0 && end == start - 1) { 194 sc->sc_range[r].size += size; 195 break; 196 } 197 /* Avoid wrap-around bugs. */ 198 end = start - 1 + size; 199 if (sc->sc_range[r].addr > 0 && 200 end == sc->sc_range[r].addr - 1) { 201 sc->sc_range[r].addr = start; 202 sc->sc_range[r].size += size; 203 break; 204 } 205 } 206 if (r == ranges) { 207 /* New range; add using insertion sort */ 208 r = 0; 209 while (r < ranges && sc->sc_range[r].addr < start) 210 r++; 211 for (s = ranges; s > r; s--) 212 sc->sc_range[s] = sc->sc_range[s-1]; 213 sc->sc_range[r].addr = start; 214 sc->sc_range[r].size = size; 215 ranges++; 216 } 217 } 218 219 /* 220 * Ranges are sorted so quickly go over the list to merge ranges 221 * that grew toward each other while building the ranges. 222 */ 223 r = 0; 224 while (r < ranges - 1) { 225 end = sc->sc_range[r].addr + sc->sc_range[r].size; 226 if (end != sc->sc_range[r+1].addr) { 227 r++; 228 continue; 229 } 230 sc->sc_range[r].size += sc->sc_range[r+1].size; 231 for (s = r + 1; s < ranges - 1; s++) 232 sc->sc_range[s] = sc->sc_range[s+1]; 233 bzero(&sc->sc_range[s], sizeof(sc->sc_range[s])); 234 ranges--; 235 } 236 237 /* 238 * Configure LAW for the LBC ranges and map the physical memory 239 * range into KVA. 240 */ 241 for (r = 0; r < ranges; r++) { 242 start = sc->sc_range[r].addr; 243 size = sc->sc_range[r].size; 244 error = law_enable(OCP85XX_TGTIF_LBC, start, size); 245 if (error) 246 return (error); 247 sc->sc_range[r].kva = (vm_offset_t)pmap_mapdev(start, size); 248 } 249 250 /* XXX: need something better here? */ 251 if (ranges == 0) 252 return (EINVAL); 253 254 /* Assign KVA to banks based on the enclosing range. */ 255 for (i = 0; i < LBC_DEV_MAX; i++) { 256 size = sc->sc_banks[i].size; 257 if (size == 0) 258 continue; 259 260 start = sc->sc_banks[i].addr; 261 for (r = 0; r < ranges; r++) { 262 end = sc->sc_range[r].addr - 1 + sc->sc_range[r].size; 263 if (start >= sc->sc_range[r].addr && 264 start - 1 + size <= end) 265 break; 266 } 267 if (r < ranges) { 268 sc->sc_banks[i].kva = sc->sc_range[r].kva + 269 (start - sc->sc_range[r].addr); 270 } 271 } 272 273 return (0); 274 } 275 276 static int 277 lbc_banks_enable(struct lbc_softc *sc) 278 { 279 uint32_t size; 280 uint32_t regval; 281 int error, i; 282 283 for (i = 0; i < LBC_DEV_MAX; i++) { 284 size = sc->sc_banks[i].size; 285 if (size == 0) 286 continue; 287 288 /* 289 * Compute and program BR value. 290 */ 291 regval = sc->sc_banks[i].addr; 292 switch (sc->sc_banks[i].width) { 293 case 8: 294 regval |= (1 << 11); 295 break; 296 case 16: 297 regval |= (2 << 11); 298 break; 299 case 32: 300 regval |= (3 << 11); 301 break; 302 default: 303 error = EINVAL; 304 goto fail; 305 } 306 regval |= (sc->sc_banks[i].decc << 9); 307 regval |= (sc->sc_banks[i].wp << 8); 308 regval |= (sc->sc_banks[i].msel << 5); 309 regval |= (sc->sc_banks[i].atom << 2); 310 regval |= 1; 311 bus_space_write_4(sc->sc_bst, sc->sc_bsh, 312 LBC85XX_BR(i), regval); 313 314 /* 315 * Compute and program OR value. 316 */ 317 regval = lbc_address_mask(size); 318 switch (sc->sc_banks[i].msel) { 319 case LBCRES_MSEL_GPCM: 320 /* TODO Add flag support for option registers */ 321 regval |= 0x0ff7; 322 break; 323 case LBCRES_MSEL_FCM: 324 /* TODO Add flag support for options register */ 325 regval |= 0x0796; 326 break; 327 case LBCRES_MSEL_UPMA: 328 case LBCRES_MSEL_UPMB: 329 case LBCRES_MSEL_UPMC: 330 printf("UPM mode not supported yet!"); 331 error = ENOSYS; 332 goto fail; 333 } 334 bus_space_write_4(sc->sc_bst, sc->sc_bsh, 335 LBC85XX_OR(i), regval); 336 } 337 338 return (0); 339 340 fail: 341 lbc_banks_unmap(sc); 342 return (error); 343 } 344 345 static void 346 fdt_lbc_fixup(phandle_t node, struct lbc_softc *sc, struct lbc_devinfo *di) 347 { 348 pcell_t width; 349 int bank; 350 351 if (OF_getprop(node, "bank-width", (void *)&width, sizeof(width)) <= 0) 352 return; 353 354 bank = di->di_bank; 355 if (sc->sc_banks[bank].size == 0) 356 return; 357 358 /* Express width in bits. */ 359 sc->sc_banks[bank].width = width * 8; 360 } 361 362 static int 363 fdt_lbc_reg_decode(phandle_t node, struct lbc_softc *sc, 364 struct lbc_devinfo *di) 365 { 366 rman_res_t start, end, count; 367 pcell_t *reg, *regptr; 368 pcell_t addr_cells, size_cells; 369 int tuple_size, tuples; 370 int i, j, rv, bank; 371 372 if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells) != 0) 373 return (ENXIO); 374 375 tuple_size = sizeof(pcell_t) * (addr_cells + size_cells); 376 tuples = OF_getencprop_alloc_multi(node, "reg", tuple_size, 377 (void **)®); 378 debugf("addr_cells = %d, size_cells = %d\n", addr_cells, size_cells); 379 debugf("tuples = %d, tuple size = %d\n", tuples, tuple_size); 380 if (tuples <= 0) 381 /* No 'reg' property in this node. */ 382 return (0); 383 384 regptr = reg; 385 for (i = 0; i < tuples; i++) { 386 bank = fdt_data_get((void *)reg, 1); 387 di->di_bank = bank; 388 reg += 1; 389 390 /* Get address/size. */ 391 start = count = 0; 392 for (j = 0; j < addr_cells - 1; j++) { 393 start <<= 32; 394 start |= reg[j]; 395 } 396 for (j = 0; j < size_cells; j++) { 397 count <<= 32; 398 count |= reg[addr_cells + j - 1]; 399 } 400 reg += addr_cells - 1 + size_cells; 401 402 /* Calculate address range relative to VA base. */ 403 start = sc->sc_banks[bank].kva + start; 404 end = start + count - 1; 405 406 debugf("reg addr bank = %d, start = %jx, end = %jx, " 407 "count = %jx\n", bank, start, end, count); 408 409 /* Use bank (CS) cell as rid. */ 410 resource_list_add(&di->di_res, SYS_RES_MEMORY, bank, start, 411 end, count); 412 } 413 rv = 0; 414 OF_prop_free(regptr); 415 return (rv); 416 } 417 418 static void 419 lbc_intr(void *arg) 420 { 421 struct lbc_softc *sc = arg; 422 uint32_t ltesr; 423 424 ltesr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LTESR); 425 sc->sc_ltesr = ltesr; 426 bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LTESR, ltesr); 427 wakeup(sc->sc_dev); 428 } 429 430 static int 431 lbc_probe(device_t dev) 432 { 433 434 if (!(ofw_bus_is_compatible(dev, "fsl,lbc") || 435 ofw_bus_is_compatible(dev, "fsl,elbc"))) 436 return (ENXIO); 437 438 device_set_desc(dev, "Freescale Local Bus Controller"); 439 return (BUS_PROBE_DEFAULT); 440 } 441 442 static int 443 lbc_attach(device_t dev) 444 { 445 struct lbc_softc *sc; 446 struct lbc_devinfo *di; 447 struct rman *rm; 448 uintmax_t offset, size; 449 vm_paddr_t start; 450 device_t cdev; 451 phandle_t node, child; 452 pcell_t *ranges, *rangesptr; 453 int tuple_size, tuples; 454 int par_addr_cells; 455 int bank, error, i, j; 456 457 sc = device_get_softc(dev); 458 sc->sc_dev = dev; 459 460 sc->sc_mrid = 0; 461 sc->sc_mres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_mrid, 462 RF_ACTIVE); 463 if (sc->sc_mres == NULL) 464 return (ENXIO); 465 466 sc->sc_bst = rman_get_bustag(sc->sc_mres); 467 sc->sc_bsh = rman_get_bushandle(sc->sc_mres); 468 469 for (bank = 0; bank < LBC_DEV_MAX; bank++) { 470 bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_BR(bank), 0); 471 bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_OR(bank), 0); 472 } 473 474 /* 475 * Initialize configuration register: 476 * - enable Local Bus 477 * - set data buffer control signal function 478 * - disable parity byte select 479 * - set ECC parity type 480 * - set bus monitor timing and timer prescale 481 */ 482 bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LBCR, 0); 483 484 /* 485 * Initialize clock ratio register: 486 * - disable PLL bypass mode 487 * - configure LCLK delay cycles for the assertion of LALE 488 * - set system clock divider 489 */ 490 bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LCRR, 0x00030008); 491 492 bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LTEDR, 0); 493 bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LTESR, ~0); 494 bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LTEIR, 0x64080001); 495 496 sc->sc_irid = 0; 497 sc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irid, 498 RF_ACTIVE | RF_SHAREABLE); 499 if (sc->sc_ires != NULL) { 500 error = bus_setup_intr(dev, sc->sc_ires, 501 INTR_TYPE_MISC | INTR_MPSAFE, NULL, lbc_intr, sc, 502 &sc->sc_icookie); 503 if (error) { 504 device_printf(dev, "could not activate interrupt\n"); 505 bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid, 506 sc->sc_ires); 507 sc->sc_ires = NULL; 508 } 509 } 510 511 sc->sc_ltesr = ~0; 512 513 rangesptr = NULL; 514 515 rm = &sc->sc_rman; 516 rm->rm_type = RMAN_ARRAY; 517 rm->rm_descr = "Local Bus Space"; 518 error = rman_init(rm); 519 if (error) 520 goto fail; 521 522 error = rman_manage_region(rm, rm->rm_start, rm->rm_end); 523 if (error) { 524 rman_fini(rm); 525 goto fail; 526 } 527 528 /* 529 * Process 'ranges' property. 530 */ 531 node = ofw_bus_get_node(dev); 532 if ((fdt_addrsize_cells(node, &sc->sc_addr_cells, 533 &sc->sc_size_cells)) != 0) { 534 error = ENXIO; 535 goto fail; 536 } 537 538 par_addr_cells = fdt_parent_addr_cells(node); 539 if (par_addr_cells > 2) { 540 device_printf(dev, "unsupported parent #addr-cells\n"); 541 error = ERANGE; 542 goto fail; 543 } 544 tuple_size = sizeof(pcell_t) * (sc->sc_addr_cells + par_addr_cells + 545 sc->sc_size_cells); 546 547 tuples = OF_getencprop_alloc_multi(node, "ranges", tuple_size, 548 (void **)&ranges); 549 if (tuples < 0) { 550 device_printf(dev, "could not retrieve 'ranges' property\n"); 551 error = ENXIO; 552 goto fail; 553 } 554 rangesptr = ranges; 555 556 debugf("par addr_cells = %d, addr_cells = %d, size_cells = %d, " 557 "tuple_size = %d, tuples = %d\n", par_addr_cells, 558 sc->sc_addr_cells, sc->sc_size_cells, tuple_size, tuples); 559 560 start = 0; 561 size = 0; 562 for (i = 0; i < tuples; i++) { 563 /* The first cell is the bank (chip select) number. */ 564 bank = fdt_data_get(ranges, 1); 565 if (bank < 0 || bank > LBC_DEV_MAX) { 566 device_printf(dev, "bank out of range: %d\n", bank); 567 error = ERANGE; 568 goto fail; 569 } 570 ranges += 1; 571 572 /* 573 * Remaining cells of the child address define offset into 574 * this CS. 575 */ 576 offset = 0; 577 for (j = 0; j < sc->sc_addr_cells - 1; j++) { 578 offset <<= sizeof(pcell_t) * 8; 579 offset |= *ranges; 580 ranges++; 581 } 582 583 /* Parent bus start address of this bank. */ 584 start = 0; 585 for (j = 0; j < par_addr_cells; j++) { 586 start <<= sizeof(pcell_t) * 8; 587 start |= *ranges; 588 ranges++; 589 } 590 591 size = fdt_data_get((void *)ranges, sc->sc_size_cells); 592 ranges += sc->sc_size_cells; 593 debugf("bank = %d, start = %jx, size = %jx\n", bank, 594 (uintmax_t)start, size); 595 596 sc->sc_banks[bank].addr = start + offset; 597 sc->sc_banks[bank].size = size; 598 599 /* 600 * Attributes for the bank. 601 * 602 * XXX Note there are no DT bindings defined for them at the 603 * moment, so we need to provide some defaults. 604 */ 605 sc->sc_banks[bank].width = 16; 606 sc->sc_banks[bank].msel = LBCRES_MSEL_GPCM; 607 sc->sc_banks[bank].decc = LBCRES_DECC_DISABLED; 608 sc->sc_banks[bank].atom = LBCRES_ATOM_DISABLED; 609 sc->sc_banks[bank].wp = 0; 610 } 611 612 /* 613 * Initialize mem-mappings for the LBC banks (i.e. chip selects). 614 */ 615 error = lbc_banks_map(sc); 616 if (error) 617 goto fail; 618 619 /* 620 * Walk the localbus and add direct subordinates as our children. 621 */ 622 for (child = OF_child(node); child != 0; child = OF_peer(child)) { 623 di = malloc(sizeof(*di), M_LBC, M_WAITOK | M_ZERO); 624 625 if (ofw_bus_gen_setup_devinfo(&di->di_ofw, child) != 0) { 626 free(di, M_LBC); 627 device_printf(dev, "could not set up devinfo\n"); 628 continue; 629 } 630 631 resource_list_init(&di->di_res); 632 633 if (fdt_lbc_reg_decode(child, sc, di)) { 634 device_printf(dev, "could not process 'reg' " 635 "property\n"); 636 ofw_bus_gen_destroy_devinfo(&di->di_ofw); 637 free(di, M_LBC); 638 continue; 639 } 640 641 fdt_lbc_fixup(child, sc, di); 642 643 /* Add newbus device for this FDT node */ 644 cdev = device_add_child(dev, NULL, -1); 645 if (cdev == NULL) { 646 device_printf(dev, "could not add child: %s\n", 647 di->di_ofw.obd_name); 648 resource_list_free(&di->di_res); 649 ofw_bus_gen_destroy_devinfo(&di->di_ofw); 650 free(di, M_LBC); 651 continue; 652 } 653 debugf("added child name='%s', node=%x\n", di->di_ofw.obd_name, 654 child); 655 device_set_ivars(cdev, di); 656 } 657 658 /* 659 * Enable the LBC. 660 */ 661 lbc_banks_enable(sc); 662 663 OF_prop_free(rangesptr); 664 return (bus_generic_attach(dev)); 665 666 fail: 667 OF_prop_free(rangesptr); 668 bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_mrid, sc->sc_mres); 669 return (error); 670 } 671 672 static int 673 lbc_shutdown(device_t dev) 674 { 675 676 /* TODO */ 677 return(0); 678 } 679 680 static struct resource * 681 lbc_alloc_resource(device_t bus, device_t child, int type, int *rid, 682 rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 683 { 684 struct lbc_softc *sc; 685 struct lbc_devinfo *di; 686 struct resource_list_entry *rle; 687 struct resource *res; 688 struct rman *rm; 689 int needactivate; 690 691 /* We only support default allocations. */ 692 if (!RMAN_IS_DEFAULT_RANGE(start, end)) 693 return (NULL); 694 695 sc = device_get_softc(bus); 696 if (type == SYS_RES_IRQ) 697 return (bus_alloc_resource(bus, type, rid, start, end, count, 698 flags)); 699 700 /* 701 * Request for the default allocation with a given rid: use resource 702 * list stored in the local device info. 703 */ 704 if ((di = device_get_ivars(child)) == NULL) 705 return (NULL); 706 707 if (type == SYS_RES_IOPORT) 708 type = SYS_RES_MEMORY; 709 710 rid = &di->di_bank; 711 712 rle = resource_list_find(&di->di_res, type, *rid); 713 if (rle == NULL) { 714 device_printf(bus, "no default resources for " 715 "rid = %d, type = %d\n", *rid, type); 716 return (NULL); 717 } 718 start = rle->start; 719 count = rle->count; 720 end = start + count - 1; 721 722 sc = device_get_softc(bus); 723 724 needactivate = flags & RF_ACTIVE; 725 flags &= ~RF_ACTIVE; 726 727 rm = &sc->sc_rman; 728 729 res = rman_reserve_resource(rm, start, end, count, flags, child); 730 if (res == NULL) { 731 device_printf(bus, "failed to reserve resource %#jx - %#jx " 732 "(%#jx)\n", start, end, count); 733 return (NULL); 734 } 735 736 rman_set_rid(res, *rid); 737 rman_set_bustag(res, &bs_be_tag); 738 rman_set_bushandle(res, rman_get_start(res)); 739 740 if (needactivate) 741 if (bus_activate_resource(child, type, *rid, res)) { 742 device_printf(child, "resource activation failed\n"); 743 rman_release_resource(res); 744 return (NULL); 745 } 746 747 return (res); 748 } 749 750 static int 751 lbc_print_child(device_t dev, device_t child) 752 { 753 struct lbc_devinfo *di; 754 struct resource_list *rl; 755 int rv; 756 757 di = device_get_ivars(child); 758 rl = &di->di_res; 759 760 rv = 0; 761 rv += bus_print_child_header(dev, child); 762 rv += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx"); 763 rv += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd"); 764 rv += bus_print_child_footer(dev, child); 765 766 return (rv); 767 } 768 769 static int 770 lbc_release_resource(device_t dev, device_t child, int type, int rid, 771 struct resource *res) 772 { 773 int err; 774 775 if (rman_get_flags(res) & RF_ACTIVE) { 776 err = bus_deactivate_resource(child, type, rid, res); 777 if (err) 778 return (err); 779 } 780 781 return (rman_release_resource(res)); 782 } 783 784 static int 785 lbc_activate_resource(device_t bus __unused, device_t child __unused, 786 int type __unused, int rid __unused, struct resource *r) 787 { 788 789 /* Child resources were already mapped, just activate. */ 790 return (rman_activate_resource(r)); 791 } 792 793 static int 794 lbc_deactivate_resource(device_t bus __unused, device_t child __unused, 795 int type __unused, int rid __unused, struct resource *r) 796 { 797 798 return (rman_deactivate_resource(r)); 799 } 800 801 static const struct ofw_bus_devinfo * 802 lbc_get_devinfo(device_t bus, device_t child) 803 { 804 struct lbc_devinfo *di; 805 806 di = device_get_ivars(child); 807 return (&di->di_ofw); 808 } 809 810 void 811 lbc_write_reg(device_t child, u_int off, uint32_t val) 812 { 813 device_t dev; 814 struct lbc_softc *sc; 815 816 dev = device_get_parent(child); 817 818 if (off >= 0x1000) { 819 device_printf(dev, "%s(%s): invalid offset %#x\n", 820 __func__, device_get_nameunit(child), off); 821 return; 822 } 823 824 sc = device_get_softc(dev); 825 826 if (off == LBC85XX_LTESR && sc->sc_ltesr != ~0u) { 827 sc->sc_ltesr ^= (val & sc->sc_ltesr); 828 return; 829 } 830 831 if (off == LBC85XX_LTEATR && (val & 1) == 0) 832 sc->sc_ltesr = ~0u; 833 bus_space_write_4(sc->sc_bst, sc->sc_bsh, off, val); 834 } 835 836 uint32_t 837 lbc_read_reg(device_t child, u_int off) 838 { 839 device_t dev; 840 struct lbc_softc *sc; 841 uint32_t val; 842 843 dev = device_get_parent(child); 844 845 if (off >= 0x1000) { 846 device_printf(dev, "%s(%s): invalid offset %#x\n", 847 __func__, device_get_nameunit(child), off); 848 return (~0U); 849 } 850 851 sc = device_get_softc(dev); 852 853 if (off == LBC85XX_LTESR && sc->sc_ltesr != ~0U) 854 val = sc->sc_ltesr; 855 else 856 val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, off); 857 return (val); 858 } 859