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