1 /*- 2 * Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org> 3 * Copyright (c) 2017 The FreeBSD Foundation 4 * All rights reserved. 5 * 6 * Portions of this software were developed by Landon Fuller 7 * under sponsorship from the FreeBSD Foundation. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer, 14 * without modification. 15 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 16 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 17 * redistribution must be conditioned upon including a substantially 18 * similar Disclaimer requirement for further binary redistribution. 19 * 20 * NO WARRANTY 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 24 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 25 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 26 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 29 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 31 * THE POSSIBILITY OF SUCH DAMAGES. 32 */ 33 34 #include <sys/cdefs.h> 35 __FBSDID("$FreeBSD$"); 36 37 #include <sys/param.h> 38 #include <sys/bus.h> 39 #include <sys/kernel.h> 40 #include <sys/malloc.h> 41 #include <sys/module.h> 42 43 #include <machine/bus.h> 44 45 #include <dev/bhnd/bhnd_erom.h> 46 47 #include <dev/bhnd/cores/chipc/chipcreg.h> 48 49 #include "sibareg.h" 50 #include "sibavar.h" 51 52 struct siba_erom; 53 struct siba_erom_io; 54 55 56 static int siba_eio_init(struct siba_erom_io *io, 57 struct bhnd_erom_io *eio, u_int ncores); 58 59 static uint32_t siba_eio_read_4(struct siba_erom_io *io, 60 u_int core_idx, bus_size_t offset); 61 62 static struct siba_core_id siba_eio_read_core_id(struct siba_erom_io *io, 63 u_int core_idx, int unit); 64 65 static int siba_eio_read_chipid(struct siba_erom_io *io, 66 bus_addr_t enum_addr, 67 struct bhnd_chipid *cid); 68 69 /** 70 * SIBA EROM generic I/O context 71 */ 72 struct siba_erom_io { 73 struct bhnd_erom_io *eio; /**< erom I/O callbacks */ 74 bhnd_addr_t base_addr; /**< address of first core */ 75 u_int ncores; /**< core count */ 76 }; 77 78 /** 79 * SIBA EROM per-instance state. 80 */ 81 struct siba_erom { 82 struct bhnd_erom obj; 83 struct siba_erom_io io; /**< i/o context */ 84 }; 85 86 #define EROM_LOG(io, fmt, ...) do { \ 87 printf("%s: " fmt, __FUNCTION__, ##__VA_ARGS__); \ 88 } while(0) 89 90 /* SIBA implementation of BHND_EROM_PROBE() */ 91 static int 92 siba_erom_probe(bhnd_erom_class_t *cls, struct bhnd_erom_io *eio, 93 const struct bhnd_chipid *hint, struct bhnd_chipid *cid) 94 { 95 struct siba_erom_io io; 96 uint32_t idreg; 97 int error; 98 99 /* Initialize I/O context, assuming at least the first core is mapped */ 100 if ((error = siba_eio_init(&io, eio, 1))) 101 return (error); 102 103 /* Try using the provided hint. */ 104 if (hint != NULL) { 105 struct siba_core_id sid; 106 107 /* Validate bus type */ 108 if (hint->chip_type != BHND_CHIPTYPE_SIBA) 109 return (ENXIO); 110 111 /* 112 * Verify the first core's IDHIGH/IDLOW identification. 113 * 114 * The core must be a Broadcom core, but must *not* be 115 * a chipcommon core; those shouldn't be hinted. 116 * 117 * The first core on EXTIF-equipped devices varies, but on the 118 * BCM4710, it's a SDRAM core (0x803). 119 */ 120 121 sid = siba_eio_read_core_id(&io, 0, 0); 122 123 if (sid.core_info.vendor != BHND_MFGID_BCM) 124 return (ENXIO); 125 126 if (sid.core_info.device == BHND_COREID_CC) 127 return (EINVAL); 128 129 *cid = *hint; 130 } else { 131 /* Validate bus type */ 132 idreg = siba_eio_read_4(&io, 0, CHIPC_ID); 133 if (CHIPC_GET_BITS(idreg, CHIPC_ID_BUS) != BHND_CHIPTYPE_SIBA) 134 return (ENXIO); 135 136 /* Identify the chipset */ 137 if ((error = siba_eio_read_chipid(&io, SIBA_ENUM_ADDR, cid))) 138 return (error); 139 140 /* Verify the chip type */ 141 if (cid->chip_type != BHND_CHIPTYPE_SIBA) 142 return (ENXIO); 143 } 144 145 /* 146 * gcc hack: ensure bhnd_chipid.ncores cannot exceed SIBA_MAX_CORES 147 * without triggering build failure due to -Wtype-limits 148 * 149 * if (cid.ncores > SIBA_MAX_CORES) 150 * return (EINVAL) 151 */ 152 _Static_assert((2^sizeof(cid->ncores)) <= SIBA_MAX_CORES, 153 "ncores could result in over-read of backing resource"); 154 155 return (0); 156 } 157 158 /* SIBA implementation of BHND_EROM_INIT() */ 159 static int 160 siba_erom_init(bhnd_erom_t *erom, const struct bhnd_chipid *cid, 161 struct bhnd_erom_io *eio) 162 { 163 struct siba_erom *sc; 164 int error; 165 166 sc = (struct siba_erom *)erom; 167 168 /* Attempt to map the full core enumeration space */ 169 error = bhnd_erom_io_map(eio, cid->enum_addr, 170 cid->ncores * SIBA_CORE_SIZE); 171 if (error) { 172 printf("%s: failed to map %u cores: %d\n", __FUNCTION__, 173 cid->ncores, error); 174 return (error); 175 } 176 177 /* Initialize I/O context */ 178 return (siba_eio_init(&sc->io, eio, cid->ncores)); 179 } 180 181 /* SIBA implementation of BHND_EROM_FINI() */ 182 static void 183 siba_erom_fini(bhnd_erom_t *erom) 184 { 185 struct siba_erom *sc = (struct siba_erom *)erom; 186 187 bhnd_erom_io_fini(sc->io.eio); 188 } 189 190 /* Initialize siba_erom resource I/O context */ 191 static int 192 siba_eio_init(struct siba_erom_io *io, struct bhnd_erom_io *eio, u_int ncores) 193 { 194 io->eio = eio; 195 io->ncores = ncores; 196 return (0); 197 } 198 199 /** 200 * Read a 32-bit value from @p offset relative to the base address of 201 * the given @p core_idx. 202 * 203 * @param io EROM I/O context. 204 * @param core_idx Core index. 205 * @param offset Core register offset. 206 */ 207 static uint32_t 208 siba_eio_read_4(struct siba_erom_io *io, u_int core_idx, bus_size_t offset) 209 { 210 /* Sanity check core index and offset */ 211 if (core_idx >= io->ncores) 212 panic("core index %u out of range (ncores=%u)", core_idx, 213 io->ncores); 214 215 if (offset > SIBA_CORE_SIZE - sizeof(uint32_t)) 216 panic("invalid core offset %#jx", (uintmax_t)offset); 217 218 /* Perform read */ 219 return (bhnd_erom_io_read(io->eio, SIBA_CORE_OFFSET(core_idx) + offset, 220 4)); 221 } 222 223 /** 224 * Read and parse identification registers for the given @p core_index. 225 * 226 * @param io EROM I/O context. 227 * @param core_idx The core index. 228 * @param unit The caller-specified unit number to be included in the return 229 * value. 230 */ 231 static struct siba_core_id 232 siba_eio_read_core_id(struct siba_erom_io *io, u_int core_idx, int unit) 233 { 234 uint32_t idhigh, idlow; 235 236 idhigh = siba_eio_read_4(io, core_idx, SB0_REG_ABS(SIBA_CFG0_IDHIGH)); 237 idlow = siba_eio_read_4(io, core_idx, SB0_REG_ABS(SIBA_CFG0_IDLOW)); 238 239 return (siba_parse_core_id(idhigh, idlow, core_idx, unit)); 240 } 241 242 /** 243 * Read and parse the chip identification register from the ChipCommon core. 244 * 245 * @param io EROM I/O context. 246 * @param enum_addr The physical address mapped by @p io. 247 * @param cid On success, the parsed chip identifier. 248 */ 249 static int 250 siba_eio_read_chipid(struct siba_erom_io *io, bus_addr_t enum_addr, 251 struct bhnd_chipid *cid) 252 { 253 struct siba_core_id ccid; 254 uint32_t idreg; 255 256 /* Identify the chipcommon core */ 257 ccid = siba_eio_read_core_id(io, 0, 0); 258 if (ccid.core_info.vendor != BHND_MFGID_BCM || 259 ccid.core_info.device != BHND_COREID_CC) 260 { 261 if (bootverbose) { 262 EROM_LOG(io, "first core not chipcommon " 263 "(vendor=%#hx, core=%#hx)\n", ccid.core_info.vendor, 264 ccid.core_info.device); 265 } 266 return (ENXIO); 267 } 268 269 /* Identify the chipset */ 270 idreg = siba_eio_read_4(io, 0, CHIPC_ID); 271 *cid = bhnd_parse_chipid(idreg, enum_addr); 272 273 /* Fix up the core count in-place */ 274 return (bhnd_chipid_fixed_ncores(cid, ccid.core_info.hwrev, 275 &cid->ncores)); 276 } 277 278 static int 279 siba_erom_lookup_core(bhnd_erom_t *erom, const struct bhnd_core_match *desc, 280 struct bhnd_core_info *core) 281 { 282 struct siba_erom *sc; 283 struct bhnd_core_match imatch; 284 285 sc = (struct siba_erom *)erom; 286 287 /* We can't determine a core's unit number during the initial scan. */ 288 imatch = *desc; 289 imatch.m.match.core_unit = 0; 290 291 /* Locate the first matching core */ 292 for (u_int i = 0; i < sc->io.ncores; i++) { 293 struct siba_core_id sid; 294 struct bhnd_core_info ci; 295 296 /* Read the core info */ 297 sid = siba_eio_read_core_id(&sc->io, i, 0); 298 ci = sid.core_info; 299 300 /* Check for initial match */ 301 if (!bhnd_core_matches(&ci, &imatch)) 302 continue; 303 304 /* Re-scan preceding cores to determine the unit number. */ 305 for (u_int j = 0; j < i; j++) { 306 sid = siba_eio_read_core_id(&sc->io, j, 0); 307 308 /* Bump the unit number? */ 309 if (sid.core_info.vendor == ci.vendor && 310 sid.core_info.device == ci.device) 311 ci.unit++; 312 } 313 314 /* Check for full match against now-valid unit number */ 315 if (!bhnd_core_matches(&ci, desc)) 316 continue; 317 318 /* Matching core found */ 319 *core = ci; 320 return (0); 321 } 322 323 /* Not found */ 324 return (ENOENT); 325 } 326 327 static int 328 siba_erom_lookup_core_addr(bhnd_erom_t *erom, const struct bhnd_core_match *desc, 329 bhnd_port_type type, u_int port, u_int region, struct bhnd_core_info *info, 330 bhnd_addr_t *addr, bhnd_size_t *size) 331 { 332 struct siba_erom *sc; 333 struct bhnd_core_info core; 334 struct siba_core_id sid; 335 uint32_t am, am_addr, am_size; 336 u_int am_offset; 337 u_int addrspace; 338 int error; 339 340 sc = (struct siba_erom *)erom; 341 342 /* Locate the requested core */ 343 if ((error = siba_erom_lookup_core(erom, desc, &core))) 344 return (error); 345 346 /* Fetch full siba core ident */ 347 sid = siba_eio_read_core_id(&sc->io, core.core_idx, core.unit); 348 349 /* Is port valid? */ 350 if (!siba_is_port_valid(sid.num_addrspace, type, port)) 351 return (ENOENT); 352 353 /* Is region valid? */ 354 if (region >= siba_addrspace_region_count(sid.num_addrspace, port)) 355 return (ENOENT); 356 357 /* Map the bhnd port values to a siba addrspace index */ 358 error = siba_addrspace_index(sid.num_addrspace, type, port, region, 359 &addrspace); 360 if (error) 361 return (error); 362 363 /* Determine the register offset */ 364 am_offset = siba_admatch_offset(addrspace); 365 if (am_offset == 0) { 366 printf("addrspace %u is unsupported", addrspace); 367 return (ENODEV); 368 } 369 370 /* Read and parse the address match register */ 371 am = siba_eio_read_4(&sc->io, core.core_idx, am_offset); 372 373 if ((error = siba_parse_admatch(am, &am_addr, &am_size))) { 374 printf("failed to decode address match register value 0x%x\n", 375 am); 376 return (error); 377 } 378 379 if (info != NULL) 380 *info = core; 381 382 *addr = am_addr; 383 *size = am_size; 384 385 return (0); 386 } 387 388 /* BHND_EROM_GET_CORE_TABLE() */ 389 static int 390 siba_erom_get_core_table(bhnd_erom_t *erom, struct bhnd_core_info **cores, 391 u_int *num_cores) 392 { 393 struct siba_erom *sc; 394 struct bhnd_core_info *out; 395 396 sc = (struct siba_erom *)erom; 397 398 /* Allocate our core array */ 399 out = malloc(sizeof(*out) * sc->io.ncores, M_BHND, M_NOWAIT); 400 if (out == NULL) 401 return (ENOMEM); 402 403 *cores = out; 404 *num_cores = sc->io.ncores; 405 406 /* Enumerate all cores. */ 407 for (u_int i = 0; i < sc->io.ncores; i++) { 408 struct siba_core_id sid; 409 410 /* Read the core info */ 411 sid = siba_eio_read_core_id(&sc->io, i, 0); 412 out[i] = sid.core_info; 413 414 /* Determine unit number */ 415 for (u_int j = 0; j < i; j++) { 416 if (out[j].vendor == out[i].vendor && 417 out[j].device == out[i].device) 418 out[i].unit++; 419 } 420 } 421 422 return (0); 423 } 424 425 /* BHND_EROM_FREE_CORE_TABLE() */ 426 static void 427 siba_erom_free_core_table(bhnd_erom_t *erom, struct bhnd_core_info *cores) 428 { 429 free(cores, M_BHND); 430 } 431 432 /* BHND_EROM_DUMP() */ 433 static int 434 siba_erom_dump(bhnd_erom_t *erom) 435 { 436 struct siba_erom *sc; 437 int error; 438 439 sc = (struct siba_erom *)erom; 440 441 /* Enumerate all cores. */ 442 for (u_int i = 0; i < sc->io.ncores; i++) { 443 uint32_t idhigh, idlow; 444 uint32_t nraddr; 445 446 idhigh = siba_eio_read_4(&sc->io, i, 447 SB0_REG_ABS(SIBA_CFG0_IDHIGH)); 448 idlow = siba_eio_read_4(&sc->io, i, 449 SB0_REG_ABS(SIBA_CFG0_IDLOW)); 450 451 printf("siba core %u:\n", i); 452 printf("\tvendor:\t0x%04x\n", SIBA_REG_GET(idhigh, IDH_VENDOR)); 453 printf("\tdevice:\t0x%04x\n", SIBA_REG_GET(idhigh, IDH_DEVICE)); 454 printf("\trev:\t0x%04x\n", SIBA_IDH_CORE_REV(idhigh)); 455 printf("\tsbrev:\t0x%02x\n", SIBA_REG_GET(idlow, IDL_SBREV)); 456 457 /* Enumerate the address match registers */ 458 nraddr = SIBA_REG_GET(idlow, IDL_NRADDR); 459 printf("\tnraddr\t0x%04x\n", nraddr); 460 461 for (size_t addrspace = 0; addrspace < nraddr; addrspace++) { 462 uint32_t am, am_addr, am_size; 463 u_int am_offset; 464 465 /* Determine the register offset */ 466 am_offset = siba_admatch_offset(addrspace); 467 if (am_offset == 0) { 468 printf("addrspace %zu unsupported", 469 addrspace); 470 break; 471 } 472 473 /* Read and parse the address match register */ 474 am = siba_eio_read_4(&sc->io, i, am_offset); 475 error = siba_parse_admatch(am, &am_addr, &am_size); 476 if (error) { 477 printf("failed to decode address match " 478 "register value 0x%x\n", am); 479 continue; 480 } 481 482 printf("\taddrspace %zu\n", addrspace); 483 printf("\t\taddr: 0x%08x\n", am_addr); 484 printf("\t\tsize: 0x%08x\n", am_size); 485 } 486 } 487 488 return (0); 489 } 490 491 static kobj_method_t siba_erom_methods[] = { 492 KOBJMETHOD(bhnd_erom_probe, siba_erom_probe), 493 KOBJMETHOD(bhnd_erom_init, siba_erom_init), 494 KOBJMETHOD(bhnd_erom_fini, siba_erom_fini), 495 KOBJMETHOD(bhnd_erom_get_core_table, siba_erom_get_core_table), 496 KOBJMETHOD(bhnd_erom_free_core_table, siba_erom_free_core_table), 497 KOBJMETHOD(bhnd_erom_lookup_core, siba_erom_lookup_core), 498 KOBJMETHOD(bhnd_erom_lookup_core_addr, siba_erom_lookup_core_addr), 499 KOBJMETHOD(bhnd_erom_dump, siba_erom_dump), 500 501 KOBJMETHOD_END 502 }; 503 504 BHND_EROM_DEFINE_CLASS(siba_erom, siba_erom_parser, siba_erom_methods, sizeof(struct siba_erom)); 505