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