2 * Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
3 * Copyright (c) 2017 The FreeBSD Foundation
6 * Portions of this software were developed by Landon Fuller
7 * under sponsorship from the FreeBSD Foundation.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
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.
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.
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
37 #include <sys/param.h>
39 #include <sys/kernel.h>
40 #include <sys/malloc.h>
41 #include <sys/module.h>
43 #include <machine/bus.h>
45 #include <dev/bhnd/bhnd_erom.h>
47 #include <dev/bhnd/cores/chipc/chipcreg.h>
56 static int siba_eio_init(struct siba_erom_io *io,
57 struct bhnd_erom_io *eio, u_int ncores);
59 static uint32_t siba_eio_read_4(struct siba_erom_io *io,
60 u_int core_idx, bus_size_t offset);
62 static struct siba_core_id siba_eio_read_core_id(struct siba_erom_io *io,
63 u_int core_idx, int unit);
65 static int siba_eio_read_chipid(struct siba_erom_io *io,
67 struct bhnd_chipid *cid);
70 * SIBA EROM generic I/O context
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 */
79 * SIBA EROM per-instance state.
83 struct siba_erom_io io; /**< i/o context */
86 #define EROM_LOG(io, fmt, ...) do { \
87 printf("%s: " fmt, __FUNCTION__, ##__VA_ARGS__); \
90 /* SIBA implementation of BHND_EROM_PROBE() */
92 siba_erom_probe(bhnd_erom_class_t *cls, struct bhnd_erom_io *eio,
93 const struct bhnd_chipid *hint, struct bhnd_chipid *cid)
95 struct siba_erom_io io;
99 /* Initialize I/O context, assuming at least the first core is mapped */
100 if ((error = siba_eio_init(&io, eio, 1)))
103 /* Try using the provided hint. */
105 struct siba_core_id sid;
107 /* Validate bus type */
108 if (hint->chip_type != BHND_CHIPTYPE_SIBA)
112 * Verify the first core's IDHIGH/IDLOW identification.
114 * The core must be a Broadcom core, but must *not* be
115 * a chipcommon core; those shouldn't be hinted.
117 * The first core on EXTIF-equipped devices varies, but on the
118 * BCM4710, it's a SDRAM core (0x803).
121 sid = siba_eio_read_core_id(&io, 0, 0);
123 if (sid.core_info.vendor != BHND_MFGID_BCM)
126 if (sid.core_info.device == BHND_COREID_CC)
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)
136 /* Identify the chipset */
137 if ((error = siba_eio_read_chipid(&io, SIBA_ENUM_ADDR, cid)))
140 /* Verify the chip type */
141 if (cid->chip_type != BHND_CHIPTYPE_SIBA)
146 * gcc hack: ensure bhnd_chipid.ncores cannot exceed SIBA_MAX_CORES
147 * without triggering build failure due to -Wtype-limits
149 * if (cid.ncores > SIBA_MAX_CORES)
152 _Static_assert((2^sizeof(cid->ncores)) <= SIBA_MAX_CORES,
153 "ncores could result in over-read of backing resource");
158 /* SIBA implementation of BHND_EROM_INIT() */
160 siba_erom_init(bhnd_erom_t *erom, const struct bhnd_chipid *cid,
161 struct bhnd_erom_io *eio)
163 struct siba_erom *sc;
166 sc = (struct siba_erom *)erom;
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);
172 printf("%s: failed to map %u cores: %d\n", __FUNCTION__,
177 /* Initialize I/O context */
178 return (siba_eio_init(&sc->io, eio, cid->ncores));
181 /* SIBA implementation of BHND_EROM_FINI() */
183 siba_erom_fini(bhnd_erom_t *erom)
185 struct siba_erom *sc = (struct siba_erom *)erom;
187 bhnd_erom_io_fini(sc->io.eio);
190 /* Initialize siba_erom resource I/O context */
192 siba_eio_init(struct siba_erom_io *io, struct bhnd_erom_io *eio, u_int ncores)
200 * Read a 32-bit value from @p offset relative to the base address of
201 * the given @p core_idx.
203 * @param io EROM I/O context.
204 * @param core_idx Core index.
205 * @param offset Core register offset.
208 siba_eio_read_4(struct siba_erom_io *io, u_int core_idx, bus_size_t offset)
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,
215 if (offset > SIBA_CORE_SIZE - sizeof(uint32_t))
216 panic("invalid core offset %#jx", (uintmax_t)offset);
219 return (bhnd_erom_io_read(io->eio, SIBA_CORE_OFFSET(core_idx) + offset,
224 * Read and parse identification registers for the given @p core_index.
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
231 static struct siba_core_id
232 siba_eio_read_core_id(struct siba_erom_io *io, u_int core_idx, int unit)
234 uint32_t idhigh, idlow;
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));
239 return (siba_parse_core_id(idhigh, idlow, core_idx, unit));
243 * Read and parse the chip identification register from the ChipCommon core.
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.
250 siba_eio_read_chipid(struct siba_erom_io *io, bus_addr_t enum_addr,
251 struct bhnd_chipid *cid)
253 struct siba_core_id ccid;
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)
262 EROM_LOG(io, "first core not chipcommon "
263 "(vendor=%#hx, core=%#hx)\n", ccid.core_info.vendor,
264 ccid.core_info.device);
269 /* Identify the chipset */
270 idreg = siba_eio_read_4(io, 0, CHIPC_ID);
271 *cid = bhnd_parse_chipid(idreg, enum_addr);
273 /* Fix up the core count in-place */
274 return (bhnd_chipid_fixed_ncores(cid, ccid.core_info.hwrev,
279 siba_erom_lookup_core(bhnd_erom_t *erom, const struct bhnd_core_match *desc,
280 struct bhnd_core_info *core)
282 struct siba_erom *sc;
283 struct bhnd_core_match imatch;
285 sc = (struct siba_erom *)erom;
287 /* We can't determine a core's unit number during the initial scan. */
289 imatch.m.match.core_unit = 0;
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;
296 /* Read the core info */
297 sid = siba_eio_read_core_id(&sc->io, i, 0);
300 /* Check for initial match */
301 if (!bhnd_core_matches(&ci, &imatch))
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);
308 /* Bump the unit number? */
309 if (sid.core_info.vendor == ci.vendor &&
310 sid.core_info.device == ci.device)
314 /* Check for full match against now-valid unit number */
315 if (!bhnd_core_matches(&ci, desc))
318 /* Matching core found */
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)
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;
337 u_int addrspace, cfg;
341 sc = (struct siba_erom *)erom;
343 /* Locate the requested core */
344 if ((error = siba_erom_lookup_core(erom, desc, &core)))
347 /* Fetch full siba core ident */
348 sid = siba_eio_read_core_id(&sc->io, core.core_idx, core.unit);
351 if (!siba_is_port_valid(&sid, type, port))
354 /* Is region valid? */
355 if (region >= siba_port_region_count(&sid, type, port))
358 /* Is this a siba configuration region? If so, this is mapped to an
359 * offset within the device0.0 port */
360 error = siba_cfg_index(&sid, type, port, region, &cfg);
362 bhnd_addr_t region_addr;
363 bhnd_addr_t region_size;
364 bhnd_size_t cfg_offset, cfg_size;
366 cfg_offset = SIBA_CFG_OFFSET(cfg);
367 cfg_size = SIBA_CFG_SIZE;
369 /* Fetch the device0.0 addr/size */
370 error = siba_erom_lookup_core_addr(erom, desc, BHND_PORT_DEVICE,
371 0, 0, NULL, ®ion_addr, ®ion_size);
375 /* Verify that our offset fits within the region */
376 if (region_size < cfg_size) {
377 printf("%s%u.%u offset %ju exceeds %s0.0 size %ju\n",
378 bhnd_port_type_name(type), port, region, cfg_offset,
379 bhnd_port_type_name(BHND_PORT_DEVICE), region_size);
384 if (BHND_ADDR_MAX - region_addr < cfg_offset) {
385 printf("%s%u.%u offset %ju would overflow %s0.0 addr "
386 "%ju\n", bhnd_port_type_name(type), port, region,
387 cfg_offset, bhnd_port_type_name(BHND_PORT_DEVICE),
396 *addr = region_addr + cfg_offset;
402 * Otherwise, must be a device port.
404 * Map the bhnd device port to a siba addrspace index. Unlike siba(4)
405 * bus drivers, we do not exclude the siba(4) configuration blocks from
406 * the first device port.
408 error = siba_addrspace_index(&sid, type, port, region, &addrspace);
412 /* Determine the register offset */
413 am_offset = siba_admatch_offset(addrspace);
414 if (am_offset == 0) {
415 printf("addrspace %u is unsupported", addrspace);
419 /* Read and parse the address match register */
420 am = siba_eio_read_4(&sc->io, core.core_idx, am_offset);
422 if ((error = siba_parse_admatch(am, &am_addr, &am_size))) {
423 printf("failed to decode address match register value 0x%x\n",
437 /* BHND_EROM_GET_CORE_TABLE() */
439 siba_erom_get_core_table(bhnd_erom_t *erom, struct bhnd_core_info **cores,
442 struct siba_erom *sc;
443 struct bhnd_core_info *out;
445 sc = (struct siba_erom *)erom;
447 /* Allocate our core array */
448 out = malloc(sizeof(*out) * sc->io.ncores, M_BHND, M_NOWAIT);
453 *num_cores = sc->io.ncores;
455 /* Enumerate all cores. */
456 for (u_int i = 0; i < sc->io.ncores; i++) {
457 struct siba_core_id sid;
459 /* Read the core info */
460 sid = siba_eio_read_core_id(&sc->io, i, 0);
461 out[i] = sid.core_info;
463 /* Determine unit number */
464 for (u_int j = 0; j < i; j++) {
465 if (out[j].vendor == out[i].vendor &&
466 out[j].device == out[i].device)
474 /* BHND_EROM_FREE_CORE_TABLE() */
476 siba_erom_free_core_table(bhnd_erom_t *erom, struct bhnd_core_info *cores)
481 /* BHND_EROM_DUMP() */
483 siba_erom_dump(bhnd_erom_t *erom)
485 struct siba_erom *sc;
488 sc = (struct siba_erom *)erom;
490 /* Enumerate all cores. */
491 for (u_int i = 0; i < sc->io.ncores; i++) {
492 uint32_t idhigh, idlow;
495 idhigh = siba_eio_read_4(&sc->io, i,
496 SB0_REG_ABS(SIBA_CFG0_IDHIGH));
497 idlow = siba_eio_read_4(&sc->io, i,
498 SB0_REG_ABS(SIBA_CFG0_IDLOW));
500 printf("siba core %u:\n", i);
501 printf("\tvendor:\t0x%04x\n", SIBA_REG_GET(idhigh, IDH_VENDOR));
502 printf("\tdevice:\t0x%04x\n", SIBA_REG_GET(idhigh, IDH_DEVICE));
503 printf("\trev:\t0x%04x\n", SIBA_IDH_CORE_REV(idhigh));
504 printf("\tsbrev:\t0x%02x\n", SIBA_REG_GET(idlow, IDL_SBREV));
506 /* Enumerate the address match registers */
507 nraddr = SIBA_REG_GET(idlow, IDL_NRADDR);
508 printf("\tnraddr\t0x%04x\n", nraddr);
510 for (size_t addrspace = 0; addrspace < nraddr; addrspace++) {
511 uint32_t am, am_addr, am_size;
514 /* Determine the register offset */
515 am_offset = siba_admatch_offset(addrspace);
516 if (am_offset == 0) {
517 printf("addrspace %zu unsupported",
522 /* Read and parse the address match register */
523 am = siba_eio_read_4(&sc->io, i, am_offset);
524 error = siba_parse_admatch(am, &am_addr, &am_size);
526 printf("failed to decode address match "
527 "register value 0x%x\n", am);
531 printf("\taddrspace %zu\n", addrspace);
532 printf("\t\taddr: 0x%08x\n", am_addr);
533 printf("\t\tsize: 0x%08x\n", am_size);
540 static kobj_method_t siba_erom_methods[] = {
541 KOBJMETHOD(bhnd_erom_probe, siba_erom_probe),
542 KOBJMETHOD(bhnd_erom_init, siba_erom_init),
543 KOBJMETHOD(bhnd_erom_fini, siba_erom_fini),
544 KOBJMETHOD(bhnd_erom_get_core_table, siba_erom_get_core_table),
545 KOBJMETHOD(bhnd_erom_free_core_table, siba_erom_free_core_table),
546 KOBJMETHOD(bhnd_erom_lookup_core, siba_erom_lookup_core),
547 KOBJMETHOD(bhnd_erom_lookup_core_addr, siba_erom_lookup_core_addr),
548 KOBJMETHOD(bhnd_erom_dump, siba_erom_dump),
553 BHND_EROM_DEFINE_CLASS(siba_erom, siba_erom_parser, siba_erom_methods, sizeof(struct siba_erom));