146684Skris/*- 216Salm * SPDX-License-Identifier: BSD-3-Clause 316Salm * 41057Salm * Copyright (c) 2006-2008, Juniper Networks, Inc. 516Salm * Copyright (c) 2008 Semihalf, Rafal Czubak 616Salm * Copyright (c) 2009 The FreeBSD Foundation 716Salm * All rights reserved. 816Salm * 916Salm * Portions of this software were developed by Semihalf 1016Salm * under sponsorship from the FreeBSD Foundation. 1116Salm * 1216Salm * Redistribution and use in source and binary forms, with or without 1316Salm * modification, are permitted provided that the following conditions 1416Salm * are met: 1516Salm * 1. Redistributions of source code must retain the above copyright 161057Salm * notice, this list of conditions and the following disclaimer. 1716Salm * 2. Redistributions in binary form must reproduce the above copyright 1816Salm * notice, this list of conditions and the following disclaimer in the 191057Salm * documentation and/or other materials provided with the distribution. 2016Salm * 3. The name of the author may not be used to endorse or promote products 2116Salm * derived from this software without specific prior written permission. 2216Salm * 2316Salm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2416Salm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2516Salm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2616Salm * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2716Salm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 2827963Ssteve * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 2999109Sobrien * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 3099109Sobrien * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 3116Salm * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3216Salm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 331297Salm * SUCH DAMAGE. 3416Salm */ 3516Salm 3616Salm#include "opt_platform.h" 3716Salm 38241720Sed#include <sys/param.h> 39241720Sed#include <sys/systm.h> 40241720Sed#include <sys/ktr.h> 41241720Sed#include <sys/kernel.h> 4216Salm#include <sys/malloc.h> 431057Salm#include <sys/module.h> 4416Salm#include <sys/bus.h> 4516Salm#include <sys/rman.h> 4690109Simp#include <machine/bus.h> 4716Salm 481057Salm#include <vm/vm.h> 491057Salm#include <vm/pmap.h> 501057Salm 5116Salm#include <dev/fdt/fdt_common.h> 5216Salm#include <dev/ofw/ofw_bus.h> 531057Salm#include <dev/ofw/ofw_bus_subr.h> 5416Salm 5516Salm#include <powerpc/mpc85xx/mpc85xx.h> 5616Salm 5716Salm#include "ofw_bus_if.h" 5816Salm#include "lbc.h" 5982771Sache 6016Salm#ifdef DEBUG 6181220Smike#define debugf(fmt, args...) do { printf("%s(): ", __func__); \ 6216Salm printf(fmt,##args); } while (0) 6316Salm#else 6416Salm#define debugf(fmt, args...) 651057Salm#endif 661057Salm 6716Salmstatic MALLOC_DEFINE(M_LBC, "localbus", "localbus devices information"); 6816Salm 6981220Smikestatic int lbc_probe(device_t); 7016Salmstatic int lbc_attach(device_t); 7116Salmstatic int lbc_shutdown(device_t); 7216Salmstatic int lbc_map_resource(device_t, device_t, struct resource *, 7316Salm struct resource_map_request *, struct resource_map *); 7416Salmstatic int lbc_unmap_resource(device_t, device_t, struct resource *, 7516Salm struct resource_map *map); 7616Salmstatic int lbc_activate_resource(device_t bus, device_t child, 7716Salm struct resource *r); 781057Salmstatic int lbc_deactivate_resource(device_t bus, device_t child, 7916Salm struct resource *r); 8081220Smikestatic struct rman *lbc_get_rman(device_t, int, u_int); 8190109Simpstatic struct resource *lbc_alloc_resource(device_t, device_t, int, int *, 8216Salm rman_res_t, rman_res_t, rman_res_t, u_int); 8316Salmstatic int lbc_adjust_resource(device_t, device_t, struct resource *, 8416Salm rman_res_t, rman_res_t); 8581220Smikestatic int lbc_print_child(device_t, device_t); 8616Salmstatic int lbc_release_resource(device_t, device_t, struct resource *); 8716Salmstatic const struct ofw_bus_devinfo *lbc_get_devinfo(device_t, device_t); 8816Salm 8981220Smike/* 9016Salm * Bus interface definition 9116Salm */ 9216Salmstatic device_method_t lbc_methods[] = { 9316Salm /* Device interface */ 9416Salm DEVMETHOD(device_probe, lbc_probe), 9516Salm DEVMETHOD(device_attach, lbc_attach), 9681220Smike DEVMETHOD(device_shutdown, lbc_shutdown), 97225215Sbrueffer 9816Salm /* Bus interface */ 9916Salm DEVMETHOD(bus_print_child, lbc_print_child), 1001057Salm DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 10116Salm DEVMETHOD(bus_teardown_intr, NULL), 10216Salm 10382771Sache DEVMETHOD(bus_get_rman, lbc_get_rman), 10416Salm DEVMETHOD(bus_alloc_resource, lbc_alloc_resource), 10581220Smike DEVMETHOD(bus_adjust_resource, lbc_adjust_resource), 106225215Sbrueffer DEVMETHOD(bus_release_resource, lbc_release_resource), 10716Salm DEVMETHOD(bus_activate_resource, lbc_activate_resource), 10816Salm DEVMETHOD(bus_deactivate_resource, lbc_deactivate_resource), 10982771Sache DEVMETHOD(bus_map_resource, lbc_map_resource), 11016Salm DEVMETHOD(bus_unmap_resource, lbc_unmap_resource), 11116Salm 1121057Salm /* OFW bus interface */ 11316Salm DEVMETHOD(ofw_bus_get_devinfo, lbc_get_devinfo), 11416Salm DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 11516Salm DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 11681220Smike DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 117225215Sbrueffer DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 11816Salm DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 11916Salm { 0, 0 } 12016Salm}; 12116Salm 1221057Salmstatic driver_t lbc_driver = { 12316Salm "lbc", 12416Salm lbc_methods, 12516Salm sizeof(struct lbc_softc) 12616Salm}; 12716Salm 1281057SalmEARLY_DRIVER_MODULE(lbc, ofwbus, lbc_driver, 0, 0, BUS_PASS_BUS); 12916Salm 13090109Simp/* 13116Salm * Calculate address mask used by OR(n) registers. Use memory region size to 13216Salm * determine mask value. The size must be a power of two and within the range 13316Salm * of 32KB - 4GB. Otherwise error code is returned. Value representing 1341057Salm * 4GB size can be passed as 0xffffffff. 1351297Salm */ 1361057Salmstatic uint32_t 1371057Salmlbc_address_mask(uint32_t size) 13816Salm{ 13916Salm int n = 15; 14016Salm 1411057Salm if (size == ~0) 14216Salm return (0); 14390109Simp 14416Salm while (n < 32) { 1451057Salm if (size == (1U << n)) 14616Salm break; 14716Salm n++; 1481057Salm } 14916Salm 1501057Salm if (n == 32) 15181220Smike return (EINVAL); 15249Salm 15349Salm return (0xffff8000 << (n - 15)); 15449Salm} 15516Salm 15616Salmstatic void 15716Salmlbc_banks_unmap(struct lbc_softc *sc) 1581057Salm{ 15916Salm int r; 16090109Simp 16116Salm r = 0; 1621057Salm while (r < LBC_DEV_MAX) { 16316Salm if (sc->sc_range[r].size == 0) 16416Salm return; 1651057Salm 16616Salm pmap_unmapdev((void *)sc->sc_range[r].kva, 1671057Salm sc->sc_range[r].size); 16816Salm law_disable(OCP85XX_TGTIF_LBC, sc->sc_range[r].addr, 1691057Salm sc->sc_range[r].size); 17016Salm r++; 1711057Salm } 1721057Salm} 1731057Salm 17416Salmstatic int 17516Salmlbc_banks_map(struct lbc_softc *sc) 17616Salm{ 17716Salm vm_paddr_t end, start; 1781057Salm vm_size_t size; 17916Salm u_int i, r, ranges, s; 1801057Salm int error; 18116Salm 1821057Salm bzero(sc->sc_range, sizeof(sc->sc_range)); 18316Salm 1841057Salm /* 18516Salm * Determine number of discontiguous address ranges to program. 18616Salm */ 18716Salm ranges = 0; 188241720Sed for (i = 0; i < LBC_DEV_MAX; i++) { 18916Salm size = sc->sc_banks[i].size; 1901057Salm if (size == 0) 1911057Salm continue; 19290109Simp 19316Salm start = sc->sc_banks[i].addr; 19498481Sjmallett for (r = 0; r < ranges; r++) { 1951297Salm /* Avoid wrap-around bugs. */ 1961297Salm end = sc->sc_range[r].addr - 1 + sc->sc_range[r].size; 1971057Salm if (start > 0 && end == start - 1) { 1981297Salm sc->sc_range[r].size += size; 19916Salm break; 20030247Seivind } 20124181Simp /* Avoid wrap-around bugs. */ 20224181Simp end = start - 1 + size; 20324181Simp if (sc->sc_range[r].addr > 0 && 20424181Simp end == sc->sc_range[r].addr - 1) { 20581220Smike sc->sc_range[r].addr = start; 2061297Salm sc->sc_range[r].size += size; 20716Salm break; 20816Salm } 2091297Salm } 21016Salm if (r == ranges) { 21116Salm /* New range; add using insertion sort */ 21216Salm r = 0; 21316Salm while (r < ranges && sc->sc_range[r].addr < start) 2141057Salm r++; 2151057Salm for (s = ranges; s > r; s--) 21690109Simp sc->sc_range[s] = sc->sc_range[s-1]; 21716Salm sc->sc_range[r].addr = start; 21816Salm sc->sc_range[r].size = size; 21916Salm ranges++; 22016Salm } 22181220Smike } 22216Salm 22316Salm /* 22416Salm * Ranges are sorted so quickly go over the list to merge ranges 22516Salm * that grew toward each other while building the ranges. 22616Salm */ 22716Salm r = 0; 22816Salm while (r < ranges - 1) { 22916Salm end = sc->sc_range[r].addr + sc->sc_range[r].size; 23016Salm if (end != sc->sc_range[r+1].addr) { 23116Salm r++; 2321057Salm continue; 23316Salm } 23490109Simp sc->sc_range[r].size += sc->sc_range[r+1].size; 23516Salm for (s = r + 1; s < ranges - 1; s++) 23616Salm sc->sc_range[s] = sc->sc_range[s+1]; 23716Salm bzero(&sc->sc_range[s], sizeof(sc->sc_range[s])); 23816Salm ranges--; 23916Salm } 24016Salm 24116Salm /* 24287Salm * Configure LAW for the LBC ranges and map the physical memory 24387Salm * range into KVA. 244241720Sed */ 24587Salm for (r = 0; r < ranges; r++) { 2461057Salm start = sc->sc_range[r].addr; 24787Salm size = sc->sc_range[r].size; 24890109Simp error = law_enable(OCP85XX_TGTIF_LBC, start, size); 24987Salm if (error) 25087Salm return (error); 25187Salm sc->sc_range[r].kva = (vm_offset_t)pmap_mapdev(start, size); 2528855Srgrimes } 2531057Salm 2541057Salm /* XXX: need something better here? */ 2551057Salm if (ranges == 0) 2561057Salm return (EINVAL); 2571057Salm 2581057Salm /* Assign KVA to banks based on the enclosing range. */ 25932138Shelbig for (i = 0; i < LBC_DEV_MAX; i++) { 26032138Shelbig size = sc->sc_banks[i].size; 26132138Shelbig if (size == 0) 26232138Shelbig continue; 2631057Salm 26487Salm start = sc->sc_banks[i].addr; 2651057Salm for (r = 0; r < ranges; r++) { 26687Salm end = sc->sc_range[r].addr - 1 + sc->sc_range[r].size; 26787Salm if (start >= sc->sc_range[r].addr && 26887Salm start - 1 + size <= end) 26987Salm break; 27087Salm } 2711057Salm if (r < ranges) { 27287Salm sc->sc_banks[i].kva = sc->sc_range[r].kva + 27390109Simp (start - sc->sc_range[r].addr); 27487Salm } 27587Salm } 27687Salm 27787Salm return (0); 27887Salm} 27987Salm 28087Salmstatic int 28187Salmlbc_banks_enable(struct lbc_softc *sc) 28287Salm{ 28387Salm uint32_t size; 28487Salm 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 344fail: 345 lbc_banks_unmap(sc); 346 return (error); 347} 348 349static void 350fdt_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 366static int 367fdt_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 422static void 423lbc_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 434static int 435lbc_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 446static int 447lbc_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, -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 670fail: 671 OF_prop_free(rangesptr); 672 bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_mrid, sc->sc_mres); 673 return (error); 674} 675 676static int 677lbc_shutdown(device_t dev) 678{ 679 680 /* TODO */ 681 return(0); 682} 683 684static struct rman * 685lbc_get_rman(device_t bus, int type, u_int flags) 686{ 687 struct lbc_softc *sc; 688 689 sc = device_get_softc(bus); 690 switch (type) { 691 case SYS_RES_MEMORY: 692 return (&sc->sc_rman); 693 default: 694 return (NULL); 695 } 696} 697 698static struct resource * 699lbc_alloc_resource(device_t bus, device_t child, int type, int *rid, 700 rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 701{ 702 struct lbc_devinfo *di; 703 struct resource_list_entry *rle; 704 705 /* We only support default allocations. */ 706 if (!RMAN_IS_DEFAULT_RANGE(start, end)) 707 return (NULL); 708 709 if (type == SYS_RES_IRQ) 710 return (bus_alloc_resource(bus, type, rid, start, end, count, 711 flags)); 712 713 /* 714 * Request for the default allocation with a given rid: use resource 715 * list stored in the local device info. 716 */ 717 if ((di = device_get_ivars(child)) == NULL) 718 return (NULL); 719 720 if (type == SYS_RES_IOPORT) 721 type = SYS_RES_MEMORY; 722 723 /* 724 * XXX: We are supposed to return a value to the user, so this 725 * doesn't seem right. 726 */ 727 rid = &di->di_bank; 728 729 rle = resource_list_find(&di->di_res, type, *rid); 730 if (rle == NULL) { 731 device_printf(bus, "no default resources for " 732 "rid = %d, type = %d\n", *rid, type); 733 return (NULL); 734 } 735 start = rle->start; 736 count = rle->count; 737 end = start + count - 1; 738 739 return (bus_generic_rman_alloc_resource(bus, child, type, rid, start, 740 end, count, flags)); 741} 742 743static int 744lbc_print_child(device_t dev, device_t child) 745{ 746 struct lbc_devinfo *di; 747 struct resource_list *rl; 748 int rv; 749 750 di = device_get_ivars(child); 751 rl = &di->di_res; 752 753 rv = 0; 754 rv += bus_print_child_header(dev, child); 755 rv += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx"); 756 rv += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd"); 757 rv += bus_print_child_footer(dev, child); 758 759 return (rv); 760} 761 762static int 763lbc_adjust_resource(device_t dev, device_t child, struct resource *r, 764 rman_res_t start, rman_res_t end) 765{ 766 switch (rman_get_type(r)) { 767 case SYS_RES_MEMORY: 768 return (bus_generic_rman_adjust_resource(dev, child, r, start, 769 end)); 770 case SYS_RES_IRQ: 771 return (bus_generic_adjust_resource(dev, child, r, start, end)); 772 default: 773 return (EINVAL); 774 } 775} 776 777static int 778lbc_release_resource(device_t dev, device_t child, struct resource *res) 779{ 780 switch (rman_get_type(res)) { 781 case SYS_RES_MEMORY: 782 return (bus_generic_rman_release_resource(dev, child, res)); 783 case SYS_RES_IRQ: 784 return (bus_generic_release_resource(dev, child, res)); 785 default: 786 return (EINVAL); 787 } 788} 789 790static int 791lbc_activate_resource(device_t bus, device_t child, struct resource *r) 792{ 793 switch (rman_get_type(r)) { 794 case SYS_RES_MEMORY: 795 return (bus_generic_rman_activate_resource(bus, child, r)); 796 case SYS_RES_IRQ: 797 return (bus_generic_activate_resource(bus, child, r)); 798 default: 799 return (EINVAL); 800 } 801} 802 803static int 804lbc_deactivate_resource(device_t bus, device_t child, struct resource *r) 805{ 806 switch (rman_get_type(r)) { 807 case SYS_RES_MEMORY: 808 return (bus_generic_rman_deactivate_resource(bus, child, r)); 809 case SYS_RES_IRQ: 810 return (bus_generic_deactivate_resource(bus, child, r)); 811 default: 812 return (EINVAL); 813 } 814} 815 816static int 817lbc_map_resource(device_t bus, device_t child, struct resource *r, 818 struct resource_map_request *argsp, struct resource_map *map) 819{ 820 struct resource_map_request args; 821 rman_res_t length, start; 822 int error; 823 824 /* Resources must be active to be mapped. */ 825 if (!(rman_get_flags(r) & RF_ACTIVE)) 826 return (ENXIO); 827 828 /* Mappings are only supported on I/O and memory resources. */ 829 switch (rman_get_type(r)) { 830 case SYS_RES_IOPORT: 831 case SYS_RES_MEMORY: 832 break; 833 default: 834 return (EINVAL); 835 } 836 837 resource_init_map_request(&args); 838 error = resource_validate_map_request(r, argsp, &args, &start, &length); 839 if (error) 840 return (error); 841 842 map->r_bustag = &bs_be_tag; 843 map->r_bushandle = start; 844 map->r_size = length; 845 map->r_vaddr = NULL; 846 return (0); 847} 848 849static int 850lbc_unmap_resource(device_t bus, device_t child, struct resource *r, 851 struct resource_map *map) 852{ 853 854 /* Mappings are only supported on I/O and memory resources. */ 855 switch (rman_get_type(r)) { 856 case SYS_RES_IOPORT: 857 case SYS_RES_MEMORY: 858 break; 859 default: 860 return (EINVAL); 861 } 862 return (0); 863} 864 865static const struct ofw_bus_devinfo * 866lbc_get_devinfo(device_t bus, device_t child) 867{ 868 struct lbc_devinfo *di; 869 870 di = device_get_ivars(child); 871 return (&di->di_ofw); 872} 873 874void 875lbc_write_reg(device_t child, u_int off, uint32_t val) 876{ 877 device_t dev; 878 struct lbc_softc *sc; 879 880 dev = device_get_parent(child); 881 882 if (off >= 0x1000) { 883 device_printf(dev, "%s(%s): invalid offset %#x\n", 884 __func__, device_get_nameunit(child), off); 885 return; 886 } 887 888 sc = device_get_softc(dev); 889 890 if (off == LBC85XX_LTESR && sc->sc_ltesr != ~0u) { 891 sc->sc_ltesr ^= (val & sc->sc_ltesr); 892 return; 893 } 894 895 if (off == LBC85XX_LTEATR && (val & 1) == 0) 896 sc->sc_ltesr = ~0u; 897 bus_space_write_4(sc->sc_bst, sc->sc_bsh, off, val); 898} 899 900uint32_t 901lbc_read_reg(device_t child, u_int off) 902{ 903 device_t dev; 904 struct lbc_softc *sc; 905 uint32_t val; 906 907 dev = device_get_parent(child); 908 909 if (off >= 0x1000) { 910 device_printf(dev, "%s(%s): invalid offset %#x\n", 911 __func__, device_get_nameunit(child), off); 912 return (~0U); 913 } 914 915 sc = device_get_softc(dev); 916 917 if (off == LBC85XX_LTESR && sc->sc_ltesr != ~0U) 918 val = sc->sc_ltesr; 919 else 920 val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, off); 921 return (val); 922} 923