2 * Copyright (c) 2015-2016 Landon Fuller <landonf@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
33 #include <sys/param.h>
35 #include <sys/kernel.h>
36 #include <sys/malloc.h>
37 #include <sys/module.h>
39 #include <machine/bus.h>
41 #include <dev/bhnd/bhnd_erom.h>
43 #include <dev/bhnd/cores/chipc/chipcreg.h>
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);
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);
60 static uint32_t siba_eio_read_4(struct siba_erom_io *io,
61 u_int core_idx, bus_size_t offset);
63 static struct siba_core_id siba_eio_read_core_id(struct siba_erom_io *io,
64 u_int core_idx, int unit);
66 static int siba_eio_read_chipid(struct siba_erom_io *io,
68 struct bhnd_chipid *cid);
71 * SIBA EROM generic I/O context
74 u_int ncores; /**< core count */
75 bus_size_t offset; /**< base read offset */
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 */
84 bus_space_tag_t bst; /**< bus space tag */
85 bus_space_handle_t bsh; /**< bus space handle */
89 * SIBA EROM per-instance state.
93 struct siba_erom_io io; /**< i/o context */
96 #define EROM_LOG(io, fmt, ...) do { \
97 if (io->dev != NULL) { \
98 device_printf(io->dev, "%s: " fmt, __FUNCTION__, \
101 printf("%s: " fmt, __FUNCTION__, ##__VA_ARGS__); \
106 siba_erom_probe_common(struct siba_erom_io *io, const struct bhnd_chipid *hint,
107 struct bhnd_chipid *cid)
112 /* Try using the provided hint. */
114 struct siba_core_id sid;
116 /* Validate bus type */
117 if (hint->chip_type != BHND_CHIPTYPE_SIBA)
121 * Verify the first core's IDHIGH/IDLOW identification.
123 * The core must be a Broadcom core, but must *not* be
124 * a chipcommon core; those shouldn't be hinted.
126 * The first core on EXTIF-equipped devices varies, but on the
127 * BCM4710, it's a SDRAM core (0x803).
130 sid = siba_eio_read_core_id(io, 0, 0);
132 if (sid.core_info.vendor != BHND_MFGID_BCM)
135 if (sid.core_info.device == BHND_COREID_CC)
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)
145 /* Identify the chipset */
146 if ((error = siba_eio_read_chipid(io, SIBA_ENUM_ADDR, cid)))
149 /* Verify the chip type */
150 if (cid->chip_type != BHND_CHIPTYPE_SIBA)
155 * gcc hack: ensure bhnd_chipid.ncores cannot exceed SIBA_MAX_CORES
156 * without triggering build failure due to -Wtype-limits
158 * if (cid.ncores > SIBA_MAX_CORES)
161 _Static_assert((2^sizeof(cid->ncores)) <= SIBA_MAX_CORES,
162 "ncores could result in over-read of backing resource");
167 /* SIBA implementation of BHND_EROM_PROBE() */
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)
173 struct siba_erom_io io;
176 rid = rman_get_rid(res->res);
178 /* Initialize I/O context, assuming at least 1 core exists. */
179 if ((error = siba_eio_init(&io, NULL, res, rid, offset, 1)))
182 return (siba_erom_probe_common(&io, hint, cid));
185 /* SIBA implementation of BHND_EROM_PROBE_STATIC() */
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)
191 struct siba_erom_io io;
194 /* Initialize I/O context, assuming at least 1 core exists. */
195 if ((error = siba_eio_init_static(&io, bst, bsh, 0, 1)))
198 return (siba_erom_probe_common(&io, hint, cid));
201 /* SIBA implementation of BHND_EROM_INIT() */
203 siba_erom_init(bhnd_erom_t *erom, const struct bhnd_chipid *cid,
204 device_t parent, int rid)
206 struct siba_erom *sc;
207 struct bhnd_resource *res;
210 sc = (struct siba_erom *)erom;
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);
219 /* Initialize I/O context */
220 error = siba_eio_init(&sc->io, parent, res, rid, 0x0, cid->ncores);
222 bhnd_release_resource(parent, SYS_RES_MEMORY, rid, res);
227 /* SIBA implementation of BHND_EROM_INIT_STATIC() */
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)
232 struct siba_erom *sc;
234 sc = (struct siba_erom *)erom;
236 /* Initialize I/O context */
237 return (siba_eio_init_static(&sc->io, bst, bsh, 0x0, cid->ncores));
240 /* SIBA implementation of BHND_EROM_FINI() */
242 siba_erom_fini(bhnd_erom_t *erom)
244 struct siba_erom *sc = (struct siba_erom *)erom;
246 if (sc->io.res != NULL) {
247 bhnd_release_resource(sc->io.dev, SYS_RES_MEMORY, sc->io.rid,
255 /* Initialize siba_erom resource I/O context */
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)
269 /* Initialize siba_erom bus space I/O context */
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)
285 * Read a 32-bit value from @p offset relative to the base address of
286 * the given @p core_idx.
288 * @param io EROM I/O context.
289 * @param core_idx Core index.
290 * @param offset Core register offset.
293 siba_eio_read_4(struct siba_erom_io *io, u_int core_idx, bus_size_t offset)
295 bus_size_t core_offset;
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,
302 if (offset > SIBA_CORE_SIZE - sizeof(uint32_t))
303 panic("invalid core offset %#jx", (uintmax_t)offset);
306 core_offset = io->offset + SIBA_CORE_OFFSET(core_idx) + offset;
308 return (bhnd_bus_read_4(io->res, core_offset));
310 return (bus_space_read_4(io->bst, io->bsh, core_offset));
314 * Read and parse identification registers for the given @p core_index.
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
321 static struct siba_core_id
322 siba_eio_read_core_id(struct siba_erom_io *io, u_int core_idx, int unit)
324 uint32_t idhigh, idlow;
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));
329 return (siba_parse_core_id(idhigh, idlow, core_idx, unit));
333 * Read and parse the chip identification register from the ChipCommon core.
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.
340 siba_eio_read_chipid(struct siba_erom_io *io, bus_addr_t enum_addr,
341 struct bhnd_chipid *cid)
343 struct siba_core_id ccid;
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)
352 EROM_LOG(io, "first core not chipcommon "
353 "(vendor=%#hx, core=%#hx)\n", ccid.core_info.vendor,
354 ccid.core_info.device);
359 /* Identify the chipset */
360 idreg = siba_eio_read_4(io, 0, CHIPC_ID);
361 *cid = bhnd_parse_chipid(idreg, enum_addr);
363 /* Fix up the core count in-place */
364 return (bhnd_chipid_fixed_ncores(cid, ccid.core_info.hwrev,
369 siba_erom_lookup_core(bhnd_erom_t *erom, const struct bhnd_core_match *desc,
370 struct bhnd_core_info *core)
372 struct siba_erom *sc;
373 struct bhnd_core_match imatch;
375 sc = (struct siba_erom *)erom;
377 /* We can't determine a core's unit number during the initial scan. */
379 imatch.m.match.core_unit = 0;
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;
386 /* Read the core info */
387 sid = siba_eio_read_core_id(&sc->io, i, 0);
390 /* Check for initial match */
391 if (!bhnd_core_matches(&ci, &imatch))
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);
398 /* Bump the unit number? */
399 if (sid.core_info.vendor == ci.vendor &&
400 sid.core_info.device == ci.device)
404 /* Check for full match against now-valid unit number */
405 if (!bhnd_core_matches(&ci, desc))
408 /* Matching core found */
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)
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;
430 sc = (struct siba_erom *)erom;
432 /* Locate the requested core */
433 if ((error = siba_erom_lookup_core(erom, desc, &core)))
436 /* Fetch full siba core ident */
437 sid = siba_eio_read_core_id(&sc->io, core.core_idx, core.unit);
440 if (!siba_is_port_valid(sid.num_addrspace, type, port))
443 /* Is region valid? */
444 if (region >= siba_addrspace_region_count(sid.num_addrspace, port))
447 /* Map the bhnd port values to a siba addrspace index */
448 error = siba_addrspace_index(sid.num_addrspace, type, port, region,
453 /* Determine the register offset */
454 am_offset = siba_admatch_offset(addrspace);
455 if (am_offset == 0) {
456 printf("addrspace %u is unsupported", addrspace);
460 /* Read and parse the address match register */
461 am = siba_eio_read_4(&sc->io, core.core_idx, am_offset);
463 if ((error = siba_parse_admatch(am, &am_addr, &am_size))) {
464 printf("failed to decode address match register value 0x%x\n",
478 /* BHND_EROM_GET_CORE_TABLE() */
480 siba_erom_get_core_table(bhnd_erom_t *erom, struct bhnd_core_info **cores,
483 struct siba_erom *sc;
484 struct bhnd_core_info *out;
486 sc = (struct siba_erom *)erom;
488 /* Allocate our core array */
489 out = malloc(sizeof(*out) * sc->io.ncores, M_BHND, M_NOWAIT);
494 *num_cores = sc->io.ncores;
496 /* Enumerate all cores. */
497 for (u_int i = 0; i < sc->io.ncores; i++) {
498 struct siba_core_id sid;
500 /* Read the core info */
501 sid = siba_eio_read_core_id(&sc->io, i, 0);
502 out[i] = sid.core_info;
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)
515 /* BHND_EROM_FREE_CORE_TABLE() */
517 siba_erom_free_core_table(bhnd_erom_t *erom, struct bhnd_core_info *cores)
522 static kobj_method_t siba_erom_methods[] = {
523 KOBJMETHOD(bhnd_erom_probe, siba_erom_probe),
524 KOBJMETHOD(bhnd_erom_probe_static, siba_erom_probe_static),
525 KOBJMETHOD(bhnd_erom_init, siba_erom_init),
526 KOBJMETHOD(bhnd_erom_init_static, siba_erom_init_static),
527 KOBJMETHOD(bhnd_erom_fini, siba_erom_fini),
528 KOBJMETHOD(bhnd_erom_get_core_table, siba_erom_get_core_table),
529 KOBJMETHOD(bhnd_erom_free_core_table, siba_erom_free_core_table),
530 KOBJMETHOD(bhnd_erom_lookup_core, siba_erom_lookup_core),
531 KOBJMETHOD(bhnd_erom_lookup_core_addr, siba_erom_lookup_core_addr),
536 BHND_EROM_DEFINE_CLASS(siba_erom, siba_erom_parser, siba_erom_methods, sizeof(struct siba_erom));