1 /*- 2 * Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.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 39 #include <machine/bus.h> 40 41 #include <dev/bhnd/bhnd_erom.h> 42 43 #include <dev/bhnd/cores/chipc/chipcreg.h> 44 45 #include "sibareg.h" 46 #include "sibavar.h" 47 48 struct siba_erom; 49 struct siba_erom_io; 50 51 52 static int siba_eio_init(struct siba_erom_io *io, 53 device_t parent, struct bhnd_resource *res, 54 int rid, bus_size_t offset, u_int ncores); 55 56 static int siba_eio_init_static(struct siba_erom_io *io, 57 bus_space_tag_t bst, bus_space_handle_t bsh, 58 bus_size_t offset, u_int ncores); 59 60 static uint32_t siba_eio_read_4(struct siba_erom_io *io, 61 u_int core_idx, bus_size_t offset); 62 63 static struct siba_core_id siba_eio_read_core_id(struct siba_erom_io *io, 64 u_int core_idx, int unit); 65 66 static int siba_eio_read_chipid(struct siba_erom_io *io, 67 bus_addr_t enum_addr, 68 struct bhnd_chipid *cid); 69 70 /** 71 * SIBA EROM generic I/O context 72 */ 73 struct siba_erom_io { 74 u_int ncores; /**< core count */ 75 bus_size_t offset; /**< base read offset */ 76 77 /* resource state */ 78 device_t dev; /**< parent dev to use for resource allocations, 79 or NULL if unavailable. */ 80 struct bhnd_resource *res; /**< memory resource, or NULL */ 81 int rid; /**< memory resource ID */ 82 83 /* bus tag state */ 84 bus_space_tag_t bst; /**< bus space tag */ 85 bus_space_handle_t bsh; /**< bus space handle */ 86 }; 87 88 /** 89 * SIBA EROM per-instance state. 90 */ 91 struct siba_erom { 92 struct bhnd_erom obj; 93 struct siba_erom_io io; /**< i/o context */ 94 }; 95 96 #define EROM_LOG(io, fmt, ...) do { \ 97 if (io->dev != NULL) { \ 98 device_printf(io->dev, "%s: " fmt, __FUNCTION__, \ 99 ##__VA_ARGS__); \ 100 } else { \ 101 printf("%s: " fmt, __FUNCTION__, ##__VA_ARGS__); \ 102 } \ 103 } while(0) 104 105 static int 106 siba_erom_probe_common(struct siba_erom_io *io, const struct bhnd_chipid *hint, 107 struct bhnd_chipid *cid) 108 { 109 uint32_t idreg; 110 int error; 111 112 /* Try using the provided hint. */ 113 if (hint != NULL) { 114 struct siba_core_id sid; 115 116 /* Validate bus type */ 117 if (hint->chip_type != BHND_CHIPTYPE_SIBA) 118 return (ENXIO); 119 120 /* 121 * Verify the first core's IDHIGH/IDLOW identification. 122 * 123 * The core must be a Broadcom core, but must *not* be 124 * a chipcommon core; those shouldn't be hinted. 125 * 126 * The first core on EXTIF-equipped devices varies, but on the 127 * BCM4710, it's a SDRAM core (0x803). 128 */ 129 130 sid = siba_eio_read_core_id(io, 0, 0); 131 132 if (sid.core_info.vendor != BHND_MFGID_BCM) 133 return (ENXIO); 134 135 if (sid.core_info.device == BHND_COREID_CC) 136 return (EINVAL); 137 138 *cid = *hint; 139 } else { 140 /* Validate bus type */ 141 idreg = siba_eio_read_4(io, 0, CHIPC_ID); 142 if (CHIPC_GET_BITS(idreg, CHIPC_ID_BUS) != BHND_CHIPTYPE_SIBA) 143 return (ENXIO); 144 145 /* Identify the chipset */ 146 if ((error = siba_eio_read_chipid(io, SIBA_ENUM_ADDR, cid))) 147 return (error); 148 149 /* Verify the chip type */ 150 if (cid->chip_type != BHND_CHIPTYPE_SIBA) 151 return (ENXIO); 152 } 153 154 /* 155 * gcc hack: ensure bhnd_chipid.ncores cannot exceed SIBA_MAX_CORES 156 * without triggering build failure due to -Wtype-limits 157 * 158 * if (cid.ncores > SIBA_MAX_CORES) 159 * return (EINVAL) 160 */ 161 _Static_assert((2^sizeof(cid->ncores)) <= SIBA_MAX_CORES, 162 "ncores could result in over-read of backing resource"); 163 164 return (0); 165 } 166 167 /* SIBA implementation of BHND_EROM_PROBE() */ 168 static int 169 siba_erom_probe(bhnd_erom_class_t *cls, struct bhnd_resource *res, 170 bus_size_t offset, const struct bhnd_chipid *hint, 171 struct bhnd_chipid *cid) 172 { 173 struct siba_erom_io io; 174 int error, rid; 175 176 rid = rman_get_rid(res->res); 177 178 /* Initialize I/O context, assuming at least 1 core exists. */ 179 if ((error = siba_eio_init(&io, NULL, res, rid, offset, 1))) 180 return (error); 181 182 return (siba_erom_probe_common(&io, hint, cid)); 183 } 184 185 /* SIBA implementation of BHND_EROM_PROBE_STATIC() */ 186 static int 187 siba_erom_probe_static(bhnd_erom_class_t *cls, bus_space_tag_t bst, 188 bus_space_handle_t bsh, bus_addr_t paddr, const struct bhnd_chipid *hint, 189 struct bhnd_chipid *cid) 190 { 191 struct siba_erom_io io; 192 int error; 193 194 /* Initialize I/O context, assuming at least 1 core exists. */ 195 if ((error = siba_eio_init_static(&io, bst, bsh, 0, 1))) 196 return (error); 197 198 return (siba_erom_probe_common(&io, hint, cid)); 199 } 200 201 /* SIBA implementation of BHND_EROM_INIT() */ 202 static int 203 siba_erom_init(bhnd_erom_t *erom, const struct bhnd_chipid *cid, 204 device_t parent, int rid) 205 { 206 struct siba_erom *sc; 207 struct bhnd_resource *res; 208 int error; 209 210 sc = (struct siba_erom *)erom; 211 212 /* Allocate backing resource */ 213 res = bhnd_alloc_resource(parent, SYS_RES_MEMORY, &rid, 214 cid->enum_addr, cid->enum_addr + SIBA_ENUM_SIZE -1, SIBA_ENUM_SIZE, 215 RF_ACTIVE|RF_SHAREABLE); 216 if (res == NULL) 217 return (ENOMEM); 218 219 /* Initialize I/O context */ 220 error = siba_eio_init(&sc->io, parent, res, rid, 0x0, cid->ncores); 221 if (error) 222 bhnd_release_resource(parent, SYS_RES_MEMORY, rid, res); 223 224 return (error); 225 } 226 227 /* SIBA implementation of BHND_EROM_INIT_STATIC() */ 228 static int 229 siba_erom_init_static(bhnd_erom_t *erom, const struct bhnd_chipid *cid, 230 bus_space_tag_t bst, bus_space_handle_t bsh) 231 { 232 struct siba_erom *sc; 233 234 sc = (struct siba_erom *)erom; 235 236 /* Initialize I/O context */ 237 return (siba_eio_init_static(&sc->io, bst, bsh, 0x0, cid->ncores)); 238 } 239 240 /* SIBA implementation of BHND_EROM_FINI() */ 241 static void 242 siba_erom_fini(bhnd_erom_t *erom) 243 { 244 struct siba_erom *sc = (struct siba_erom *)erom; 245 246 if (sc->io.res != NULL) { 247 bhnd_release_resource(sc->io.dev, SYS_RES_MEMORY, sc->io.rid, 248 sc->io.res); 249 250 sc->io.res = NULL; 251 sc->io.rid = -1; 252 } 253 } 254 255 /* Initialize siba_erom resource I/O context */ 256 static int 257 siba_eio_init(struct siba_erom_io *io, device_t parent, 258 struct bhnd_resource *res, int rid, bus_size_t offset, u_int ncores) 259 { 260 io->dev = parent; 261 io->res = res; 262 io->rid = rid; 263 io->offset = offset; 264 io->ncores = ncores; 265 266 return (0); 267 } 268 269 /* Initialize siba_erom bus space I/O context */ 270 static int 271 siba_eio_init_static(struct siba_erom_io *io, bus_space_tag_t bst, 272 bus_space_handle_t bsh, bus_size_t offset, u_int ncores) 273 { 274 io->res = NULL; 275 io->rid = -1; 276 io->bst = bst; 277 io->bsh = bsh; 278 io->offset = offset; 279 io->ncores = ncores; 280 281 return (0); 282 } 283 284 /** 285 * Read a 32-bit value from @p offset relative to the base address of 286 * the given @p core_idx. 287 * 288 * @param io EROM I/O context. 289 * @param core_idx Core index. 290 * @param offset Core register offset. 291 */ 292 static uint32_t 293 siba_eio_read_4(struct siba_erom_io *io, u_int core_idx, bus_size_t offset) 294 { 295 bus_size_t core_offset; 296 297 /* Sanity check core index and offset */ 298 if (core_idx >= io->ncores) 299 panic("core index %u out of range (ncores=%u)", core_idx, 300 io->ncores); 301 302 if (offset > SIBA_CORE_SIZE - sizeof(uint32_t)) 303 panic("invalid core offset %#jx", (uintmax_t)offset); 304 305 /* Perform read */ 306 core_offset = io->offset + SIBA_CORE_OFFSET(core_idx) + offset; 307 if (io->res != NULL) 308 return (bhnd_bus_read_4(io->res, core_offset)); 309 else 310 return (bus_space_read_4(io->bst, io->bsh, core_offset)); 311 } 312 313 /** 314 * Read and parse identification registers for the given @p core_index. 315 * 316 * @param io EROM I/O context. 317 * @param core_idx The core index. 318 * @param unit The caller-specified unit number to be included in the return 319 * value. 320 */ 321 static struct siba_core_id 322 siba_eio_read_core_id(struct siba_erom_io *io, u_int core_idx, int unit) 323 { 324 uint32_t idhigh, idlow; 325 326 idhigh = siba_eio_read_4(io, core_idx, SB0_REG_ABS(SIBA_CFG0_IDHIGH)); 327 idlow = siba_eio_read_4(io, core_idx, SB0_REG_ABS(SIBA_CFG0_IDLOW)); 328 329 return (siba_parse_core_id(idhigh, idlow, core_idx, unit)); 330 } 331 332 /** 333 * Read and parse the chip identification register from the ChipCommon core. 334 * 335 * @param io EROM I/O context. 336 * @param enum_addr The physical address mapped by @p io. 337 * @param cid On success, the parsed chip identifier. 338 */ 339 static int 340 siba_eio_read_chipid(struct siba_erom_io *io, bus_addr_t enum_addr, 341 struct bhnd_chipid *cid) 342 { 343 struct siba_core_id ccid; 344 uint32_t idreg; 345 346 /* Identify the chipcommon core */ 347 ccid = siba_eio_read_core_id(io, 0, 0); 348 if (ccid.core_info.vendor != BHND_MFGID_BCM || 349 ccid.core_info.device != BHND_COREID_CC) 350 { 351 if (bootverbose) { 352 EROM_LOG(io, "first core not chipcommon " 353 "(vendor=%#hx, core=%#hx)\n", ccid.core_info.vendor, 354 ccid.core_info.device); 355 } 356 return (ENXIO); 357 } 358 359 /* Identify the chipset */ 360 idreg = siba_eio_read_4(io, 0, CHIPC_ID); 361 *cid = bhnd_parse_chipid(idreg, enum_addr); 362 363 /* Fix up the core count in-place */ 364 return (bhnd_chipid_fixed_ncores(cid, ccid.core_info.hwrev, 365 &cid->ncores)); 366 } 367 368 static int 369 siba_erom_lookup_core(bhnd_erom_t *erom, const struct bhnd_core_match *desc, 370 struct bhnd_core_info *core) 371 { 372 struct siba_erom *sc; 373 struct bhnd_core_match imatch; 374 375 sc = (struct siba_erom *)erom; 376 377 /* We can't determine a core's unit number during the initial scan. */ 378 imatch = *desc; 379 imatch.m.match.core_unit = 0; 380 381 /* Locate the first matching core */ 382 for (u_int i = 0; i < sc->io.ncores; i++) { 383 struct siba_core_id sid; 384 struct bhnd_core_info ci; 385 386 /* Read the core info */ 387 sid = siba_eio_read_core_id(&sc->io, i, 0); 388 ci = sid.core_info; 389 390 /* Check for initial match */ 391 if (!bhnd_core_matches(&ci, &imatch)) 392 continue; 393 394 /* Re-scan preceding cores to determine the unit number. */ 395 for (u_int j = 0; j < i; j++) { 396 sid = siba_eio_read_core_id(&sc->io, i, 0); 397 398 /* Bump the unit number? */ 399 if (sid.core_info.vendor == ci.vendor && 400 sid.core_info.device == ci.device) 401 ci.unit++; 402 } 403 404 /* Check for full match against now-valid unit number */ 405 if (!bhnd_core_matches(&ci, desc)) 406 continue; 407 408 /* Matching core found */ 409 *core = ci; 410 return (0); 411 } 412 413 /* Not found */ 414 return (ENOENT); 415 } 416 417 static int 418 siba_erom_lookup_core_addr(bhnd_erom_t *erom, const struct bhnd_core_match *desc, 419 bhnd_port_type type, u_int port, u_int region, struct bhnd_core_info *info, 420 bhnd_addr_t *addr, bhnd_size_t *size) 421 { 422 struct siba_erom *sc; 423 struct bhnd_core_info core; 424 struct siba_core_id sid; 425 uint32_t am, am_addr, am_size; 426 u_int am_offset; 427 u_int addrspace; 428 int error; 429 430 sc = (struct siba_erom *)erom; 431 432 /* Locate the requested core */ 433 if ((error = siba_erom_lookup_core(erom, desc, &core))) 434 return (error); 435 436 /* Fetch full siba core ident */ 437 sid = siba_eio_read_core_id(&sc->io, core.core_idx, core.unit); 438 439 /* Is port valid? */ 440 if (!siba_is_port_valid(sid.num_addrspace, type, port)) 441 return (ENOENT); 442 443 /* Is region valid? */ 444 if (region >= siba_addrspace_region_count(sid.num_addrspace, port)) 445 return (ENOENT); 446 447 /* Map the bhnd port values to a siba addrspace index */ 448 error = siba_addrspace_index(sid.num_addrspace, type, port, region, 449 &addrspace); 450 if (error) 451 return (error); 452 453 /* Determine the register offset */ 454 am_offset = siba_admatch_offset(addrspace); 455 if (am_offset == 0) { 456 printf("addrspace %u is unsupported", addrspace); 457 return (ENODEV); 458 } 459 460 /* Read and parse the address match register */ 461 am = siba_eio_read_4(&sc->io, core.core_idx, am_offset); 462 463 if ((error = siba_parse_admatch(am, &am_addr, &am_size))) { 464 printf("failed to decode address match register value 0x%x\n", 465 am); 466 return (error); 467 } 468 469 if (info != NULL) 470 *info = core; 471 472 *addr = am_addr; 473 *size = am_size; 474 475 return (0); 476 } 477 478 /* BHND_EROM_GET_CORE_TABLE() */ 479 static int 480 siba_erom_get_core_table(bhnd_erom_t *erom, struct bhnd_core_info **cores, 481 u_int *num_cores) 482 { 483 struct siba_erom *sc; 484 struct bhnd_core_info *out; 485 486 sc = (struct siba_erom *)erom; 487 488 /* Allocate our core array */ 489 out = malloc(sizeof(*out) * sc->io.ncores, M_BHND, M_NOWAIT); 490 if (out == NULL) 491 return (ENOMEM); 492 493 *cores = out; 494 *num_cores = sc->io.ncores; 495 496 /* Enumerate all cores. */ 497 for (u_int i = 0; i < sc->io.ncores; i++) { 498 struct siba_core_id sid; 499 500 /* Read the core info */ 501 sid = siba_eio_read_core_id(&sc->io, i, 0); 502 out[i] = sid.core_info; 503 504 /* Determine unit number */ 505 for (u_int j = 0; j < i; j++) { 506 if (out[j].vendor == out[i].vendor && 507 out[j].device == out[i].device) 508 out[i].unit++; 509 } 510 } 511 512 return (0); 513 } 514 515 /* BHND_EROM_FREE_CORE_TABLE() */ 516 static void 517 siba_erom_free_core_table(bhnd_erom_t *erom, struct bhnd_core_info *cores) 518 { 519 free(cores, M_BHND); 520 } 521 522 /* BHND_EROM_DUMP() */ 523 static int 524 siba_erom_dump(bhnd_erom_t *erom) 525 { 526 struct siba_erom *sc; 527 int error; 528 529 sc = (struct siba_erom *)erom; 530 531 /* Enumerate all cores. */ 532 for (u_int i = 0; i < sc->io.ncores; i++) { 533 uint32_t idhigh, idlow; 534 uint32_t nraddr; 535 536 idhigh = siba_eio_read_4(&sc->io, i, 537 SB0_REG_ABS(SIBA_CFG0_IDHIGH)); 538 idlow = siba_eio_read_4(&sc->io, i, 539 SB0_REG_ABS(SIBA_CFG0_IDLOW)); 540 541 printf("siba core %u:\n", i); 542 printf("\tvendor:\t0x%04x\n", SIBA_REG_GET(idhigh, IDH_VENDOR)); 543 printf("\tdevice:\t0x%04x\n", SIBA_REG_GET(idhigh, IDH_DEVICE)); 544 printf("\trev:\t0x%04x\n", SIBA_IDH_CORE_REV(idhigh)); 545 printf("\tsbrev:\t0x%02x\n", SIBA_REG_GET(idlow, IDL_SBREV)); 546 547 /* Enumerate the address match registers */ 548 nraddr = SIBA_REG_GET(idlow, IDL_NRADDR); 549 printf("\tnraddr\t0x%04x\n", nraddr); 550 551 for (size_t addrspace = 0; addrspace < nraddr; addrspace++) { 552 uint32_t am, am_addr, am_size; 553 u_int am_offset; 554 555 /* Determine the register offset */ 556 am_offset = siba_admatch_offset(addrspace); 557 if (am_offset == 0) { 558 printf("addrspace %zu unsupported", 559 addrspace); 560 break; 561 } 562 563 /* Read and parse the address match register */ 564 am = siba_eio_read_4(&sc->io, i, am_offset); 565 error = siba_parse_admatch(am, &am_addr, &am_size); 566 if (error) { 567 printf("failed to decode address match " 568 "register value 0x%x\n", am); 569 continue; 570 } 571 572 printf("\taddrspace %zu\n", addrspace); 573 printf("\t\taddr: 0x%08x\n", am_addr); 574 printf("\t\tsize: 0x%08x\n", am_size); 575 } 576 } 577 578 return (0); 579 } 580 581 static kobj_method_t siba_erom_methods[] = { 582 KOBJMETHOD(bhnd_erom_probe, siba_erom_probe), 583 KOBJMETHOD(bhnd_erom_probe_static, siba_erom_probe_static), 584 KOBJMETHOD(bhnd_erom_init, siba_erom_init), 585 KOBJMETHOD(bhnd_erom_init_static, siba_erom_init_static), 586 KOBJMETHOD(bhnd_erom_fini, siba_erom_fini), 587 KOBJMETHOD(bhnd_erom_get_core_table, siba_erom_get_core_table), 588 KOBJMETHOD(bhnd_erom_free_core_table, siba_erom_free_core_table), 589 KOBJMETHOD(bhnd_erom_lookup_core, siba_erom_lookup_core), 590 KOBJMETHOD(bhnd_erom_lookup_core_addr, siba_erom_lookup_core_addr), 591 KOBJMETHOD(bhnd_erom_dump, siba_erom_dump), 592 593 KOBJMETHOD_END 594 }; 595 596 BHND_EROM_DEFINE_CLASS(siba_erom, siba_erom_parser, siba_erom_methods, sizeof(struct siba_erom)); 597