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