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>
47 static bhnd_erom_class_t *
48 siba_get_erom_class(driver_t *driver)
50 return (&siba_erom_parser);
54 siba_probe(device_t dev)
56 device_set_desc(dev, "SIBA BHND bus");
57 return (BUS_PROBE_DEFAULT);
61 * Default siba(4) bus driver implementation of DEVICE_ATTACH().
63 * This implementation initializes internal siba(4) state and performs
64 * bus enumeration, and must be called by subclassing drivers in
65 * DEVICE_ATTACH() before any other bus methods.
68 siba_attach(device_t dev)
70 struct siba_softc *sc;
73 sc = device_get_softc(dev);
76 /* Enumerate children */
77 if ((error = siba_add_children(dev))) {
78 device_delete_children(dev);
86 siba_detach(device_t dev)
88 return (bhnd_generic_detach(dev));
92 siba_resume(device_t dev)
94 return (bhnd_generic_resume(dev));
98 siba_suspend(device_t dev)
100 return (bhnd_generic_suspend(dev));
104 siba_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
106 const struct siba_devinfo *dinfo;
107 const struct bhnd_core_info *cfg;
109 dinfo = device_get_ivars(child);
110 cfg = &dinfo->core_id.core_info;
113 case BHND_IVAR_VENDOR:
114 *result = cfg->vendor;
116 case BHND_IVAR_DEVICE:
117 *result = cfg->device;
119 case BHND_IVAR_HWREV:
120 *result = cfg->hwrev;
122 case BHND_IVAR_DEVICE_CLASS:
123 *result = bhnd_core_class(cfg);
125 case BHND_IVAR_VENDOR_NAME:
126 *result = (uintptr_t) bhnd_vendor_name(cfg->vendor);
128 case BHND_IVAR_DEVICE_NAME:
129 *result = (uintptr_t) bhnd_core_name(cfg);
131 case BHND_IVAR_CORE_INDEX:
132 *result = cfg->core_idx;
134 case BHND_IVAR_CORE_UNIT:
143 siba_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
146 case BHND_IVAR_VENDOR:
147 case BHND_IVAR_DEVICE:
148 case BHND_IVAR_HWREV:
149 case BHND_IVAR_DEVICE_CLASS:
150 case BHND_IVAR_VENDOR_NAME:
151 case BHND_IVAR_DEVICE_NAME:
152 case BHND_IVAR_CORE_INDEX:
153 case BHND_IVAR_CORE_UNIT:
160 static struct resource_list *
161 siba_get_resource_list(device_t dev, device_t child)
163 struct siba_devinfo *dinfo = device_get_ivars(child);
164 return (&dinfo->resources);
168 siba_reset_core(device_t dev, device_t child, uint16_t flags)
170 struct siba_devinfo *dinfo;
172 if (device_get_parent(child) != dev)
173 BHND_BUS_RESET_CORE(device_get_parent(dev), child, flags);
175 dinfo = device_get_ivars(child);
177 /* Can't reset the core without access to the CFG0 registers */
178 if (dinfo->cfg[0] == NULL)
181 // TODO - perform reset
187 siba_suspend_core(device_t dev, device_t child)
189 struct siba_devinfo *dinfo;
191 if (device_get_parent(child) != dev)
192 BHND_BUS_SUSPEND_CORE(device_get_parent(dev), child);
194 dinfo = device_get_ivars(child);
196 /* Can't suspend the core without access to the CFG0 registers */
197 if (dinfo->cfg[0] == NULL)
200 // TODO - perform suspend
206 siba_read_config(device_t dev, device_t child, bus_size_t offset, u_int width)
208 struct siba_devinfo *dinfo;
211 /* Must be directly attached */
212 if (device_get_parent(child) != dev)
215 /* CFG0 registers must be available */
216 dinfo = device_get_ivars(child);
217 if (dinfo->cfg[0] == NULL)
220 /* Offset must fall within CFG0 */
221 r_size = rman_get_size(dinfo->cfg[0]->res);
222 if (r_size < offset || r_size - offset < width)
227 return (bhnd_bus_read_1(dinfo->cfg[0], offset));
229 return (bhnd_bus_read_2(dinfo->cfg[0], offset));
231 return (bhnd_bus_read_4(dinfo->cfg[0], offset));
239 siba_write_config(device_t dev, device_t child, bus_size_t offset, uint32_t val,
242 struct siba_devinfo *dinfo;
245 /* Must be directly attached */
246 if (device_get_parent(child) != dev)
249 /* CFG0 registers must be available */
250 dinfo = device_get_ivars(child);
251 if (dinfo->cfg[0] == NULL)
254 /* Offset must fall within CFG0 */
255 r_size = rman_get_size(dinfo->cfg[0]->res);
256 if (r_size < offset || r_size - offset < width)
261 bhnd_bus_write_1(dinfo->cfg[0], offset, val);
263 bhnd_bus_write_2(dinfo->cfg[0], offset, val);
265 bhnd_bus_write_4(dinfo->cfg[0], offset, val);
270 siba_get_port_count(device_t dev, device_t child, bhnd_port_type type)
272 struct siba_devinfo *dinfo;
274 /* delegate non-bus-attached devices to our parent */
275 if (device_get_parent(child) != dev)
276 return (BHND_BUS_GET_PORT_COUNT(device_get_parent(dev), child,
279 dinfo = device_get_ivars(child);
280 return (siba_addrspace_port_count(dinfo->core_id.num_addrspace));
284 siba_get_region_count(device_t dev, device_t child, bhnd_port_type type,
287 struct siba_devinfo *dinfo;
289 /* delegate non-bus-attached devices to our parent */
290 if (device_get_parent(child) != dev)
291 return (BHND_BUS_GET_REGION_COUNT(device_get_parent(dev), child,
294 dinfo = device_get_ivars(child);
295 if (!siba_is_port_valid(dinfo->core_id.num_addrspace, type, port))
298 return (siba_addrspace_region_count(dinfo->core_id.num_addrspace,
303 siba_get_port_rid(device_t dev, device_t child, bhnd_port_type port_type,
304 u_int port_num, u_int region_num)
306 struct siba_devinfo *dinfo;
307 struct siba_addrspace *addrspace;
309 /* delegate non-bus-attached devices to our parent */
310 if (device_get_parent(child) != dev)
311 return (BHND_BUS_GET_PORT_RID(device_get_parent(dev), child,
312 port_type, port_num, region_num));
314 dinfo = device_get_ivars(child);
315 addrspace = siba_find_addrspace(dinfo, port_type, port_num, region_num);
316 if (addrspace == NULL)
319 return (addrspace->sa_rid);
323 siba_decode_port_rid(device_t dev, device_t child, int type, int rid,
324 bhnd_port_type *port_type, u_int *port_num, u_int *region_num)
326 struct siba_devinfo *dinfo;
328 /* delegate non-bus-attached devices to our parent */
329 if (device_get_parent(child) != dev)
330 return (BHND_BUS_DECODE_PORT_RID(device_get_parent(dev), child,
331 type, rid, port_type, port_num, region_num));
333 dinfo = device_get_ivars(child);
335 /* Ports are always memory mapped */
336 if (type != SYS_RES_MEMORY)
339 for (int i = 0; i < dinfo->core_id.num_addrspace; i++) {
340 if (dinfo->addrspace[i].sa_rid != rid)
343 *port_type = BHND_PORT_DEVICE;
344 *port_num = siba_addrspace_port(i);
345 *region_num = siba_addrspace_region(i);
354 siba_get_region_addr(device_t dev, device_t child, bhnd_port_type port_type,
355 u_int port_num, u_int region_num, bhnd_addr_t *addr, bhnd_size_t *size)
357 struct siba_devinfo *dinfo;
358 struct siba_addrspace *addrspace;
360 /* delegate non-bus-attached devices to our parent */
361 if (device_get_parent(child) != dev) {
362 return (BHND_BUS_GET_REGION_ADDR(device_get_parent(dev), child,
363 port_type, port_num, region_num, addr, size));
366 dinfo = device_get_ivars(child);
367 addrspace = siba_find_addrspace(dinfo, port_type, port_num, region_num);
368 if (addrspace == NULL)
371 *addr = addrspace->sa_base;
372 *size = addrspace->sa_size - addrspace->sa_bus_reserved;
377 * Default siba(4) bus driver implementation of BHND_BUS_GET_INTR_COUNT().
379 * This implementation consults @p child's configuration block mapping,
380 * returning SIBA_CORE_NUM_INTR if a valid CFG0 block is mapped.
383 siba_get_intr_count(device_t dev, device_t child)
385 struct siba_devinfo *dinfo;
387 /* delegate non-bus-attached devices to our parent */
388 if (device_get_parent(child) != dev)
389 return (BHND_BUS_GET_INTR_COUNT(device_get_parent(dev), child));
391 dinfo = device_get_ivars(child);
393 /* We can get/set interrupt sbflags on any core with a valid cfg0
394 * block; whether the core actually makes use of it is another matter
396 if (dinfo->cfg[0] == NULL)
399 return (SIBA_CORE_NUM_INTR);
403 * Default siba(4) bus driver implementation of BHND_BUS_GET_CORE_IVEC().
405 * This implementation consults @p child's CFG0 register block,
406 * returning the interrupt flag assigned to @p child.
409 siba_get_core_ivec(device_t dev, device_t child, u_int intr, uint32_t *ivec)
411 struct siba_devinfo *dinfo;
414 /* delegate non-bus-attached devices to our parent */
415 if (device_get_parent(child) != dev)
416 return (BHND_BUS_GET_CORE_IVEC(device_get_parent(dev), child,
419 /* Must be a valid interrupt ID */
420 if (intr >= siba_get_intr_count(dev, child))
423 /* Fetch sbflag number */
424 dinfo = device_get_ivars(child);
425 tpsflag = bhnd_bus_read_4(dinfo->cfg[0], SIBA_CFG0_TPSFLAG);
426 *ivec = SIBA_REG_GET(tpsflag, TPS_NUM0);
432 * Register all address space mappings for @p di.
434 * @param dev The siba bus device.
435 * @param di The device info instance on which to register all address
437 * @param r A resource mapping the enumeration table block for @p di.
440 siba_register_addrspaces(device_t dev, struct siba_devinfo *di,
441 struct bhnd_resource *r)
443 struct siba_core_id *cid;
451 /* Register the device address space entries */
452 for (uint8_t i = 0; i < di->core_id.num_addrspace; i++) {
455 uint32_t bus_reserved;
457 /* Determine the register offset */
458 adm_offset = siba_admatch_offset(i);
459 if (adm_offset == 0) {
460 device_printf(dev, "addrspace %hhu is unsupported", i);
464 /* Fetch the address match register value */
465 adm = bhnd_bus_read_4(r, adm_offset);
467 /* Parse the value */
468 if ((error = siba_parse_admatch(adm, &addr, &size))) {
469 device_printf(dev, "failed to decode address "
470 " match register value 0x%x\n", adm);
474 /* If this is the device's core/enumeration addrespace,
475 * reserve the Sonics configuration register blocks for the
478 if (i == SIBA_CORE_ADDRSPACE)
479 bus_reserved = cid->num_cfg_blocks * SIBA_CFG_SIZE;
481 /* Append the region info */
482 error = siba_append_dinfo_region(di, i, addr, size,
492 * Map per-core configuration blocks for @p dinfo.
494 * @param dev The siba bus device.
495 * @param dinfo The device info instance on which to map all per-core
496 * configuration blocks.
499 siba_map_cfg_resources(device_t dev, struct siba_devinfo *dinfo)
501 struct siba_addrspace *addrspace;
502 rman_res_t r_start, r_count, r_end;
505 num_cfg = dinfo->core_id.num_cfg_blocks;
506 if (num_cfg > SIBA_MAX_CFG) {
507 device_printf(dev, "config block count %hhu out of range\n",
512 /* Fetch the core register address space */
513 addrspace = siba_find_addrspace(dinfo, BHND_PORT_DEVICE, 0, 0);
514 if (addrspace == NULL) {
515 device_printf(dev, "missing device registers\n");
520 * Map the per-core configuration blocks
522 for (uint8_t i = 0; i < num_cfg; i++) {
523 /* Determine the config block's address range; configuration
524 * blocks are allocated starting at SIBA_CFG0_OFFSET,
525 * growing downwards. */
526 r_start = addrspace->sa_base + SIBA_CFG0_OFFSET;
527 r_start -= i * SIBA_CFG_SIZE;
529 r_count = SIBA_CFG_SIZE;
530 r_end = r_start + r_count - 1;
532 /* Allocate the config resource */
533 dinfo->cfg_rid[i] = SIBA_CFG_RID(dinfo, i);
534 dinfo->cfg[i] = BHND_BUS_ALLOC_RESOURCE(dev, dev,
535 SYS_RES_MEMORY, &dinfo->cfg_rid[i], r_start, r_end,
538 if (dinfo->cfg[i] == NULL) {
539 device_printf(dev, "failed to allocate SIBA_CFG%hhu\n",
549 static struct bhnd_devinfo *
550 siba_alloc_bhnd_dinfo(device_t dev)
552 struct siba_devinfo *dinfo = siba_alloc_dinfo(dev);
553 return ((struct bhnd_devinfo *)dinfo);
557 siba_free_bhnd_dinfo(device_t dev, struct bhnd_devinfo *dinfo)
559 siba_free_dinfo(dev, (struct siba_devinfo *)dinfo);
563 * Scan the core table and add all valid discovered cores to
566 * @param dev The siba bus device.
569 siba_add_children(device_t dev)
571 const struct bhnd_chipid *chipid;
572 struct bhnd_core_info *cores;
573 struct siba_devinfo *dinfo;
574 struct bhnd_resource *r;
582 chipid = BHND_BUS_GET_CHIPID(dev, dev);
584 /* Allocate our temporary core table and enumerate all cores */
585 cores = malloc(sizeof(*cores) * chipid->ncores, M_BHND, M_NOWAIT);
590 for (u_int i = 0; i < chipid->ncores; i++) {
591 struct siba_core_id cid;
593 uint32_t idhigh, idlow;
594 rman_res_t r_count, r_end, r_start;
597 /* Map the core's register block */
599 r_start = SIBA_CORE_ADDR(i);
600 r_count = SIBA_CORE_SIZE;
601 r_end = r_start + SIBA_CORE_SIZE - 1;
602 r = bhnd_alloc_resource(dev, SYS_RES_MEMORY, &rid, r_start,
603 r_end, r_count, RF_ACTIVE);
609 /* Add the child device */
610 child = BUS_ADD_CHILD(dev, 0, NULL, -1);
616 /* Read the core info */
617 idhigh = bhnd_bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDHIGH));
618 idlow = bhnd_bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDLOW));
620 cid = siba_parse_core_id(idhigh, idlow, i, 0);
621 cores[i] = cid.core_info;
623 /* Determine unit number */
624 for (u_int j = 0; j < i; j++) {
625 if (cores[j].vendor == cores[i].vendor &&
626 cores[j].device == cores[i].device)
630 /* Initialize per-device bus info */
631 if ((dinfo = device_get_ivars(child)) == NULL) {
636 if ((error = siba_init_dinfo(dev, dinfo, &cid)))
639 /* Register the core's address space(s). */
640 if ((error = siba_register_addrspaces(dev, dinfo, r)))
643 /* Release our resource covering the register blocks
644 * we're about to map */
645 bhnd_release_resource(dev, SYS_RES_MEMORY, rid, r);
648 /* Map the core's config blocks */
649 if ((error = siba_map_cfg_resources(dev, dinfo)))
652 /* Assign interrupts */
653 nintr = bhnd_get_intr_count(child);
654 for (int rid = 0; rid < nintr; rid++) {
655 error = BHND_BUS_ASSIGN_INTR(dev, child, rid);
657 device_printf(dev, "failed to assign interrupt "
658 "%d to core %u: %d\n", rid, i, error);
662 /* If pins are floating or the hardware is otherwise
663 * unpopulated, the device shouldn't be used. */
664 if (bhnd_is_hw_disabled(child))
665 device_disable(child);
667 /* Issue bus callback for fully initialized child. */
668 BHND_BUS_CHILD_ADDED(dev, child);
676 bhnd_release_resource(dev, SYS_RES_MEMORY, rid, r);
681 static device_method_t siba_methods[] = {
682 /* Device interface */
683 DEVMETHOD(device_probe, siba_probe),
684 DEVMETHOD(device_attach, siba_attach),
685 DEVMETHOD(device_detach, siba_detach),
686 DEVMETHOD(device_resume, siba_resume),
687 DEVMETHOD(device_suspend, siba_suspend),
690 DEVMETHOD(bus_read_ivar, siba_read_ivar),
691 DEVMETHOD(bus_write_ivar, siba_write_ivar),
692 DEVMETHOD(bus_get_resource_list, siba_get_resource_list),
695 DEVMETHOD(bhnd_bus_get_erom_class, siba_get_erom_class),
696 DEVMETHOD(bhnd_bus_alloc_devinfo, siba_alloc_bhnd_dinfo),
697 DEVMETHOD(bhnd_bus_free_devinfo, siba_free_bhnd_dinfo),
698 DEVMETHOD(bhnd_bus_reset_core, siba_reset_core),
699 DEVMETHOD(bhnd_bus_suspend_core, siba_suspend_core),
700 DEVMETHOD(bhnd_bus_read_config, siba_read_config),
701 DEVMETHOD(bhnd_bus_write_config, siba_write_config),
702 DEVMETHOD(bhnd_bus_get_port_count, siba_get_port_count),
703 DEVMETHOD(bhnd_bus_get_region_count, siba_get_region_count),
704 DEVMETHOD(bhnd_bus_get_port_rid, siba_get_port_rid),
705 DEVMETHOD(bhnd_bus_decode_port_rid, siba_decode_port_rid),
706 DEVMETHOD(bhnd_bus_get_region_addr, siba_get_region_addr),
707 DEVMETHOD(bhnd_bus_get_intr_count, siba_get_intr_count),
708 DEVMETHOD(bhnd_bus_get_core_ivec, siba_get_core_ivec),
713 DEFINE_CLASS_1(bhnd, siba_driver, siba_methods, sizeof(struct siba_softc), bhnd_driver);
715 MODULE_VERSION(siba, 1);
716 MODULE_DEPEND(siba, bhnd, 1, 1, 1);