2 * Copyright (c) 2015 Landon Fuller <landon@landonf.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>
38 #include <sys/systm.h>
40 #include <machine/bus.h>
42 #include <dev/bhnd/cores/chipc/chipcreg.h>
48 siba_probe(device_t dev)
50 device_set_desc(dev, "SIBA BHND bus");
51 return (BUS_PROBE_DEFAULT);
55 siba_attach(device_t dev)
57 struct siba_devinfo *dinfo;
58 struct siba_softc *sc;
63 sc = device_get_softc(dev);
66 /* Fetch references to the siba SIBA_CFG* blocks for all
67 * registered devices */
68 if ((error = device_get_children(dev, &devs, &ndevs)))
71 for (int i = 0; i < ndevs; i++) {
72 struct siba_addrspace *addrspace;
74 dinfo = device_get_ivars(devs[i]);
76 KASSERT(!device_is_suspended(devs[i]),
77 ("siba(4) stateful suspend handling requires that devices "
78 "not be suspended before siba_attach()"));
80 /* Fetch the core register address space */
81 addrspace = siba_find_addrspace(dinfo, BHND_PORT_DEVICE, 0, 0);
82 if (addrspace == NULL) {
84 "missing device registers for core %d\n", i);
90 * Map the per-core configuration blocks
92 KASSERT(dinfo->core_id.num_cfg_blocks <= SIBA_MAX_CFG,
93 ("config block count %u out of range",
94 dinfo->core_id.num_cfg_blocks));
96 for (u_int cfgidx = 0; cfgidx < dinfo->core_id.num_cfg_blocks;
99 rman_res_t r_start, r_count, r_end;
101 /* Determine the config block's address range; configuration
102 * blocks are allocated starting at SIBA_CFG0_OFFSET,
103 * growing downwards. */
104 r_start = addrspace->sa_base + SIBA_CFG0_OFFSET;
105 r_start -= cfgidx * SIBA_CFG_SIZE;
107 r_count = SIBA_CFG_SIZE;
108 r_end = r_start + r_count - 1;
110 /* Allocate the config resource */
111 dinfo->cfg_rid[cfgidx] = 0;
112 dinfo->cfg[cfgidx] = BHND_BUS_ALLOC_RESOURCE(dev, dev,
113 SYS_RES_MEMORY, &dinfo->cfg_rid[cfgidx], r_start,
114 r_end, r_count, RF_ACTIVE);
116 if (dinfo->cfg[cfgidx] == NULL) {
117 device_printf(dev, "failed allocating CFG_%u for "
118 "core %d\n", cfgidx, i);
130 /* Delegate remainder to standard bhnd method implementation */
131 return (bhnd_generic_attach(dev));
135 siba_detach(device_t dev)
137 return (bhnd_generic_detach(dev));
141 siba_resume(device_t dev)
143 return (bhnd_generic_resume(dev));
147 siba_suspend(device_t dev)
149 return (bhnd_generic_suspend(dev));
153 siba_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
155 const struct siba_devinfo *dinfo;
156 const struct bhnd_core_info *cfg;
158 dinfo = device_get_ivars(child);
159 cfg = &dinfo->core_id.core_info;
162 case BHND_IVAR_VENDOR:
163 *result = cfg->vendor;
165 case BHND_IVAR_DEVICE:
166 *result = cfg->device;
168 case BHND_IVAR_HWREV:
169 *result = cfg->hwrev;
171 case BHND_IVAR_DEVICE_CLASS:
172 *result = bhnd_core_class(cfg);
174 case BHND_IVAR_VENDOR_NAME:
175 *result = (uintptr_t) bhnd_vendor_name(cfg->vendor);
177 case BHND_IVAR_DEVICE_NAME:
178 *result = (uintptr_t) bhnd_core_name(cfg);
180 case BHND_IVAR_CORE_INDEX:
181 *result = cfg->core_idx;
183 case BHND_IVAR_CORE_UNIT:
192 siba_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
195 case BHND_IVAR_VENDOR:
196 case BHND_IVAR_DEVICE:
197 case BHND_IVAR_HWREV:
198 case BHND_IVAR_DEVICE_CLASS:
199 case BHND_IVAR_VENDOR_NAME:
200 case BHND_IVAR_DEVICE_NAME:
201 case BHND_IVAR_CORE_INDEX:
202 case BHND_IVAR_CORE_UNIT:
209 static struct resource_list *
210 siba_get_resource_list(device_t dev, device_t child)
212 struct siba_devinfo *dinfo = device_get_ivars(child);
213 return (&dinfo->resources);
217 siba_find_hostb_device(device_t dev)
219 struct siba_softc *sc = device_get_softc(dev);
221 /* This is set (or not) by the concrete siba driver subclass. */
222 return (sc->hostb_dev);
226 siba_reset_core(device_t dev, device_t child, uint16_t flags)
228 struct siba_devinfo *dinfo;
230 if (device_get_parent(child) != dev)
231 BHND_BUS_RESET_CORE(device_get_parent(dev), child, flags);
233 dinfo = device_get_ivars(child);
235 /* Can't reset the core without access to the CFG0 registers */
236 if (dinfo->cfg[0] == NULL)
239 // TODO - perform reset
245 siba_suspend_core(device_t dev, device_t child)
247 struct siba_devinfo *dinfo;
249 if (device_get_parent(child) != dev)
250 BHND_BUS_SUSPEND_CORE(device_get_parent(dev), child);
252 dinfo = device_get_ivars(child);
254 /* Can't suspend the core without access to the CFG0 registers */
255 if (dinfo->cfg[0] == NULL)
258 // TODO - perform suspend
264 siba_read_config(device_t dev, device_t child, bus_size_t offset, u_int width)
266 struct siba_devinfo *dinfo;
269 /* Must be directly attached */
270 if (device_get_parent(child) != dev)
273 /* CFG0 registers must be available */
274 dinfo = device_get_ivars(child);
275 if (dinfo->cfg[0] == NULL)
278 /* Offset must fall within CFG0 */
279 r_size = rman_get_size(dinfo->cfg[0]->res);
280 if (r_size < offset || r_size - offset < width)
285 return (bhnd_bus_read_1(dinfo->cfg[0], offset));
287 return (bhnd_bus_read_2(dinfo->cfg[0], offset));
289 return (bhnd_bus_read_4(dinfo->cfg[0], offset));
297 siba_write_config(device_t dev, device_t child, bus_size_t offset, uint32_t val,
300 struct siba_devinfo *dinfo;
303 /* Must be directly attached */
304 if (device_get_parent(child) != dev)
307 /* CFG0 registers must be available */
308 dinfo = device_get_ivars(child);
309 if (dinfo->cfg[0] == NULL)
312 /* Offset must fall within CFG0 */
313 r_size = rman_get_size(dinfo->cfg[0]->res);
314 if (r_size < offset || r_size - offset < width)
319 bhnd_bus_write_1(dinfo->cfg[0], offset, val);
321 bhnd_bus_write_2(dinfo->cfg[0], offset, val);
323 bhnd_bus_write_4(dinfo->cfg[0], offset, val);
328 siba_get_port_count(device_t dev, device_t child, bhnd_port_type type)
330 struct siba_devinfo *dinfo;
332 /* delegate non-bus-attached devices to our parent */
333 if (device_get_parent(child) != dev)
334 return (BHND_BUS_GET_PORT_COUNT(device_get_parent(dev), child,
337 dinfo = device_get_ivars(child);
338 return (siba_addrspace_port_count(dinfo));
342 siba_get_region_count(device_t dev, device_t child, bhnd_port_type type,
345 struct siba_devinfo *dinfo;
347 /* delegate non-bus-attached devices to our parent */
348 if (device_get_parent(child) != dev)
349 return (BHND_BUS_GET_REGION_COUNT(device_get_parent(dev), child,
352 dinfo = device_get_ivars(child);
353 if (!siba_is_port_valid(dinfo, type, port))
356 return (siba_addrspace_region_count(dinfo, port));
360 siba_get_port_rid(device_t dev, device_t child, bhnd_port_type port_type,
361 u_int port_num, u_int region_num)
363 struct siba_devinfo *dinfo;
364 struct siba_addrspace *addrspace;
366 /* delegate non-bus-attached devices to our parent */
367 if (device_get_parent(child) != dev)
368 return (BHND_BUS_GET_PORT_RID(device_get_parent(dev), child,
369 port_type, port_num, region_num));
371 dinfo = device_get_ivars(child);
372 addrspace = siba_find_addrspace(dinfo, port_type, port_num, region_num);
373 if (addrspace == NULL)
376 return (addrspace->sa_rid);
380 siba_decode_port_rid(device_t dev, device_t child, int type, int rid,
381 bhnd_port_type *port_type, u_int *port_num, u_int *region_num)
383 struct siba_devinfo *dinfo;
385 /* delegate non-bus-attached devices to our parent */
386 if (device_get_parent(child) != dev)
387 return (BHND_BUS_DECODE_PORT_RID(device_get_parent(dev), child,
388 type, rid, port_type, port_num, region_num));
390 dinfo = device_get_ivars(child);
392 /* Ports are always memory mapped */
393 if (type != SYS_RES_MEMORY)
396 for (int i = 0; i < dinfo->core_id.num_addrspace; i++) {
397 if (dinfo->addrspace[i].sa_rid != rid)
400 *port_type = BHND_PORT_DEVICE;
401 *port_num = siba_addrspace_port(i);
402 *region_num = siba_addrspace_region(i);
411 siba_get_region_addr(device_t dev, device_t child, bhnd_port_type port_type,
412 u_int port_num, u_int region_num, bhnd_addr_t *addr, bhnd_size_t *size)
414 struct siba_devinfo *dinfo;
415 struct siba_addrspace *addrspace;
417 /* delegate non-bus-attached devices to our parent */
418 if (device_get_parent(child) != dev) {
419 return (BHND_BUS_GET_REGION_ADDR(device_get_parent(dev), child,
420 port_type, port_num, region_num, addr, size));
423 dinfo = device_get_ivars(child);
424 addrspace = siba_find_addrspace(dinfo, port_type, port_num, region_num);
425 if (addrspace == NULL)
428 *addr = addrspace->sa_base;
429 *size = addrspace->sa_size - addrspace->sa_bus_reserved;
435 * Register all address space mappings for @p di.
437 * @param dev The siba bus device.
438 * @param di The device info instance on which to register all address
440 * @param r A resource mapping the enumeration table block for @p di.
443 siba_register_addrspaces(device_t dev, struct siba_devinfo *di,
446 struct siba_core_id *cid;
454 /* Register the device address space entries */
455 for (uint8_t i = 0; i < di->core_id.num_addrspace; i++) {
458 uint32_t bus_reserved;
460 /* Determine the register offset */
461 adm_offset = siba_admatch_offset(i);
462 if (adm_offset == 0) {
463 device_printf(dev, "addrspace %hhu is unsupported", i);
467 /* Fetch the address match register value */
468 adm = bus_read_4(r, adm_offset);
470 /* Parse the value */
471 if ((error = siba_parse_admatch(adm, &addr, &size))) {
472 device_printf(dev, "failed to decode address "
473 " match register value 0x%x\n", adm);
477 /* If this is the device's core/enumeration addrespace,
478 * reserve the Sonics configuration register blocks for the
481 if (i == SIBA_CORE_ADDRSPACE)
482 bus_reserved = cid->num_cfg_blocks * SIBA_CFG_SIZE;
484 /* Append the region info */
485 error = siba_append_dinfo_region(di, i, addr, size,
494 static struct bhnd_devinfo *
495 siba_alloc_bhnd_dinfo(device_t dev)
497 struct siba_devinfo *dinfo = siba_alloc_dinfo(dev);
498 return ((struct bhnd_devinfo *)dinfo);
502 siba_free_bhnd_dinfo(device_t dev, struct bhnd_devinfo *dinfo)
504 siba_free_dinfo(dev, (struct siba_devinfo *)dinfo);
509 siba_get_core_table(device_t dev, device_t child, struct bhnd_core_info **cores,
512 const struct bhnd_chipid *chipid;
513 struct bhnd_core_info *table;
514 struct bhnd_resource *r;
518 /* Fetch the core count from our chip identification */
519 chipid = BHND_BUS_GET_CHIPID(dev, dev);
521 /* Allocate our local core table */
522 table = malloc(sizeof(*table) * chipid->ncores, M_BHND, M_NOWAIT);
526 /* Enumerate all cores. */
527 for (u_int i = 0; i < chipid->ncores; i++) {
528 struct siba_core_id cid;
529 uint32_t idhigh, idlow;
531 /* Map the core's register block */
533 r = bhnd_alloc_resource(dev, SYS_RES_MEMORY, &rid,
534 SIBA_CORE_ADDR(i), SIBA_CORE_ADDR(i) + SIBA_CORE_SIZE - 1,
535 SIBA_CORE_SIZE, RF_ACTIVE);
541 /* Read the core info */
542 idhigh = bhnd_bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDHIGH));
543 idlow = bhnd_bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDLOW));
545 cid = siba_parse_core_id(idhigh, idlow, i, 0);
546 table[i] = cid.core_info;
548 /* Determine unit number */
549 for (u_int j = 0; j < i; j++) {
550 if (table[j].vendor == table[i].vendor &&
551 table[j].device == table[i].device)
555 /* Release our resource */
556 bhnd_release_resource(dev, SYS_RES_MEMORY, rid, r);
560 /* Provide the result values (performed last to avoid modifying
561 * cores/num_cores if enumeration failed). */
563 *num_cores = chipid->ncores;
572 bhnd_release_resource(dev, SYS_RES_MEMORY, rid, r);
578 * Scan the core table and add all valid discovered cores to
581 * @param dev The siba bus device.
582 * @param chipid The chip identifier, if the device does not provide a
583 * ChipCommon core. Should o NULL otherwise.
586 siba_add_children(device_t dev, const struct bhnd_chipid *chipid)
588 struct bhnd_chipid ccid;
589 struct bhnd_core_info *cores;
590 struct siba_devinfo *dinfo;
600 * Try to determine the number of device cores via the ChipCommon
601 * identification registers.
603 * A small number of very early devices do not include a ChipCommon
604 * core, in which case our caller must supply the chip identification
605 * information via a non-NULL chipid parameter.
607 if (chipid == NULL) {
608 uint32_t idhigh, ccreg;
609 uint16_t vendor, device;
612 /* Map the first core's register block. If the ChipCommon core
613 * exists, it will always be the first core. */
615 r = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
616 SIBA_CORE_ADDR(0), SIBA_CORE_SIZE,
617 SIBA_CORE_ADDR(0) + SIBA_CORE_SIZE - 1,
620 /* Identify the core */
621 idhigh = bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDHIGH));
622 vendor = SIBA_REG_GET(idhigh, IDH_VENDOR);
623 device = SIBA_REG_GET(idhigh, IDH_DEVICE);
624 ccrev = SIBA_IDH_CORE_REV(idhigh);
626 if (vendor != OCP_VENDOR_BCM || device != BHND_COREID_CC) {
628 "cannot identify device: no chipcommon core "
634 /* Identify the chipset */
635 ccreg = bus_read_4(r, CHIPC_ID);
636 ccid = bhnd_parse_chipid(ccreg, SIBA_ENUM_ADDR);
638 /* Fix up the core count */
639 error = bhnd_chipid_fixed_ncores(&ccid, ccrev, &ccid.ncores);
641 device_printf(dev, "unable to determine core count for "
642 "chipset 0x%hx\n", ccid.chip_id);
647 bus_release_resource(dev, SYS_RES_MEMORY, rid, r);
650 /* Allocate our temporary core table and enumerate all cores */
651 cores = malloc(sizeof(*cores) * chipid->ncores, M_BHND, M_NOWAIT);
656 for (u_int i = 0; i < chipid->ncores; i++) {
657 struct siba_core_id cid;
659 uint32_t idhigh, idlow;
660 rman_res_t r_count, r_end, r_start;
662 /* Map the core's register block */
664 r_start = SIBA_CORE_ADDR(i);
665 r_count = SIBA_CORE_SIZE;
666 r_end = r_start + SIBA_CORE_SIZE - 1;
667 r = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, r_start,
668 r_end, r_count, RF_ACTIVE);
674 /* Add the child device */
675 child = BUS_ADD_CHILD(dev, 0, NULL, -1);
681 /* Read the core info */
682 idhigh = bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDHIGH));
683 idlow = bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDLOW));
685 cid = siba_parse_core_id(idhigh, idlow, i, 0);
686 cores[i] = cid.core_info;
688 /* Determine unit number */
689 for (u_int j = 0; j < i; j++) {
690 if (cores[j].vendor == cores[i].vendor &&
691 cores[j].device == cores[i].device)
695 /* Initialize per-device bus info */
696 if ((dinfo = device_get_ivars(child)) == NULL) {
701 if ((error = siba_init_dinfo(dev, dinfo, &cid)))
704 /* Register the core's address space(s). */
705 if ((error = siba_register_addrspaces(dev, dinfo, r)))
708 /* If pins are floating or the hardware is otherwise
709 * unpopulated, the device shouldn't be used. */
710 if (bhnd_is_hw_disabled(child))
711 device_disable(child);
713 /* Release our resource */
714 bus_release_resource(dev, SYS_RES_MEMORY, rid, r);
717 /* Issue bus callback for fully initialized child. */
718 BHND_BUS_CHILD_ADDED(dev, child);
726 bus_release_resource(dev, SYS_RES_MEMORY, rid, r);
731 static device_method_t siba_methods[] = {
732 /* Device interface */
733 DEVMETHOD(device_probe, siba_probe),
734 DEVMETHOD(device_attach, siba_attach),
735 DEVMETHOD(device_detach, siba_detach),
736 DEVMETHOD(device_resume, siba_resume),
737 DEVMETHOD(device_suspend, siba_suspend),
740 DEVMETHOD(bus_read_ivar, siba_read_ivar),
741 DEVMETHOD(bus_write_ivar, siba_write_ivar),
742 DEVMETHOD(bus_get_resource_list, siba_get_resource_list),
745 DEVMETHOD(bhnd_bus_find_hostb_device, siba_find_hostb_device),
746 DEVMETHOD(bhnd_bus_get_core_table, siba_get_core_table),
747 DEVMETHOD(bhnd_bus_alloc_devinfo, siba_alloc_bhnd_dinfo),
748 DEVMETHOD(bhnd_bus_free_devinfo, siba_free_bhnd_dinfo),
749 DEVMETHOD(bhnd_bus_reset_core, siba_reset_core),
750 DEVMETHOD(bhnd_bus_suspend_core, siba_suspend_core),
751 DEVMETHOD(bhnd_bus_read_config, siba_read_config),
752 DEVMETHOD(bhnd_bus_write_config, siba_write_config),
753 DEVMETHOD(bhnd_bus_get_port_count, siba_get_port_count),
754 DEVMETHOD(bhnd_bus_get_region_count, siba_get_region_count),
755 DEVMETHOD(bhnd_bus_get_port_rid, siba_get_port_rid),
756 DEVMETHOD(bhnd_bus_decode_port_rid, siba_decode_port_rid),
757 DEVMETHOD(bhnd_bus_get_region_addr, siba_get_region_addr),
762 DEFINE_CLASS_1(bhnd, siba_driver, siba_methods, sizeof(struct siba_softc), bhnd_driver);
764 MODULE_VERSION(siba, 1);
765 MODULE_DEPEND(siba, bhnd, 1, 1, 1);