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