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