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_eromvar.h>
47 #include <dev/bhnd/cores/chipc/chipcreg.h>
52 #include "siba_eromvar.h"
58 static int siba_eio_init(struct siba_erom_io *io,
59 struct bhnd_erom_io *eio, u_int ncores);
61 static uint32_t siba_eio_read_4(struct siba_erom_io *io,
62 u_int core_idx, bus_size_t offset);
64 static int siba_eio_read_core_id(struct siba_erom_io *io,
65 u_int core_idx, int unit,
66 struct siba_core_id *sid);
68 static int siba_eio_read_chipid(struct siba_erom_io *io,
70 struct bhnd_chipid *cid);
73 * SIBA EROM generic I/O context
76 struct bhnd_erom_io *eio; /**< erom I/O callbacks */
77 bhnd_addr_t base_addr; /**< address of first core */
78 u_int ncores; /**< core count */
82 * SIBA EROM per-instance state.
86 struct siba_erom_io io; /**< i/o context */
89 #define EROM_LOG(io, fmt, ...) do { \
90 printf("%s: " fmt, __FUNCTION__, ##__VA_ARGS__); \
93 /* SIBA implementation of BHND_EROM_PROBE() */
95 siba_erom_probe(bhnd_erom_class_t *cls, struct bhnd_erom_io *eio,
96 const struct bhnd_chipid *hint, struct bhnd_chipid *cid)
98 struct siba_erom_io io;
102 /* Initialize I/O context, assuming at least the first core is mapped */
103 if ((error = siba_eio_init(&io, eio, 1)))
106 /* Try using the provided hint. */
108 struct siba_core_id sid;
110 /* Validate bus type */
111 if (hint->chip_type != BHND_CHIPTYPE_SIBA)
115 * Verify the first core's IDHIGH/IDLOW identification.
117 * The core must be a Broadcom core, but must *not* be
118 * a chipcommon core; those shouldn't be hinted.
120 * The first core on EXTIF-equipped devices varies, but on the
121 * BCM4710, it's a SDRAM core (0x803).
124 if ((error = siba_eio_read_core_id(&io, 0, 0, &sid)))
127 if (sid.core_info.vendor != BHND_MFGID_BCM)
130 if (sid.core_info.device == BHND_COREID_CC)
135 /* Validate bus type */
136 idreg = siba_eio_read_4(&io, 0, CHIPC_ID);
137 if (CHIPC_GET_BITS(idreg, CHIPC_ID_BUS) != BHND_CHIPTYPE_SIBA)
140 /* Identify the chipset */
141 if ((error = siba_eio_read_chipid(&io, SIBA_ENUM_ADDR, cid)))
144 /* Verify the chip type */
145 if (cid->chip_type != BHND_CHIPTYPE_SIBA)
150 * gcc hack: ensure bhnd_chipid.ncores cannot exceed SIBA_MAX_CORES
151 * without triggering build failure due to -Wtype-limits
153 * if (cid.ncores > SIBA_MAX_CORES)
156 _Static_assert((2^sizeof(cid->ncores)) <= SIBA_MAX_CORES,
157 "ncores could result in over-read of backing resource");
162 /* SIBA implementation of BHND_EROM_INIT() */
164 siba_erom_init(bhnd_erom_t *erom, const struct bhnd_chipid *cid,
165 struct bhnd_erom_io *eio)
167 struct siba_erom *sc;
170 sc = (struct siba_erom *)erom;
172 /* Attempt to map the full core enumeration space */
173 error = bhnd_erom_io_map(eio, cid->enum_addr,
174 cid->ncores * SIBA_CORE_SIZE);
176 printf("%s: failed to map %u cores: %d\n", __FUNCTION__,
181 /* Initialize I/O context */
182 return (siba_eio_init(&sc->io, eio, cid->ncores));
185 /* SIBA implementation of BHND_EROM_FINI() */
187 siba_erom_fini(bhnd_erom_t *erom)
189 struct siba_erom *sc = (struct siba_erom *)erom;
191 bhnd_erom_io_fini(sc->io.eio);
194 /* Initialize siba_erom resource I/O context */
196 siba_eio_init(struct siba_erom_io *io, struct bhnd_erom_io *eio, u_int ncores)
204 * Read a 32-bit value from @p offset relative to the base address of
205 * the given @p core_idx.
207 * @param io EROM I/O context.
208 * @param core_idx Core index.
209 * @param offset Core register offset.
212 siba_eio_read_4(struct siba_erom_io *io, u_int core_idx, bus_size_t offset)
214 /* Sanity check core index and offset */
215 if (core_idx >= io->ncores)
216 panic("core index %u out of range (ncores=%u)", core_idx,
219 if (offset > SIBA_CORE_SIZE - sizeof(uint32_t))
220 panic("invalid core offset %#jx", (uintmax_t)offset);
223 return (bhnd_erom_io_read(io->eio, SIBA_CORE_OFFSET(core_idx) + offset,
228 * Read and parse identification registers for the given @p core_index.
230 * @param io EROM I/O context.
231 * @param core_idx The core index.
232 * @param unit The caller-specified unit number to be included in the return
234 * @param[out] sid On success, the parsed siba core id.
237 * @retval non-zero if reading or parsing the identification registers
238 * otherwise fails, a regular unix error code will be
242 siba_eio_read_core_id(struct siba_erom_io *io, u_int core_idx, int unit,
243 struct siba_core_id *sid)
245 struct siba_admatch admatch[SIBA_MAX_ADDRSPACE];
246 uint32_t idhigh, idlow;
251 uint8_t num_admatch_en;
257 idhigh = siba_eio_read_4(io, core_idx, SB0_REG_ABS(SIBA_CFG0_IDHIGH));
258 idlow = siba_eio_read_4(io, core_idx, SB0_REG_ABS(SIBA_CFG0_IDLOW));
259 tpsflag = siba_eio_read_4(io, core_idx, SB0_REG_ABS(SIBA_CFG0_TPSFLAG));
261 ocp_vendor = SIBA_REG_GET(idhigh, IDH_VENDOR);
262 sonics_rev = SIBA_REG_GET(idlow, IDL_SBREV);
263 num_admatch = SIBA_REG_GET(idlow, IDL_NRADDR) + 1 /* + enum block */;
264 if (num_admatch > nitems(admatch)) {
265 printf("core%u: invalid admatch count %hhu\n", core_idx,
270 /* Determine backplane interrupt distribution configuration */
271 intr_en = ((tpsflag & SIBA_TPS_F0EN0) != 0);
272 intr_flag = SIBA_REG_GET(tpsflag, TPS_NUM0);
274 /* Determine the number of sonics config register blocks */
275 num_cfg = SIBA_CFG_NUM_2_2;
276 if (sonics_rev >= SIBA_IDL_SBREV_2_3)
277 num_cfg = SIBA_CFG_NUM_2_3;
279 /* Parse all admatch descriptors */
281 for (uint8_t i = 0; i < num_admatch; i++) {
285 KASSERT(i < nitems(admatch), ("invalid admatch index"));
287 /* Determine the register offset */
288 am_offset = siba_admatch_offset(i);
289 if (am_offset == 0) {
290 printf("core%u: addrspace %hhu is unsupported",
295 /* Read and parse the address match register */
296 am_value = siba_eio_read_4(io, core_idx, am_offset);
297 error = siba_parse_admatch(am_value, &admatch[num_admatch_en]);
299 printf("core%u: failed to decode admatch[%hhu] "
300 "register value 0x%x\n", core_idx, i, am_value);
304 /* Skip disabled entries */
305 if (!admatch[num_admatch_en].am_enabled)
308 /* Reject unsupported negative matches. These are not used on
309 * any known devices */
310 if (admatch[num_admatch_en].am_negative) {
311 printf("core%u: unsupported negative admatch[%hhu] "
312 "value 0x%x\n", core_idx, i, am_value);
319 /* Populate the result */
320 *sid = (struct siba_core_id) {
322 .vendor = siba_get_bhnd_mfgid(ocp_vendor),
323 .device = SIBA_REG_GET(idhigh, IDH_DEVICE),
324 .hwrev = SIBA_IDH_CORE_REV(idhigh),
325 .core_idx = core_idx,
328 .sonics_vendor = ocp_vendor,
329 .sonics_rev = sonics_rev,
331 .intr_flag = intr_flag,
332 .num_admatch = num_admatch_en,
333 .num_cfg_blocks = num_cfg
335 memcpy(sid->admatch, admatch, num_admatch_en * sizeof(admatch[0]));
341 * Read and parse the SSB identification registers for the given @p core_index,
342 * returning the siba(4) core identification in @p sid.
344 * @param sc A siba EROM instance.
345 * @param core_idx The index of the core to be identified.
346 * @param[out] result On success, the parsed siba core id.
349 * @retval non-zero if reading or parsing the identification registers
350 * otherwise fails, a regular unix error code will be
354 siba_erom_get_core_id(struct siba_erom *sc, u_int core_idx,
355 struct siba_core_id *result)
357 struct siba_core_id sid;
360 /* Fetch the core info, assuming a unit number of 0 */
361 if ((error = siba_eio_read_core_id(&sc->io, core_idx, 0, &sid)))
364 /* Scan preceding cores to determine the real unit number. */
365 for (u_int i = 0; i < core_idx; i++) {
366 struct siba_core_id prev;
368 if ((error = siba_eio_read_core_id(&sc->io, i, 0, &prev)))
371 /* Bump the unit number? */
372 if (sid.core_info.vendor == prev.core_info.vendor &&
373 sid.core_info.device == prev.core_info.device)
374 sid.core_info.unit++;
382 * Read and parse the chip identification register from the ChipCommon core.
384 * @param io EROM I/O context.
385 * @param enum_addr The physical address mapped by @p io.
386 * @param cid On success, the parsed chip identifier.
389 siba_eio_read_chipid(struct siba_erom_io *io, bus_addr_t enum_addr,
390 struct bhnd_chipid *cid)
392 struct siba_core_id ccid;
395 /* Identify the chipcommon core */
396 if ((error = siba_eio_read_core_id(io, 0, 0, &ccid)))
399 if (ccid.core_info.vendor != BHND_MFGID_BCM ||
400 ccid.core_info.device != BHND_COREID_CC)
403 EROM_LOG(io, "first core not chipcommon "
404 "(vendor=%#hx, core=%#hx)\n", ccid.core_info.vendor,
405 ccid.core_info.device);
410 /* Identify the chipset */
411 if ((error = bhnd_erom_read_chipid(io->eio, cid)))
414 /* Do we need to fix up the core count? */
415 if (CHIPC_NCORES_MIN_HWREV(ccid.core_info.hwrev))
418 switch (cid->chip_id) {
419 case BHND_CHIPID_BCM4306:
422 case BHND_CHIPID_BCM4704:
425 case BHND_CHIPID_BCM5365:
427 * BCM5365 does support ID_NUMCORE in at least
428 * some of its revisions, but for unknown
429 * reasons, Broadcom's drivers always exclude
430 * the ChipCommon revision (0x5) used by BCM5365
431 * from the set of revisions supporting
432 * ID_NUMCORE, and instead supply a fixed value.
434 * Presumably, at least some of these devices
435 * shipped with a broken ID_NUMCORE value.
447 siba_erom_lookup_core(bhnd_erom_t *erom, const struct bhnd_core_match *desc,
448 struct bhnd_core_info *core)
450 struct siba_erom *sc;
451 struct bhnd_core_match imatch;
454 sc = (struct siba_erom *)erom;
456 /* We can't determine a core's unit number during the initial scan. */
458 imatch.m.match.core_unit = 0;
460 /* Locate the first matching core */
461 for (u_int i = 0; i < sc->io.ncores; i++) {
462 struct siba_core_id sid;
463 struct bhnd_core_info ci;
465 /* Read the core info */
466 if ((error = siba_eio_read_core_id(&sc->io, i, 0, &sid)))
471 /* Check for initial match */
472 if (!bhnd_core_matches(&ci, &imatch))
475 /* Re-scan preceding cores to determine the unit number. */
476 for (u_int j = 0; j < i; j++) {
477 error = siba_eio_read_core_id(&sc->io, j, 0, &sid);
481 /* Bump the unit number? */
482 if (sid.core_info.vendor == ci.vendor &&
483 sid.core_info.device == ci.device)
487 /* Check for full match against now-valid unit number */
488 if (!bhnd_core_matches(&ci, desc))
491 /* Matching core found */
501 siba_erom_lookup_core_addr(bhnd_erom_t *erom, const struct bhnd_core_match *desc,
502 bhnd_port_type type, u_int port, u_int region, struct bhnd_core_info *info,
503 bhnd_addr_t *addr, bhnd_size_t *size)
505 struct siba_erom *sc;
506 struct bhnd_core_info core;
507 struct siba_core_id sid;
508 struct siba_admatch admatch;
511 u_int addrspace, cfg;
515 sc = (struct siba_erom *)erom;
517 /* Locate the requested core */
518 if ((error = siba_erom_lookup_core(erom, desc, &core)))
521 /* Fetch full siba core ident */
522 error = siba_eio_read_core_id(&sc->io, core.core_idx, core.unit, &sid);
527 if (!siba_is_port_valid(&sid, type, port))
530 /* Is region valid? */
531 if (region >= siba_port_region_count(&sid, type, port))
534 /* Is this a siba configuration region? If so, this is mapped to an
535 * offset within the device0.0 port */
536 error = siba_cfg_index(&sid, type, port, region, &cfg);
538 bhnd_addr_t region_addr;
539 bhnd_addr_t region_size;
540 bhnd_size_t cfg_offset, cfg_size;
542 cfg_offset = SIBA_CFG_OFFSET(cfg);
543 cfg_size = SIBA_CFG_SIZE;
545 /* Fetch the device0.0 addr/size */
546 error = siba_erom_lookup_core_addr(erom, desc, BHND_PORT_DEVICE,
547 0, 0, NULL, ®ion_addr, ®ion_size);
551 /* Verify that our offset fits within the region */
552 if (region_size < cfg_size) {
553 printf("%s%u.%u offset %ju exceeds %s0.0 size %ju\n",
554 bhnd_port_type_name(type), port, region, cfg_offset,
555 bhnd_port_type_name(BHND_PORT_DEVICE), region_size);
560 if (BHND_ADDR_MAX - region_addr < cfg_offset) {
561 printf("%s%u.%u offset %ju would overflow %s0.0 addr "
562 "%ju\n", bhnd_port_type_name(type), port, region,
563 cfg_offset, bhnd_port_type_name(BHND_PORT_DEVICE),
572 *addr = region_addr + cfg_offset;
578 * Otherwise, must be a device port.
580 * Map the bhnd device port to a siba addrspace index. Unlike siba(4)
581 * bus drivers, we do not exclude the siba(4) configuration blocks from
582 * the first device port.
584 error = siba_addrspace_index(&sid, type, port, region, &addrspace);
588 /* Determine the register offset */
589 am_offset = siba_admatch_offset(addrspace);
590 if (am_offset == 0) {
591 printf("addrspace %u is unsupported", addrspace);
595 /* Read and parse the address match register */
596 am = siba_eio_read_4(&sc->io, core.core_idx, am_offset);
598 if ((error = siba_parse_admatch(am, &admatch))) {
599 printf("failed to decode address match register value 0x%x\n",
607 *addr = admatch.am_base;
608 *size = admatch.am_size;
613 /* BHND_EROM_GET_CORE_TABLE() */
615 siba_erom_get_core_table(bhnd_erom_t *erom, struct bhnd_core_info **cores,
618 struct siba_erom *sc;
619 struct bhnd_core_info *out;
622 sc = (struct siba_erom *)erom;
624 /* Allocate our core array */
625 out = mallocarray(sc->io.ncores, sizeof(*out), M_BHND, M_NOWAIT);
630 *num_cores = sc->io.ncores;
632 /* Enumerate all cores. */
633 for (u_int i = 0; i < sc->io.ncores; i++) {
634 struct siba_core_id sid;
636 /* Read the core info */
637 if ((error = siba_eio_read_core_id(&sc->io, i, 0, &sid)))
640 out[i] = sid.core_info;
642 /* Determine unit number */
643 for (u_int j = 0; j < i; j++) {
644 if (out[j].vendor == out[i].vendor &&
645 out[j].device == out[i].device)
653 /* BHND_EROM_FREE_CORE_TABLE() */
655 siba_erom_free_core_table(bhnd_erom_t *erom, struct bhnd_core_info *cores)
660 /* BHND_EROM_DUMP() */
662 siba_erom_dump(bhnd_erom_t *erom)
664 struct siba_erom *sc;
667 sc = (struct siba_erom *)erom;
669 /* Enumerate all cores. */
670 for (u_int i = 0; i < sc->io.ncores; i++) {
671 uint32_t idhigh, idlow;
674 idhigh = siba_eio_read_4(&sc->io, i,
675 SB0_REG_ABS(SIBA_CFG0_IDHIGH));
676 idlow = siba_eio_read_4(&sc->io, i,
677 SB0_REG_ABS(SIBA_CFG0_IDLOW));
679 printf("siba core %u:\n", i);
680 printf("\tvendor:\t0x%04x\n", SIBA_REG_GET(idhigh, IDH_VENDOR));
681 printf("\tdevice:\t0x%04x\n", SIBA_REG_GET(idhigh, IDH_DEVICE));
682 printf("\trev:\t0x%04x\n", SIBA_IDH_CORE_REV(idhigh));
683 printf("\tsbrev:\t0x%02x\n", SIBA_REG_GET(idlow, IDL_SBREV));
685 /* Enumerate the address match registers */
686 nraddr = SIBA_REG_GET(idlow, IDL_NRADDR);
687 printf("\tnraddr\t0x%04x\n", nraddr);
689 for (size_t addrspace = 0; addrspace < nraddr; addrspace++) {
690 struct siba_admatch admatch;
694 /* Determine the register offset */
695 am_offset = siba_admatch_offset(addrspace);
696 if (am_offset == 0) {
697 printf("addrspace %zu unsupported",
702 /* Read and parse the address match register */
703 am = siba_eio_read_4(&sc->io, i, am_offset);
704 if ((error = siba_parse_admatch(am, &admatch))) {
705 printf("failed to decode address match "
706 "register value 0x%x\n", am);
710 printf("\taddrspace %zu\n", addrspace);
711 printf("\t\taddr: 0x%08x\n", admatch.am_base);
712 printf("\t\tsize: 0x%08x\n", admatch.am_size);
719 static kobj_method_t siba_erom_methods[] = {
720 KOBJMETHOD(bhnd_erom_probe, siba_erom_probe),
721 KOBJMETHOD(bhnd_erom_init, siba_erom_init),
722 KOBJMETHOD(bhnd_erom_fini, siba_erom_fini),
723 KOBJMETHOD(bhnd_erom_get_core_table, siba_erom_get_core_table),
724 KOBJMETHOD(bhnd_erom_free_core_table, siba_erom_free_core_table),
725 KOBJMETHOD(bhnd_erom_lookup_core, siba_erom_lookup_core),
726 KOBJMETHOD(bhnd_erom_lookup_core_addr, siba_erom_lookup_core_addr),
727 KOBJMETHOD(bhnd_erom_dump, siba_erom_dump),
732 BHND_EROM_DEFINE_CLASS(siba_erom, siba_erom_parser, siba_erom_methods, sizeof(struct siba_erom));