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