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