1 /*- 2 * Copyright (c) 2015 Landon Fuller <landon@landonf.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer, 10 * without modification. 11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13 * redistribution must be conditioned upon including a substantially 14 * similar Disclaimer requirement for further binary redistribution. 15 * 16 * NO WARRANTY 17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27 * THE POSSIBILITY OF SUCH DAMAGES. 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 #include <sys/param.h> 34 #include <sys/bus.h> 35 #include <sys/kernel.h> 36 #include <sys/malloc.h> 37 #include <sys/module.h> 38 #include <sys/systm.h> 39 40 #include <machine/bus.h> 41 42 #include "bcmavar.h" 43 44 #include "bcma_eromreg.h" 45 #include "bcma_eromvar.h" 46 #include <dev/bhnd/bhnd_core.h> 47 48 int 49 bcma_probe(device_t dev) 50 { 51 device_set_desc(dev, "BCMA BHND bus"); 52 return (BUS_PROBE_DEFAULT); 53 } 54 55 int 56 bcma_attach(device_t dev) 57 { 58 struct bcma_devinfo *dinfo; 59 device_t *devs, child; 60 int ndevs; 61 int error; 62 63 64 if ((error = device_get_children(dev, &devs, &ndevs))) 65 return (error); 66 67 /* 68 * Map our children's agent register block. 69 */ 70 for (int i = 0; i < ndevs; i++) { 71 bhnd_addr_t addr; 72 bhnd_size_t size; 73 rman_res_t r_start, r_count, r_end; 74 75 child = devs[i]; 76 dinfo = device_get_ivars(child); 77 78 KASSERT(!device_is_suspended(child), 79 ("bcma(4) stateful suspend handling requires that devices " 80 "not be suspended before bcma_attach()")); 81 82 /* Verify that the agent register block exists and is 83 * mappable */ 84 if (bhnd_get_port_rid(child, BHND_PORT_AGENT, 0, 0) == -1) 85 continue; 86 87 /* Fetch the address of the agent register block */ 88 error = bhnd_get_region_addr(child, BHND_PORT_AGENT, 0, 0, 89 &addr, &size); 90 if (error) { 91 device_printf(dev, "failed fetching agent register " 92 "block address for core %d\n", i); 93 goto cleanup; 94 } 95 96 /* Allocate the resource */ 97 r_start = addr; 98 r_count = size; 99 r_end = r_start + r_count - 1; 100 101 dinfo->rid_agent = i + 1; 102 dinfo->res_agent = BHND_BUS_ALLOC_RESOURCE(dev, dev, 103 SYS_RES_MEMORY, &dinfo->rid_agent, r_start, r_end, r_count, 104 RF_ACTIVE); 105 if (dinfo->res_agent == NULL) { 106 device_printf(dev, "failed allocating agent register " 107 "block for core %d\n", i); 108 error = ENXIO; 109 goto cleanup; 110 } 111 } 112 113 cleanup: 114 free(devs, M_BHND); 115 if (error) 116 return (error); 117 118 return (bhnd_generic_attach(dev)); 119 } 120 121 int 122 bcma_detach(device_t dev) 123 { 124 return (bhnd_generic_detach(dev)); 125 } 126 127 static int 128 bcma_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) 129 { 130 const struct bcma_devinfo *dinfo; 131 const struct bhnd_core_info *ci; 132 133 dinfo = device_get_ivars(child); 134 ci = &dinfo->corecfg->core_info; 135 136 switch (index) { 137 case BHND_IVAR_VENDOR: 138 *result = ci->vendor; 139 return (0); 140 case BHND_IVAR_DEVICE: 141 *result = ci->device; 142 return (0); 143 case BHND_IVAR_HWREV: 144 *result = ci->hwrev; 145 return (0); 146 case BHND_IVAR_DEVICE_CLASS: 147 *result = bhnd_core_class(ci); 148 return (0); 149 case BHND_IVAR_VENDOR_NAME: 150 *result = (uintptr_t) bhnd_vendor_name(ci->vendor); 151 return (0); 152 case BHND_IVAR_DEVICE_NAME: 153 *result = (uintptr_t) bhnd_core_name(ci); 154 return (0); 155 case BHND_IVAR_CORE_INDEX: 156 *result = ci->core_idx; 157 return (0); 158 case BHND_IVAR_CORE_UNIT: 159 *result = ci->unit; 160 return (0); 161 default: 162 return (ENOENT); 163 } 164 } 165 166 static int 167 bcma_write_ivar(device_t dev, device_t child, int index, uintptr_t value) 168 { 169 switch (index) { 170 case BHND_IVAR_VENDOR: 171 case BHND_IVAR_DEVICE: 172 case BHND_IVAR_HWREV: 173 case BHND_IVAR_DEVICE_CLASS: 174 case BHND_IVAR_VENDOR_NAME: 175 case BHND_IVAR_DEVICE_NAME: 176 case BHND_IVAR_CORE_INDEX: 177 case BHND_IVAR_CORE_UNIT: 178 return (EINVAL); 179 default: 180 return (ENOENT); 181 } 182 } 183 184 static struct resource_list * 185 bcma_get_resource_list(device_t dev, device_t child) 186 { 187 struct bcma_devinfo *dinfo = device_get_ivars(child); 188 return (&dinfo->resources); 189 } 190 191 static device_t 192 bcma_find_hostb_device(device_t dev) 193 { 194 struct bcma_softc *sc = device_get_softc(dev); 195 196 /* This is set (or not) by the concrete bcma driver subclass. */ 197 return (sc->hostb_dev); 198 } 199 200 static int 201 bcma_reset_core(device_t dev, device_t child, uint16_t flags) 202 { 203 struct bcma_devinfo *dinfo; 204 205 if (device_get_parent(child) != dev) 206 BHND_BUS_RESET_CORE(device_get_parent(dev), child, flags); 207 208 dinfo = device_get_ivars(child); 209 210 /* Can't reset the core without access to the agent registers */ 211 if (dinfo->res_agent == NULL) 212 return (ENODEV); 213 214 /* Start reset */ 215 bhnd_bus_write_4(dinfo->res_agent, BHND_RESET_CF, BHND_RESET_CF_ENABLE); 216 bhnd_bus_read_4(dinfo->res_agent, BHND_RESET_CF); 217 DELAY(10); 218 219 /* Disable clock */ 220 bhnd_bus_write_4(dinfo->res_agent, BHND_CF, flags); 221 bhnd_bus_read_4(dinfo->res_agent, BHND_CF); 222 DELAY(10); 223 224 /* Enable clocks & force clock gating */ 225 bhnd_bus_write_4(dinfo->res_agent, BHND_CF, BHND_CF_CLOCK_EN | 226 BHND_CF_FGC | flags); 227 bhnd_bus_read_4(dinfo->res_agent, BHND_CF); 228 DELAY(10); 229 230 /* Complete reset */ 231 bhnd_bus_write_4(dinfo->res_agent, BHND_RESET_CF, 0); 232 bhnd_bus_read_4(dinfo->res_agent, BHND_RESET_CF); 233 DELAY(10); 234 235 /* Release force clock gating */ 236 bhnd_bus_write_4(dinfo->res_agent, BHND_CF, BHND_CF_CLOCK_EN | flags); 237 bhnd_bus_read_4(dinfo->res_agent, BHND_CF); 238 DELAY(10); 239 240 return (0); 241 } 242 243 static int 244 bcma_suspend_core(device_t dev, device_t child) 245 { 246 struct bcma_devinfo *dinfo; 247 248 if (device_get_parent(child) != dev) 249 BHND_BUS_SUSPEND_CORE(device_get_parent(dev), child); 250 251 dinfo = device_get_ivars(child); 252 253 /* Can't suspend the core without access to the agent registers */ 254 if (dinfo->res_agent == NULL) 255 return (ENODEV); 256 257 // TODO - perform suspend 258 259 return (ENXIO); 260 } 261 262 static uint32_t 263 bcma_read_config(device_t dev, device_t child, bus_size_t offset, u_int width) 264 { 265 struct bcma_devinfo *dinfo; 266 struct bhnd_resource *r; 267 268 /* Must be a directly attached child core */ 269 if (device_get_parent(child) != dev) 270 return (UINT32_MAX); 271 272 /* Fetch the agent registers */ 273 dinfo = device_get_ivars(child); 274 if ((r = dinfo->res_agent) == NULL) 275 return (UINT32_MAX); 276 277 /* Verify bounds */ 278 if (offset > rman_get_size(r->res)) 279 return (UINT32_MAX); 280 281 if (rman_get_size(r->res) - offset < width) 282 return (UINT32_MAX); 283 284 switch (width) { 285 case 1: 286 return (bhnd_bus_read_1(r, offset)); 287 case 2: 288 return (bhnd_bus_read_2(r, offset)); 289 case 4: 290 return (bhnd_bus_read_4(r, offset)); 291 default: 292 return (UINT32_MAX); 293 } 294 } 295 296 static void 297 bcma_write_config(device_t dev, device_t child, bus_size_t offset, uint32_t val, 298 u_int width) 299 { 300 struct bcma_devinfo *dinfo; 301 struct bhnd_resource *r; 302 303 /* Must be a directly attached child core */ 304 if (device_get_parent(child) != dev) 305 return; 306 307 /* Fetch the agent registers */ 308 dinfo = device_get_ivars(child); 309 if ((r = dinfo->res_agent) == NULL) 310 return; 311 312 /* Verify bounds */ 313 if (offset > rman_get_size(r->res)) 314 return; 315 316 if (rman_get_size(r->res) - offset < width) 317 return; 318 319 switch (width) { 320 case 1: 321 bhnd_bus_write_1(r, offset, val); 322 break; 323 case 2: 324 bhnd_bus_write_2(r, offset, val); 325 break; 326 case 4: 327 bhnd_bus_write_4(r, offset, val); 328 break; 329 default: 330 break; 331 } 332 } 333 334 static u_int 335 bcma_get_port_count(device_t dev, device_t child, bhnd_port_type type) 336 { 337 struct bcma_devinfo *dinfo; 338 339 /* delegate non-bus-attached devices to our parent */ 340 if (device_get_parent(child) != dev) 341 return (BHND_BUS_GET_PORT_COUNT(device_get_parent(dev), child, 342 type)); 343 344 dinfo = device_get_ivars(child); 345 switch (type) { 346 case BHND_PORT_DEVICE: 347 return (dinfo->corecfg->num_dev_ports); 348 case BHND_PORT_BRIDGE: 349 return (dinfo->corecfg->num_bridge_ports); 350 case BHND_PORT_AGENT: 351 return (dinfo->corecfg->num_wrapper_ports); 352 default: 353 device_printf(dev, "%s: unknown type (%d)\n", 354 __func__, 355 type); 356 return (0); 357 } 358 } 359 360 static u_int 361 bcma_get_region_count(device_t dev, device_t child, bhnd_port_type type, 362 u_int port_num) 363 { 364 struct bcma_devinfo *dinfo; 365 struct bcma_sport_list *ports; 366 struct bcma_sport *port; 367 368 /* delegate non-bus-attached devices to our parent */ 369 if (device_get_parent(child) != dev) 370 return (BHND_BUS_GET_REGION_COUNT(device_get_parent(dev), child, 371 type, port_num)); 372 373 dinfo = device_get_ivars(child); 374 ports = bcma_corecfg_get_port_list(dinfo->corecfg, type); 375 376 STAILQ_FOREACH(port, ports, sp_link) { 377 if (port->sp_num == port_num) 378 return (port->sp_num_maps); 379 } 380 381 /* not found */ 382 return (0); 383 } 384 385 static int 386 bcma_get_port_rid(device_t dev, device_t child, bhnd_port_type port_type, 387 u_int port_num, u_int region_num) 388 { 389 struct bcma_devinfo *dinfo; 390 struct bcma_map *map; 391 struct bcma_sport_list *ports; 392 struct bcma_sport *port; 393 394 dinfo = device_get_ivars(child); 395 ports = bcma_corecfg_get_port_list(dinfo->corecfg, port_type); 396 397 STAILQ_FOREACH(port, ports, sp_link) { 398 if (port->sp_num != port_num) 399 continue; 400 401 STAILQ_FOREACH(map, &port->sp_maps, m_link) 402 if (map->m_region_num == region_num) 403 return map->m_rid; 404 } 405 406 return -1; 407 } 408 409 static int 410 bcma_decode_port_rid(device_t dev, device_t child, int type, int rid, 411 bhnd_port_type *port_type, u_int *port_num, u_int *region_num) 412 { 413 struct bcma_devinfo *dinfo; 414 struct bcma_map *map; 415 struct bcma_sport_list *ports; 416 struct bcma_sport *port; 417 418 dinfo = device_get_ivars(child); 419 420 /* Ports are always memory mapped */ 421 if (type != SYS_RES_MEMORY) 422 return (EINVAL); 423 424 /* Starting with the most likely device list, search all three port 425 * lists */ 426 bhnd_port_type types[] = { 427 BHND_PORT_DEVICE, 428 BHND_PORT_AGENT, 429 BHND_PORT_BRIDGE 430 }; 431 432 for (int i = 0; i < nitems(types); i++) { 433 ports = bcma_corecfg_get_port_list(dinfo->corecfg, types[i]); 434 435 STAILQ_FOREACH(port, ports, sp_link) { 436 STAILQ_FOREACH(map, &port->sp_maps, m_link) { 437 if (map->m_rid != rid) 438 continue; 439 440 *port_type = port->sp_type; 441 *port_num = port->sp_num; 442 *region_num = map->m_region_num; 443 return (0); 444 } 445 } 446 } 447 448 return (ENOENT); 449 } 450 451 static int 452 bcma_get_region_addr(device_t dev, device_t child, bhnd_port_type port_type, 453 u_int port_num, u_int region_num, bhnd_addr_t *addr, bhnd_size_t *size) 454 { 455 struct bcma_devinfo *dinfo; 456 struct bcma_map *map; 457 struct bcma_sport_list *ports; 458 struct bcma_sport *port; 459 460 dinfo = device_get_ivars(child); 461 ports = bcma_corecfg_get_port_list(dinfo->corecfg, port_type); 462 463 /* Search the port list */ 464 STAILQ_FOREACH(port, ports, sp_link) { 465 if (port->sp_num != port_num) 466 continue; 467 468 STAILQ_FOREACH(map, &port->sp_maps, m_link) { 469 if (map->m_region_num != region_num) 470 continue; 471 472 /* Found! */ 473 *addr = map->m_base; 474 *size = map->m_size; 475 return (0); 476 } 477 } 478 479 return (ENOENT); 480 } 481 482 static struct bhnd_devinfo * 483 bcma_alloc_bhnd_dinfo(device_t dev) 484 { 485 struct bcma_devinfo *dinfo = bcma_alloc_dinfo(dev); 486 return ((struct bhnd_devinfo *)dinfo); 487 } 488 489 static void 490 bcma_free_bhnd_dinfo(device_t dev, struct bhnd_devinfo *dinfo) 491 { 492 bcma_free_dinfo(dev, (struct bcma_devinfo *)dinfo); 493 } 494 495 496 static int 497 bcma_get_core_table(device_t dev, device_t child, struct bhnd_core_info **cores, 498 u_int *num_cores) 499 { 500 struct bcma_softc *sc; 501 struct bcma_erom erom; 502 const struct bhnd_chipid *cid; 503 struct resource *r; 504 int error; 505 int rid; 506 507 sc = device_get_softc(dev); 508 509 /* Map the EROM table. */ 510 cid = BHND_BUS_GET_CHIPID(dev, dev); 511 rid = 0; 512 r = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, cid->enum_addr, 513 cid->enum_addr + BCMA_EROM_TABLE_SIZE, BCMA_EROM_TABLE_SIZE, 514 RF_ACTIVE); 515 if (r == NULL) { 516 device_printf(dev, "failed to allocate EROM resource\n"); 517 return (ENXIO); 518 } 519 520 /* Enumerate all declared cores */ 521 if ((error = bcma_erom_open(&erom, r, BCMA_EROM_TABLE_START))) 522 goto cleanup; 523 524 error = bcma_erom_get_core_info(&erom, cores, num_cores); 525 526 cleanup: 527 bus_release_resource(dev, SYS_RES_MEMORY, rid, r); 528 return (error); 529 } 530 531 /** 532 * Scan a device enumeration ROM table, adding all valid discovered cores to 533 * the bus. 534 * 535 * @param bus The bcma bus. 536 * @param erom_res An active resource mapping the EROM core. 537 * @param erom_offset Base offset of the EROM core's register mapping. 538 */ 539 int 540 bcma_add_children(device_t bus, struct resource *erom_res, bus_size_t erom_offset) 541 { 542 struct bcma_erom erom; 543 struct bcma_corecfg *corecfg; 544 struct bcma_devinfo *dinfo; 545 device_t child; 546 int error; 547 548 corecfg = NULL; 549 550 /* Initialize our reader */ 551 error = bcma_erom_open(&erom, erom_res, erom_offset); 552 if (error) 553 return (error); 554 555 /* Add all cores. */ 556 while (!error) { 557 /* Parse next core */ 558 error = bcma_erom_parse_corecfg(&erom, &corecfg); 559 if (error && error == ENOENT) { 560 return (0); 561 } else if (error) { 562 goto failed; 563 } 564 565 /* Add the child device */ 566 child = BUS_ADD_CHILD(bus, 0, NULL, -1); 567 if (child == NULL) { 568 error = ENXIO; 569 goto failed; 570 } 571 572 /* Initialize device ivars */ 573 dinfo = device_get_ivars(child); 574 if ((error = bcma_init_dinfo(bus, dinfo, corecfg))) 575 goto failed; 576 577 /* The dinfo instance now owns the corecfg value */ 578 corecfg = NULL; 579 580 /* If pins are floating or the hardware is otherwise 581 * unpopulated, the device shouldn't be used. */ 582 if (bhnd_is_hw_disabled(child)) 583 device_disable(child); 584 585 /* Issue bus callback for fully initialized child. */ 586 BHND_BUS_CHILD_ADDED(bus, child); 587 } 588 589 /* Hit EOF parsing cores? */ 590 if (error == ENOENT) 591 return (0); 592 593 failed: 594 if (corecfg != NULL) 595 bcma_free_corecfg(corecfg); 596 597 return (error); 598 } 599 600 601 static device_method_t bcma_methods[] = { 602 /* Device interface */ 603 DEVMETHOD(device_probe, bcma_probe), 604 DEVMETHOD(device_attach, bcma_attach), 605 DEVMETHOD(device_detach, bcma_detach), 606 607 /* Bus interface */ 608 DEVMETHOD(bus_read_ivar, bcma_read_ivar), 609 DEVMETHOD(bus_write_ivar, bcma_write_ivar), 610 DEVMETHOD(bus_get_resource_list, bcma_get_resource_list), 611 612 /* BHND interface */ 613 DEVMETHOD(bhnd_bus_find_hostb_device, bcma_find_hostb_device), 614 DEVMETHOD(bhnd_bus_alloc_devinfo, bcma_alloc_bhnd_dinfo), 615 DEVMETHOD(bhnd_bus_free_devinfo, bcma_free_bhnd_dinfo), 616 DEVMETHOD(bhnd_bus_get_core_table, bcma_get_core_table), 617 DEVMETHOD(bhnd_bus_reset_core, bcma_reset_core), 618 DEVMETHOD(bhnd_bus_suspend_core, bcma_suspend_core), 619 DEVMETHOD(bhnd_bus_read_config, bcma_read_config), 620 DEVMETHOD(bhnd_bus_write_config, bcma_write_config), 621 DEVMETHOD(bhnd_bus_get_port_count, bcma_get_port_count), 622 DEVMETHOD(bhnd_bus_get_region_count, bcma_get_region_count), 623 DEVMETHOD(bhnd_bus_get_port_rid, bcma_get_port_rid), 624 DEVMETHOD(bhnd_bus_decode_port_rid, bcma_decode_port_rid), 625 DEVMETHOD(bhnd_bus_get_region_addr, bcma_get_region_addr), 626 627 DEVMETHOD_END 628 }; 629 630 DEFINE_CLASS_1(bhnd, bcma_driver, bcma_methods, sizeof(struct bcma_softc), bhnd_driver); 631 MODULE_VERSION(bcma, 1); 632 MODULE_DEPEND(bcma, bhnd, 1, 1, 1); 633