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