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