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