diff --git a/sys/dev/bhnd/bcma/bcma.c b/sys/dev/bhnd/bcma/bcma.c new file mode 100644 index 000000000000..f1387e747054 --- /dev/null +++ b/sys/dev/bhnd/bcma/bcma.c @@ -0,0 +1,482 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include + +#include "bcmavar.h" + +#include "bcma_eromreg.h" +#include "bcma_eromvar.h" + +int +bcma_probe(device_t dev) +{ + device_set_desc(dev, "BCMA BHND bus"); + return (BUS_PROBE_DEFAULT); +} + +int +bcma_attach(device_t dev) +{ + struct bcma_devinfo *dinfo; + device_t *devs, child; + int ndevs; + int error; + + + if ((error = device_get_children(dev, &devs, &ndevs))) + return (error); + + /* + * Map our children's agent register block. + */ + for (int i = 0; i < ndevs; i++) { + bhnd_addr_t addr; + bhnd_size_t size; + rman_res_t r_start, r_count, r_end; + + child = devs[i]; + dinfo = device_get_ivars(child); + + KASSERT(!device_is_suspended(child), + ("bcma(4) stateful suspend handling requires that devices " + "not be suspended before bcma_attach()")); + + /* Verify that the agent register block exists and is + * mappable */ + if (bhnd_get_port_rid(child, BHND_PORT_AGENT, 0, 0) == -1) + continue; + + /* Fetch the address of the agent register block */ + error = bhnd_get_region_addr(child, BHND_PORT_AGENT, 0, 0, + &addr, &size); + if (error) { + device_printf(dev, "failed fetching agent register " + "block address for core %d\n", i); + goto cleanup; + } + + /* Allocate the resource */ + r_start = addr; + r_count = size; + r_end = r_start + r_count - 1; + + dinfo->rid_agent = 0; + dinfo->res_agent = bhnd_alloc_resource(dev, SYS_RES_MEMORY, + &dinfo->rid_agent, r_start, r_end, r_count, RF_ACTIVE); + if (dinfo->res_agent == NULL) { + device_printf(dev, "failed allocating agent register " + "block for core %d\n", i); + error = ENXIO; + goto cleanup; + } + } + +cleanup: + free(devs, M_BHND); + if (error) + return (error); + + return (bhnd_generic_attach(dev)); +} + +int +bcma_detach(device_t dev) +{ + return (bhnd_generic_detach(dev)); +} + +static int +bcma_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) +{ + const struct bcma_devinfo *dinfo; + const struct bhnd_core_info *ci; + + dinfo = device_get_ivars(child); + ci = &dinfo->corecfg->core_info; + + switch (index) { + case BHND_IVAR_VENDOR: + *result = ci->vendor; + return (0); + case BHND_IVAR_DEVICE: + *result = ci->device; + return (0); + case BHND_IVAR_HWREV: + *result = ci->hwrev; + return (0); + case BHND_IVAR_DEVICE_CLASS: + *result = bhnd_core_class(ci); + return (0); + case BHND_IVAR_VENDOR_NAME: + *result = (uintptr_t) bhnd_vendor_name(ci->vendor); + return (0); + case BHND_IVAR_DEVICE_NAME: + *result = (uintptr_t) bhnd_core_name(ci); + return (0); + case BHND_IVAR_CORE_INDEX: + *result = ci->core_idx; + return (0); + case BHND_IVAR_CORE_UNIT: + *result = ci->unit; + return (0); + default: + return (ENOENT); + } +} + +static int +bcma_write_ivar(device_t dev, device_t child, int index, uintptr_t value) +{ + switch (index) { + case BHND_IVAR_VENDOR: + case BHND_IVAR_DEVICE: + case BHND_IVAR_HWREV: + case BHND_IVAR_DEVICE_CLASS: + case BHND_IVAR_VENDOR_NAME: + case BHND_IVAR_DEVICE_NAME: + case BHND_IVAR_CORE_INDEX: + case BHND_IVAR_CORE_UNIT: + return (EINVAL); + default: + return (ENOENT); + } +} + +static void +bcma_child_deleted(device_t dev, device_t child) +{ + struct bcma_devinfo *dinfo = device_get_ivars(child); + if (dinfo != NULL) + bcma_free_dinfo(dev, dinfo); +} + +static struct resource_list * +bcma_get_resource_list(device_t dev, device_t child) +{ + struct bcma_devinfo *dinfo = device_get_ivars(child); + return (&dinfo->resources); +} + + +static int +bcma_reset_core(device_t dev, device_t child, uint16_t flags) +{ + struct bcma_devinfo *dinfo; + + if (device_get_parent(child) != dev) + BHND_BUS_RESET_CORE(device_get_parent(dev), child, flags); + + dinfo = device_get_ivars(child); + + /* Can't reset the core without access to the agent registers */ + if (dinfo->res_agent == NULL) + return (ENODEV); + + // TODO - perform reset + + return (ENXIO); +} + +static int +bcma_suspend_core(device_t dev, device_t child) +{ + struct bcma_devinfo *dinfo; + + if (device_get_parent(child) != dev) + BHND_BUS_SUSPEND_CORE(device_get_parent(dev), child); + + dinfo = device_get_ivars(child); + + /* Can't suspend the core without access to the agent registers */ + if (dinfo->res_agent == NULL) + return (ENODEV); + + // TODO - perform suspend + + return (ENXIO); +} + +static u_int +bcma_get_port_count(device_t dev, device_t child, bhnd_port_type type) +{ + struct bcma_devinfo *dinfo; + + /* delegate non-bus-attached devices to our parent */ + if (device_get_parent(child) != dev) + return (BHND_BUS_GET_PORT_COUNT(device_get_parent(dev), child, + type)); + + dinfo = device_get_ivars(child); + switch (type) { + case BHND_PORT_DEVICE: + return (dinfo->corecfg->num_dev_ports); + case BHND_PORT_BRIDGE: + return (dinfo->corecfg->num_bridge_ports); + case BHND_PORT_AGENT: + return (dinfo->corecfg->num_wrapper_ports); + } +} + +static u_int +bcma_get_region_count(device_t dev, device_t child, bhnd_port_type type, + u_int port_num) +{ + struct bcma_devinfo *dinfo; + struct bcma_sport_list *ports; + struct bcma_sport *port; + + /* delegate non-bus-attached devices to our parent */ + if (device_get_parent(child) != dev) + return (BHND_BUS_GET_REGION_COUNT(device_get_parent(dev), child, + type, port_num)); + + dinfo = device_get_ivars(child); + ports = bcma_corecfg_get_port_list(dinfo->corecfg, type); + + STAILQ_FOREACH(port, ports, sp_link) { + if (port->sp_num == port_num) + return (port->sp_num_maps); + } + + /* not found */ + return (0); +} + +static int +bcma_get_port_rid(device_t dev, device_t child, bhnd_port_type port_type, + u_int port_num, u_int region_num) +{ + struct bcma_devinfo *dinfo; + struct bcma_map *map; + struct bcma_sport_list *ports; + struct bcma_sport *port; + + dinfo = device_get_ivars(child); + ports = bcma_corecfg_get_port_list(dinfo->corecfg, port_type); + + STAILQ_FOREACH(port, ports, sp_link) { + if (port->sp_num != port_num) + continue; + + STAILQ_FOREACH(map, &port->sp_maps, m_link) + if (map->m_region_num == region_num) + return map->m_rid; + } + + return -1; +} + +static int +bcma_decode_port_rid(device_t dev, device_t child, int type, int rid, + bhnd_port_type *port_type, u_int *port_num, u_int *region_num) +{ + struct bcma_devinfo *dinfo; + struct bcma_map *map; + struct bcma_sport_list *ports; + struct bcma_sport *port; + + dinfo = device_get_ivars(child); + + /* Ports are always memory mapped */ + if (type != SYS_RES_MEMORY) + return (EINVAL); + + /* Starting with the most likely device list, search all three port + * lists */ + bhnd_port_type types[] = { + BHND_PORT_DEVICE, + BHND_PORT_AGENT, + BHND_PORT_BRIDGE + }; + + for (int i = 0; i < nitems(types); i++) { + ports = bcma_corecfg_get_port_list(dinfo->corecfg, types[i]); + + STAILQ_FOREACH(port, ports, sp_link) { + STAILQ_FOREACH(map, &port->sp_maps, m_link) { + if (map->m_rid != rid) + continue; + + *port_type = port->sp_type; + *port_num = port->sp_num; + *region_num = map->m_region_num; + return (0); + } + } + } + + return (ENOENT); +} + +static int +bcma_get_region_addr(device_t dev, device_t child, bhnd_port_type port_type, + u_int port_num, u_int region_num, bhnd_addr_t *addr, bhnd_size_t *size) +{ + struct bcma_devinfo *dinfo; + struct bcma_map *map; + struct bcma_sport_list *ports; + struct bcma_sport *port; + + dinfo = device_get_ivars(child); + ports = bcma_corecfg_get_port_list(dinfo->corecfg, port_type); + + /* Search the port list */ + STAILQ_FOREACH(port, ports, sp_link) { + if (port->sp_num != port_num) + continue; + + STAILQ_FOREACH(map, &port->sp_maps, m_link) { + if (map->m_region_num != region_num) + continue; + + /* Found! */ + *addr = map->m_base; + *size = map->m_size; + return (0); + } + } + + return (ENOENT); +} + +/** + * Scan a device enumeration ROM table, adding all valid discovered cores to + * the bus. + * + * @param bus The bcma bus. + * @param erom_res An active resource mapping the EROM core. + * @param erom_offset Base offset of the EROM core's register mapping. + */ +int +bcma_add_children(device_t bus, struct resource *erom_res, bus_size_t erom_offset) +{ + struct bcma_erom erom; + struct bcma_corecfg *corecfg; + struct bcma_devinfo *dinfo; + device_t child; + int error; + + dinfo = NULL; + corecfg = NULL; + + /* Initialize our reader */ + error = bcma_erom_open(&erom, erom_res, erom_offset); + if (error) + return (error); + + /* Add all cores. */ + while (!error) { + /* Parse next core */ + error = bcma_erom_parse_corecfg(&erom, &corecfg); + if (error && error == ENOENT) { + return (0); + } else if (error) { + goto failed; + } + + /* Allocate per-device bus info */ + dinfo = bcma_alloc_dinfo(bus, corecfg); + if (dinfo == NULL) { + error = ENXIO; + goto failed; + } + + /* The dinfo instance now owns the corecfg value */ + corecfg = NULL; + + /* Add the child device */ + child = device_add_child(bus, NULL, -1); + if (child == NULL) { + error = ENXIO; + goto failed; + } + + /* The child device now owns the dinfo pointer */ + device_set_ivars(child, dinfo); + dinfo = NULL; + + /* If pins are floating or the hardware is otherwise + * unpopulated, the device shouldn't be used. */ + if (bhnd_is_hw_disabled(child)) + device_disable(child); + } + + /* Hit EOF parsing cores? */ + if (error == ENOENT) + return (0); + +failed: + if (dinfo != NULL) + bcma_free_dinfo(bus, dinfo); + + if (corecfg != NULL) + bcma_free_corecfg(corecfg); + + return (error); +} + + +static device_method_t bcma_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, bcma_probe), + DEVMETHOD(device_attach, bcma_attach), + DEVMETHOD(device_detach, bcma_detach), + + /* Bus interface */ + DEVMETHOD(bus_child_deleted, bcma_child_deleted), + DEVMETHOD(bus_read_ivar, bcma_read_ivar), + DEVMETHOD(bus_write_ivar, bcma_write_ivar), + DEVMETHOD(bus_get_resource_list, bcma_get_resource_list), + + /* BHND interface */ + DEVMETHOD(bhnd_bus_reset_core, bcma_reset_core), + DEVMETHOD(bhnd_bus_suspend_core, bcma_suspend_core), + DEVMETHOD(bhnd_bus_get_port_count, bcma_get_port_count), + DEVMETHOD(bhnd_bus_get_region_count, bcma_get_region_count), + DEVMETHOD(bhnd_bus_get_port_rid, bcma_get_port_rid), + DEVMETHOD(bhnd_bus_decode_port_rid, bcma_decode_port_rid), + DEVMETHOD(bhnd_bus_get_region_addr, bcma_get_region_addr), + + DEVMETHOD_END +}; + +DEFINE_CLASS_1(bhnd, bcma_driver, bcma_methods, sizeof(struct bcma_softc), bhnd_driver); +MODULE_VERSION(bcma, 1); +MODULE_DEPEND(bcma, bhnd, 1, 1, 1); diff --git a/sys/dev/bhnd/bcma/bcma.h b/sys/dev/bhnd/bcma/bcma.h new file mode 100644 index 000000000000..cd18b5883301 --- /dev/null +++ b/sys/dev/bhnd/bcma/bcma.h @@ -0,0 +1,49 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $FreeBSD$ + */ + +#ifndef _BCMA_BCMA_H_ +#define _BCMA_BCMA_H_ + +#include +#include +#include +#include +#include + +#include + +/* + * Broadcom AMBA backplane types and data structures. + */ + +DECLARE_CLASS(bcma_driver); + +#endif /* _BCMA_BCMA_H_ */ \ No newline at end of file diff --git a/sys/dev/bhnd/bcma/bcma_bhndb.c b/sys/dev/bhnd/bcma/bcma_bhndb.c new file mode 100644 index 000000000000..bb617b0ee578 --- /dev/null +++ b/sys/dev/bhnd/bcma/bcma_bhndb.c @@ -0,0 +1,183 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include +#include +#include + +#include "bcmavar.h" + +#include "bcma_eromreg.h" +#include "bcma_eromvar.h" + +/* + * Supports attachment of bcma(4) bus devices via a bhndb bridge. + */ + +static int +bcma_bhndb_probe(device_t dev) +{ + const struct bhnd_chipid *cid; + + /* Check bus type */ + cid = BHNDB_GET_CHIPID(device_get_parent(dev), dev); + if (cid->chip_type != BHND_CHIPTYPE_BCMA) + return (ENXIO); + + /* Delegate to default probe implementation */ + return (bcma_probe(dev)); +} + +static int +bcma_bhndb_attach(device_t dev) +{ + const struct bhnd_chipid *cid; + struct resource *erom_res; + int error; + int rid; + + cid = BHNDB_GET_CHIPID(device_get_parent(dev), dev); + + /* Map the EROM resource and enumerate our children. */ + rid = 0; + erom_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, cid->enum_addr, + cid->enum_addr + BCMA_EROM_TABLE_SIZE, BCMA_EROM_TABLE_SIZE, + RF_ACTIVE); + if (erom_res == NULL) { + device_printf(dev, "failed to allocate EROM resource\n"); + return (ENXIO); + } + + error = bcma_add_children(dev, erom_res, BCMA_EROM_TABLE_START); + + /* Clean up */ + bus_release_resource(dev, SYS_RES_MEMORY, rid, erom_res); + if (error) + return (error); + + /* Initialize full bridge configuration */ + error = BHNDB_INIT_FULL_CONFIG(device_get_parent(dev), dev, + bhndb_bcma_priority_table); + if (error) + return (error); + + /* Call our superclass' implementation */ + return (bcma_attach(dev)); +} + +static int +bcma_bhndb_suspend_child(device_t dev, device_t child) +{ + struct bcma_devinfo *dinfo; + int error; + + if (device_get_parent(child) != dev) + BUS_SUSPEND_CHILD(device_get_parent(dev), child); + + if (device_is_suspended(child)) + return (EBUSY); + + dinfo = device_get_ivars(child); + + /* Suspend the child */ + if ((error = bhnd_generic_br_suspend_child(dev, child))) + return (error); + + /* Suspend child's agent resource */ + if (dinfo->res_agent != NULL) + BHNDB_SUSPEND_RESOURCE(device_get_parent(dev), dev, + SYS_RES_MEMORY, dinfo->res_agent->res); + + return (0); +} + +static int +bcma_bhndb_resume_child(device_t dev, device_t child) +{ + struct bcma_devinfo *dinfo; + int error; + + if (device_get_parent(child) != dev) + BUS_SUSPEND_CHILD(device_get_parent(dev), child); + + if (!device_is_suspended(child)) + return (EBUSY); + + dinfo = device_get_ivars(child); + + /* Resume child's agent resource */ + if (dinfo->res_agent != NULL) { + error = BHNDB_RESUME_RESOURCE(device_get_parent(dev), dev, + SYS_RES_MEMORY, dinfo->res_agent->res); + if (error) + return (error); + } + + /* Resume the child */ + if ((error = bhnd_generic_br_resume_child(dev, child))) { + /* On failure, re-suspend the agent resource */ + if (dinfo->res_agent != NULL) { + BHNDB_SUSPEND_RESOURCE(device_get_parent(dev), dev, + SYS_RES_MEMORY, dinfo->res_agent->res); + } + + return (error); + } + + return (0); +} + +static device_method_t bcma_bhndb_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, bcma_bhndb_probe), + DEVMETHOD(device_attach, bcma_bhndb_attach), + + /* Bus interface */ + DEVMETHOD(bus_suspend_child, bcma_bhndb_suspend_child), + DEVMETHOD(bus_resume_child, bcma_bhndb_resume_child), + + DEVMETHOD_END +}; + +DEFINE_CLASS_1(bhnd, bcma_bhndb_driver, bcma_bhndb_methods, + sizeof(struct bcma_softc), bcma_driver); + +DRIVER_MODULE(bcma_bhndb, bhndb, bcma_bhndb_driver, bhnd_devclass, NULL, NULL); + +MODULE_VERSION(bcma_bhndb, 1); +MODULE_DEPEND(bcma_bhndb, bcma, 1, 1, 1); +MODULE_DEPEND(bcma_bhndb, bhndb, 1, 1, 1); diff --git a/sys/dev/bhnd/bcma/bcma_dmp.h b/sys/dev/bhnd/bcma/bcma_dmp.h new file mode 100644 index 000000000000..4be5a8ebe8b4 --- /dev/null +++ b/sys/dev/bhnd/bcma/bcma_dmp.h @@ -0,0 +1,193 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * Copyright (c) 2010 Broadcom Corporation + * + * Portions of this file were derived from the aidmp.h header + * distributed with Broadcom's initial brcm80211 Linux driver release, as + * contributed to the Linux staging repository. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef _BCMA_BCMA_DMP_H_ +#define _BCMA_BCMA_DMP_H_ + +/* + * PL-368 Device Management Plugin (DMP) Registers & Constants + * + * The "DMP" core used in Broadcom HND devices has been described + * by Broadcom engineers (and in published header files) as being + * ARM's PL-368 "Device Management Plugin" system IP, included with + * the CoreLink AMBA Designer tooling. + * + * Documentation for the PL-368 is not publicly available, however, + * and the only public reference by ARM to its existence appears to be + * in the proprietary "NIC-301 Interconnect Device Management (PL368)" + * errata publication, available to licensees as part of ARM's + * CoreLink Controllers and Peripherals Engineering Errata. + */ + +/* Out-of-band Router registers */ +#define BCMA_OOB_BUSCONFIG 0x020 +#define BCMA_OOB_STATUSA 0x100 +#define BCMA_OOB_STATUSB 0x104 +#define BCMA_OOB_STATUSC 0x108 +#define BCMA_OOB_STATUSD 0x10c +#define BCMA_OOB_ENABLEA0 0x200 +#define BCMA_OOB_ENABLEA1 0x204 +#define BCMA_OOB_ENABLEA2 0x208 +#define BCMA_OOB_ENABLEA3 0x20c +#define BCMA_OOB_ENABLEB0 0x280 +#define BCMA_OOB_ENABLEB1 0x284 +#define BCMA_OOB_ENABLEB2 0x288 +#define BCMA_OOB_ENABLEB3 0x28c +#define BCMA_OOB_ENABLEC0 0x300 +#define BCMA_OOB_ENABLEC1 0x304 +#define BCMA_OOB_ENABLEC2 0x308 +#define BCMA_OOB_ENABLEC3 0x30c +#define BCMA_OOB_ENABLED0 0x380 +#define BCMA_OOB_ENABLED1 0x384 +#define BCMA_OOB_ENABLED2 0x388 +#define BCMA_OOB_ENABLED3 0x38c +#define BCMA_OOB_ITCR 0xf00 +#define BCMA_OOB_ITIPOOBA 0xf10 +#define BCMA_OOB_ITIPOOBB 0xf14 +#define BCMA_OOB_ITIPOOBC 0xf18 +#define BCMA_OOB_ITIPOOBD 0xf1c +#define BCMA_OOB_ITOPOOBA 0xf30 +#define BCMA_OOB_ITOPOOBB 0xf34 +#define BCMA_OOB_ITOPOOBC 0xf38 +#define BCMA_OOB_ITOPOOBD 0xf3c + +/* DMP wrapper registers */ +#define BCMA_DMP_OOBSELINA30 0x000 +#define BCMA_DMP_OOBSELINA74 0x004 +#define BCMA_DMP_OOBSELINB30 0x020 +#define BCMA_DMP_OOBSELINB74 0x024 +#define BCMA_DMP_OOBSELINC30 0x040 +#define BCMA_DMP_OOBSELINC74 0x044 +#define BCMA_DMP_OOBSELIND30 0x060 +#define BCMA_DMP_OOBSELIND74 0x064 +#define BCMA_DMP_OOBSELOUTA30 0x100 +#define BCMA_DMP_OOBSELOUTA74 0x104 +#define BCMA_DMP_OOBSELOUTB30 0x120 +#define BCMA_DMP_OOBSELOUTB74 0x124 +#define BCMA_DMP_OOBSELOUTC30 0x140 +#define BCMA_DMP_OOBSELOUTC74 0x144 +#define BCMA_DMP_OOBSELOUTD30 0x160 +#define BCMA_DMP_OOBSELOUTD74 0x164 +#define BCMA_DMP_OOBSYNCA 0x200 +#define BCMA_DMP_OOBSELOUTAEN 0x204 +#define BCMA_DMP_OOBSYNCB 0x220 +#define BCMA_DMP_OOBSELOUTBEN 0x224 +#define BCMA_DMP_OOBSYNCC 0x240 +#define BCMA_DMP_OOBSELOUTCEN 0x244 +#define BCMA_DMP_OOBSYNCD 0x260 +#define BCMA_DMP_OOBSELOUTDEN 0x264 +#define BCMA_DMP_OOBAEXTWIDTH 0x300 +#define BCMA_DMP_OOBAINWIDTH 0x304 +#define BCMA_DMP_OOBAOUTWIDTH 0x308 +#define BCMA_DMP_OOBBEXTWIDTH 0x320 +#define BCMA_DMP_OOBBINWIDTH 0x324 +#define BCMA_DMP_OOBBOUTWIDTH 0x328 +#define BCMA_DMP_OOBCEXTWIDTH 0x340 +#define BCMA_DMP_OOBCINWIDTH 0x344 +#define BCMA_DMP_OOBCOUTWIDTH 0x348 +#define BCMA_DMP_OOBDEXTWIDTH 0x360 +#define BCMA_DMP_OOBDINWIDTH 0x364 +#define BCMA_DMP_OOBDOUTWIDTH 0x368 + +// This was inherited from Broadcom's aidmp.h header +// Is it required for any of our use-cases? +#if 0 /* defined(IL_BIGENDIAN) && defined(BCMHND74K) */ +/* Selective swapped defines for those registers we need in + * big-endian code. + */ +#define BCMA_DMP_IOCTRLSET 0x404 +#define BCMA_DMP_IOCTRLCLEAR 0x400 +#define BCMA_DMP_IOCTRL 0x40c +#define BCMA_DMP_IOSTATUS 0x504 +#define BCMA_DMP_RESETCTRL 0x804 +#define BCMA_DMP_RESETSTATUS 0x800 + +#else /* !IL_BIGENDIAN || !BCMHND74K */ + +#define BCMA_DMP_IOCTRLSET 0x400 +#define BCMA_DMP_IOCTRLCLEAR 0x404 +#define BCMA_DMP_IOCTRL 0x408 +#define BCMA_DMP_IOSTATUS 0x500 +#define BCMA_DMP_RESETCTRL 0x800 +#define BCMA_DMP_RESETSTATUS 0x804 + +#endif /* IL_BIGENDIAN && BCMHND74K */ + +#define BCMA_DMP_IOCTRLWIDTH 0x700 +#define BCMA_DMP_IOSTATUSWIDTH 0x704 + +#define BCMA_DMP_RESETREADID 0x808 +#define BCMA_DMP_RESETWRITEID 0x80c +#define BCMA_DMP_ERRLOGCTRL 0xa00 +#define BCMA_DMP_ERRLOGDONE 0xa04 +#define BCMA_DMP_ERRLOGSTATUS 0xa08 +#define BCMA_DMP_ERRLOGADDRLO 0xa0c +#define BCMA_DMP_ERRLOGADDRHI 0xa10 +#define BCMA_DMP_ERRLOGID 0xa14 +#define BCMA_DMP_ERRLOGUSER 0xa18 +#define BCMA_DMP_ERRLOGFLAGS 0xa1c +#define BCMA_DMP_INTSTATUS 0xa00 +#define BCMA_DMP_CONFIG 0xe00 +#define BCMA_DMP_ITCR 0xf00 +#define BCMA_DMP_ITIPOOBA 0xf10 +#define BCMA_DMP_ITIPOOBB 0xf14 +#define BCMA_DMP_ITIPOOBC 0xf18 +#define BCMA_DMP_ITIPOOBD 0xf1c +#define BCMA_DMP_ITIPOOBAOUT 0xf30 +#define BCMA_DMP_ITIPOOBBOUT 0xf34 +#define BCMA_DMP_ITIPOOBCOUT 0xf38 +#define BCMA_DMP_ITIPOOBDOUT 0xf3c +#define BCMA_DMP_ITOPOOBA 0xf50 +#define BCMA_DMP_ITOPOOBB 0xf54 +#define BCMA_DMP_ITOPOOBC 0xf58 +#define BCMA_DMP_ITOPOOBD 0xf5c +#define BCMA_DMP_ITOPOOBAIN 0xf70 +#define BCMA_DMP_ITOPOOBBIN 0xf74 +#define BCMA_DMP_ITOPOOBCIN 0xf78 +#define BCMA_DMP_ITOPOOBDIN 0xf7c +#define BCMA_DMP_ITOPRESET 0xf90 +#define BCMA_DMP_PERIPHERIALID4 0xfd0 +#define BCMA_DMP_PERIPHERIALID5 0xfd4 +#define BCMA_DMP_PERIPHERIALID6 0xfd8 +#define BCMA_DMP_PERIPHERIALID7 0xfdc +#define BCMA_DMP_PERIPHERIALID0 0xfe0 +#define BCMA_DMP_PERIPHERIALID1 0xfe4 +#define BCMA_DMP_PERIPHERIALID2 0xfe8 +#define BCMA_DMP_PERIPHERIALID3 0xfec +#define BCMA_DMP_COMPONENTID0 0xff0 +#define BCMA_DMP_COMPONENTID1 0xff4 +#define BCMA_DMP_COMPONENTID2 0xff8 +#define BCMA_DMP_COMPONENTID3 0xffc + +/* resetctrl */ +#define BMCA_DMP_RC_RESET 1 + +/* config */ +#define BCMA_DMP_CFG_OOB 0x00000020 +#define BCMA_DMP_CFG_IOS 0x00000010 +#define BCMA_DMP_CFGIOC 0x00000008 +#define BCMA_DMP_CFGTO 0x00000004 +#define BCMA_DMP_CFGERRL 0x00000002 +#define BCMA_DMP_CFGRST 0x00000001 + +#endif /* _BCMA_BCMA_DMP_H_ */ diff --git a/sys/dev/bhnd/bcma/bcma_erom.c b/sys/dev/bhnd/bcma/bcma_erom.c new file mode 100644 index 000000000000..2fd327503a86 --- /dev/null +++ b/sys/dev/bhnd/bcma/bcma_erom.c @@ -0,0 +1,897 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include +#include + +#include "bcma_eromreg.h" +#include "bcma_eromvar.h" + +/* + * BCMA Enumeration ROM (EROM) Table + * + * Provides auto-discovery of BCMA cores on Broadcom's HND SoC. + * + * The EROM core address can be found at BCMA_CC_EROM_ADDR within the + * ChipCommon registers. The table itself is comprised of 32-bit + * type-tagged entries, organized into an array of variable-length + * core descriptor records. + * + * The final core descriptor is followed by a 32-bit BCMA_EROM_TABLE_EOF (0xF) + * marker. + */ + +static const char *erom_entry_type_name (uint8_t entry); +static int erom_read32(struct bcma_erom *erom, uint32_t *entry); +static int erom_skip32(struct bcma_erom *erom); + +static int erom_skip_core(struct bcma_erom *erom); +static int erom_skip_mport(struct bcma_erom *erom); +static int erom_skip_sport_region(struct bcma_erom *erom); + +static int erom_seek_next(struct bcma_erom *erom, uint8_t etype); + +#define EROM_LOG(erom, fmt, ...) \ + device_printf(erom->dev, "erom[0x%llx]: " fmt, \ + (unsigned long long) (erom->offset), ##__VA_ARGS__); + +/** + * Open an EROM table for reading. + * + * @param[out] erom On success, will be populated with a valid EROM + * read state. + * @param r An active resource mapping the EROM core. + * @param offset Offset of the EROM core within @p resource. + * + * @retval 0 success + * @retval non-zero if the erom table could not be opened. + */ +int +bcma_erom_open(struct bcma_erom *erom, struct resource *r, bus_size_t offset) +{ + /* Initialize the EROM reader */ + erom->dev = rman_get_device(r); + erom->r = r; + erom->start = offset + BCMA_EROM_TABLE_START; + erom->offset = 0; + + return (0); +} + +/** Return the type name for an EROM entry */ +static const char * +erom_entry_type_name (uint8_t entry) +{ + switch (BCMA_EROM_GET_ATTR(entry, ENTRY_TYPE)) { + case BCMA_EROM_ENTRY_TYPE_CORE: + return "core"; + case BCMA_EROM_ENTRY_TYPE_MPORT: + return "mport"; + case BCMA_EROM_ENTRY_TYPE_REGION: + return "region"; + default: + return "unknown"; + } +} + +/** + * Return the current read position. + */ +bus_size_t +bcma_erom_tell(struct bcma_erom *erom) +{ + return (erom->offset); +} + +/** + * Seek to an absolute read position. + */ +void +bcma_erom_seek(struct bcma_erom *erom, bus_size_t offset) +{ + erom->offset = offset; +} + +/** + * Read a 32-bit entry value from the EROM table without advancing the + * read position. + * + * @param erom EROM read state. + * @param entry Will contain the read result on success. + * @retval 0 success + * @retval ENOENT The end of the EROM table was reached. + * @retval non-zero The read could not be completed. + */ +int +bcma_erom_peek32(struct bcma_erom *erom, uint32_t *entry) +{ + if (erom->offset >= BCMA_EROM_TABLE_SIZE) { + EROM_LOG(erom, "BCMA EROM table missing terminating EOF\n"); + return (EINVAL); + } + + *entry = bus_read_4(erom->r, erom->start + erom->offset); + return (0); +} + +/** + * Read a 32-bit entry value from the EROM table. + * + * @param erom EROM read state. + * @param entry Will contain the read result on success. + * @retval 0 success + * @retval ENOENT The end of the EROM table was reached. + * @retval non-zero The read could not be completed. + */ +static int +erom_read32(struct bcma_erom *erom, uint32_t *entry) +{ + int error; + + if ((error = bcma_erom_peek32(erom, entry)) == 0) + erom->offset += 4; + + return (error); +} + +/** + * Read and discard 32-bit entry value from the EROM table. + * + * @param erom EROM read state. + * @retval 0 success + * @retval ENOENT The end of the EROM table was reached. + * @retval non-zero The read could not be completed. + */ +static int +erom_skip32(struct bcma_erom *erom) +{ + uint32_t entry; + + return erom_read32(erom, &entry); +} + +/** + * Read and discard a core descriptor from the EROM table. + * + * @param erom EROM read state. + * @retval 0 success + * @retval ENOENT The end of the EROM table was reached. + * @retval non-zero The read could not be completed. + */ +static int +erom_skip_core(struct bcma_erom *erom) +{ + struct bcma_erom_core core; + return (bcma_erom_parse_core(erom, &core)); +} + +/** + * Read and discard a master port descriptor from the EROM table. + * + * @param erom EROM read state. + * @retval 0 success + * @retval ENOENT The end of the EROM table was reached. + * @retval non-zero The read could not be completed. + */ +static int +erom_skip_mport(struct bcma_erom *erom) +{ + struct bcma_erom_mport mp; + return (bcma_erom_parse_mport(erom, &mp)); +} + +/** + * Read and discard a port region descriptor from the EROM table. + * + * @param erom EROM read state. + * @retval 0 success + * @retval ENOENT The end of the EROM table was reached. + * @retval non-zero The read could not be completed. + */ +static int +erom_skip_sport_region(struct bcma_erom *erom) +{ + struct bcma_erom_sport_region r; + return (bcma_erom_parse_sport_region(erom, &r)); +} + +/** + * Seek to the next entry matching the given EROM entry type. + * + * @param erom EROM read state. + * @param etype One of BCMA_EROM_ENTRY_TYPE_CORE, + * BCMA_EROM_ENTRY_TYPE_MPORT, or BCMA_EROM_ENTRY_TYPE_REGION. + * @retval 0 success + * @retval ENOENT The end of the EROM table was reached. + * @retval non-zero Reading or parsing the descriptor failed. + */ +static int +erom_seek_next(struct bcma_erom *erom, uint8_t etype) +{ + uint32_t entry; + int error; + + /* Iterate until we hit an entry matching the requested type. */ + while (!(error = bcma_erom_peek32(erom, &entry))) { + /* Handle EOF */ + if (entry == BCMA_EROM_TABLE_EOF) + return (ENOENT); + + /* Invalid entry */ + if (!BCMA_EROM_GET_ATTR(entry, ENTRY_ISVALID)) + return (EINVAL); + + /* Entry type matches? */ + if (BCMA_EROM_GET_ATTR(entry, ENTRY_TYPE) == etype) + return (0); + + /* Skip non-matching entry types. */ + switch (BCMA_EROM_GET_ATTR(entry, ENTRY_TYPE)) { + case BCMA_EROM_ENTRY_TYPE_CORE: + if ((error = erom_skip_core(erom))) + return (error); + + break; + + case BCMA_EROM_ENTRY_TYPE_MPORT: + if ((error = erom_skip_mport(erom))) + return (error); + + break; + + case BCMA_EROM_ENTRY_TYPE_REGION: + if ((error = erom_skip_sport_region(erom))) + return (error); + break; + + default: + /* Unknown entry type! */ + return (EINVAL); + } + } + + return (error); +} + +/** + * Return the read position to the start of the EROM table. + * + * @param erom EROM read state. + */ +void +bcma_erom_reset(struct bcma_erom *erom) +{ + erom->offset = 0; +} + +/** + * Seek to the requested core entry. + * + * @param erom EROM read state. + * @param core_index Index of the core to seek to. + * @retval 0 success + * @retval ENOENT The end of the EROM table was reached before @p index was + * found. + * @retval non-zero Reading or parsing failed. + */ +int +bcma_erom_seek_core_index(struct bcma_erom *erom, u_int core_index) +{ + int error; + + /* Start search at top of EROM */ + bcma_erom_reset(erom); + + /* Skip core descriptors till we hit the requested entry */ + for (u_int i = 0; i < core_index; i++) { + struct bcma_erom_core core; + + /* Read past the core descriptor */ + if ((error = bcma_erom_parse_core(erom, &core))) + return (error); + + /* Seek to the next readable core entry */ + error = erom_seek_next(erom, BCMA_EROM_ENTRY_TYPE_CORE); + if (error) + return (error); + } + + return (0); +} + + +/** + * Read the next core descriptor from the EROM table. + * + * @param erom EROM read state. + * @param[out] core On success, will be populated with the parsed core + * descriptor data. + * @retval 0 success + * @retval ENOENT The end of the EROM table was reached. + * @retval non-zero Reading or parsing the core descriptor failed. + */ +int +bcma_erom_parse_core(struct bcma_erom *erom, struct bcma_erom_core *core) +{ + uint32_t entry; + int error; + + /* Parse CoreDescA */ + if ((error = erom_read32(erom, &entry))) + return (error); + + /* Handle EOF */ + if (entry == BCMA_EROM_TABLE_EOF) + return (ENOENT); + + if (!BCMA_EROM_ENTRY_IS(entry, CORE)) { + EROM_LOG(erom, "Unexpected EROM entry 0x%x (type=%s)\n", + entry, erom_entry_type_name(entry)); + + return (EINVAL); + } + + core->vendor = BCMA_EROM_GET_ATTR(entry, COREA_DESIGNER); + core->device = BCMA_EROM_GET_ATTR(entry, COREA_ID); + + /* Parse CoreDescB */ + if ((error = erom_read32(erom, &entry))) + return (error); + + if (!BCMA_EROM_ENTRY_IS(entry, CORE)) { + return (EINVAL); + } + + core->rev = BCMA_EROM_GET_ATTR(entry, COREB_REV); + core->num_mport = BCMA_EROM_GET_ATTR(entry, COREB_NUM_MP); + core->num_dport = BCMA_EROM_GET_ATTR(entry, COREB_NUM_DP); + core->num_mwrap = BCMA_EROM_GET_ATTR(entry, COREB_NUM_WMP); + core->num_swrap = BCMA_EROM_GET_ATTR(entry, COREB_NUM_WSP); + + return (0); +} + +/** + * Read the next master port descriptor from the EROM table. + * + * @param erom EROM read state. + * @param[out] mport On success, will be populated with the parsed + * descriptor data. + * @retval 0 success + * @retval non-zero Reading or parsing the descriptor failed. + */ +int +bcma_erom_parse_mport(struct bcma_erom *erom, + struct bcma_erom_mport *mport) +{ + uint32_t entry; + int error; + + /* Parse the master port descriptor */ + if ((error = erom_read32(erom, &entry))) + return (error); + + if (!BCMA_EROM_ENTRY_IS(entry, MPORT)) + return (EINVAL); + + mport->port_vid = BCMA_EROM_GET_ATTR(entry, MPORT_ID); + mport->port_num = BCMA_EROM_GET_ATTR(entry, MPORT_NUM); + + return (0); +} + +/** + * Read the next slave port region descriptor from the EROM table. + * + * @param erom EROM read state. + * @param[out] mport On success, will be populated with the parsed + * descriptor data. + * @retval 0 success + * @retval ENOENT The end of the region descriptor table was reached. + * @retval non-zero Reading or parsing the descriptor failed. + */ +int +bcma_erom_parse_sport_region(struct bcma_erom *erom, + struct bcma_erom_sport_region *region) +{ + uint32_t entry; + uint8_t size_type; + int error; + + /* Peek at the region descriptor */ + if (bcma_erom_peek32(erom, &entry)) + return (EINVAL); + + /* A non-region entry signals the end of the region table */ + if (!BCMA_EROM_ENTRY_IS(entry, REGION)) { + return (ENOENT); + } else { + erom_skip32(erom); + } + + region->base_addr = BCMA_EROM_GET_ATTR(entry, REGION_BASE); + region->region_type = BCMA_EROM_GET_ATTR(entry, REGION_TYPE); + region->region_port = BCMA_EROM_GET_ATTR(entry, REGION_PORT); + size_type = BCMA_EROM_GET_ATTR(entry, REGION_SIZE); + + /* If region address is 64-bit, fetch the high bits. */ + if (BCMA_EROM_GET_ATTR(entry, REGION_64BIT)) { + if ((error = erom_read32(erom, &entry))) + return (error); + + region->base_addr |= ((bhnd_addr_t) entry << 32); + } + + /* Parse the region size; it's either encoded as the binary logarithm + * of the number of 4K pages (i.e. log2 n), or its encoded as a + * 32-bit/64-bit literal value directly following the current entry. */ + if (size_type == BCMA_EROM_REGION_SIZE_OTHER) { + if ((error = erom_read32(erom, &entry))) + return (error); + + region->size = BCMA_EROM_GET_ATTR(entry, RSIZE_VAL); + + if (BCMA_EROM_GET_ATTR(entry, RSIZE_64BIT)) { + if ((error = erom_read32(erom, &entry))) + return (error); + region->size |= ((bhnd_size_t) entry << 32); + } + } else { + region->size = BCMA_EROM_REGION_SIZE_BASE << size_type; + } + + /* Verify that addr+size does not overflow. */ + if (region->size != 0 && + BHND_ADDR_MAX - (region->size - 1) < region->base_addr) + { + EROM_LOG(erom, "%s%u: invalid address map %llx:%llx\n", + erom_entry_type_name(region->region_type), + region->region_port, + (unsigned long long) region->base_addr, + (unsigned long long) region->size); + + return (EINVAL); + } + + return (0); +} + +/** + * Parse all cores descriptors from @p erom and return the array + * in @p cores and the count in @p num_cores. The current EROM read position + * is left unmodified. + * + * The memory allocated for the table should be freed using + * `free(*cores, M_BHND)`. @p cores and @p num_cores are not changed + * when an error is returned. + * + * @param erom EROM read state. + * @param[out] cores the table of parsed core descriptors. + * @param[out] num_cores the number of core records in @p cores. + */ +int +bcma_erom_get_core_info(struct bcma_erom *erom, + struct bhnd_core_info **cores, + u_int *num_cores) +{ + struct bhnd_core_info *buffer; + bus_size_t initial_offset; + u_int count; + int error; + + buffer = NULL; + initial_offset = bcma_erom_tell(erom); + + /* Determine the core count */ + bcma_erom_reset(erom); + for (count = 0, error = 0; !error; count++) { + struct bcma_erom_core core; + + /* Seek to the first readable core entry */ + error = erom_seek_next(erom, BCMA_EROM_ENTRY_TYPE_CORE); + if (error == ENOENT) + break; + else if (error) + goto cleanup; + + /* Read past the core descriptor */ + if ((error = bcma_erom_parse_core(erom, &core))) + goto cleanup; + } + + /* Allocate our output buffer */ + buffer = malloc(sizeof(struct bhnd_core_info) * count, M_BHND, + M_NOWAIT); + if (buffer == NULL) { + error = ENOMEM; + goto cleanup; + } + + /* Parse all core descriptors */ + bcma_erom_reset(erom); + for (u_int i = 0; i < count; i++) { + struct bcma_erom_core core; + + /* Parse the core */ + error = erom_seek_next(erom, BCMA_EROM_ENTRY_TYPE_CORE); + if (error) + goto cleanup; + + error = bcma_erom_parse_core(erom, &core); + if (error) + goto cleanup; + + /* Convert to a bhnd info record */ + buffer[i].vendor = core.vendor; + buffer[i].device = core.device; + buffer[i].hwrev = core.rev; + buffer[i].core_idx = i; + buffer[i].unit = 0; + + /* Determine the unit number */ + for (u_int j = 0; j < i; j++) { + if (buffer[i].vendor == buffer[j].vendor && + buffer[i].device == buffer[j].device) + buffer[i].unit++;; + } + } + +cleanup: + if (!error) { + *cores = buffer; + *num_cores = count; + } else { + if (buffer != NULL) + free(buffer, M_BHND); + } + + /* Restore the initial position */ + bcma_erom_seek(erom, initial_offset); + return (error); +} + + +/** + * Register all MMIO region descriptors for the given slave port. + * + * @param erom EROM read state. + * @param corecfg Core info to be populated with the scanned port regions. + * @param port_num Port index for which regions will be parsed. + * @param region_type The region type to be parsed. + * @param[out] offset The offset at which to perform parsing. On success, this + * will be updated to point to the next EROM table entry. + */ +static int +erom_corecfg_fill_port_regions(struct bcma_erom *erom, + struct bcma_corecfg *corecfg, bcma_pid_t port_num, + uint8_t region_type) +{ + struct bcma_sport *sport; + struct bcma_sport_list *sports; + bus_size_t entry_offset; + int error; + bhnd_port_type port_type; + + error = 0; + + /* Determine the port type for this region type. */ + switch (region_type) { + case BCMA_EROM_REGION_TYPE_DEVICE: + port_type = BHND_PORT_DEVICE; + break; + case BCMA_EROM_REGION_TYPE_BRIDGE: + port_type = BHND_PORT_BRIDGE; + break; + case BCMA_EROM_REGION_TYPE_MWRAP: + case BCMA_EROM_REGION_TYPE_SWRAP: + port_type = BHND_PORT_AGENT; + break; + default: + EROM_LOG(erom, "unsupported region type %hhx\n", + region_type); + return (EINVAL); + }; + + /* Fetch the list to be populated */ + sports = bcma_corecfg_get_port_list(corecfg, port_type); + + /* Allocate a new port descriptor */ + sport = bcma_alloc_sport(port_num, port_type); + if (sport == NULL) + return (ENOMEM); + + /* Read all address regions defined for this port */ + for (bcma_rmid_t region_num = 0;; region_num++) { + struct bcma_map *map; + struct bcma_erom_sport_region spr; + + /* No valid port definition should come anywhere near + * BCMA_RMID_MAX. */ + if (region_num == BCMA_RMID_MAX) { + EROM_LOG(erom, "core%u %s%u: region count reached " + "upper limit of %u\n", + corecfg->core_info.core_idx, + bhnd_port_type_name(port_type), + port_num, BCMA_RMID_MAX); + + error = EINVAL; + goto cleanup; + } + + /* Parse the next region entry. */ + entry_offset = bcma_erom_tell(erom); + error = bcma_erom_parse_sport_region(erom, &spr); + if (error && error != ENOENT) { + EROM_LOG(erom, "core%u %s%u.%u: invalid slave port " + "address region\n", + corecfg->core_info.core_idx, + bhnd_port_type_name(port_type), + port_num, region_num); + goto cleanup; + } + + /* ENOENT signals no further region entries */ + if (error == ENOENT) { + /* No further entries */ + error = 0; + break; + } + + /* A region or type mismatch also signals no further region + * entries */ + if (spr.region_port != port_num || + spr.region_type != region_type) + { + /* We don't want to consume this entry */ + bcma_erom_seek(erom, entry_offset); + + error = 0; + goto cleanup; + } + + /* + * Create the map entry. + */ + map = malloc(sizeof(struct bcma_map), M_BHND, M_NOWAIT); + if (map == NULL) { + error = ENOMEM; + goto cleanup; + } + + map->m_region_num = region_num; + map->m_base = spr.base_addr; + map->m_size = spr.size; + map->m_rid = -1; + + /* Add the region map to the port */ + STAILQ_INSERT_TAIL(&sport->sp_maps, map, m_link); + sport->sp_num_maps++; + } + +cleanup: + /* Append the new port descriptor on success, or deallocate the + * partially parsed descriptor on failure. */ + if (error == 0) { + STAILQ_INSERT_TAIL(sports, sport, sp_link); + } else if (sport != NULL) { + bcma_free_sport(sport); + } + + return error; +} + +/** + * Parse the next core entry from the EROM table and produce a bcma_corecfg + * to be owned by the caller. + * + * @param erom EROM read state. + * @param[out] result On success, the core's device info. The caller inherits + * ownership of this allocation. + * + * @return If successful, returns 0. If the end of the EROM table is hit, + * ENOENT will be returned. On error, returns a non-zero error value. + */ +int +bcma_erom_parse_corecfg(struct bcma_erom *erom, struct bcma_corecfg **result) +{ + struct bcma_corecfg *cfg; + struct bcma_erom_core core; + uint8_t first_region_type; + bus_size_t initial_offset; + u_int core_index; + int core_unit; + int error; + + cfg = NULL; + initial_offset = bcma_erom_tell(erom); + + /* Parse the next core entry */ + if ((error = bcma_erom_parse_core(erom, &core))) + return (error); + + /* Determine the core's index and unit numbers */ + bcma_erom_reset(erom); + core_unit = 0; + core_index = 0; + for (; bcma_erom_tell(erom) != initial_offset; core_index++) { + struct bcma_erom_core prev_core; + + /* Parse next core */ + if ((error = erom_seek_next(erom, BCMA_EROM_ENTRY_TYPE_CORE))) + return (error); + + if ((error = bcma_erom_parse_core(erom, &prev_core))) + return (error); + + /* Is earlier unit? */ + if (core.vendor == prev_core.vendor && + core.device == prev_core.device) + { + core_unit++; + } + + /* Seek to next core */ + if ((error = erom_seek_next(erom, BCMA_EROM_ENTRY_TYPE_CORE))) + return (error); + } + + /* We already parsed the core descriptor */ + if ((error = erom_skip_core(erom))) + return (error); + + /* Allocate our corecfg */ + cfg = bcma_alloc_corecfg(core_index, core_unit, core.vendor, + core.device, core.rev); + if (cfg == NULL) + return (ENOMEM); + + /* These are 5-bit values in the EROM table, and should never be able + * to overflow BCMA_PID_MAX. */ + KASSERT(core.num_mport <= BCMA_PID_MAX, ("unsupported mport count")); + KASSERT(core.num_dport <= BCMA_PID_MAX, ("unsupported dport count")); + KASSERT(core.num_mwrap + core.num_swrap <= BCMA_PID_MAX, + ("unsupported wport count")); + + if (bootverbose) { + EROM_LOG(erom, + "core%u: %s %s (cid=%hx, rev=%hu, unit=%d)\n", + core_index, + bhnd_vendor_name(core.vendor), + bhnd_find_core_name(core.vendor, core.device), + core.device, core.rev, core_unit); + } + + cfg->num_master_ports = core.num_mport; + cfg->num_dev_ports = 0; /* determined below */ + cfg->num_bridge_ports = 0; /* determined blow */ + cfg->num_wrapper_ports = core.num_mwrap + core.num_swrap; + + /* Parse Master Port Descriptors */ + for (uint8_t i = 0; i < core.num_mport; i++) { + struct bcma_mport *mport; + struct bcma_erom_mport mpd; + + /* Parse the master port descriptor */ + error = bcma_erom_parse_mport(erom, &mpd); + if (error) + goto failed; + + /* Initialize a new bus mport structure */ + mport = malloc(sizeof(struct bcma_mport), M_BHND, M_NOWAIT); + if (mport == NULL) { + error = ENOMEM; + goto failed; + } + + mport->mp_vid = mpd.port_vid; + mport->mp_num = mpd.port_num; + + /* Update dinfo */ + STAILQ_INSERT_TAIL(&cfg->master_ports, mport, mp_link); + } + + + /* + * Determine whether this is a bridge device; if so, we can + * expect the first sequence of address region descriptors to + * be of EROM_REGION_TYPE_BRIDGE instead of + * BCMA_EROM_REGION_TYPE_DEVICE. + * + * It's unclear whether this is the correct mechanism by which we + * should detect/handle bridge devices, but this approach matches + * that of (some of) Broadcom's published drivers. + */ + if (core.num_dport > 0) { + uint32_t entry; + + if ((error = bcma_erom_peek32(erom, &entry))) + goto failed; + + if (BCMA_EROM_ENTRY_IS(entry, REGION) && + BCMA_EROM_GET_ATTR(entry, REGION_TYPE) == BCMA_EROM_REGION_TYPE_BRIDGE) + { + first_region_type = BCMA_EROM_REGION_TYPE_BRIDGE; + cfg->num_dev_ports = 0; + cfg->num_bridge_ports = core.num_dport; + } else { + first_region_type = BCMA_EROM_REGION_TYPE_DEVICE; + cfg->num_dev_ports = core.num_dport; + cfg->num_bridge_ports = 0; + } + } + + /* Device/bridge port descriptors */ + for (uint8_t sp_num = 0; sp_num < core.num_dport; sp_num++) { + error = erom_corecfg_fill_port_regions(erom, cfg, sp_num, + first_region_type); + + if (error) + goto failed; + } + + /* Wrapper (aka device management) descriptors (for master ports). */ + for (uint8_t sp_num = 0; sp_num < core.num_mwrap; sp_num++) { + error = erom_corecfg_fill_port_regions(erom, cfg, sp_num, + BCMA_EROM_REGION_TYPE_MWRAP); + + if (error) + goto failed; + } + + + /* Wrapper (aka device management) descriptors (for slave ports). */ + for (uint8_t i = 0; i < core.num_swrap; i++) { + /* Slave wrapper ports are not numbered distinctly from master + * wrapper ports. */ + uint8_t sp_num = core.num_mwrap + i; + error = erom_corecfg_fill_port_regions(erom, cfg, sp_num, + BCMA_EROM_REGION_TYPE_SWRAP); + + if (error) + goto failed; + } + + *result = cfg; + return (0); + +failed: + if (cfg != NULL) + bcma_free_corecfg(cfg); + + return error; +} diff --git a/sys/dev/bhnd/bcma/bcma_eromreg.h b/sys/dev/bhnd/bcma/bcma_eromreg.h new file mode 100644 index 000000000000..b95484b1ccdb --- /dev/null +++ b/sys/dev/bhnd/bcma/bcma_eromreg.h @@ -0,0 +1,135 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * Copyright (c) 2010 Broadcom Corporation + * + * Portions of this file were derived from the aidmp.h header + * distributed with Broadcom's initial brcm80211 Linux driver release, as + * contributed to the Linux staging repository. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef _BCMA_BCMA_EROM_REG_H_ +#define _BCMA_BCMA_EROM_REG_H_ + +/* Enumeration ROM device registers */ +#define BCMA_EROM_TABLE_START 0x000 /**< device enumeration table offset */ +#define BCMA_EROM_REMAPCONTROL 0xe00 +#define BCMA_EROM_REMAPSELECT 0xe04 +#define BCMA_EROM_MASTERSELECT 0xe10 +#define BCMA_EROM_ITCR 0xf00 +#define BCMA_EROM_ITIP 0xf04 +#define BCMA_EROM_TABLE_SIZE BCMA_EROM_REMAPCONTROL - BCMA_EROM_TABLE_START + +/** + * Extract an entry attribute by applying _MASK and _SHIFT defines. + * + * @param _entry The entry containing the desired attribute + * @param _attr The BCMA EROM attribute name (e.g. ENTRY_ISVALID), to be + * concatenated with the `BCMA_EROM_` prefix and `_MASK`/`_SHIFT` suffixes. + */ +#define BCMA_EROM_GET_ATTR(_entry, _attr) \ + ((_entry & BCMA_EROM_ ## _attr ## _MASK) \ + >> BCMA_EROM_ ## _attr ## _SHIFT) + +/** + * Test an EROM entry's validity and type. + * + * @param _entry The entry to test. + * @param _type The required type + * @retval true if the entry type matches and the BCMA_EROM_ENTRY_ISVALID flag + * is set. + * @retval false if the entry is not valid, or if the type does not match. + */ +#define BCMA_EROM_ENTRY_IS(_entry, _type) \ + (BCMA_EROM_GET_ATTR(_entry, ENTRY_ISVALID) && \ + BCMA_EROM_GET_ATTR(_entry, ENTRY_TYPE) == BCMA_EROM_ENTRY_TYPE_ ## _type) + +/* + * Enumeration ROM Constants + */ +#define BCMA_EROM_TABLE_EOF 0xF /* end of EROM table */ + +#define BCMA_EROM_ENTRY_ISVALID_MASK 0x1 /* is entry valid? */ +#define BCMA_EROM_ENTRY_ISVALID_SHIFT 0 + +/* EROM Entry Types */ +#define BCMA_EROM_ENTRY_TYPE_MASK 0x6 /* entry type mask */ +#define BCMA_EROM_ENTRY_TYPE_SHIFT 0 +# define BCMA_EROM_ENTRY_TYPE_CORE 0x0 /* core descriptor */ +# define BCMA_EROM_ENTRY_TYPE_MPORT 0x2 /* master port descriptor */ +# define BCMA_EROM_ENTRY_TYPE_REGION 0x4 /* address region descriptor */ + +/* EROM Core DescriptorA (31:0) */ +#define BCMA_EROM_COREA_DESIGNER_MASK 0xFFF00000 /* core designer (JEP-106 mfg id) */ +#define BCMA_EROM_COREA_DESIGNER_SHIFT 20 +#define BCMA_EROM_COREA_ID_MASK 0x000FFF00 /* broadcom-assigned core id */ +#define BCMA_EROM_COREA_ID_SHIFT 8 +#define BCMA_EROM_COREA_CLASS_MASK 0x000000F0 /* core class */ +#define BCMA_EROM_COREA_CLASS_SHIFT 4 + +/* EROM Core DescriptorB (63:32) */ +#define BCMA_EROM_COREB_NUM_MP_MASK 0x000001F0 /* master port count */ +#define BCMA_EROM_COREB_NUM_MP_SHIFT 4 +#define BCMA_EROM_COREB_NUM_DP_MASK 0x00003E00 /* device/bridge port count */ +#define BCMA_EROM_COREB_NUM_DP_SHIFT 9 +#define BCMA_EROM_COREB_NUM_WMP_MASK 0x0007C000 /* master wrapper port count */ +#define BCMA_EROM_COREB_NUM_WMP_SHIFT 14 +#define BCMA_EROM_COREB_NUM_WSP_MASK 0x00F80000 /* slave wrapper port count */ +#define BCMA_EROM_COREB_NUM_WSP_SHIFT 19 +#define BCMA_EROM_COREB_REV_MASK 0xFF000000 /* broadcom-assigned core revision */ +#define BCMA_EROM_COREB_REV_SHIFT 24 + +/* EROM Master Port Descriptor + * + * The attribute descriptions are derived from background information + * on the AXI bus and PL301 interconnect, but are undocumented + * by Broadcom and may be incorrect. + */ +#define BCMA_EROM_MPORT_NUM_MASK 0x0000FF00 /* AXI master number (unique per interconnect) */ +#define BCMA_EROM_MPORT_NUM_SHIFT 8 +#define BCMA_EROM_MPORT_ID_MASK 0x000000F0 /* AXI master ID (unique per master). */ +#define BCMA_EROM_MPORT_ID_SHIFT 4 + + +/* EROM Slave Port MMIO Region Descriptor */ +#define BCMA_EROM_REGION_BASE_MASK 0xFFFFF000 /* region base address */ +#define BCMA_EROM_REGION_BASE_SHIFT 0 +#define BCMA_EROM_REGION_64BIT_MASK 0x00000008 /* base address spans two 32-bit entries */ +#define BCMA_EROM_REGION_64BIT_SHIFT 0 +#define BCMA_EROM_REGION_PORT_MASK 0x00000F00 /* region's associated port */ +#define BCMA_EROM_REGION_PORT_SHIFT 8 +#define BCMA_EROM_REGION_TYPE_MASK 0x000000C0 /* region type */ +#define BCMA_EROM_REGION_TYPE_SHIFT 6 +#define BCMA_EROM_REGION_TYPE_DEVICE 0 /* region maps to a device */ +#define BCMA_EROM_REGION_TYPE_BRIDGE 1 /* region maps to a bridge (e.g. AXI2APB) */ +#define BCMA_EROM_REGION_TYPE_SWRAP 2 /* region maps to a slave port's DMP agent/wrapper */ +#define BCMA_EROM_REGION_TYPE_MWRAP 3 /* region maps to a master port's DMP agent/wrapper */ + +#define BCMA_EROM_REGION_SIZE_MASK 0x00000030 /* region size encoding */ +#define BCMA_EROM_REGION_SIZE_SHIFT 4 +#define BCMA_EROM_REGION_SIZE_4K 0 /* 4K region */ +#define BCMA_EROM_REGION_SIZE_8K 1 /* 8K region */ +#define BCMA_EROM_REGION_SIZE_16K 2 /* 16K region */ +#define BCMA_EROM_REGION_SIZE_OTHER 3 /* defined by an additional size descriptor entry. */ +#define BCMA_EROM_REGION_SIZE_BASE 0x1000 + +/* Region Size Descriptor */ +#define BCMA_EROM_RSIZE_VAL_MASK 0xFFFFF000 /* region size */ +#define BCMA_EROM_RSIZE_VAL_SHIFT 0 +#define BCMA_EROM_RSIZE_64BIT_MASK 0x00000008 /* size spans two 32-bit entries */ +#define BCMA_EROM_RSIZE_64BIT_SHIFT 0 + +#endif /* _BCMA_BCMA_EROM_REG_H_ */ diff --git a/sys/dev/bhnd/bcma/bcma_eromvar.h b/sys/dev/bhnd/bcma/bcma_eromvar.h new file mode 100644 index 000000000000..6c99939bbbca --- /dev/null +++ b/sys/dev/bhnd/bcma/bcma_eromvar.h @@ -0,0 +1,104 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $FreeBSD$ + */ + +#ifndef _BCMA_BCMA_EROMVAR_H_ +#define _BCMA_BCMA_EROMVAR_H_ + +#include + +#include "bcmavar.h" + +/** + * EROM read context. + */ +struct bcma_erom { + device_t dev; /**< EROM parent device */ + struct resource *r; /**< EROM table resource. */ + bus_size_t start; /**< EROM table offset */ + bus_size_t offset; /**< current read offset */ +}; + +/** EROM core descriptor. */ +struct bcma_erom_core { + uint16_t vendor; /**< core's designer */ + uint16_t device; /**< core's device identifier */ + uint16_t rev; /**< core's hardware revision */ + u_long num_mport; /**< number of master port descriptors */ + u_long num_dport; /**< number of slave port descriptors */ + u_long num_mwrap; /**< number of master wrapper slave port descriptors */ + u_long num_swrap; /**< number of slave wrapper slave port descriptors */ +}; + +/** EROM master port descriptor. */ +struct bcma_erom_mport { + uint8_t port_num; /**< the port number (bus-unique) */ + uint8_t port_vid; /**< the port VID. A single physical + master port may have multiple VIDs; + the canonical port address is + composed of the port number + the + port VID */ +}; + +/** EROM slave port region descriptor. */ +struct bcma_erom_sport_region { + uint8_t region_port; /**< the slave port mapping this region */ + uint8_t region_type; /**< the mapping port's type */ + bhnd_addr_t base_addr; /**< region base address */ + bhnd_addr_t size; /**< region size */ +}; + +int bcma_erom_open(struct bcma_erom *erom, struct resource *r, + bus_size_t offset); + +int bcma_erom_peek32(struct bcma_erom *erom, uint32_t *entry); +bus_size_t bcma_erom_tell(struct bcma_erom *erom); +void bcma_erom_seek(struct bcma_erom *erom, bus_size_t offset); +void bcma_erom_reset(struct bcma_erom *erom); + +int bcma_erom_seek_core_index(struct bcma_erom *erom, + u_int core_index); +int bcma_erom_parse_core(struct bcma_erom *erom, + struct bcma_erom_core *core); + +int bcma_erom_parse_mport(struct bcma_erom *erom, + struct bcma_erom_mport *mport); + +int bcma_erom_parse_sport_region(struct bcma_erom *erom, + struct bcma_erom_sport_region *region); + +int bcma_erom_get_core_info(struct bcma_erom *erom, + struct bhnd_core_info **cores, + u_int *num_cores); + +int bcma_erom_parse_corecfg(struct bcma_erom *erom, + struct bcma_corecfg **result); + +#endif /* _BCMA_BCMA_EROMVAR_H_ */ diff --git a/sys/dev/bhnd/bcma/bcma_subr.c b/sys/dev/bhnd/bcma/bcma_subr.c new file mode 100644 index 000000000000..53d75644464f --- /dev/null +++ b/sys/dev/bhnd/bcma/bcma_subr.c @@ -0,0 +1,279 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "bcmavar.h" + + /** + * Allocate and initialize new core config structure. + * + * @param core_index Core index on the bus. + * @param core_unit Core unit number. + * @param vendor Core designer. + * @param device Core identifier (e.g. part number). + * @param hwrev Core revision. + */ +struct bcma_corecfg * +bcma_alloc_corecfg(u_int core_index, int core_unit, uint16_t vendor, + uint16_t device, uint8_t hwrev) +{ + struct bcma_corecfg *cfg; + + cfg = malloc(sizeof(*cfg), M_BHND, M_NOWAIT); + if (cfg == NULL) + return NULL; + + cfg->core_info = (struct bhnd_core_info) { + .vendor = vendor, + .device = device, + .hwrev = hwrev, + .core_idx = core_index, + .unit = core_unit + }; + + STAILQ_INIT(&cfg->master_ports); + cfg->num_master_ports = 0; + + STAILQ_INIT(&cfg->dev_ports); + cfg->num_dev_ports = 0; + + STAILQ_INIT(&cfg->bridge_ports); + cfg->num_bridge_ports = 0; + + STAILQ_INIT(&cfg->wrapper_ports); + cfg->num_wrapper_ports = 0; + + return (cfg); +} + +/** + * Deallocate the given core config and any associated resources. + * + * @param corecfg Core info to be deallocated. + */ +void +bcma_free_corecfg(struct bcma_corecfg *corecfg) +{ + struct bcma_mport *mport, *mnext; + struct bcma_sport *sport, *snext; + + STAILQ_FOREACH_SAFE(mport, &corecfg->master_ports, mp_link, mnext) { + free(mport, M_BHND); + } + + STAILQ_FOREACH_SAFE(sport, &corecfg->dev_ports, sp_link, snext) { + bcma_free_sport(sport); + } + + STAILQ_FOREACH_SAFE(sport, &corecfg->bridge_ports, sp_link, snext) { + bcma_free_sport(sport); + } + + STAILQ_FOREACH_SAFE(sport, &corecfg->wrapper_ports, sp_link, snext) { + bcma_free_sport(sport); + } + + free(corecfg, M_BHND); +} + +/** + * Return the @p cfg port list for @p type. + * + * @param cfg The core configuration. + * @param type The requested port type. + */ +struct bcma_sport_list * +bcma_corecfg_get_port_list(struct bcma_corecfg *cfg, bhnd_port_type type) +{ + switch (type) { + case BHND_PORT_DEVICE: + return (&cfg->dev_ports); + break; + case BHND_PORT_BRIDGE: + return (&cfg->bridge_ports); + break; + case BHND_PORT_AGENT: + return (&cfg->wrapper_ports); + break; + } +} + +/** + * Populate the resource list and bcma_map RIDs using the maps defined on + * @p ports. + * + * @param bus The requesting bus device. + * @param dinfo The device info instance to be initialized. + * @param ports The set of ports to be enumerated + */ +static void +bcma_dinfo_init_resource_info(device_t bus, struct bcma_devinfo *dinfo, + struct bcma_sport_list *ports) +{ + struct bcma_map *map; + struct bcma_sport *port; + bhnd_addr_t end; + + STAILQ_FOREACH(port, ports, sp_link) { + STAILQ_FOREACH(map, &port->sp_maps, m_link) { + /* + * Create the corresponding device resource list entry. + * + * We necessarily skip registration if the region's + * device memory range is not representable via + * rman_res_t. + * + * When rman_res_t is migrated to uintmax_t, any + * range should be representable. + */ + end = map->m_base + map->m_size; + if (map->m_base <= RM_MAX_END && end <= RM_MAX_END) { + map->m_rid = resource_list_add_next( + &dinfo->resources, SYS_RES_MEMORY, + map->m_base, end, map->m_size); + } else if (bootverbose) { + device_printf(bus, + "core%u %s%u.%u: region %llx-%llx extends " + "beyond supported addressable range\n", + dinfo->corecfg->core_info.core_idx, + bhnd_port_type_name(port->sp_type), + port->sp_num, map->m_region_num, + (unsigned long long) map->m_base, + (unsigned long long) end); + } + } + } +} + +/** + * Allocate and initialize new device info structure, assuming ownership + * of the provided core configuration. + * + * @param bus The requesting bus device. + * @param corecfg Device core configuration. + */ +struct bcma_devinfo * +bcma_alloc_dinfo(device_t bus, struct bcma_corecfg *corecfg) +{ + struct bcma_devinfo *dinfo; + + dinfo = malloc(sizeof(struct bcma_devinfo), M_BHND, M_NOWAIT); + if (dinfo == NULL) + return NULL; + + dinfo->corecfg = corecfg; + dinfo->res_agent = NULL; + dinfo->rid_agent = -1; + + resource_list_init(&dinfo->resources); + + /* The device ports must always be initialized first to ensure that + * rid 0 maps to the first device port */ + bcma_dinfo_init_resource_info(bus, dinfo, &corecfg->dev_ports); + + bcma_dinfo_init_resource_info(bus, dinfo, &corecfg->bridge_ports); + bcma_dinfo_init_resource_info(bus, dinfo, &corecfg->wrapper_ports); + + return dinfo; +} + +/** + * Deallocate the given device info structure and any associated resources. + * + * @param bus The requesting bus device. + * @param dinfo Device info to be deallocated. + */ +void +bcma_free_dinfo(device_t bus, struct bcma_devinfo *dinfo) +{ + bcma_free_corecfg(dinfo->corecfg); + resource_list_free(&dinfo->resources); + + /* Release agent resource, if any */ + if (dinfo->res_agent != NULL) { + bhnd_release_resource(bus, SYS_RES_MEMORY, dinfo->rid_agent, + dinfo->res_agent); + } + + free(dinfo, M_BHND); +} + + +/** + * Allocate and initialize new slave port descriptor. + * + * @param port_num Per-core port number. + * @param port_type Port type. + */ +struct bcma_sport * +bcma_alloc_sport(bcma_pid_t port_num, bhnd_port_type port_type) +{ + struct bcma_sport *sport; + + sport = malloc(sizeof(struct bcma_sport), M_BHND, M_NOWAIT); + if (sport == NULL) + return NULL; + + sport->sp_num = port_num; + sport->sp_type = port_type; + sport->sp_num_maps = 0; + STAILQ_INIT(&sport->sp_maps); + + return sport; +} + +/** + * Deallocate all resources associated with the given port descriptor. + * + * @param sport Port descriptor to be deallocated. + */ +void +bcma_free_sport(struct bcma_sport *sport) { + struct bcma_map *map, *mapnext; + + STAILQ_FOREACH_SAFE(map, &sport->sp_maps, m_link, mapnext) { + free(map, M_BHND); + } + + free(sport, M_BHND); +} + diff --git a/sys/dev/bhnd/bcma/bcmavar.h b/sys/dev/bhnd/bcma/bcmavar.h new file mode 100644 index 000000000000..48a530736f56 --- /dev/null +++ b/sys/dev/bhnd/bcma/bcmavar.h @@ -0,0 +1,149 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $FreeBSD$ + */ + +#ifndef _BCMA_BCMAVAR_H_ +#define _BCMA_BCMAVAR_H_ + +#include +#include +#include + +#include +#include + +#include "bcma.h" + +/* + * Internal definitions shared by bcma(4) driver implementations. + */ + +/** BCMA port identifier. */ +typedef u_int bcma_pid_t; +#define BCMA_PID_MAX UINT_MAX /**< Maximum bcma_pid_t value */ + +/** BCMA per-port region map identifier. */ +typedef u_int bcma_rmid_t; +#define BCMA_RMID_MAX UINT_MAX /**< Maximum bcma_rmid_t value */ + +struct bcma_devinfo; +struct bcma_corecfg; +struct bcma_map; +struct bcma_mport; +struct bcma_sport; + +int bcma_probe(device_t dev); +int bcma_attach(device_t dev); +int bcma_detach(device_t dev); + +int bcma_add_children(device_t bus, + struct resource *erom_res, bus_size_t erom_offset); + +struct bcma_sport_list *bcma_corecfg_get_port_list(struct bcma_corecfg *cfg, + bhnd_port_type type); + +struct bcma_devinfo *bcma_alloc_dinfo(device_t bus, + struct bcma_corecfg *corecfg); +void bcma_free_dinfo(device_t bus, + struct bcma_devinfo *dinfo); + +struct bcma_corecfg *bcma_alloc_corecfg(u_int core_index, int core_unit, + uint16_t vendor, uint16_t device, uint8_t hwrev); +void bcma_free_corecfg(struct bcma_corecfg *corecfg); + +struct bcma_sport *bcma_alloc_sport(bcma_pid_t port_num, bhnd_port_type port_type); +void bcma_free_sport(struct bcma_sport *sport); + +/** BCMA master port descriptor */ +struct bcma_mport { + bcma_pid_t mp_num; /**< AXI port identifier (bus-unique) */ + bcma_pid_t mp_vid; /**< AXI master virtual ID (core-unique) */ + STAILQ_ENTRY(bcma_mport) mp_link; +}; + +/** BCMA memory region descriptor */ +struct bcma_map { + bcma_rmid_t m_region_num; /**< region identifier (port-unique). */ + bhnd_addr_t m_base; /**< base address */ + bhnd_size_t m_size; /**< size */ + int m_rid; /**< bus resource id, or -1. */ + + STAILQ_ENTRY(bcma_map) m_link; +}; + +/** BCMA slave port descriptor */ +struct bcma_sport { + bcma_pid_t sp_num; /**< slave port number (core-unique) */ + bhnd_port_type sp_type; /**< port type */ + + u_long sp_num_maps; /**< number of regions mapped to this port */ + STAILQ_HEAD(, bcma_map) sp_maps; + STAILQ_ENTRY(bcma_sport) sp_link; +}; + +STAILQ_HEAD(bcma_mport_list, bcma_mport); +STAILQ_HEAD(bcma_sport_list, bcma_sport); + +/** BCMA IP core/block configuration */ +struct bcma_corecfg { + struct bhnd_core_info core_info; /**< standard core info */ + + u_long num_master_ports; /**< number of master port descriptors. */ + struct bcma_mport_list master_ports; /**< master port descriptors */ + + u_long num_dev_ports; /**< number of device slave port descriptors. */ + struct bcma_sport_list dev_ports; /**< device port descriptors */ + + u_long num_bridge_ports; /**< number of bridge slave port descriptors. */ + struct bcma_sport_list bridge_ports; /**< bridge port descriptors */ + + u_long num_wrapper_ports; /**< number of wrapper slave port descriptors. */ + struct bcma_sport_list wrapper_ports; /**< wrapper port descriptors */ +}; + +/** + * BCMA per-device info + */ +struct bcma_devinfo { + struct resource_list resources; /**< Slave port memory regions. */ + struct bcma_corecfg *corecfg; /**< IP core/block config */ + + struct bhnd_resource *res_agent; /**< Agent (wrapper) resource, or NULL. Not + * all bcma(4) cores have or require an agent. */ + int rid_agent; /**< Agent resource ID, or -1 */ +}; + + +/** BMCA per-instance state */ +struct bcma_softc { + struct bhnd_softc bhnd_sc; /**< bhnd state */ +}; + +#endif /* _BCMA_BCMAVAR_H_ */ \ No newline at end of file diff --git a/sys/dev/bhnd/bcmsrom_fmt.h b/sys/dev/bhnd/bcmsrom_fmt.h new file mode 100644 index 000000000000..10f00e497630 --- /dev/null +++ b/sys/dev/bhnd/bcmsrom_fmt.h @@ -0,0 +1,373 @@ +/*- + * Copyright (c) 2010 Broadcom Corporation + * + * This file is derived from the bcmsrom.h header distributed with Broadcom's + * brcm80211 Linux driver release, as contributed to the Linux staging + * repository. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef _BHND_BCMSROM_FMT_H_ +#define _BHND_BCMSROM_FMT_H_ + +/* Maximum srom: 6 Kilobits == 768 bytes */ +#define SROM_MAX 768 +#define SROM_MAXW 384 +#define VARS_MAX 4096 + +/* PCI fields */ +#define PCI_F0DEVID 48 + +#define SROM_WORDS 64 + +#define SROM3_SWRGN_OFF 28 /* s/w region offset in words */ + +#define SROM_SSID 2 + +#define SROM_WL1LHMAXP 29 + +#define SROM_WL1LPAB0 30 +#define SROM_WL1LPAB1 31 +#define SROM_WL1LPAB2 32 + +#define SROM_WL1HPAB0 33 +#define SROM_WL1HPAB1 34 +#define SROM_WL1HPAB2 35 + +#define SROM_MACHI_IL0 36 +#define SROM_MACMID_IL0 37 +#define SROM_MACLO_IL0 38 +#define SROM_MACHI_ET0 39 +#define SROM_MACMID_ET0 40 +#define SROM_MACLO_ET0 41 +#define SROM_MACHI_ET1 42 +#define SROM_MACMID_ET1 43 +#define SROM_MACLO_ET1 44 +#define SROM3_MACHI 37 +#define SROM3_MACMID 38 +#define SROM3_MACLO 39 + +#define SROM_BXARSSI2G 40 +#define SROM_BXARSSI5G 41 + +#define SROM_TRI52G 42 +#define SROM_TRI5GHL 43 + +#define SROM_RXPO52G 45 + +#define SROM2_ENETPHY 45 + +#define SROM_AABREV 46 +/* Fields in AABREV */ +#define SROM_BR_MASK 0x00ff +#define SROM_CC_MASK 0x0f00 +#define SROM_CC_SHIFT 8 +#define SROM_AA0_MASK 0x3000 +#define SROM_AA0_SHIFT 12 +#define SROM_AA1_MASK 0xc000 +#define SROM_AA1_SHIFT 14 + +#define SROM_WL0PAB0 47 +#define SROM_WL0PAB1 48 +#define SROM_WL0PAB2 49 + +#define SROM_LEDBH10 50 +#define SROM_LEDBH32 51 + +#define SROM_WL10MAXP 52 + +#define SROM_WL1PAB0 53 +#define SROM_WL1PAB1 54 +#define SROM_WL1PAB2 55 + +#define SROM_ITT 56 + +#define SROM_BFL 57 +#define SROM_BFL2 28 +#define SROM3_BFL2 61 + +#define SROM_AG10 58 + +#define SROM_CCODE 59 + +#define SROM_OPO 60 + +#define SROM3_LEDDC 62 + +#define SROM_CRCREV 63 + +/* SROM Rev 4: Reallocate the software part of the srom to accommodate + * MIMO features. It assumes up to two PCIE functions and 440 bytes + * of useable srom i.e. the useable storage in chips with OTP that + * implements hardware redundancy. + */ + +#define SROM4_WORDS 220 + +#define SROM4_SIGN 32 +#define SROM4_SIGNATURE 0x5372 + +#define SROM4_BREV 33 + +#define SROM4_BFL0 34 +#define SROM4_BFL1 35 +#define SROM4_BFL2 36 +#define SROM4_BFL3 37 +#define SROM5_BFL0 37 +#define SROM5_BFL1 38 +#define SROM5_BFL2 39 +#define SROM5_BFL3 40 + +#define SROM4_MACHI 38 +#define SROM4_MACMID 39 +#define SROM4_MACLO 40 +#define SROM5_MACHI 41 +#define SROM5_MACMID 42 +#define SROM5_MACLO 43 + +#define SROM4_CCODE 41 +#define SROM4_REGREV 42 +#define SROM5_CCODE 34 +#define SROM5_REGREV 35 + +#define SROM4_LEDBH10 43 +#define SROM4_LEDBH32 44 +#define SROM5_LEDBH10 59 +#define SROM5_LEDBH32 60 + +#define SROM4_LEDDC 45 +#define SROM5_LEDDC 45 + +#define SROM4_AA 46 +#define SROM4_AA2G_MASK 0x00ff +#define SROM4_AA2G_SHIFT 0 +#define SROM4_AA5G_MASK 0xff00 +#define SROM4_AA5G_SHIFT 8 + +#define SROM4_AG10 47 +#define SROM4_AG32 48 + +#define SROM4_TXPID2G 49 +#define SROM4_TXPID5G 51 +#define SROM4_TXPID5GL 53 +#define SROM4_TXPID5GH 55 + +#define SROM4_TXRXC 61 +#define SROM4_TXCHAIN_MASK 0x000f +#define SROM4_TXCHAIN_SHIFT 0 +#define SROM4_RXCHAIN_MASK 0x00f0 +#define SROM4_RXCHAIN_SHIFT 4 +#define SROM4_SWITCH_MASK 0xff00 +#define SROM4_SWITCH_SHIFT 8 + +/* Per-path fields */ +#define MAX_PATH_SROM 4 +#define SROM4_PATH0 64 +#define SROM4_PATH1 87 +#define SROM4_PATH2 110 +#define SROM4_PATH3 133 + +#define SROM4_2G_ITT_MAXP 0 +#define SROM4_2G_PA 1 +#define SROM4_5G_ITT_MAXP 5 +#define SROM4_5GLH_MAXP 6 +#define SROM4_5G_PA 7 +#define SROM4_5GL_PA 11 +#define SROM4_5GH_PA 15 + +/* Fields in the ITT_MAXP and 5GLH_MAXP words */ +#define B2G_MAXP_MASK 0xff +#define B2G_ITT_SHIFT 8 +#define B5G_MAXP_MASK 0xff +#define B5G_ITT_SHIFT 8 +#define B5GH_MAXP_MASK 0xff +#define B5GL_MAXP_SHIFT 8 + +/* All the miriad power offsets */ +#define SROM4_2G_CCKPO 156 +#define SROM4_2G_OFDMPO 157 +#define SROM4_5G_OFDMPO 159 +#define SROM4_5GL_OFDMPO 161 +#define SROM4_5GH_OFDMPO 163 +#define SROM4_2G_MCSPO 165 +#define SROM4_5G_MCSPO 173 +#define SROM4_5GL_MCSPO 181 +#define SROM4_5GH_MCSPO 189 +#define SROM4_CDDPO 197 +#define SROM4_STBCPO 198 +#define SROM4_BW40PO 199 +#define SROM4_BWDUPPO 200 + +#define SROM4_CRCREV 219 + +/* SROM Rev 8: Make space for a 48word hardware header for PCIe rev >= 6. + * This is acombined srom for both MIMO and SISO boards, usable in + * the .130 4Kilobit OTP with hardware redundancy. + */ + +#define SROM8_SIGN 64 + +#define SROM8_BREV 65 + +#define SROM8_BFL0 66 +#define SROM8_BFL1 67 +#define SROM8_BFL2 68 +#define SROM8_BFL3 69 + +#define SROM8_MACHI 70 +#define SROM8_MACMID 71 +#define SROM8_MACLO 72 + +#define SROM8_CCODE 73 +#define SROM8_REGREV 74 + +#define SROM8_LEDBH10 75 +#define SROM8_LEDBH32 76 + +#define SROM8_LEDDC 77 + +#define SROM8_AA 78 + +#define SROM8_AG10 79 +#define SROM8_AG32 80 + +#define SROM8_TXRXC 81 + +#define SROM8_BXARSSI2G 82 +#define SROM8_BXARSSI5G 83 +#define SROM8_TRI52G 84 +#define SROM8_TRI5GHL 85 +#define SROM8_RXPO52G 86 + +#define SROM8_FEM2G 87 +#define SROM8_FEM5G 88 +#define SROM8_FEM_ANTSWLUT_MASK 0xf800 +#define SROM8_FEM_ANTSWLUT_SHIFT 11 +#define SROM8_FEM_TR_ISO_MASK 0x0700 +#define SROM8_FEM_TR_ISO_SHIFT 8 +#define SROM8_FEM_PDET_RANGE_MASK 0x00f8 +#define SROM8_FEM_PDET_RANGE_SHIFT 3 +#define SROM8_FEM_EXTPA_GAIN_MASK 0x0006 +#define SROM8_FEM_EXTPA_GAIN_SHIFT 1 +#define SROM8_FEM_TSSIPOS_MASK 0x0001 +#define SROM8_FEM_TSSIPOS_SHIFT 0 + +#define SROM8_THERMAL 89 + +/* Temp sense related entries */ +#define SROM8_MPWR_RAWTS 90 +#define SROM8_TS_SLP_OPT_CORRX 91 +/* FOC: freiquency offset correction, HWIQ: H/W IOCAL enable, IQSWP: IQ CAL swap disable */ +#define SROM8_FOC_HWIQ_IQSWP 92 + +/* Temperature delta for PHY calibration */ +#define SROM8_PHYCAL_TEMPDELTA 93 + +/* Per-path offsets & fields */ +#define SROM8_PATH0 96 +#define SROM8_PATH1 112 +#define SROM8_PATH2 128 +#define SROM8_PATH3 144 + +#define SROM8_2G_ITT_MAXP 0 +#define SROM8_2G_PA 1 +#define SROM8_5G_ITT_MAXP 4 +#define SROM8_5GLH_MAXP 5 +#define SROM8_5G_PA 6 +#define SROM8_5GL_PA 9 +#define SROM8_5GH_PA 12 + +/* All the miriad power offsets */ +#define SROM8_2G_CCKPO 160 + +#define SROM8_2G_OFDMPO 161 +#define SROM8_5G_OFDMPO 163 +#define SROM8_5GL_OFDMPO 165 +#define SROM8_5GH_OFDMPO 167 + +#define SROM8_2G_MCSPO 169 +#define SROM8_5G_MCSPO 177 +#define SROM8_5GL_MCSPO 185 +#define SROM8_5GH_MCSPO 193 + +#define SROM8_CDDPO 201 +#define SROM8_STBCPO 202 +#define SROM8_BW40PO 203 +#define SROM8_BWDUPPO 204 + +/* SISO PA parameters are in the path0 spaces */ +#define SROM8_SISO 96 + +/* Legacy names for SISO PA paramters */ +#define SROM8_W0_ITTMAXP (SROM8_SISO + SROM8_2G_ITT_MAXP) +#define SROM8_W0_PAB0 (SROM8_SISO + SROM8_2G_PA) +#define SROM8_W0_PAB1 (SROM8_SISO + SROM8_2G_PA + 1) +#define SROM8_W0_PAB2 (SROM8_SISO + SROM8_2G_PA + 2) +#define SROM8_W1_ITTMAXP (SROM8_SISO + SROM8_5G_ITT_MAXP) +#define SROM8_W1_MAXP_LCHC (SROM8_SISO + SROM8_5GLH_MAXP) +#define SROM8_W1_PAB0 (SROM8_SISO + SROM8_5G_PA) +#define SROM8_W1_PAB1 (SROM8_SISO + SROM8_5G_PA + 1) +#define SROM8_W1_PAB2 (SROM8_SISO + SROM8_5G_PA + 2) +#define SROM8_W1_PAB0_LC (SROM8_SISO + SROM8_5GL_PA) +#define SROM8_W1_PAB1_LC (SROM8_SISO + SROM8_5GL_PA + 1) +#define SROM8_W1_PAB2_LC (SROM8_SISO + SROM8_5GL_PA + 2) +#define SROM8_W1_PAB0_HC (SROM8_SISO + SROM8_5GH_PA) +#define SROM8_W1_PAB1_HC (SROM8_SISO + SROM8_5GH_PA + 1) +#define SROM8_W1_PAB2_HC (SROM8_SISO + SROM8_5GH_PA + 2) + +#define SROM8_CRCREV 219 + +/* SROM REV 9 */ +#define SROM9_2GPO_CCKBW20 160 +#define SROM9_2GPO_CCKBW20UL 161 +#define SROM9_2GPO_LOFDMBW20 162 +#define SROM9_2GPO_LOFDMBW20UL 164 + +#define SROM9_5GLPO_LOFDMBW20 166 +#define SROM9_5GLPO_LOFDMBW20UL 168 +#define SROM9_5GMPO_LOFDMBW20 170 +#define SROM9_5GMPO_LOFDMBW20UL 172 +#define SROM9_5GHPO_LOFDMBW20 174 +#define SROM9_5GHPO_LOFDMBW20UL 176 + +#define SROM9_2GPO_MCSBW20 178 +#define SROM9_2GPO_MCSBW20UL 180 +#define SROM9_2GPO_MCSBW40 182 + +#define SROM9_5GLPO_MCSBW20 184 +#define SROM9_5GLPO_MCSBW20UL 186 +#define SROM9_5GLPO_MCSBW40 188 +#define SROM9_5GMPO_MCSBW20 190 +#define SROM9_5GMPO_MCSBW20UL 192 +#define SROM9_5GMPO_MCSBW40 194 +#define SROM9_5GHPO_MCSBW20 196 +#define SROM9_5GHPO_MCSBW20UL 198 +#define SROM9_5GHPO_MCSBW40 200 + +#define SROM9_PO_MCS32 202 +#define SROM9_PO_LOFDM40DUP 203 + +#define SROM9_REV_CRC 219 + +typedef struct { + u8 tssipos; /* TSSI positive slope, 1: positive, 0: negative */ + u8 extpagain; /* Ext PA gain-type: full-gain: 0, pa-lite: 1, no_pa: 2 */ + u8 pdetrange; /* support 32 combinations of different Pdet dynamic ranges */ + u8 triso; /* TR switch isolation */ + u8 antswctrllut; /* antswctrl lookup table configuration: 32 possible choices */ +} srom_fem_t; + +#endif /* _BHND_BCMSROM_TBL_H_ */ diff --git a/sys/dev/bhnd/bcmsrom_tbl.h b/sys/dev/bhnd/bcmsrom_tbl.h new file mode 100644 index 000000000000..1373f3f44727 --- /dev/null +++ b/sys/dev/bhnd/bcmsrom_tbl.h @@ -0,0 +1,577 @@ +/*- + * Copyright (c) 2010 Broadcom Corporation + * + * This file is derived from the bcmsrom.h header distributed with Broadcom's + * brcm80211 Linux driver release, as contributed to the Linux staging + * repository. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef _BHND_BCMSROM_TBL_H_ +#define _BHND_BCMSROM_TBL_H_ + +#include "bcmsrom_fmt.h" + +typedef struct { + const char *name; + u32 revmask; + u32 flags; + u16 off; + u16 mask; +} sromvar_t; + +#define SRFL_MORE 1 /* value continues as described by the next entry */ +#define SRFL_NOFFS 2 /* value bits can't be all one's */ +#define SRFL_PRHEX 4 /* value is in hexdecimal format */ +#define SRFL_PRSIGN 8 /* value is in signed decimal format */ +#define SRFL_CCODE 0x10 /* value is in country code format */ +#define SRFL_ETHADDR 0x20 /* value is an Ethernet address */ +#define SRFL_LEDDC 0x40 /* value is an LED duty cycle */ +#define SRFL_NOVAR 0x80 /* do not generate a nvram param, entry is for mfgc */ + +/* Assumptions: + * - Ethernet address spans across 3 consective words + * + * Table rules: + * - Add multiple entries next to each other if a value spans across multiple words + * (even multiple fields in the same word) with each entry except the last having + * it's SRFL_MORE bit set. + * - Ethernet address entry does not follow above rule and must not have SRFL_MORE + * bit set. Its SRFL_ETHADDR bit implies it takes multiple words. + * - The last entry's name field must be NULL to indicate the end of the table. Other + * entries must have non-NULL name. + */ + +static const sromvar_t pci_sromvars[] = { + {"devid", 0xffffff00, SRFL_PRHEX | SRFL_NOVAR, PCI_F0DEVID, 0xffff}, + {"boardrev", 0x0000000e, SRFL_PRHEX, SROM_AABREV, SROM_BR_MASK}, + {"boardrev", 0x000000f0, SRFL_PRHEX, SROM4_BREV, 0xffff}, + {"boardrev", 0xffffff00, SRFL_PRHEX, SROM8_BREV, 0xffff}, + {"boardflags", 0x00000002, SRFL_PRHEX, SROM_BFL, 0xffff}, + {"boardflags", 0x00000004, SRFL_PRHEX | SRFL_MORE, SROM_BFL, 0xffff}, + {"", 0, 0, SROM_BFL2, 0xffff}, + {"boardflags", 0x00000008, SRFL_PRHEX | SRFL_MORE, SROM_BFL, 0xffff}, + {"", 0, 0, SROM3_BFL2, 0xffff}, + {"boardflags", 0x00000010, SRFL_PRHEX | SRFL_MORE, SROM4_BFL0, 0xffff}, + {"", 0, 0, SROM4_BFL1, 0xffff}, + {"boardflags", 0x000000e0, SRFL_PRHEX | SRFL_MORE, SROM5_BFL0, 0xffff}, + {"", 0, 0, SROM5_BFL1, 0xffff}, + {"boardflags", 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL0, 0xffff}, + {"", 0, 0, SROM8_BFL1, 0xffff}, + {"boardflags2", 0x00000010, SRFL_PRHEX | SRFL_MORE, SROM4_BFL2, 0xffff}, + {"", 0, 0, SROM4_BFL3, 0xffff}, + {"boardflags2", 0x000000e0, SRFL_PRHEX | SRFL_MORE, SROM5_BFL2, 0xffff}, + {"", 0, 0, SROM5_BFL3, 0xffff}, + {"boardflags2", 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL2, 0xffff}, + {"", 0, 0, SROM8_BFL3, 0xffff}, + {"boardtype", 0xfffffffc, SRFL_PRHEX, SROM_SSID, 0xffff}, + {"boardnum", 0x00000006, 0, SROM_MACLO_IL0, 0xffff}, + {"boardnum", 0x00000008, 0, SROM3_MACLO, 0xffff}, + {"boardnum", 0x00000010, 0, SROM4_MACLO, 0xffff}, + {"boardnum", 0x000000e0, 0, SROM5_MACLO, 0xffff}, + {"boardnum", 0xffffff00, 0, SROM8_MACLO, 0xffff}, + {"cc", 0x00000002, 0, SROM_AABREV, SROM_CC_MASK}, + {"regrev", 0x00000008, 0, SROM_OPO, 0xff00}, + {"regrev", 0x00000010, 0, SROM4_REGREV, 0x00ff}, + {"regrev", 0x000000e0, 0, SROM5_REGREV, 0x00ff}, + {"regrev", 0xffffff00, 0, SROM8_REGREV, 0x00ff}, + {"ledbh0", 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0x00ff}, + {"ledbh1", 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0xff00}, + {"ledbh2", 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0x00ff}, + {"ledbh3", 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0xff00}, + {"ledbh0", 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0x00ff}, + {"ledbh1", 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0xff00}, + {"ledbh2", 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0x00ff}, + {"ledbh3", 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0xff00}, + {"ledbh0", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0x00ff}, + {"ledbh1", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0xff00}, + {"ledbh2", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0x00ff}, + {"ledbh3", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0xff00}, + {"ledbh0", 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0x00ff}, + {"ledbh1", 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0xff00}, + {"ledbh2", 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0x00ff}, + {"ledbh3", 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0xff00}, + {"pa0b0", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB0, 0xffff}, + {"pa0b1", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB1, 0xffff}, + {"pa0b2", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB2, 0xffff}, + {"pa0itssit", 0x0000000e, 0, SROM_ITT, 0x00ff}, + {"pa0maxpwr", 0x0000000e, 0, SROM_WL10MAXP, 0x00ff}, + {"pa0b0", 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB0, 0xffff}, + {"pa0b1", 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB1, 0xffff}, + {"pa0b2", 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB2, 0xffff}, + {"pa0itssit", 0xffffff00, 0, SROM8_W0_ITTMAXP, 0xff00}, + {"pa0maxpwr", 0xffffff00, 0, SROM8_W0_ITTMAXP, 0x00ff}, + {"opo", 0x0000000c, 0, SROM_OPO, 0x00ff}, + {"opo", 0xffffff00, 0, SROM8_2G_OFDMPO, 0x00ff}, + {"aa2g", 0x0000000e, 0, SROM_AABREV, SROM_AA0_MASK}, + {"aa2g", 0x000000f0, 0, SROM4_AA, 0x00ff}, + {"aa2g", 0xffffff00, 0, SROM8_AA, 0x00ff}, + {"aa5g", 0x0000000e, 0, SROM_AABREV, SROM_AA1_MASK}, + {"aa5g", 0x000000f0, 0, SROM4_AA, 0xff00}, + {"aa5g", 0xffffff00, 0, SROM8_AA, 0xff00}, + {"ag0", 0x0000000e, 0, SROM_AG10, 0x00ff}, + {"ag1", 0x0000000e, 0, SROM_AG10, 0xff00}, + {"ag0", 0x000000f0, 0, SROM4_AG10, 0x00ff}, + {"ag1", 0x000000f0, 0, SROM4_AG10, 0xff00}, + {"ag2", 0x000000f0, 0, SROM4_AG32, 0x00ff}, + {"ag3", 0x000000f0, 0, SROM4_AG32, 0xff00}, + {"ag0", 0xffffff00, 0, SROM8_AG10, 0x00ff}, + {"ag1", 0xffffff00, 0, SROM8_AG10, 0xff00}, + {"ag2", 0xffffff00, 0, SROM8_AG32, 0x00ff}, + {"ag3", 0xffffff00, 0, SROM8_AG32, 0xff00}, + {"pa1b0", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB0, 0xffff}, + {"pa1b1", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB1, 0xffff}, + {"pa1b2", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB2, 0xffff}, + {"pa1lob0", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB0, 0xffff}, + {"pa1lob1", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB1, 0xffff}, + {"pa1lob2", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB2, 0xffff}, + {"pa1hib0", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB0, 0xffff}, + {"pa1hib1", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB1, 0xffff}, + {"pa1hib2", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB2, 0xffff}, + {"pa1itssit", 0x0000000e, 0, SROM_ITT, 0xff00}, + {"pa1maxpwr", 0x0000000e, 0, SROM_WL10MAXP, 0xff00}, + {"pa1lomaxpwr", 0x0000000c, 0, SROM_WL1LHMAXP, 0xff00}, + {"pa1himaxpwr", 0x0000000c, 0, SROM_WL1LHMAXP, 0x00ff}, + {"pa1b0", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0, 0xffff}, + {"pa1b1", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1, 0xffff}, + {"pa1b2", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2, 0xffff}, + {"pa1lob0", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0_LC, 0xffff}, + {"pa1lob1", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1_LC, 0xffff}, + {"pa1lob2", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2_LC, 0xffff}, + {"pa1hib0", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0_HC, 0xffff}, + {"pa1hib1", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1_HC, 0xffff}, + {"pa1hib2", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2_HC, 0xffff}, + {"pa1itssit", 0xffffff00, 0, SROM8_W1_ITTMAXP, 0xff00}, + {"pa1maxpwr", 0xffffff00, 0, SROM8_W1_ITTMAXP, 0x00ff}, + {"pa1lomaxpwr", 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0xff00}, + {"pa1himaxpwr", 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0x00ff}, + {"bxa2g", 0x00000008, 0, SROM_BXARSSI2G, 0x1800}, + {"rssisav2g", 0x00000008, 0, SROM_BXARSSI2G, 0x0700}, + {"rssismc2g", 0x00000008, 0, SROM_BXARSSI2G, 0x00f0}, + {"rssismf2g", 0x00000008, 0, SROM_BXARSSI2G, 0x000f}, + {"bxa2g", 0xffffff00, 0, SROM8_BXARSSI2G, 0x1800}, + {"rssisav2g", 0xffffff00, 0, SROM8_BXARSSI2G, 0x0700}, + {"rssismc2g", 0xffffff00, 0, SROM8_BXARSSI2G, 0x00f0}, + {"rssismf2g", 0xffffff00, 0, SROM8_BXARSSI2G, 0x000f}, + {"bxa5g", 0x00000008, 0, SROM_BXARSSI5G, 0x1800}, + {"rssisav5g", 0x00000008, 0, SROM_BXARSSI5G, 0x0700}, + {"rssismc5g", 0x00000008, 0, SROM_BXARSSI5G, 0x00f0}, + {"rssismf5g", 0x00000008, 0, SROM_BXARSSI5G, 0x000f}, + {"bxa5g", 0xffffff00, 0, SROM8_BXARSSI5G, 0x1800}, + {"rssisav5g", 0xffffff00, 0, SROM8_BXARSSI5G, 0x0700}, + {"rssismc5g", 0xffffff00, 0, SROM8_BXARSSI5G, 0x00f0}, + {"rssismf5g", 0xffffff00, 0, SROM8_BXARSSI5G, 0x000f}, + {"tri2g", 0x00000008, 0, SROM_TRI52G, 0x00ff}, + {"tri5g", 0x00000008, 0, SROM_TRI52G, 0xff00}, + {"tri5gl", 0x00000008, 0, SROM_TRI5GHL, 0x00ff}, + {"tri5gh", 0x00000008, 0, SROM_TRI5GHL, 0xff00}, + {"tri2g", 0xffffff00, 0, SROM8_TRI52G, 0x00ff}, + {"tri5g", 0xffffff00, 0, SROM8_TRI52G, 0xff00}, + {"tri5gl", 0xffffff00, 0, SROM8_TRI5GHL, 0x00ff}, + {"tri5gh", 0xffffff00, 0, SROM8_TRI5GHL, 0xff00}, + {"rxpo2g", 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0x00ff}, + {"rxpo5g", 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0xff00}, + {"rxpo2g", 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0x00ff}, + {"rxpo5g", 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0xff00}, + {"txchain", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_TXCHAIN_MASK}, + {"rxchain", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_RXCHAIN_MASK}, + {"antswitch", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_SWITCH_MASK}, + {"txchain", 0xffffff00, SRFL_NOFFS, SROM8_TXRXC, SROM4_TXCHAIN_MASK}, + {"rxchain", 0xffffff00, SRFL_NOFFS, SROM8_TXRXC, SROM4_RXCHAIN_MASK}, + {"antswitch", 0xffffff00, SRFL_NOFFS, SROM8_TXRXC, SROM4_SWITCH_MASK}, + {"tssipos2g", 0xffffff00, 0, SROM8_FEM2G, SROM8_FEM_TSSIPOS_MASK}, + {"extpagain2g", 0xffffff00, 0, SROM8_FEM2G, SROM8_FEM_EXTPA_GAIN_MASK}, + {"pdetrange2g", 0xffffff00, 0, SROM8_FEM2G, SROM8_FEM_PDET_RANGE_MASK}, + {"triso2g", 0xffffff00, 0, SROM8_FEM2G, SROM8_FEM_TR_ISO_MASK}, + {"antswctl2g", 0xffffff00, 0, SROM8_FEM2G, SROM8_FEM_ANTSWLUT_MASK}, + {"tssipos5g", 0xffffff00, 0, SROM8_FEM5G, SROM8_FEM_TSSIPOS_MASK}, + {"extpagain5g", 0xffffff00, 0, SROM8_FEM5G, SROM8_FEM_EXTPA_GAIN_MASK}, + {"pdetrange5g", 0xffffff00, 0, SROM8_FEM5G, SROM8_FEM_PDET_RANGE_MASK}, + {"triso5g", 0xffffff00, 0, SROM8_FEM5G, SROM8_FEM_TR_ISO_MASK}, + {"antswctl5g", 0xffffff00, 0, SROM8_FEM5G, SROM8_FEM_ANTSWLUT_MASK}, + {"tempthresh", 0xffffff00, 0, SROM8_THERMAL, 0xff00}, + {"tempoffset", 0xffffff00, 0, SROM8_THERMAL, 0x00ff}, + {"txpid2ga0", 0x000000f0, 0, SROM4_TXPID2G, 0x00ff}, + {"txpid2ga1", 0x000000f0, 0, SROM4_TXPID2G, 0xff00}, + {"txpid2ga2", 0x000000f0, 0, SROM4_TXPID2G+1, 0x00ff}, + {"txpid2ga3", 0x000000f0, 0, SROM4_TXPID2G+1, 0xff00}, + {"txpid5ga0", 0x000000f0, 0, SROM4_TXPID5G, 0x00ff}, + {"txpid5ga1", 0x000000f0, 0, SROM4_TXPID5G, 0xff00}, + {"txpid5ga2", 0x000000f0, 0, SROM4_TXPID5G+1, 0x00ff}, + {"txpid5ga3", 0x000000f0, 0, SROM4_TXPID5G+1, 0xff00}, + {"txpid5gla0", 0x000000f0, 0, SROM4_TXPID5GL, 0x00ff}, + {"txpid5gla1", 0x000000f0, 0, SROM4_TXPID5GL, 0xff00}, + {"txpid5gla2", 0x000000f0, 0, SROM4_TXPID5GL+1, 0x00ff}, + {"txpid5gla3", 0x000000f0, 0, SROM4_TXPID5GL+1, 0xff00}, + {"txpid5gha0", 0x000000f0, 0, SROM4_TXPID5GH, 0x00ff}, + {"txpid5gha1", 0x000000f0, 0, SROM4_TXPID5GH, 0xff00}, + {"txpid5gha2", 0x000000f0, 0, SROM4_TXPID5GH+1, 0x00ff}, + {"txpid5gha3", 0x000000f0, 0, SROM4_TXPID5GH+1, 0xff00}, + + {"ccode", 0x0000000f, SRFL_CCODE, SROM_CCODE, 0xffff}, + {"ccode", 0x00000010, SRFL_CCODE, SROM4_CCODE, 0xffff}, + {"ccode", 0x000000e0, SRFL_CCODE, SROM5_CCODE, 0xffff}, + {"ccode", 0xffffff00, SRFL_CCODE, SROM8_CCODE, 0xffff}, + {"macaddr", 0xffffff00, SRFL_ETHADDR, SROM8_MACHI, 0xffff}, + {"macaddr", 0x000000e0, SRFL_ETHADDR, SROM5_MACHI, 0xffff}, + {"macaddr", 0x00000010, SRFL_ETHADDR, SROM4_MACHI, 0xffff}, + {"macaddr", 0x00000008, SRFL_ETHADDR, SROM3_MACHI, 0xffff}, + {"il0macaddr", 0x00000007, SRFL_ETHADDR, SROM_MACHI_IL0, 0xffff}, + {"et1macaddr", 0x00000007, SRFL_ETHADDR, SROM_MACHI_ET1, 0xffff}, + {"leddc", 0xffffff00, SRFL_NOFFS | SRFL_LEDDC, SROM8_LEDDC, 0xffff}, + {"leddc", 0x000000e0, SRFL_NOFFS | SRFL_LEDDC, SROM5_LEDDC, 0xffff}, + {"leddc", 0x00000010, SRFL_NOFFS | SRFL_LEDDC, SROM4_LEDDC, 0xffff}, + {"leddc", 0x00000008, SRFL_NOFFS | SRFL_LEDDC, SROM3_LEDDC, 0xffff}, + {"rawtempsense",0xffffff00, SRFL_PRHEX, SROM8_MPWR_RAWTS, 0x01ff}, + {"measpower", 0xffffff00, SRFL_PRHEX, SROM8_MPWR_RAWTS, 0xfe00}, + {"tempsense_slope",0xffffff00, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX, 0x00ff}, + {"tempcorrx", 0xffffff00, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX, 0xfc00}, + {"tempsense_option",0xffffff00, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX, 0x0300}, + {"freqoffset_corr",0xffffff00, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, 0x000f}, + {"iqcal_swp_dis",0xffffff00, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, 0x0010}, + {"hw_iqcal_en", 0xffffff00, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, 0x0020}, + {"phycal_tempdelta",0xffffff00, 0, SROM8_PHYCAL_TEMPDELTA, 0x00ff}, + + {"cck2gpo", 0x000000f0, 0, SROM4_2G_CCKPO, 0xffff}, + {"cck2gpo", 0x00000100, 0, SROM8_2G_CCKPO, 0xffff}, + {"ofdm2gpo", 0x000000f0, SRFL_MORE, SROM4_2G_OFDMPO, 0xffff}, + {"", 0, 0, SROM4_2G_OFDMPO+1, 0xffff}, + {"ofdm5gpo", 0x000000f0, SRFL_MORE, SROM4_5G_OFDMPO, 0xffff}, + {"", 0, 0, SROM4_5G_OFDMPO+1, 0xffff}, + {"ofdm5glpo", 0x000000f0, SRFL_MORE, SROM4_5GL_OFDMPO, 0xffff}, + {"", 0, 0, SROM4_5GL_OFDMPO+1, 0xffff}, + {"ofdm5ghpo", 0x000000f0, SRFL_MORE, SROM4_5GH_OFDMPO, 0xffff}, + {"", 0, 0, SROM4_5GH_OFDMPO+1, 0xffff}, + {"ofdm2gpo", 0x00000100, SRFL_MORE, SROM8_2G_OFDMPO, 0xffff}, + {"", 0, 0, SROM8_2G_OFDMPO+1, 0xffff}, + {"ofdm5gpo", 0x00000100, SRFL_MORE, SROM8_5G_OFDMPO, 0xffff}, + {"", 0, 0, SROM8_5G_OFDMPO+1, 0xffff}, + {"ofdm5glpo", 0x00000100, SRFL_MORE, SROM8_5GL_OFDMPO, 0xffff}, + {"", 0, 0, SROM8_5GL_OFDMPO+1, 0xffff}, + {"ofdm5ghpo", 0x00000100, SRFL_MORE, SROM8_5GH_OFDMPO, 0xffff}, + {"", 0, 0, SROM8_5GH_OFDMPO+1, 0xffff}, + + {"mcs2gpo0", 0x000000f0, 0, SROM4_2G_MCSPO, 0xffff}, + {"mcs2gpo1", 0x000000f0, 0, SROM4_2G_MCSPO+1, 0xffff}, + {"mcs2gpo2", 0x000000f0, 0, SROM4_2G_MCSPO+2, 0xffff}, + {"mcs2gpo3", 0x000000f0, 0, SROM4_2G_MCSPO+3, 0xffff}, + {"mcs2gpo4", 0x000000f0, 0, SROM4_2G_MCSPO+4, 0xffff}, + {"mcs2gpo5", 0x000000f0, 0, SROM4_2G_MCSPO+5, 0xffff}, + {"mcs2gpo6", 0x000000f0, 0, SROM4_2G_MCSPO+6, 0xffff}, + {"mcs2gpo7", 0x000000f0, 0, SROM4_2G_MCSPO+7, 0xffff}, + + {"mcs5gpo0", 0x000000f0, 0, SROM4_5G_MCSPO, 0xffff}, + {"mcs5gpo1", 0x000000f0, 0, SROM4_5G_MCSPO+1, 0xffff}, + {"mcs5gpo2", 0x000000f0, 0, SROM4_5G_MCSPO+2, 0xffff}, + {"mcs5gpo3", 0x000000f0, 0, SROM4_5G_MCSPO+3, 0xffff}, + {"mcs5gpo4", 0x000000f0, 0, SROM4_5G_MCSPO+4, 0xffff}, + {"mcs5gpo5", 0x000000f0, 0, SROM4_5G_MCSPO+5, 0xffff}, + {"mcs5gpo6", 0x000000f0, 0, SROM4_5G_MCSPO+6, 0xffff}, + {"mcs5gpo7", 0x000000f0, 0, SROM4_5G_MCSPO+7, 0xffff}, + + {"mcs5glpo0", 0x000000f0, 0, SROM4_5GL_MCSPO, 0xffff}, + {"mcs5glpo1", 0x000000f0, 0, SROM4_5GL_MCSPO+1, 0xffff}, + {"mcs5glpo2", 0x000000f0, 0, SROM4_5GL_MCSPO+2, 0xffff}, + {"mcs5glpo3", 0x000000f0, 0, SROM4_5GL_MCSPO+3, 0xffff}, + {"mcs5glpo4", 0x000000f0, 0, SROM4_5GL_MCSPO+4, 0xffff}, + {"mcs5glpo5", 0x000000f0, 0, SROM4_5GL_MCSPO+5, 0xffff}, + {"mcs5glpo6", 0x000000f0, 0, SROM4_5GL_MCSPO+6, 0xffff}, + {"mcs5glpo7", 0x000000f0, 0, SROM4_5GL_MCSPO+7, 0xffff}, + + {"mcs5ghpo0", 0x000000f0, 0, SROM4_5GH_MCSPO, 0xffff}, + {"mcs5ghpo1", 0x000000f0, 0, SROM4_5GH_MCSPO+1, 0xffff}, + {"mcs5ghpo2", 0x000000f0, 0, SROM4_5GH_MCSPO+2, 0xffff}, + {"mcs5ghpo3", 0x000000f0, 0, SROM4_5GH_MCSPO+3, 0xffff}, + {"mcs5ghpo4", 0x000000f0, 0, SROM4_5GH_MCSPO+4, 0xffff}, + {"mcs5ghpo5", 0x000000f0, 0, SROM4_5GH_MCSPO+5, 0xffff}, + {"mcs5ghpo6", 0x000000f0, 0, SROM4_5GH_MCSPO+6, 0xffff}, + {"mcs5ghpo7", 0x000000f0, 0, SROM4_5GH_MCSPO+7, 0xffff}, + + {"mcs2gpo0", 0x00000100, 0, SROM8_2G_MCSPO, 0xffff}, + {"mcs2gpo1", 0x00000100, 0, SROM8_2G_MCSPO+1, 0xffff}, + {"mcs2gpo2", 0x00000100, 0, SROM8_2G_MCSPO+2, 0xffff}, + {"mcs2gpo3", 0x00000100, 0, SROM8_2G_MCSPO+3, 0xffff}, + {"mcs2gpo4", 0x00000100, 0, SROM8_2G_MCSPO+4, 0xffff}, + {"mcs2gpo5", 0x00000100, 0, SROM8_2G_MCSPO+5, 0xffff}, + {"mcs2gpo6", 0x00000100, 0, SROM8_2G_MCSPO+6, 0xffff}, + {"mcs2gpo7", 0x00000100, 0, SROM8_2G_MCSPO+7, 0xffff}, + + {"mcs5gpo0", 0x00000100, 0, SROM8_5G_MCSPO, 0xffff}, + {"mcs5gpo1", 0x00000100, 0, SROM8_5G_MCSPO+1, 0xffff}, + {"mcs5gpo2", 0x00000100, 0, SROM8_5G_MCSPO+2, 0xffff}, + {"mcs5gpo3", 0x00000100, 0, SROM8_5G_MCSPO+3, 0xffff}, + {"mcs5gpo4", 0x00000100, 0, SROM8_5G_MCSPO+4, 0xffff}, + {"mcs5gpo5", 0x00000100, 0, SROM8_5G_MCSPO+5, 0xffff}, + {"mcs5gpo6", 0x00000100, 0, SROM8_5G_MCSPO+6, 0xffff}, + {"mcs5gpo7", 0x00000100, 0, SROM8_5G_MCSPO+7, 0xffff}, + + {"mcs5glpo0", 0x00000100, 0, SROM8_5GL_MCSPO, 0xffff}, + {"mcs5glpo1", 0x00000100, 0, SROM8_5GL_MCSPO+1, 0xffff}, + {"mcs5glpo2", 0x00000100, 0, SROM8_5GL_MCSPO+2, 0xffff}, + {"mcs5glpo3", 0x00000100, 0, SROM8_5GL_MCSPO+3, 0xffff}, + {"mcs5glpo4", 0x00000100, 0, SROM8_5GL_MCSPO+4, 0xffff}, + {"mcs5glpo5", 0x00000100, 0, SROM8_5GL_MCSPO+5, 0xffff}, + {"mcs5glpo6", 0x00000100, 0, SROM8_5GL_MCSPO+6, 0xffff}, + {"mcs5glpo7", 0x00000100, 0, SROM8_5GL_MCSPO+7, 0xffff}, + {"mcs5ghpo0", 0x00000100, 0, SROM8_5GH_MCSPO, 0xffff}, + {"mcs5ghpo1", 0x00000100, 0, SROM8_5GH_MCSPO+1, 0xffff}, + {"mcs5ghpo2", 0x00000100, 0, SROM8_5GH_MCSPO+2, 0xffff}, + {"mcs5ghpo3", 0x00000100, 0, SROM8_5GH_MCSPO+3, 0xffff}, + {"mcs5ghpo4", 0x00000100, 0, SROM8_5GH_MCSPO+4, 0xffff}, + {"mcs5ghpo5", 0x00000100, 0, SROM8_5GH_MCSPO+5, 0xffff}, + {"mcs5ghpo6", 0x00000100, 0, SROM8_5GH_MCSPO+6, 0xffff}, + {"mcs5ghpo7", 0x00000100, 0, SROM8_5GH_MCSPO+7, 0xffff}, + {"cddpo", 0x000000f0, 0, SROM4_CDDPO, 0xffff}, + {"stbcpo", 0x000000f0, 0, SROM4_STBCPO, 0xffff}, + {"bw40po", 0x000000f0, 0, SROM4_BW40PO, 0xffff}, + {"bwduppo", 0x000000f0, 0, SROM4_BWDUPPO, 0xffff}, + {"cddpo", 0x00000100, 0, SROM8_CDDPO, 0xffff}, + {"stbcpo", 0x00000100, 0, SROM8_STBCPO, 0xffff}, + {"bw40po", 0x00000100, 0, SROM8_BW40PO, 0xffff}, + {"bwduppo", 0x00000100, 0, SROM8_BWDUPPO, 0xffff}, + + /* power per rate from sromrev 9 */ + {"cckbw202gpo", 0xfffffe00, 0, SROM9_2GPO_CCKBW20, 0xffff}, + {"cckbw20ul2gpo",0xfffffe00, 0, SROM9_2GPO_CCKBW20UL, 0xffff}, + {"legofdmbw202gpo",0xfffffe00, SRFL_MORE, SROM9_2GPO_LOFDMBW20, 0xffff}, + {"", 0, 0, SROM9_2GPO_LOFDMBW20+1, 0xffff}, + {"legofdmbw20ul2gpo",0xfffffe00,SRFL_MORE, SROM9_2GPO_LOFDMBW20UL, 0xffff}, + {"", 0, 0, SROM9_2GPO_LOFDMBW20UL+1,0xffff}, + {"legofdmbw205glpo",0xfffffe00, SRFL_MORE, SROM9_5GLPO_LOFDMBW20, 0xffff}, + {"", 0, 0, SROM9_5GLPO_LOFDMBW20+1,0xffff}, + {"legofdmbw20ul5glpo",0xfffffe00,SRFL_MORE, SROM9_5GLPO_LOFDMBW20UL,0xffff}, + {"", 0, 0, SROM9_5GLPO_LOFDMBW20UL+1,0xffff}, + {"legofdmbw205gmpo",0xfffffe00, SRFL_MORE, SROM9_5GMPO_LOFDMBW20, 0xffff}, + {"", 0, 0, SROM9_5GMPO_LOFDMBW20+1,0xffff}, + {"legofdmbw20ul5gmpo",0xfffffe00,SRFL_MORE, SROM9_5GMPO_LOFDMBW20UL,0xffff}, + {"", 0, 0, SROM9_5GMPO_LOFDMBW20UL+1,0xffff}, + {"legofdmbw205ghpo",0xfffffe00, SRFL_MORE, SROM9_5GHPO_LOFDMBW20, 0xffff}, + {"", 0, 0, SROM9_5GHPO_LOFDMBW20+1,0xffff}, + {"legofdmbw20ul5ghpo",0xfffffe00,SRFL_MORE, SROM9_5GHPO_LOFDMBW20UL,0xffff}, + {"", 0, 0, SROM9_5GHPO_LOFDMBW20UL+1,0xffff}, + {"mcsbw202gpo", 0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW20, 0xffff}, + {"", 0, 0, SROM9_2GPO_MCSBW20+1, 0xffff}, + {"mcsbw20ul2gpo",0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW20UL, 0xffff}, + {"", 0, 0, SROM9_2GPO_MCSBW20UL+1, 0xffff}, + {"mcsbw402gpo", 0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW40, 0xffff}, + {"", 0, 0, SROM9_2GPO_MCSBW40+1, 0xffff}, + {"mcsbw205glpo",0xfffffe00, SRFL_MORE, SROM9_5GLPO_MCSBW20, 0xffff}, + {"", 0, 0, SROM9_5GLPO_MCSBW20+1, 0xffff}, + {"mcsbw20ul5glpo",0xfffffe00, SRFL_MORE, SROM9_5GLPO_MCSBW20UL, 0xffff}, + {"", 0, 0, SROM9_5GLPO_MCSBW20UL+1,0xffff}, + {"mcsbw405glpo",0xfffffe00, SRFL_MORE, SROM9_5GLPO_MCSBW40, 0xffff}, + {"", 0, 0, SROM9_5GLPO_MCSBW40+1, 0xffff}, + {"mcsbw205gmpo",0xfffffe00, SRFL_MORE, SROM9_5GMPO_MCSBW20, 0xffff}, + {"", 0, 0, SROM9_5GMPO_MCSBW20+1, 0xffff}, + {"mcsbw20ul5gmpo",0xfffffe00, SRFL_MORE, SROM9_5GMPO_MCSBW20UL, 0xffff}, + {"", 0, 0, SROM9_5GMPO_MCSBW20UL+1,0xffff}, + {"mcsbw405gmpo",0xfffffe00, SRFL_MORE, SROM9_5GMPO_MCSBW40, 0xffff}, + {"", 0, 0, SROM9_5GMPO_MCSBW40+1, 0xffff}, + {"mcsbw205ghpo",0xfffffe00, SRFL_MORE, SROM9_5GHPO_MCSBW20, 0xffff}, + {"", 0, 0, SROM9_5GHPO_MCSBW20+1, 0xffff}, + {"mcsbw20ul5ghpo",0xfffffe00, SRFL_MORE, SROM9_5GHPO_MCSBW20UL, 0xffff}, + {"", 0, 0, SROM9_5GHPO_MCSBW20UL+1,0xffff}, + {"mcsbw405ghpo",0xfffffe00, SRFL_MORE, SROM9_5GHPO_MCSBW40, 0xffff}, + {"", 0, 0, SROM9_5GHPO_MCSBW40+1, 0xffff}, + {"mcs32po", 0xfffffe00, 0, SROM9_PO_MCS32, 0xffff}, + {"legofdm40duppo",0xfffffe00, 0, SROM9_PO_LOFDM40DUP, 0xffff}, + + {NULL, 0, 0, 0, 0} +}; + +static const sromvar_t perpath_pci_sromvars[] = { + {"maxp2ga", 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0x00ff}, + {"itt2ga", 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0xff00}, + {"itt5ga", 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0xff00}, + {"pa2gw0a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA, 0xffff}, + {"pa2gw1a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA+1, 0xffff}, + {"pa2gw2a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA+2, 0xffff}, + {"pa2gw3a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA+3, 0xffff}, + {"maxp5ga", 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0x00ff}, + {"maxp5gha", 0x000000f0, 0, SROM4_5GLH_MAXP, 0x00ff}, + {"maxp5gla", 0x000000f0, 0, SROM4_5GLH_MAXP, 0xff00}, + {"pa5gw0a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA, 0xffff}, + {"pa5gw1a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA+1, 0xffff}, + {"pa5gw2a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA+2, 0xffff}, + {"pa5gw3a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA+3, 0xffff}, + {"pa5glw0a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA, 0xffff}, + {"pa5glw1a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA+1, 0xffff}, + {"pa5glw2a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA+2, 0xffff}, + {"pa5glw3a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA+3, 0xffff}, + {"pa5ghw0a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA, 0xffff}, + {"pa5ghw1a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA+1, 0xffff}, + {"pa5ghw2a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA+2, 0xffff}, + {"pa5ghw3a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA+3, 0xffff}, + {"maxp2ga", 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0x00ff}, + {"itt2ga", 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0xff00}, + {"itt5ga", 0xffffff00, 0, SROM8_5G_ITT_MAXP, 0xff00}, + {"pa2gw0a", 0xffffff00, SRFL_PRHEX, SROM8_2G_PA, 0xffff}, + {"pa2gw1a", 0xffffff00, SRFL_PRHEX, SROM8_2G_PA+1, 0xffff}, + {"pa2gw2a", 0xffffff00, SRFL_PRHEX, SROM8_2G_PA+2, 0xffff}, + {"maxp5ga", 0xffffff00, 0, SROM8_5G_ITT_MAXP, 0x00ff}, + {"maxp5gha", 0xffffff00, 0, SROM8_5GLH_MAXP, 0x00ff}, + {"maxp5gla", 0xffffff00, 0, SROM8_5GLH_MAXP, 0xff00}, + {"pa5gw0a", 0xffffff00, SRFL_PRHEX, SROM8_5G_PA, 0xffff}, + {"pa5gw1a", 0xffffff00, SRFL_PRHEX, SROM8_5G_PA+1, 0xffff}, + {"pa5gw2a", 0xffffff00, SRFL_PRHEX, SROM8_5G_PA+2, 0xffff}, + {"pa5glw0a", 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA, 0xffff}, + {"pa5glw1a", 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA+1, 0xffff}, + {"pa5glw2a", 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA+2, 0xffff}, + {"pa5ghw0a", 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA, 0xffff}, + {"pa5ghw1a", 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA+1, 0xffff}, + {"pa5ghw2a", 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA+2, 0xffff}, + {NULL, 0, 0, 0, 0} +}; + +#if !(defined(PHY_TYPE_N) && defined(PHY_TYPE_LP)) +#define PHY_TYPE_N 4 /* N-Phy value */ +#define PHY_TYPE_LP 5 /* LP-Phy value */ +#endif /* !(defined(PHY_TYPE_N) && defined(PHY_TYPE_LP)) */ +#if !defined(PHY_TYPE_NULL) +#define PHY_TYPE_NULL 0xf /* Invalid Phy value */ +#endif /* !defined(PHY_TYPE_NULL) */ + +typedef struct { + u16 phy_type; + u16 bandrange; + u16 chain; + const char *vars; +} pavars_t; + +static const pavars_t pavars[] = { + /* NPHY */ + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_2G, 0, "pa2gw0a0 pa2gw1a0 pa2gw2a0"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_2G, 1, "pa2gw0a1 pa2gw1a1 pa2gw2a1"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GL, 0, "pa5glw0a0 pa5glw1a0 pa5glw2a0"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GL, 1, "pa5glw0a1 pa5glw1a1 pa5glw2a1"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GM, 0, "pa5gw0a0 pa5gw1a0 pa5gw2a0"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GM, 1, "pa5gw0a1 pa5gw1a1 pa5gw2a1"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GH, 0, "pa5ghw0a0 pa5ghw1a0 pa5ghw2a0"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GH, 1, "pa5ghw0a1 pa5ghw1a1 pa5ghw2a1"}, + /* LPPHY */ + {PHY_TYPE_LP, WL_CHAN_FREQ_RANGE_2G, 0, "pa0b0 pa0b1 pa0b2"}, + {PHY_TYPE_LP, WL_CHAN_FREQ_RANGE_5GL, 0, "pa1lob0 pa1lob1 pa1lob2"}, + {PHY_TYPE_LP, WL_CHAN_FREQ_RANGE_5GM, 0, "pa1b0 pa1b1 pa1b2"}, + {PHY_TYPE_LP, WL_CHAN_FREQ_RANGE_5GH, 0, "pa1hib0 pa1hib1 pa1hib2"}, + {PHY_TYPE_NULL, 0, 0, ""} +}; + +typedef struct { + u16 phy_type; + u16 bandrange; + const char *vars; +} povars_t; + +static const povars_t povars[] = { + /* NPHY */ + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_2G, + "mcs2gpo0 mcs2gpo1 mcs2gpo2 mcs2gpo3 " + "mcs2gpo4 mcs2gpo5 mcs2gpo6 mcs2gpo7"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GL, + "mcs5glpo0 mcs5glpo1 mcs5glpo2 mcs5glpo3 " + "mcs5glpo4 mcs5glpo5 mcs5glpo6 mcs5glpo7"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GM, + "mcs5gpo0 mcs5gpo1 mcs5gpo2 mcs5gpo3 " + "mcs5gpo4 mcs5gpo5 mcs5gpo6 mcs5gpo7"}, + {PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GH, + "mcs5ghpo0 mcs5ghpo1 mcs5ghpo2 mcs5ghpo3 " + "mcs5ghpo4 mcs5ghpo5 mcs5ghpo6 mcs5ghpo7"}, + {PHY_TYPE_NULL, 0, ""} +}; + +typedef struct { + u8 tag; /* Broadcom subtag name */ + u8 len; /* Length field of the tuple, note that it includes the + * subtag name (1 byte): 1 + tuple content length + */ + const char *params; +} cis_tuple_t; + +#define OTP_RAW (0xff - 1) /* Reserved tuple number for wrvar Raw input */ +#define OTP_VERS_1 (0xff - 2) /* CISTPL_VERS_1 */ +#define OTP_MANFID (0xff - 3) /* CISTPL_MANFID */ +#define OTP_RAW1 (0xff - 4) /* Like RAW, but comes first */ + +static const cis_tuple_t cis_hnbuvars[] = { + {OTP_RAW1, 0, ""}, /* special case */ + {OTP_VERS_1, 0, "smanf sproductname"}, /* special case (non BRCM tuple) */ + {OTP_MANFID, 4, "2manfid 2prodid"}, /* special case (non BRCM tuple) */ + {HNBU_SROMREV, 2, "1sromrev"}, + /* NOTE: subdevid is also written to boardtype. + * Need to write HNBU_BOARDTYPE to change it if it is different. + */ + {HNBU_CHIPID, 11, "2vendid 2devid 2chiprev 2subvendid 2subdevid"}, + {HNBU_BOARDREV, 3, "2boardrev"}, + {HNBU_PAPARMS, 10, "2pa0b0 2pa0b1 2pa0b2 1pa0itssit 1pa0maxpwr 1opo"}, + {HNBU_AA, 3, "1aa2g 1aa5g"}, + {HNBU_AA, 3, "1aa0 1aa1"}, /* backward compatibility */ + {HNBU_AG, 5, "1ag0 1ag1 1ag2 1ag3"}, + {HNBU_BOARDFLAGS, 9, "4boardflags 4boardflags2"}, + {HNBU_LEDS, 5, "1ledbh0 1ledbh1 1ledbh2 1ledbh3"}, + {HNBU_CCODE, 4, "2ccode 1cctl"}, + {HNBU_CCKPO, 3, "2cckpo"}, + {HNBU_OFDMPO, 5, "4ofdmpo"}, + {HNBU_RDLID, 3, "2rdlid"}, + {HNBU_RSSISMBXA2G, 3, "0rssismf2g 0rssismc2g 0rssisav2g 0bxa2g"}, /* special case */ + {HNBU_RSSISMBXA5G, 3, "0rssismf5g 0rssismc5g 0rssisav5g 0bxa5g"}, /* special case */ + {HNBU_XTALFREQ, 5, "4xtalfreq"}, + {HNBU_TRI2G, 2, "1tri2g"}, + {HNBU_TRI5G, 4, "1tri5gl 1tri5g 1tri5gh"}, + {HNBU_RXPO2G, 2, "1rxpo2g"}, + {HNBU_RXPO5G, 2, "1rxpo5g"}, + {HNBU_BOARDNUM, 3, "2boardnum"}, + {HNBU_MACADDR, 7, "6macaddr"}, /* special case */ + {HNBU_RDLSN, 3, "2rdlsn"}, + {HNBU_BOARDTYPE, 3, "2boardtype"}, + {HNBU_LEDDC, 3, "2leddc"}, + {HNBU_RDLRNDIS, 2, "1rdlndis"}, + {HNBU_CHAINSWITCH, 5, "1txchain 1rxchain 2antswitch"}, + {HNBU_REGREV, 2, "1regrev"}, + {HNBU_FEM, 5, "0antswctl2g, 0triso2g, 0pdetrange2g, 0extpagain2g, 0tssipos2g" "0antswctl5g, 0triso5g, 0pdetrange5g, 0extpagain5g, 0tssipos5g"}, /* special case */ + {HNBU_PAPARMS_C0, 31, "1maxp2ga0 1itt2ga0 2pa2gw0a0 2pa2gw1a0 " + "2pa2gw2a0 1maxp5ga0 1itt5ga0 1maxp5gha0 1maxp5gla0 2pa5gw0a0 " + "2pa5gw1a0 2pa5gw2a0 2pa5glw0a0 2pa5glw1a0 2pa5glw2a0 2pa5ghw0a0 " + "2pa5ghw1a0 2pa5ghw2a0"}, + {HNBU_PAPARMS_C1, 31, "1maxp2ga1 1itt2ga1 2pa2gw0a1 2pa2gw1a1 " + "2pa2gw2a1 1maxp5ga1 1itt5ga1 1maxp5gha1 1maxp5gla1 2pa5gw0a1 " + "2pa5gw1a1 2pa5gw2a1 2pa5glw0a1 2pa5glw1a1 2pa5glw2a1 2pa5ghw0a1 " + "2pa5ghw1a1 2pa5ghw2a1"}, + {HNBU_PO_CCKOFDM, 19, "2cck2gpo 4ofdm2gpo 4ofdm5gpo 4ofdm5glpo " + "4ofdm5ghpo"}, + {HNBU_PO_MCS2G, 17, "2mcs2gpo0 2mcs2gpo1 2mcs2gpo2 2mcs2gpo3 " + "2mcs2gpo4 2mcs2gpo5 2mcs2gpo6 2mcs2gpo7"}, + {HNBU_PO_MCS5GM, 17, "2mcs5gpo0 2mcs5gpo1 2mcs5gpo2 2mcs5gpo3 " + "2mcs5gpo4 2mcs5gpo5 2mcs5gpo6 2mcs5gpo7"}, + {HNBU_PO_MCS5GLH, 33, "2mcs5glpo0 2mcs5glpo1 2mcs5glpo2 2mcs5glpo3 " + "2mcs5glpo4 2mcs5glpo5 2mcs5glpo6 2mcs5glpo7 " + "2mcs5ghpo0 2mcs5ghpo1 2mcs5ghpo2 2mcs5ghpo3 " + "2mcs5ghpo4 2mcs5ghpo5 2mcs5ghpo6 2mcs5ghpo7"}, + {HNBU_CCKFILTTYPE, 2, "1cckdigfilttype"}, + {HNBU_PO_CDD, 3, "2cddpo"}, + {HNBU_PO_STBC, 3, "2stbcpo"}, + {HNBU_PO_40M, 3, "2bw40po"}, + {HNBU_PO_40MDUP, 3, "2bwduppo"}, + {HNBU_RDLRWU, 2, "1rdlrwu"}, + {HNBU_WPS, 3, "1wpsgpio 1wpsled"}, + {HNBU_USBFS, 2, "1usbfs"}, + {HNBU_CUSTOM1, 5, "4customvar1"}, + {OTP_RAW, 0, ""}, /* special case */ + {HNBU_OFDMPO5G, 13, "4ofdm5gpo 4ofdm5glpo 4ofdm5ghpo"}, + {HNBU_USBEPNUM, 3, "2usbepnum"}, + {0xFF, 0, ""} +}; + +#endif /* _BHND_BCMSROM_TBL_H_ */ diff --git a/sys/dev/bhnd/bhnd.c b/sys/dev/bhnd/bhnd.c new file mode 100644 index 000000000000..ec684dfc4b81 --- /dev/null +++ b/sys/dev/bhnd/bhnd.c @@ -0,0 +1,910 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * Broadcom Home Networking Division (HND) Bus Driver. + * + * The Broadcom HND family of devices consists of both SoCs and host-connected + * networking chipsets containing a common family of Broadcom IP cores, + * including an integrated MIPS and/or ARM cores. + * + * HND devices expose a nearly identical interface whether accessible over a + * native SoC interconnect, or when connected via a host interface such as + * PCIe. As a result, the majority of hardware support code should be re-usable + * across host drivers for HND networking chipsets, as well as FreeBSD support + * for Broadcom MIPS/ARM HND SoCs. + * + * Earlier HND models used the siba(4) on-chip interconnect, while later models + * use bcma(4); the programming model is almost entirely independent + * of the actual underlying interconect. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "bhnd.h" +#include "bhndvar.h" + +#include "bhnd_nvram_if.h" + +MALLOC_DEFINE(M_BHND, "bhnd", "bhnd bus data structures"); + +/** + * bhnd_generic_probe_nomatch() reporting configuration. + */ +static const struct bhnd_nomatch { + uint16_t vendor; /**< core designer */ + uint16_t device; /**< core id */ + bool if_verbose; /**< print when bootverbose is set. */ +} bhnd_nomatch_table[] = { + { BHND_MFGID_ARM, BHND_COREID_OOB_ROUTER, true }, + { BHND_MFGID_ARM, BHND_COREID_EROM, true }, + { BHND_MFGID_ARM, BHND_COREID_PL301, true }, + { BHND_MFGID_ARM, BHND_COREID_APB_BRIDGE, true }, + { BHND_MFGID_ARM, BHND_COREID_AXI_UNMAPPED, false }, + + { BHND_MFGID_INVALID, BHND_COREID_INVALID, false } +}; + +static device_t find_nvram_child(device_t dev); + +static int compare_ascending_probe_order(const void *lhs, + const void *rhs); +static int compare_descending_probe_order(const void *lhs, + const void *rhs); + +/** + * Helper function for implementing DEVICE_ATTACH(). + * + * This function can be used to implement DEVICE_ATTACH() for bhnd(4) + * bus implementations. It calls device_probe_and_attach() for each + * of the device's children, in order. + */ +int +bhnd_generic_attach(device_t dev) +{ + device_t *devs; + int ndevs; + int error; + + if (device_is_attached(dev)) + return (EBUSY); + + if ((error = device_get_children(dev, &devs, &ndevs))) + return (error); + + qsort(devs, ndevs, sizeof(*devs), compare_ascending_probe_order); + for (int i = 0; i < ndevs; i++) { + device_t child = devs[i]; + device_probe_and_attach(child); + } + + free(devs, M_TEMP); + return (0); +} + +/** + * Helper function for implementing DEVICE_DETACH(). + * + * This function can be used to implement DEVICE_DETACH() for bhnd(4) + * bus implementations. It calls device_detach() for each + * of the device's children, in reverse order, terminating if + * any call to device_detach() fails. + */ +int +bhnd_generic_detach(device_t dev) +{ + device_t *devs; + int ndevs; + int error; + + if (!device_is_attached(dev)) + return (EBUSY); + + if ((error = device_get_children(dev, &devs, &ndevs))) + return (error); + + /* Detach in the reverse of attach order */ + qsort(devs, ndevs, sizeof(*devs), compare_descending_probe_order); + for (int i = 0; i < ndevs; i++) { + device_t child = devs[i]; + + /* Terminate on first error */ + if ((error = device_detach(child))) + goto cleanup; + } + +cleanup: + free(devs, M_TEMP); + return (error); +} + +/** + * Helper function for implementing DEVICE_SHUTDOWN(). + * + * This function can be used to implement DEVICE_SHUTDOWN() for bhnd(4) + * bus implementations. It calls device_shutdown() for each + * of the device's children, in reverse order, terminating if + * any call to device_shutdown() fails. + */ +int +bhnd_generic_shutdown(device_t dev) +{ + device_t *devs; + int ndevs; + int error; + + if (!device_is_attached(dev)) + return (EBUSY); + + if ((error = device_get_children(dev, &devs, &ndevs))) + return (error); + + /* Shutdown in the reverse of attach order */ + qsort(devs, ndevs, sizeof(*devs), compare_descending_probe_order); + for (int i = 0; i < ndevs; i++) { + device_t child = devs[i]; + + /* Terminate on first error */ + if ((error = device_shutdown(child))) + goto cleanup; + } + +cleanup: + free(devs, M_TEMP); + return (error); +} + +/** + * Helper function for implementing DEVICE_RESUME(). + * + * This function can be used to implement DEVICE_RESUME() for bhnd(4) + * bus implementations. It calls BUS_RESUME_CHILD() for each + * of the device's children, in order, terminating if + * any call to BUS_RESUME_CHILD() fails. + */ +int +bhnd_generic_resume(device_t dev) +{ + device_t *devs; + int ndevs; + int error; + + if (!device_is_attached(dev)) + return (EBUSY); + + if ((error = device_get_children(dev, &devs, &ndevs))) + return (error); + + qsort(devs, ndevs, sizeof(*devs), compare_ascending_probe_order); + for (int i = 0; i < ndevs; i++) { + device_t child = devs[i]; + + /* Terminate on first error */ + if ((error = BUS_RESUME_CHILD(device_get_parent(child), child))) + goto cleanup; + } + +cleanup: + free(devs, M_TEMP); + return (error); +} + +/** + * Helper function for implementing DEVICE_SUSPEND(). + * + * This function can be used to implement DEVICE_SUSPEND() for bhnd(4) + * bus implementations. It calls BUS_SUSPEND_CHILD() for each + * of the device's children, in reverse order. If any call to + * BUS_SUSPEND_CHILD() fails, the suspend operation is terminated and + * any devices that were suspended are resumed immediately by calling + * their BUS_RESUME_CHILD() methods. + */ +int +bhnd_generic_suspend(device_t dev) +{ + device_t *devs; + int ndevs; + int error; + + if (!device_is_attached(dev)) + return (EBUSY); + + if ((error = device_get_children(dev, &devs, &ndevs))) + return (error); + + /* Suspend in the reverse of attach order */ + qsort(devs, ndevs, sizeof(*devs), compare_descending_probe_order); + for (int i = 0; i < ndevs; i++) { + device_t child = devs[i]; + error = BUS_SUSPEND_CHILD(device_get_parent(child), child); + + /* On error, resume suspended devices and then terminate */ + if (error) { + for (int j = 0; j < i; j++) { + BUS_RESUME_CHILD(device_get_parent(devs[j]), + devs[j]); + } + + goto cleanup; + } + } + +cleanup: + free(devs, M_TEMP); + return (error); +} + +/* + * Ascending comparison of bhnd device's probe order. + */ +static int +compare_ascending_probe_order(const void *lhs, const void *rhs) +{ + device_t ldev, rdev; + int lorder, rorder; + + ldev = (*(const device_t *) lhs); + rdev = (*(const device_t *) rhs); + + lorder = BHND_BUS_GET_PROBE_ORDER(device_get_parent(ldev), ldev); + rorder = BHND_BUS_GET_PROBE_ORDER(device_get_parent(rdev), rdev); + + if (lorder < rorder) { + return (-1); + } else if (lorder > rorder) { + return (1); + } else { + return (0); + } +} + +/* + * Descending comparison of bhnd device's probe order. + */ +static int +compare_descending_probe_order(const void *lhs, const void *rhs) +{ + return (compare_ascending_probe_order(rhs, lhs)); +} + +/** + * Helper function for implementing BHND_BUS_GET_PROBE_ORDER(). + * + * This implementation determines probe ordering based on the device's class + * and other properties, including whether the device is serving as a host + * bridge. + */ +int +bhnd_generic_get_probe_order(device_t dev, device_t child) +{ + switch (bhnd_get_class(child)) { + case BHND_DEVCLASS_CC: + return (BHND_PROBE_BUS + BHND_PROBE_ORDER_FIRST); + + case BHND_DEVCLASS_CC_B: + /* fall through */ + case BHND_DEVCLASS_PMU: + return (BHND_PROBE_BUS + BHND_PROBE_ORDER_EARLY); + + case BHND_DEVCLASS_SOC_ROUTER: + return (BHND_PROBE_BUS + BHND_PROBE_ORDER_LATE); + + case BHND_DEVCLASS_SOC_BRIDGE: + return (BHND_PROBE_BUS + BHND_PROBE_ORDER_LAST); + + case BHND_DEVCLASS_CPU: + return (BHND_PROBE_CPU + BHND_PROBE_ORDER_FIRST); + + case BHND_DEVCLASS_RAM: + /* fall through */ + case BHND_DEVCLASS_MEMC: + return (BHND_PROBE_CPU + BHND_PROBE_ORDER_EARLY); + + case BHND_DEVCLASS_NVRAM: + return (BHND_PROBE_RESOURCE + BHND_PROBE_ORDER_EARLY); + + case BHND_DEVCLASS_PCI: + case BHND_DEVCLASS_PCIE: + case BHND_DEVCLASS_PCCARD: + case BHND_DEVCLASS_ENET: + case BHND_DEVCLASS_ENET_MAC: + case BHND_DEVCLASS_ENET_PHY: + case BHND_DEVCLASS_WLAN: + case BHND_DEVCLASS_WLAN_MAC: + case BHND_DEVCLASS_WLAN_PHY: + case BHND_DEVCLASS_EROM: + case BHND_DEVCLASS_OTHER: + case BHND_DEVCLASS_INVALID: + if (bhnd_is_hostb_device(child)) + return (BHND_PROBE_ROOT + BHND_PROBE_ORDER_EARLY); + + return (BHND_PROBE_DEFAULT); + } +} + +/** + * Helper function for implementing BHND_BUS_IS_REGION_VALID(). + * + * This implementation assumes that port and region numbers are 0-indexed and + * are allocated non-sparsely, using BHND_BUS_GET_PORT_COUNT() and + * BHND_BUS_GET_REGION_COUNT() to determine if @p port and @p region fall + * within the defined range. + */ +bool +bhnd_generic_is_region_valid(device_t dev, device_t child, + bhnd_port_type type, u_int port, u_int region) +{ + if (port >= bhnd_get_port_count(child, type)) + return (false); + + if (region >= bhnd_get_region_count(child, type, port)) + return (false); + + return (true); +} + +/** + * Find an NVRAM child device on @p dev, if any. + * + * @retval device_t An NVRAM device. + * @retval NULL If no NVRAM device is found. + */ +static device_t +find_nvram_child(device_t dev) +{ + device_t chipc, nvram; + + /* Look for a directly-attached NVRAM child */ + nvram = device_find_child(dev, devclass_get_name(bhnd_nvram_devclass), + -1); + if (nvram == NULL) + return (NULL); + + /* Further checks require a bhnd(4) bus */ + if (device_get_devclass(dev) != bhnd_devclass) + return (NULL); + + /* Look for a ChipCommon-attached OTP device */ + if ((chipc = bhnd_find_child(dev, BHND_DEVCLASS_CC, -1)) != NULL) { + /* Recursively search the ChipCommon device */ + if ((nvram = find_nvram_child(chipc)) != NULL) + return (nvram); + } + + /* Not found */ + return (NULL); +} + +/** + * Helper function for implementing BHND_BUS_READ_NVRAM_VAR(). + * + * This implementation searches @p dev for a valid NVRAM device. If no NVRAM + * child device is found on @p dev, the request is delegated to the + * BHND_BUS_READ_NVRAM_VAR() method on the parent + * of @p dev. + */ +int +bhnd_generic_read_nvram_var(device_t dev, device_t child, const char *name, + void *buf, size_t *size) +{ + device_t nvram; + + /* Try to find an NVRAM device applicable to @p child */ + if ((nvram = find_nvram_child(dev)) == NULL) + return (BHND_BUS_READ_NVRAM_VAR(device_get_parent(dev), child, + name, buf, size)); + + return BHND_NVRAM_GETVAR(nvram, name, buf, size); +} + +/** + * Helper function for implementing BUS_PRINT_CHILD(). + * + * This implementation requests the device's struct resource_list via + * BUS_GET_RESOURCE_LIST. + */ +int +bhnd_generic_print_child(device_t dev, device_t child) +{ + struct resource_list *rl; + int retval = 0; + + retval += bus_print_child_header(dev, child); + + rl = BUS_GET_RESOURCE_LIST(dev, child); + if (rl != NULL) { + retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, + "%#lx"); + } + + retval += printf(" at core %u", bhnd_get_core_index(child)); + + retval += bus_print_child_domain(dev, child); + retval += bus_print_child_footer(dev, child); + + return (retval); +} + +/** + * Helper function for implementing BUS_PRINT_CHILD(). + * + * This implementation requests the device's struct resource_list via + * BUS_GET_RESOURCE_LIST. + */ +void +bhnd_generic_probe_nomatch(device_t dev, device_t child) +{ + struct resource_list *rl; + const struct bhnd_nomatch *nm; + bool report; + + /* Fetch reporting configuration for this device */ + report = true; + for (nm = bhnd_nomatch_table; nm->device != BHND_COREID_INVALID; nm++) { + if (nm->vendor != bhnd_get_vendor(child)) + continue; + + if (nm->device != bhnd_get_device(child)) + continue; + + report = false; + if (bootverbose && nm->if_verbose) + report = true; + break; + } + + if (!report) + return; + + /* Print the non-matched device info */ + device_printf(dev, "<%s %s>", bhnd_get_vendor_name(child), + bhnd_get_device_name(child)); + + rl = BUS_GET_RESOURCE_LIST(dev, child); + if (rl != NULL) + resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx"); + + printf(" at core %u (no driver attached)\n", + bhnd_get_core_index(child)); +} + +/** + * Default implementation of BUS_CHILD_PNPINFO_STR(). + */ +static int +bhnd_child_pnpinfo_str(device_t dev, device_t child, char *buf, + size_t buflen) +{ + if (device_get_parent(child) != dev) { + return (BUS_CHILD_PNPINFO_STR(device_get_parent(dev), child, + buf, buflen)); + } + + snprintf(buf, buflen, "vendor=0x%hx device=0x%hx rev=0x%hhx", + bhnd_get_vendor(child), bhnd_get_device(child), + bhnd_get_hwrev(child)); + + return (0); +} + +/** + * Default implementation of implementing BUS_PRINT_CHILD(). + */ +static int +bhnd_child_location_str(device_t dev, device_t child, char *buf, + size_t buflen) +{ + bhnd_addr_t addr; + bhnd_size_t size; + + if (device_get_parent(child) != dev) { + return (BUS_CHILD_LOCATION_STR(device_get_parent(dev), child, + buf, buflen)); + } + + + if (bhnd_get_region_addr(child, BHND_PORT_DEVICE, 0, 0, &addr, &size)) { + /* No device default port/region */ + if (buflen > 0) + *buf = '\0'; + return (0); + } + + snprintf(buf, buflen, "port0.0=0x%llx", (unsigned long long) addr); + return (0); +} + +/** + * Helper function for implementing BUS_SUSPEND_CHILD(). + * + * TODO: Power management + * + * If @p child is not a direct child of @p dev, suspension is delegated to + * the @p dev parent. + */ +int +bhnd_generic_suspend_child(device_t dev, device_t child) +{ + if (device_get_parent(child) != dev) + BUS_SUSPEND_CHILD(device_get_parent(dev), child); + + return bus_generic_suspend_child(dev, child); +} + +/** + * Helper function for implementing BUS_RESUME_CHILD(). + * + * TODO: Power management + * + * If @p child is not a direct child of @p dev, suspension is delegated to + * the @p dev parent. + */ +int +bhnd_generic_resume_child(device_t dev, device_t child) +{ + if (device_get_parent(child) != dev) + BUS_RESUME_CHILD(device_get_parent(dev), child); + + return bus_generic_resume_child(dev, child); +} + +/** + * Helper function for implementing BHND_BUS_IS_HOSTB_DEVICE(). + * + * If a parent device is available, this implementation delegates the + * request to the BHND_BUS_IS_HOSTB_DEVICE() method on the parent of @p dev. + * + * If no parent device is available (i.e. on a the bus root), false + * is returned. + */ +bool +bhnd_generic_is_hostb_device(device_t dev, device_t child) { + if (device_get_parent(dev) != NULL) + return (BHND_BUS_IS_HOSTB_DEVICE(device_get_parent(dev), + child)); + + return (false); +} + +/** + * Helper function for implementing BHND_BUS_IS_HW_DISABLED(). + * + * If a parent device is available, this implementation delegates the + * request to the BHND_BUS_IS_HW_DISABLED() method on the parent of @p dev. + * + * If no parent device is available (i.e. on a the bus root), the hardware + * is assumed to be usable and false is returned. + */ +bool +bhnd_generic_is_hw_disabled(device_t dev, device_t child) +{ + if (device_get_parent(dev) != NULL) + return (BHND_BUS_IS_HW_DISABLED(device_get_parent(dev), child)); + + return (false); +} + +/** + * Helper function for implementing BHND_BUS_GET_CHIPID(). + * + * This implementation delegates the request to the BHND_BUS_GET_CHIPID() + * method on the parent of @p dev. + */ +const struct bhnd_chipid * +bhnd_generic_get_chipid(device_t dev, device_t child) { + return (BHND_BUS_GET_CHIPID(device_get_parent(dev), child)); +} + +/** + * Helper function for implementing BHND_BUS_ALLOC_RESOURCE(). + * + * This simple implementation of BHND_BUS_ALLOC_RESOURCE() determines + * any default values via BUS_GET_RESOURCE_LIST(), and calls + * BHND_BUS_ALLOC_RESOURCE() method of the parent of @p dev. + * + * If no parent device is available, the request is instead delegated to + * BUS_ALLOC_RESOURCE(). + */ +struct bhnd_resource * +bhnd_generic_alloc_bhnd_resource(device_t dev, device_t child, int type, + int *rid, rman_res_t start, rman_res_t end, rman_res_t count, + u_int flags) +{ + struct bhnd_resource *r; + struct resource_list *rl; + struct resource_list_entry *rle; + bool isdefault; + bool passthrough; + + passthrough = (device_get_parent(child) != dev); + isdefault = (start == 0UL && end == ~0UL); + + /* the default RID must always be the first device port/region. */ + if (!passthrough && *rid == 0) { + int rid0 = bhnd_get_port_rid(child, BHND_PORT_DEVICE, 0, 0); + KASSERT(*rid == rid0, + ("rid 0 does not map to the first device port (%d)", rid0)); + } + + /* Determine locally-known defaults before delegating the request. */ + if (!passthrough && isdefault) { + /* fetch resource list from child's bus */ + rl = BUS_GET_RESOURCE_LIST(dev, child); + if (rl == NULL) + return (NULL); /* no resource list */ + + /* look for matching type/rid pair */ + rle = resource_list_find(BUS_GET_RESOURCE_LIST(dev, child), + type, *rid); + if (rle == NULL) + return (NULL); + + /* set default values */ + start = rle->start; + end = rle->end; + count = ulmax(count, rle->count); + } + + /* Try to delegate to our parent. */ + if (device_get_parent(dev) != NULL) { + return (BHND_BUS_ALLOC_RESOURCE(device_get_parent(dev), child, + type, rid, start, end, count, flags)); + } + + /* If this is the bus root, use a real bus-allocated resource */ + r = malloc(sizeof(struct bhnd_resource), M_BHND, M_NOWAIT); + if (r == NULL) + return NULL; + + /* Allocate the bus resource, marking it as 'direct' (not requiring + * any bus window remapping to perform I/O) */ + r->direct = true; + r->res = BUS_ALLOC_RESOURCE(dev, child, type, rid, start, end, + count, flags); + + if (r->res == NULL) { + free(r, M_BHND); + return NULL; + } + + return (r); +} + +/** + * Helper function for implementing BHND_BUS_RELEASE_RESOURCE(). + * + * This simple implementation of BHND_BUS_RELEASE_RESOURCE() simply calls the + * BHND_BUS_RELEASE_RESOURCE() method of the parent of @p dev. + * + * If no parent device is available, the request is delegated to + * BUS_RELEASE_RESOURCE(). + */ +int +bhnd_generic_release_bhnd_resource(device_t dev, device_t child, int type, + int rid, struct bhnd_resource *r) +{ + int error; + + /* Try to delegate to the parent. */ + if (device_get_parent(dev) != NULL) + return (BHND_BUS_RELEASE_RESOURCE(device_get_parent(dev), child, + type, rid, r)); + + /* Release the resource directly */ + if (!r->direct) { + panic("bhnd indirect resource released without " + "bhnd parent bus"); + } + + error = BUS_RELEASE_RESOURCE(dev, child, type, rid, r->res); + if (error) + return (error); + + free(r, M_BHND); + return (0); +} + +/** + * Helper function for implementing BHND_BUS_ACTIVATE_RESOURCE(). + * + * This simple implementation of BHND_BUS_ACTIVATE_RESOURCE() simply calls the + * BHND_BUS_ACTIVATE_RESOURCE() method of the parent of @p dev. + * + * If no parent device is available, the request is delegated to + * BUS_ACTIVATE_RESOURCE(). + */ +int +bhnd_generic_activate_bhnd_resource(device_t dev, device_t child, int type, + int rid, struct bhnd_resource *r) +{ + /* Try to delegate to the parent */ + if (device_get_parent(dev) != NULL) + return (BHND_BUS_ACTIVATE_RESOURCE(device_get_parent(dev), + child, type, rid, r)); + + /* Activate the resource directly */ + if (!r->direct) { + panic("bhnd indirect resource released without " + "bhnd parent bus"); + } + + return (BUS_ACTIVATE_RESOURCE(dev, child, type, rid, r->res)); +}; + +/** + * Helper function for implementing BHND_BUS_DEACTIVATE_RESOURCE(). + * + * This simple implementation of BHND_BUS_ACTIVATE_RESOURCE() simply calls the + * BHND_BUS_ACTIVATE_RESOURCE() method of the parent of @p dev. + * + * If no parent device is available, the request is delegated to + * BUS_DEACTIVATE_RESOURCE(). + */ +int +bhnd_generic_deactivate_bhnd_resource(device_t dev, device_t child, int type, + int rid, struct bhnd_resource *r) +{ + if (device_get_parent(dev) != NULL) + return (BHND_BUS_DEACTIVATE_RESOURCE(device_get_parent(dev), + child, type, rid, r)); + + /* De-activate the resource directly */ + if (!r->direct) { + panic("bhnd indirect resource released without " + "bhnd parent bus"); + } + + return (BUS_DEACTIVATE_RESOURCE(dev, child, type, rid, r->res)); +}; + +/* + * Delegate all indirect I/O to the parent device. When inherited by + * non-bridged bus implementations, resources will never be marked as + * indirect, and these methods should never be called. + */ + +static uint8_t +bhnd_read_1(device_t dev, device_t child, struct bhnd_resource *r, + bus_size_t offset) +{ + return (BHND_BUS_READ_1(device_get_parent(dev), child, r, offset)); +} + +static uint16_t +bhnd_read_2(device_t dev, device_t child, struct bhnd_resource *r, + bus_size_t offset) +{ + return (BHND_BUS_READ_2(device_get_parent(dev), child, r, offset)); +} + +static uint32_t +bhnd_read_4(device_t dev, device_t child, struct bhnd_resource *r, + bus_size_t offset) +{ + return (BHND_BUS_READ_4(device_get_parent(dev), child, r, offset)); +} + +static void +bhnd_write_1(device_t dev, device_t child, struct bhnd_resource *r, + bus_size_t offset, uint8_t value) +{ + BHND_BUS_WRITE_1(device_get_parent(dev), child, r, offset, value); +} + +static void +bhnd_write_2(device_t dev, device_t child, struct bhnd_resource *r, + bus_size_t offset, uint16_t value) +{ + BHND_BUS_WRITE_2(device_get_parent(dev), child, r, offset, value); +} + +static void +bhnd_write_4(device_t dev, device_t child, struct bhnd_resource *r, + bus_size_t offset, uint32_t value) +{ + BHND_BUS_WRITE_4(device_get_parent(dev), child, r, offset, value); +} + +static void +bhnd_barrier(device_t dev, device_t child, struct bhnd_resource *r, + bus_size_t offset, bus_size_t length, int flags) +{ + BHND_BUS_BARRIER(device_get_parent(dev), child, r, offset, length, + flags); +} + +static device_method_t bhnd_methods[] = { + /* Device interface */ \ + DEVMETHOD(device_attach, bhnd_generic_attach), + DEVMETHOD(device_detach, bhnd_generic_detach), + DEVMETHOD(device_shutdown, bhnd_generic_shutdown), + DEVMETHOD(device_suspend, bhnd_generic_suspend), + DEVMETHOD(device_resume, bhnd_generic_resume), + + /* Bus interface */ + DEVMETHOD(bus_probe_nomatch, bhnd_generic_probe_nomatch), + DEVMETHOD(bus_print_child, bhnd_generic_print_child), + DEVMETHOD(bus_child_pnpinfo_str, bhnd_child_pnpinfo_str), + DEVMETHOD(bus_child_location_str, bhnd_child_location_str), + + DEVMETHOD(bus_suspend_child, bhnd_generic_suspend_child), + DEVMETHOD(bus_resume_child, bhnd_generic_resume_child), + + DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), + DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), + DEVMETHOD(bus_delete_resource, bus_generic_rl_delete_resource), + DEVMETHOD(bus_alloc_resource, bus_generic_rl_alloc_resource), + DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource), + DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource), + DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), + DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), + + DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), + DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + DEVMETHOD(bus_config_intr, bus_generic_config_intr), + DEVMETHOD(bus_bind_intr, bus_generic_bind_intr), + DEVMETHOD(bus_describe_intr, bus_generic_describe_intr), + + DEVMETHOD(bus_get_dma_tag, bus_generic_get_dma_tag), + + /* BHND interface */ + DEVMETHOD(bhnd_bus_alloc_resource, bhnd_generic_alloc_bhnd_resource), + DEVMETHOD(bhnd_bus_release_resource, bhnd_generic_release_bhnd_resource), + DEVMETHOD(bhnd_bus_activate_resource, bhnd_generic_activate_bhnd_resource), + DEVMETHOD(bhnd_bus_activate_resource, bhnd_generic_deactivate_bhnd_resource), + DEVMETHOD(bhnd_bus_get_chipid, bhnd_generic_get_chipid), + DEVMETHOD(bhnd_bus_get_probe_order, bhnd_generic_get_probe_order), + DEVMETHOD(bhnd_bus_read_1, bhnd_read_1), + DEVMETHOD(bhnd_bus_read_2, bhnd_read_2), + DEVMETHOD(bhnd_bus_read_4, bhnd_read_4), + DEVMETHOD(bhnd_bus_write_1, bhnd_write_1), + DEVMETHOD(bhnd_bus_write_2, bhnd_write_2), + DEVMETHOD(bhnd_bus_write_4, bhnd_write_4), + DEVMETHOD(bhnd_bus_barrier, bhnd_barrier), + + DEVMETHOD_END +}; + +devclass_t bhnd_devclass; /**< bhnd bus. */ +devclass_t bhnd_hostb_devclass; /**< bhnd bus host bridge. */ +devclass_t bhnd_nvram_devclass; /**< bhnd NVRAM device */ + +DEFINE_CLASS_0(bhnd, bhnd_driver, bhnd_methods, sizeof(struct bhnd_softc)); +MODULE_VERSION(bhnd, 1); diff --git a/sys/dev/bhnd/bhnd.h b/sys/dev/bhnd/bhnd.h new file mode 100644 index 000000000000..15e56f6cd2e9 --- /dev/null +++ b/sys/dev/bhnd/bhnd.h @@ -0,0 +1,576 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $FreeBSD$ + */ + +#ifndef _BHND_BHND_H_ +#define _BHND_BHND_H_ + +#include +#include + +#include + +#include "bhnd_ids.h" +#include "bhnd_types.h" +#include "bhnd_bus_if.h" + +extern devclass_t bhnd_devclass; +extern devclass_t bhnd_hostb_devclass; +extern devclass_t bhnd_nvram_devclass; + +/** + * bhnd child instance variables + */ +enum bhnd_device_vars { + BHND_IVAR_VENDOR, /**< Designer's JEP-106 manufacturer ID. */ + BHND_IVAR_DEVICE, /**< Part number */ + BHND_IVAR_HWREV, /**< Core revision */ + BHND_IVAR_DEVICE_CLASS, /**< Core class (@sa bhnd_devclass_t) */ + BHND_IVAR_VENDOR_NAME, /**< Core vendor name */ + BHND_IVAR_DEVICE_NAME, /**< Core name */ + BHND_IVAR_CORE_INDEX, /**< Bus-assigned core number */ + BHND_IVAR_CORE_UNIT, /**< Bus-assigned core unit number, + assigned sequentially (starting at 0) for + each vendor/device pair. */ +}; + +/** + * bhnd device probe priority bands. + */ +enum { + BHND_PROBE_ROOT = 0, /**< Nexus or host bridge */ + BHND_PROBE_BUS = 1000, /**< Busses and bridges */ + BHND_PROBE_CPU = 2000, /**< CPU devices */ + BHND_PROBE_INTERRUPT = 3000, /**< Interrupt controllers. */ + BHND_PROBE_TIMER = 4000, /**< Timers and clocks. */ + BHND_PROBE_RESOURCE = 5000, /**< Resource discovery (including NVRAM/SPROM) */ + BHND_PROBE_DEFAULT = 6000, /**< Default device priority */ +}; + +/** + * Constants defining fine grained ordering within a BHND_PROBE_* priority band. + * + * Example: + * @code + * BHND_PROBE_BUS + BHND_PROBE_ORDER_FIRST + * @endcode + */ +enum { + BHND_PROBE_ORDER_FIRST = 0, + BHND_PROBE_ORDER_EARLY = 25, + BHND_PROBE_ORDER_MIDDLE = 50, + BHND_PROBE_ORDER_LATE = 75, + BHND_PROBE_ORDER_LAST = 100 + +}; + +/* + * Simplified accessors for bhnd device ivars + */ +#define BHND_ACCESSOR(var, ivar, type) \ + __BUS_ACCESSOR(bhnd, var, BHND, ivar, type) + +BHND_ACCESSOR(vendor, VENDOR, uint16_t); +BHND_ACCESSOR(device, DEVICE, uint16_t); +BHND_ACCESSOR(hwrev, HWREV, uint8_t); +BHND_ACCESSOR(class, DEVICE_CLASS, bhnd_devclass_t); +BHND_ACCESSOR(vendor_name, VENDOR_NAME, const char *); +BHND_ACCESSOR(device_name, DEVICE_NAME, const char *); +BHND_ACCESSOR(core_index, CORE_INDEX, u_int); +BHND_ACCESSOR(core_unit, CORE_UNIT, int); + +#undef BHND_ACCESSOR + +/** + * Chip Identification + * + * This is read from the ChipCommon ID register; on earlier bhnd(4) devices + * where ChipCommon is unavailable, known values must be supplied. + */ +struct bhnd_chipid { + uint16_t chip_id; /**< chip id (BHND_CHIPID_*) */ + uint8_t chip_rev; /**< chip revision */ + uint8_t chip_pkg; /**< chip package (BHND_PKGID_*) */ + uint8_t chip_type; /**< chip type (BHND_CHIPTYPE_*) */ + + bhnd_addr_t enum_addr; /**< chip_type-specific enumeration + * address; either the siba(4) base + * core register block, or the bcma(4) + * EROM core address. */ + + uint8_t ncores; /**< number of cores, if known. 0 if + * not available. */ +}; + +/** +* A bhnd(4) bus resource. +* +* This provides an abstract interface to per-core resources that may require +* bus-level remapping of address windows prior to access. +*/ +struct bhnd_resource { + struct resource *res; /**< the system resource. */ + bool direct; /**< false if the resource requires + * bus window remapping before it + * is MMIO accessible. */ +}; + +/** + * A bhnd(4) core descriptor. + */ +struct bhnd_core_info { + uint16_t vendor; /**< vendor */ + uint16_t device; /**< device */ + uint16_t hwrev; /**< hardware revision */ + u_int core_idx; /**< bus-assigned core index */ + int unit; /**< bus-assigned core unit */ +}; + + +/** + * A hardware revision match descriptor. + */ +struct bhnd_hwrev_match { + uint16_t start; /**< first revision, or BHND_HWREV_INVALID + to match on any revision. */ + uint16_t end; /**< last revision, or BHND_HWREV_INVALID + to match on any revision. */ +}; + +/** + * Wildcard hardware revision match descriptor. + */ +#define BHND_HWREV_MATCH_ANY { BHND_HWREV_INVALID, BHND_HWREV_INVALID } + + +/** A core match descriptor. */ +struct bhnd_core_match { + uint16_t vendor; /**< required JEP106 device vendor or BHND_MFGID_INVALID. */ + uint16_t device; /**< required core ID or BHND_COREID_INVALID */ + struct bhnd_hwrev_match hwrev; /**< matching revisions. */ + bhnd_devclass_t class; /**< required class or BHND_DEVCLASS_INVALID */ + int unit; /**< required core unit, or -1 */ +}; + + +/** + * Revision-specific hardware quirk descriptor. + * + * Defines a set of quirk flags applicable to a range of hardware + * revisions. + */ +struct bhnd_device_quirk { + struct bhnd_hwrev_match hwrev; /**< applicable hardware revisions */ + uint32_t quirks; /**< applicable quirk flags */ +}; + +/** + * Define a bhnd_device_quirk over a range of hardware revisions. + * + * @param _start The first applicable hardware revision. + * @param _end The last applicable hardware revision, or BHND_HWREV_INVALID + * to match on any revision. + * @param _quirks Quirk flags applicable to this revision range. + */ +#define BHND_QUIRK_HWREV_RANGE(_start, _end, _quirks) \ + { .hwrev = { _start, _end }, .quirks = _quirks } + +/** + * Define a bhnd_device_quirk for a specific hardware revision. + * + * @param _hwrev The hardware revision to match on. + * @param _quirks Quirk flags applicable to this revision. + */ +#define BHND_QUIRK_HWREV_EQ(_hwrev, _quirks) \ + BHND_QUIRK_HWREV_RANGE(_hwrev, _hwrev, _quirks) + +/** + * Define a bhnd_device_quirk for any hardware revision equal or greater + * than @p _start. + * + * @param _start The first hardware revision to match on. + * @param _quirks Quirk flags applicable to this revision. + */ +#define BHND_QUIRK_HWREV_GTE(_start, _quirks) \ + BHND_QUIRK_HWREV_RANGE(_start, BHND_HWREV_INVALID, _quirks) + +/** + * Define a bhnd_device_quirk for any hardware revision equal or less + * than @p _end. + * + * @param _end The last hardware revision to match on. + * @param _quirks Quirk flags applicable to this revision. + */ +#define BHND_QUIRK_HWREV_LTE(_end, _quirks) \ + BHND_QUIRK_HWREV_RANGE(0, _end, _quirks) + +/** Mark the end of a bhnd_device_quirk table. */ +#define BHND_QUIRK_HWREV_END { BHND_HWREV_MATCH_ANY, 0 } + +const char *bhnd_vendor_name(uint16_t vendor); +const char *bhnd_port_type_name(bhnd_port_type port_type); + +const char *bhnd_find_core_name(uint16_t vendor, + uint16_t device); +bhnd_devclass_t bhnd_find_core_class(uint16_t vendor, + uint16_t device); + +const char *bhnd_core_name(const struct bhnd_core_info *ci); +bhnd_devclass_t bhnd_core_class(const struct bhnd_core_info *ci); + + +device_t bhnd_match_child(device_t dev, + const struct bhnd_core_match *desc); + +device_t bhnd_find_child(device_t dev, + bhnd_devclass_t class, int unit); + +const struct bhnd_core_info *bhnd_match_core( + const struct bhnd_core_info *cores, + u_int num_cores, + const struct bhnd_core_match *desc); + +const struct bhnd_core_info *bhnd_find_core( + const struct bhnd_core_info *cores, + u_int num_cores, bhnd_devclass_t class); + +bool bhnd_core_matches( + const struct bhnd_core_info *core, + const struct bhnd_core_match *desc); + +bool bhnd_hwrev_matches(uint16_t hwrev, + const struct bhnd_hwrev_match *desc); + +bool bhnd_device_matches(device_t dev, + const struct bhnd_core_match *desc); + +struct bhnd_core_info bhnd_get_core_info(device_t dev); + + +int bhnd_alloc_resources(device_t dev, + struct resource_spec *rs, + struct bhnd_resource **res); + +void bhnd_release_resources(device_t dev, + const struct resource_spec *rs, + struct bhnd_resource **res); + +struct bhnd_chipid bhnd_parse_chipid(uint32_t idreg, + bhnd_addr_t enum_addr); + +int bhnd_read_chipid(device_t dev, + struct resource_spec *rs, + bus_size_t chipc_offset, + struct bhnd_chipid *result); + +void bhnd_set_generic_core_desc(device_t dev); + + +/** + * Return true if @p dev is serving as a host bridge for its parent bhnd + * bus. + * + * @param dev A bhnd bus child device. + */ +static inline bool +bhnd_is_hostb_device(device_t dev) { + return (BHND_BUS_IS_HOSTB_DEVICE(device_get_parent(dev), dev)); +} + +/** + * Return true if the hardware components required by @p dev are known to be + * unpopulated or otherwise unusable. + * + * In some cases, enumerated devices may have pins that are left floating, or + * the hardware may otherwise be non-functional; this method allows a parent + * device to explicitly specify if a successfully enumerated @p dev should + * be disabled. + * + * @param dev A bhnd bus child device. + */ +static inline bool +bhnd_is_hw_disabled(device_t dev) { + return (BHND_BUS_IS_HW_DISABLED(device_get_parent(dev), dev)); +} + +/** + * Allocate a resource from a device's parent bhnd(4) bus. + * + * @param dev The device requesting resource ownership. + * @param type The type of resource to allocate. This may be any type supported + * by the standard bus APIs. + * @param rid The bus-specific handle identifying the resource being allocated. + * @param start The start address of the resource. + * @param end The end address of the resource. + * @param count The size of the resource. + * @param flags The flags for the resource to be allocated. These may be any + * values supported by the standard bus APIs. + * + * To request the resource's default addresses, pass @p start and + * @p end values of @c 0UL and @c ~0UL, respectively, and + * a @p count of @c 1. + * + * @retval NULL The resource could not be allocated. + * @retval resource The allocated resource. + */ +static inline struct bhnd_resource * +bhnd_alloc_resource(device_t dev, int type, int *rid, rman_res_t start, + rman_res_t end, rman_res_t count, u_int flags) +{ + return BHND_BUS_ALLOC_RESOURCE(device_get_parent(dev), dev, type, rid, + start, end, count, flags); +} + + +/** + * Allocate a resource from a device's parent bhnd(4) bus, using the + * resource's default start, end, and count values. + * + * @param dev The device requesting resource ownership. + * @param type The type of resource to allocate. This may be any type supported + * by the standard bus APIs. + * @param rid The bus-specific handle identifying the resource being allocated. + * @param flags The flags for the resource to be allocated. These may be any + * values supported by the standard bus APIs. + * + * @retval NULL The resource could not be allocated. + * @retval resource The allocated resource. + */ +static inline struct bhnd_resource * +bhnd_alloc_resource_any(device_t dev, int type, int *rid, u_int flags) +{ + return bhnd_alloc_resource(dev, type, rid, 0UL, ~0UL, 1, flags); +} + +/** + * Activate a previously allocated bhnd resource. + * + * @param dev The device holding ownership of the allocated resource. + * @param type The type of the resource. + * @param rid The bus-specific handle identifying the resource. + * @param r A pointer to the resource returned by bhnd_alloc_resource or + * BHND_BUS_ALLOC_RESOURCE. + * + * @retval 0 success + * @retval non-zero an error occured while activating the resource. + */ +static inline int +bhnd_activate_resource(device_t dev, int type, int rid, + struct bhnd_resource *r) +{ + return BHND_BUS_ACTIVATE_RESOURCE(device_get_parent(dev), dev, type, + rid, r); +} + +/** + * Deactivate a previously activated bhnd resource. + * + * @param dev The device holding ownership of the activated resource. + * @param type The type of the resource. + * @param rid The bus-specific handle identifying the resource. + * @param r A pointer to the resource returned by bhnd_alloc_resource or + * BHND_BUS_ALLOC_RESOURCE. + * + * @retval 0 success + * @retval non-zero an error occured while activating the resource. + */ +static inline int +bhnd_deactivate_resource(device_t dev, int type, int rid, + struct bhnd_resource *r) +{ + return BHND_BUS_DEACTIVATE_RESOURCE(device_get_parent(dev), dev, type, + rid, r); +} + +/** + * Free a resource allocated by bhnd_alloc_resource(). + * + * @param dev The device holding ownership of the resource. + * @param type The type of the resource. + * @param rid The bus-specific handle identifying the resource. + * @param r A pointer to the resource returned by bhnd_alloc_resource or + * BHND_ALLOC_RESOURCE. + * + * @retval 0 success + * @retval non-zero an error occured while activating the resource. + */ +static inline int +bhnd_release_resource(device_t dev, int type, int rid, + struct bhnd_resource *r) +{ + return BHND_BUS_RELEASE_RESOURCE(device_get_parent(dev), dev, type, + rid, r); +} + +/** + * Return true if @p region_num is a valid region on @p port_num of + * @p type attached to @p dev. + * + * @param dev A bhnd bus child device. + * @param type The port type being queried. + * @param port_num The port number being queried. + * @param region_num The region number being queried. + */ +static inline bool +bhnd_is_region_valid(device_t dev, bhnd_port_type type, u_int port_num, + u_int region_num) +{ + return (BHND_BUS_IS_REGION_VALID(device_get_parent(dev), dev, type, + port_num, region_num)); +} + +/** + * Return the number of ports of type @p type attached to @p def. + * + * @param dev A bhnd bus child device. + * @param type The port type being queried. + */ +static inline u_int +bhnd_get_port_count(device_t dev, bhnd_port_type type) { + return (BHND_BUS_GET_PORT_COUNT(device_get_parent(dev), dev, type)); +} + +/** + * Return the number of memory regions mapped to @p child @p port of + * type @p type. + * + * @param dev A bhnd bus child device. + * @param port The port number being queried. + * @param type The port type being queried. + */ +static inline u_int +bhnd_get_region_count(device_t dev, bhnd_port_type type, u_int port) { + return (BHND_BUS_GET_REGION_COUNT(device_get_parent(dev), dev, type, + port)); +} + +/** + * Return the resource-ID for a memory region on the given device port. + * + * @param dev A bhnd bus child device. + * @param type The port type. + * @param port The port identifier. + * @param region The identifier of the memory region on @p port. + * + * @retval int The RID for the given @p port and @p region on @p device. + * @retval -1 No such port/region found. + */ +static inline int +bhnd_get_port_rid(device_t dev, bhnd_port_type type, u_int port, u_int region) +{ + return BHND_BUS_GET_PORT_RID(device_get_parent(dev), dev, type, port, + region); +} + +/** + * Decode a port / region pair on @p dev defined by @p rid. + * + * @param dev A bhnd bus child device. + * @param type The resource type. + * @param rid The resource identifier. + * @param[out] port_type The decoded port type. + * @param[out] port The decoded port identifier. + * @param[out] region The decoded region identifier. + * + * @retval 0 success + * @retval non-zero No matching port/region found. + */ +static inline int +bhnd_decode_port_rid(device_t dev, int type, int rid, bhnd_port_type *port_type, + u_int *port, u_int *region) +{ + return BHND_BUS_DECODE_PORT_RID(device_get_parent(dev), dev, type, rid, + port_type, port, region); +} + +/** + * Get the address and size of @p region on @p port. + * + * @param dev A bhnd bus child device. + * @param port_type The port type. + * @param port The port identifier. + * @param region The identifier of the memory region on @p port. + * @param[out] region_addr The region's base address. + * @param[out] region_size The region's size. + * + * @retval 0 success + * @retval non-zero No matching port/region found. + */ +static inline int +bhnd_get_region_addr(device_t dev, bhnd_port_type port_type, u_int port, + u_int region, bhnd_addr_t *region_addr, bhnd_size_t *region_size) +{ + return BHND_BUS_GET_REGION_ADDR(device_get_parent(dev), dev, port_type, + port, region, region_addr, region_size); +} + +/* + * bhnd bus-level equivalents of the bus_(read|write|set|barrier|...) + * macros (compatible with bhnd_resource). + * + * Generated with bhnd/tools/bus_macro.sh + */ +#define bhnd_bus_barrier(r, o, l, f) \ + ((r)->direct) ? \ + bus_barrier((r)->res, (o), (l), (f)) : \ + BHND_BUS_BARRIER(device_get_parent(rman_get_device((r)->res)), \ + rman_get_device((r)->res), (r), (o), (l), (f)) +#define bhnd_bus_read_1(r, o) \ + ((r)->direct) ? \ + bus_read_1((r)->res, (o)) : \ + BHND_BUS_READ_1(device_get_parent(rman_get_device((r)->res)), \ + rman_get_device((r)->res), (r), (o)) +#define bhnd_bus_write_1(r, o, v) \ + ((r)->direct) ? \ + bus_write_1((r)->res, (o), (v)) : \ + BHND_BUS_WRITE_1(device_get_parent(rman_get_device((r)->res)), \ + rman_get_device((r)->res), (r), (o), (v)) +#define bhnd_bus_read_2(r, o) \ + ((r)->direct) ? \ + bus_read_2((r)->res, (o)) : \ + BHND_BUS_READ_2(device_get_parent(rman_get_device((r)->res)), \ + rman_get_device((r)->res), (r), (o)) +#define bhnd_bus_write_2(r, o, v) \ + ((r)->direct) ? \ + bus_write_2((r)->res, (o), (v)) : \ + BHND_BUS_WRITE_2(device_get_parent(rman_get_device((r)->res)), \ + rman_get_device((r)->res), (r), (o), (v)) +#define bhnd_bus_read_4(r, o) \ + ((r)->direct) ? \ + bus_read_4((r)->res, (o)) : \ + BHND_BUS_READ_4(device_get_parent(rman_get_device((r)->res)), \ + rman_get_device((r)->res), (r), (o)) +#define bhnd_bus_write_4(r, o, v) \ + ((r)->direct) ? \ + bus_write_4((r)->res, (o), (v)) : \ + BHND_BUS_WRITE_4(device_get_parent(rman_get_device((r)->res)), \ + rman_get_device((r)->res), (r), (o), (v)) + +#endif /* _BHND_BHND_H_ */ diff --git a/sys/dev/bhnd/bhnd_bus_if.m b/sys/dev/bhnd/bhnd_bus_if.m new file mode 100644 index 000000000000..b7eb9c5d3d1e --- /dev/null +++ b/sys/dev/bhnd/bhnd_bus_if.m @@ -0,0 +1,458 @@ +#- +# Copyright (c) 2015 Landon Fuller +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# $FreeBSD$ + +#include +#include +#include + +#include + +INTERFACE bhnd_bus; + +# +# bhnd(4) bus interface +# + +HEADER { + /* forward declarations */ + struct bhnd_core_info; + struct bhnd_chipid; + struct bhnd_resource; + struct bhnd_bus_ctx; +} + +CODE { + #include + + #include + + static struct bhnd_chipid * + bhnd_bus_null_get_chipid(device_t dev, device_t child) + { + panic("bhnd_get_chipid unimplemented"); + } + + static int + bhnd_bus_null_get_port_rid(device_t dev, device_t child, + bhnd_port_type port_type, u_int port, u_int region) + { + return (-1); + } + + static int + bhnd_bus_null_decode_port_rid(device_t dev, device_t child, int type, + int rid, bhnd_port_type *port_type, u_int *port, u_int *region) + { + return (ENOENT); + } + + static int + bhnd_bus_null_get_region_addr(device_t dev, device_t child, + bhnd_port_type type, u_int port, u_int region, bhnd_addr_t *addr, + bhnd_size_t *size) + { + return (ENOENT); + } + + static int + bhnd_bus_null_read_nvram_var(device_t dev, device_t child, + const char *name, void *buf, size_t *size) + { + return (ENOENT); + } +} + +/** + * Returns true if @p child is serving as a host bridge for the bhnd + * bus. + * + * The default implementation will walk the parent device tree until + * the root node is hit, returning false. + * + * @param dev The device whose child is being examined. + * @param child The child device. + */ +METHOD bool is_hostb_device { + device_t dev; + device_t child; +} DEFAULT bhnd_generic_is_hostb_device; + +/** + * Return true if the hardware components required by @p child are unpopulated + * or otherwise unusable. + * + * In some cases, enumerated devices may have pins that are left floating, or + * the hardware may otherwise be non-functional; this method allows a parent + * device to explicitly specify if a successfully enumerated @p child should + * be disabled. + * + * @param dev The device whose child is being examined. + * @param child The child device. + */ +METHOD bool is_hw_disabled { + device_t dev; + device_t child; +} DEFAULT bhnd_generic_is_hw_disabled; + +/** + * Return the probe (and attach) order for @p child. + * + * All devices on the bhnd(4) bus will be probed, attached, or resumed in + * ascending order; they will be suspended, shutdown, and detached in + * descending order. + * + * The following device methods will be dispatched in ascending probe order + * by the bus: + * + * - DEVICE_PROBE() + * - DEVICE_ATTACH() + * - DEVICE_RESUME() + * + * The following device methods will be dispatched in descending probe order + * by the bus: + * + * - DEVICE_SHUTDOWN() + * - DEVICE_DETACH() + * - DEVICE_SUSPEND() + * + * @param dev The device whose child is being examined. + * @param child The child device. + * + * Refer to BHND_PROBE_* and BHND_PROBE_ORDER_* for the standard set of + * priorities. + */ +METHOD int get_probe_order { + device_t dev; + device_t child; +} DEFAULT bhnd_generic_get_probe_order; + +/** + * Return the BHND chip identification for the parent bus. + * + * @param dev The device whose child is being examined. + * @param child The child device. + */ +METHOD const struct bhnd_chipid * get_chipid { + device_t dev; + device_t child; +} DEFAULT bhnd_bus_null_get_chipid; + +/** + * Reset the device's hardware core. + * + * @param dev The parent of @p child. + * @param child The device to be reset. + * @param flags Device-specific core flags to be supplied on reset. + * + * @retval 0 success + * @retval non-zero error + */ +METHOD int reset_core { + device_t dev; + device_t child; + uint16_t flags; +} + +/** + * Suspend a device hardware core. + * + * @param dev The parent of @p child. + * @param child The device to be reset. + * + * @retval 0 success + * @retval non-zero error + */ +METHOD int suspend_core { + device_t dev; + device_t child; +} + +/** + * Allocate a bhnd resource. + * + * This method's semantics are functionally identical to the bus API of the same + * name; refer to BUS_ALLOC_RESOURCE for complete documentation. + */ +METHOD struct bhnd_resource * alloc_resource { + device_t dev; + device_t child; + int type; + int *rid; + rman_res_t start; + rman_res_t end; + rman_res_t count; + u_int flags; +} DEFAULT bhnd_generic_alloc_bhnd_resource; + +/** + * Release a bhnd resource. + * + * This method's semantics are functionally identical to the bus API of the same + * name; refer to BUS_RELEASE_RESOURCE for complete documentation. + */ +METHOD int release_resource { + device_t dev; + device_t child; + int type; + int rid; + struct bhnd_resource *res; +} DEFAULT bhnd_generic_release_bhnd_resource; + +/** + * Activate a bhnd resource. + * + * This method's semantics are functionally identical to the bus API of the same + * name; refer to BUS_ACTIVATE_RESOURCE for complete documentation. + */ +METHOD int activate_resource { + device_t dev; + device_t child; + int type; + int rid; + struct bhnd_resource *r; +} DEFAULT bhnd_generic_activate_bhnd_resource; + +/** + * Deactivate a bhnd resource. + * + * This method's semantics are functionally identical to the bus API of the same + * name; refer to BUS_DEACTIVATE_RESOURCE for complete documentation. + */ +METHOD int deactivate_resource { + device_t dev; + device_t child; + int type; + int rid; + struct bhnd_resource *r; +} DEFAULT bhnd_generic_deactivate_bhnd_resource; + +/** + * Return true if @p region_num is a valid region on @p port_num of + * @p type attached to @p child. + * + * @param dev The device whose child is being examined. + * @param child The child device. + * @param type The port type being queried. + * @param port_num The port number being queried. + * @param region_num The region number being queried. + */ +METHOD u_int is_region_valid { + device_t dev; + device_t child; + bhnd_port_type type; + u_int port_num; + u_int region_num; +} DEFAULT bhnd_generic_is_region_valid; + +/** + * Return the number of ports of type @p type attached to @p child. + * + * @param dev The device whose child is being examined. + * @param child The child device. + * @param type The port type being queried. + */ +METHOD u_int get_port_count { + device_t dev; + device_t child; + bhnd_port_type type; +} + +/** + * Return the number of memory regions mapped to @p child @p port of + * type @p type. + * + * @param dev The device whose child is being examined. + * @param child The child device. + * @param port The port number being queried. + * @param type The port type being queried. + */ +METHOD u_int get_region_count { + device_t dev; + device_t child; + bhnd_port_type type; + u_int port; +} + +/** + * Return the SYS_RES_MEMORY resource-ID for a port/region pair attached to + * @p child. + * + * @param dev The bus device. + * @param child The bhnd child. + * @param port_type The port type. + * @param port_num The index of the child interconnect port. + * @param region_num The index of the port-mapped address region. + * + * @retval -1 No such port/region found. + */ +METHOD int get_port_rid { + device_t dev; + device_t child; + bhnd_port_type port_type; + u_int port_num; + u_int region_num; +} DEFAULT bhnd_bus_null_get_port_rid; + + +/** + * Decode a port / region pair on @p child defined by @p type and @p rid. + * + * @param dev The bus device. + * @param child The bhnd child. + * @param type The resource type. + * @param rid The resource ID. + * @param[out] port_type The port's type. + * @param[out] port The port identifier. + * @param[out] region The identifier of the memory region on @p port. + * + * @retval 0 success + * @retval non-zero No matching type/rid found. + */ +METHOD int decode_port_rid { + device_t dev; + device_t child; + int type; + int rid; + bhnd_port_type *port_type; + u_int *port; + u_int *region; +} DEFAULT bhnd_bus_null_decode_port_rid; + +/** + * Get the address and size of @p region on @p port. + * + * @param dev The bus device. + * @param child The bhnd child. + * @param port_type The port type. + * @param port The port identifier. + * @param region The identifier of the memory region on @p port. + * @param[out] region_addr The region's base address. + * @param[out] region_size The region's size. + * + * @retval 0 success + * @retval non-zero No matching port/region found. + */ +METHOD int get_region_addr { + device_t dev; + device_t child; + bhnd_port_type port_type; + u_int port; + u_int region; + bhnd_addr_t *region_addr; + bhnd_size_t *region_size; +} DEFAULT bhnd_bus_null_get_region_addr; + +/** + * Read an NVRAM variable. + * + * It is the responsibility of the bus to delegate this request to + * the appropriate NVRAM child device, or to a parent bus implementation. + * + * @param dev The bus device. + * @param child The requesting device. + * @param name The NVRAM variable name. + * @param[out] buf On success, the requested value will be written + * to this buffer. This argment may be NULL if + * the value is not desired. + * @param[in,out] size The capacity of @p buf. On success, will be set + * to the actual size of the requested value. + * + * @retval 0 success + * @retval ENOENT The requested variable was not found. + * @retval ENOMEM If @p buf is non-NULL and a buffer of @p size is too + * small to hold the requested value. + * @retval non-zero If reading @p name otherwise fails, a regular unix + * error code will be returned. + */ +METHOD int read_nvram_var { + device_t dev; + device_t child; + const char *name; + void *buf; + size_t *size; +} DEFAULT bhnd_bus_null_read_nvram_var; + + +/** An implementation of bus_read_1() compatible with bhnd_resource */ +METHOD uint8_t read_1 { + device_t dev; + device_t child; + struct bhnd_resource *r; + bus_size_t offset; +} + +/** An implementation of bus_read_2() compatible with bhnd_resource */ +METHOD uint16_t read_2 { + device_t dev; + device_t child; + struct bhnd_resource *r; + bus_size_t offset; +} + +/** An implementation of bus_read_4() compatible with bhnd_resource */ +METHOD uint32_t read_4 { + device_t dev; + device_t child; + struct bhnd_resource *r; + bus_size_t offset; +} + +/** An implementation of bus_write_1() compatible with bhnd_resource */ +METHOD void write_1 { + device_t dev; + device_t child; + struct bhnd_resource *r; + bus_size_t offset; + uint8_t value; +} + +/** An implementation of bus_write_2() compatible with bhnd_resource */ +METHOD void write_2 { + device_t dev; + device_t child; + struct bhnd_resource *r; + bus_size_t offset; + uint16_t value; +} + +/** An implementation of bus_write_4() compatible with bhnd_resource */ +METHOD void write_4 { + device_t dev; + device_t child; + struct bhnd_resource *r; + bus_size_t offset; + uint32_t value; +} + +/** An implementation of bus_barrier() compatible with bhnd_resource */ +METHOD void barrier { + device_t dev; + device_t child; + struct bhnd_resource *r; + bus_size_t offset; + bus_size_t length; + int flags; +} diff --git a/sys/dev/bhnd/bhnd_core.h b/sys/dev/bhnd/bhnd_core.h new file mode 100644 index 000000000000..9ea955ad1c97 --- /dev/null +++ b/sys/dev/bhnd/bhnd_core.h @@ -0,0 +1,77 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * Copyright (c) 2010 Broadcom Corporation + * + * This file is derived from the hndsoc.h header distributed with + * Broadcom's initial brcm80211 Linux driver release, as + * contributed to the Linux staging repository. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef _BHND_BHND_CORE_H_ +#define _BHND_BHND_CORE_H_ + +/* Common core control flags */ +#define BHND_CF_BIST_EN 0x8000 /**< ??? */ +#define BHND_CF_PME_EN 0x4000 /**< ??? */ +#define BHND_CF_CORE_BITS 0x3ffc /**< core specific flag mask */ +#define BHND_CF_FGC 0x0002 /**< force clock gating */ +#define BHND_CF_CLOCK_EN 0x0001 /**< enable clock */ + +/* Common core status flags */ +#define BHND_SF_BIST_DONE 0x8000 /**< ??? */ +#define BHND_SF_BIST_ERROR 0x4000 /**< ??? */ +#define BHND_SF_GATED_CLK 0x2000 /**< clock gated */ +#define BHND_SF_DMA64 0x1000 /**< supports 64-bit DMA */ +#define BHND_SF_CORE_BITS 0x0fff /**< core-specific status mask */ + +/* + * A register that is common to all cores to + * communicate w/PMU regarding clock control. + * + * TODO: Determine when this register first appeared. + */ +#define BHND_CLK_CTL_ST 0x1e0 /**< clock control and status */ + +/* + * BHND_CLK_CTL_ST register + * + * Clock Mode Name Description + * High Throughput (HT) Full bandwidth, low latency. Generally supplied + * from PLL. + * Active Low Power (ALP) Register access, low speed DMA. + * Idle Low Power (ILP) No interconnect activity, or if long latency + * is permitted. + */ +#define BHND_CCS_FORCEALP 0x00000001 /**< force ALP request */ +#define BHND_CCS_FORCEHT 0x00000002 /**< force HT request */ +#define BHND_CCS_FORCEILP 0x00000004 /**< force ILP request */ +#define BHND_CCS_ALPAREQ 0x00000008 /**< ALP Avail Request */ +#define BHND_CCS_HTAREQ 0x00000010 /**< HT Avail Request */ +#define BHND_CCS_FORCEHWREQOFF 0x00000020 /**< Force HW Clock Request Off */ +#define BHND_CCS_ERSRC_REQ_MASK 0x00000700 /**< external resource requests */ +#define BHND_CCS_ERSRC_REQ_SHIFT 8 +#define BHND_CCS_ALPAVAIL 0x00010000 /**< ALP is available */ +#define BHND_CCS_HTAVAIL 0x00020000 /**< HT is available */ +#define BHND_CCS_BP_ON_APL 0x00040000 /**< RO: Backplane is running on ALP clock */ +#define BHND_CCS_BP_ON_HT 0x00080000 /**< RO: Backplane is running on HT clock */ +#define BHND_CCS_ERSRC_STS_MASK 0x07000000 /**< external resource status */ +#define BHND_CCS_ERSRC_STS_SHIFT 24 + +#define BHND_CCS0_HTAVAIL 0x00010000 /**< HT avail in chipc and pcmcia on 4328a0 */ +#define BHND_CCS0_ALPAVAIL 0x00020000 /**< ALP avail in chipc and pcmcia on 4328a0 */ + +#endif /* _BHND_BHND_CORE_H_ */ diff --git a/sys/dev/bhnd/bhnd_ids.h b/sys/dev/bhnd/bhnd_ids.h new file mode 100644 index 000000000000..fdbc6ff7502d --- /dev/null +++ b/sys/dev/bhnd/bhnd_ids.h @@ -0,0 +1,754 @@ +/*- + * Copyright (C) 1999-2013, Broadcom Corporation + * + * This file is derived from the bcmdevs.h header contributed by Broadcom + * to Android's bcmdhd driver module, and the hndsoc.h header distributed with + * with Broadcom's initial brcm80211 Linux driver release, as contributed to + * the Linux staging repository. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $Id: bcmdevs.h 387183 2013-02-24 07:42:07Z $ + * + * $FreeBSD$ + */ + +#ifndef _BHND_BHND_IDS_H_ +#define _BHND_BHND_IDS_H_ + + + +/* + * JEDEC JEP-106 Core Vendor IDs + * + * These are the JEDEC JEP-106 manufacturer ID representions (with ARM's + * non-standard 4-bit continutation code), as used in ARM's PrimeCell + * identification registers, bcma(4) EROM core descriptors, etc. + * + * @note + * Bus implementations that predate the adoption of ARM IP + * will need to convert bus-specific vendor IDs to their BHND_MFGID + * JEP-106 equivalents. + * + * @par ARM 4-bit Continuation Code + * + * BHND MFGIDs are encoded using ARM's non-standard 4-bit continuation code + * format: + * + * @code{.unparsed} + * [11:8 ][7:0 ] + * [cont code][mfg id] + * @endcode + * + * The 4-bit continuation code field specifies the number of JEP-106 + * continuation codes that prefix the manufacturer's ID code. In the case of + * ARM's JEP-106 ID of `0x7F 0x7F 0x7F 0x7F 0x3B`, the four 0x7F continuations + * are encoded as '4' in the 4-bit continuation code field (i.e. 0x43B). + */ +#define BHND_MFGID_ARM 0x043b /**< arm JEP-106 vendor id */ +#define BHND_MFGID_BCM 0x04bf /**< broadcom JEP-106 vendor id */ +#define BHND_MFGID_MIPS 0x04a7 /**< mips JEP-106 vendor id */ +#define BHND_MFGID_INVALID 0x0000 /**< invalid JEP-106 vendor id */ + +/* + * OCP (Open Core Protocol) Vendor IDs. + * + * OCP-IP assigned vendor codes are used by siba(4) + */ +#define OCP_VENDOR_BCM 0x4243 /**< Broadcom OCP vendor id */ + + +/* PCI vendor IDs */ +#define PCI_VENDOR_EPIGRAM 0xfeda +#define PCI_VENDOR_BROADCOM 0x14e4 +#define PCI_VENDOR_3COM 0x10b7 +#define PCI_VENDOR_NETGEAR 0x1385 +#define PCI_VENDOR_DIAMOND 0x1092 +#define PCI_VENDOR_INTEL 0x8086 +#define PCI_VENDOR_DELL 0x1028 +#define PCI_VENDOR_HP 0x103c +#define PCI_VENDOR_HP_COMPAQ 0x0e11 +#define PCI_VENDOR_APPLE 0x106b +#define PCI_VENDOR_SI_IMAGE 0x1095 /* Silicon Image, used by Arasan SDIO Host */ +#define PCI_VENDOR_BUFFALO 0x1154 /* Buffalo vendor id */ +#define PCI_VENDOR_TI 0x104c /* Texas Instruments */ +#define PCI_VENDOR_RICOH 0x1180 /* Ricoh */ +#define PCI_VENDOR_JMICRON 0x197b + + +/* PCMCIA vendor IDs */ +#define PCMCIA_VENDOR_BROADCOM 0x02d0 + + +/* SDIO vendor IDs */ +#define SDIO_VENDOR_BROADCOM 0x00BF + + +/* USB dongle VID/PIDs */ +#define USB_VID_BROADCOM 0x0a5c +#define USB_PID_BCM4328 0xbd12 +#define USB_PID_BCM4322 0xbd13 +#define USB_PID_BCM4319 0xbd16 +#define USB_PID_BCM43236 0xbd17 +#define USB_PID_BCM4332 0xbd18 +#define USB_PID_BCM4330 0xbd19 +#define USB_PID_BCM4334 0xbd1a +#define USB_PID_BCM43239 0xbd1b +#define USB_PID_BCM4324 0xbd1c +#define USB_PID_BCM4360 0xbd1d +#define USB_PID_BCM43143 0xbd1e +#define USB_PID_BCM43242 0xbd1f +#define USB_PID_BCM43342 0xbd21 +#define USB_PID_BCM4335 0xbd20 +#define USB_PID_BCM4350 0xbd23 +#define USB_PID_BCM43341 0xbd22 + +#define USB_PID_BCM_DNGL_BDC 0x0bdc /* BDC USB device controller IP? */ +#define USB_PID_BCM_DNGL_JTAG 0x4a44 + + +/* HW USB BLOCK [CPULESS USB] PIDs */ +#define USB_PID_CCM_HWUSB_43239 43239 + + +/* PCI Device IDs */ +#define PCI_DEVID_BCM4210 0x1072 /* never used */ +#define PCI_DEVID_BCM4230 0x1086 /* never used */ +#define PCI_DEVID_BCM4401_ENET 0x170c /* 4401b0 production enet cards */ +#define PCI_DEVID_BCM3352 0x3352 /* bcm3352 device id */ +#define PCI_DEVID_BCM3360 0x3360 /* bcm3360 device id */ +#define PCI_DEVID_BCM4211 0x4211 +#define PCI_DEVID_BCM4231 0x4231 +#define PCI_DEVID_BCM4301 0x4301 /* 4031 802.11b */ +#define PCI_DEVID_BCM4303_D11B 0x4303 /* 4303 802.11b */ +#define PCI_DEVID_BCM4306 0x4306 /* 4306 802.11b/g */ +#define PCI_DEVID_BCM4307 0x4307 /* 4307 802.11b, 10/100 ethernet, V.92 modem */ +#define PCI_DEVID_BCM4311_D11G 0x4311 /* 4311 802.11b/g id */ +#define PCI_DEVID_BCM4311_D11DUAL 0x4312 /* 4311 802.11a/b/g id */ +#define PCI_DEVID_BCM4311_D11A 0x4313 /* 4311 802.11a id */ +#define PCI_DEVID_BCM4328_D11DUAL 0x4314 /* 4328/4312 802.11a/g id */ +#define PCI_DEVID_BCM4328_D11G 0x4315 /* 4328/4312 802.11g id */ +#define PCI_DEVID_BCM4328_D11A 0x4316 /* 4328/4312 802.11a id */ +#define PCI_DEVID_BCM4318_D11G 0x4318 /* 4318 802.11b/g id */ +#define PCI_DEVID_BCM4318_D11DUAL 0x4319 /* 4318 802.11a/b/g id */ +#define PCI_DEVID_BCM4318_D11A 0x431a /* 4318 802.11a id */ +#define PCI_DEVID_BCM4325_D11DUAL 0x431b /* 4325 802.11a/g id */ +#define PCI_DEVID_BCM4325_D11G 0x431c /* 4325 802.11g id */ +#define PCI_DEVID_BCM4325_D11A 0x431d /* 4325 802.11a id */ +#define PCI_DEVID_BCM4306_D11G 0x4320 /* 4306 802.11g */ +#define PCI_DEVID_BCM4306_D11A 0x4321 /* 4306 802.11a */ +#define PCI_DEVID_BCM4306_UART 0x4322 /* 4306 uart */ +#define PCI_DEVID_BCM4306_V90 0x4323 /* 4306 v90 codec */ +#define PCI_DEVID_BCM4306_D11DUAL 0x4324 /* 4306 dual A+B */ +#define PCI_DEVID_BCM4306_D11G_ID2 0x4325 /* BCM4306_D11G; INF w/loose binding war */ +#define PCI_DEVID_BCM4321_D11N 0x4328 /* 4321 802.11n dualband id */ +#define PCI_DEVID_BCM4321_D11N2G 0x4329 /* 4321 802.11n 2.4Ghz band id */ +#define PCI_DEVID_BCM4321_D11N5G 0x432a /* 4321 802.11n 5Ghz band id */ +#define PCI_DEVID_BCM4322_D11N 0x432b /* 4322 802.11n dualband device */ +#define PCI_DEVID_BCM4322_D11N2G 0x432c /* 4322 802.11n 2.4GHz device */ +#define PCI_DEVID_BCM4322_D11N5G 0x432d /* 4322 802.11n 5GHz device */ +#define PCI_DEVID_BCM4329_D11N 0x432e /* 4329 802.11n dualband device */ +#define PCI_DEVID_BCM4329_D11N2G 0x432f /* 4329 802.11n 2.4G device */ +#define PCI_DEVID_BCM4329_D11N5G 0x4330 /* 4329 802.11n 5G device */ +#define PCI_DEVID_BCM4315_D11DUAL 0x4334 /* 4315 802.11a/g id */ +#define PCI_DEVID_BCM4315_D11G 0x4335 /* 4315 802.11g id */ +#define PCI_DEVID_BCM4315_D11A 0x4336 /* 4315 802.11a id */ +#define PCI_DEVID_BCM4319_D11N 0x4337 /* 4319 802.11n dualband device */ +#define PCI_DEVID_BCM4319_D11N2G 0x4338 /* 4319 802.11n 2.4G device */ +#define PCI_DEVID_BCM4319_D11N5G 0x4339 /* 4319 802.11n 5G device */ +#define PCI_DEVID_BCM43231_D11N2G 0x4340 /* 43231 802.11n 2.4GHz device */ +#define PCI_DEVID_BCM43221_D11N2G 0x4341 /* 43221 802.11n 2.4GHz device */ +#define PCI_DEVID_BCM43222_D11N 0x4350 /* 43222 802.11n dualband device */ +#define PCI_DEVID_BCM43222_D11N2G 0x4351 /* 43222 802.11n 2.4GHz device */ +#define PCI_DEVID_BCM43222_D11N5G 0x4352 /* 43222 802.11n 5GHz device */ +#define PCI_DEVID_BCM43224_D11N 0x4353 /* 43224 802.11n dualband device */ +#define PCI_DEVID_BCM43224_D11N_ID_VEN1 0x0576 /* Vendor specific 43224 802.11n db device */ +#define PCI_DEVID_BCM43226_D11N 0x4354 /* 43226 802.11n dualband device */ +#define PCI_DEVID_BCM43236_D11N 0x4346 /* 43236 802.11n dualband device */ +#define PCI_DEVID_BCM43236_D11N2G 0x4347 /* 43236 802.11n 2.4GHz device */ +#define PCI_DEVID_BCM43236_D11N5G 0x4348 /* 43236 802.11n 5GHz device */ +#define PCI_DEVID_BCM43225_D11N2G 0x4357 /* 43225 802.11n 2.4GHz device */ +#define PCI_DEVID_BCM43421_D11N 0xA99D /* 43421 802.11n dualband device */ +#define PCI_DEVID_BCM4313_D11N2G 0x4727 /* 4313 802.11n 2.4G device */ +#define PCI_DEVID_BCM4330_D11N 0x4360 /* 4330 802.11n dualband device */ +#define PCI_DEVID_BCM4330_D11N2G 0x4361 /* 4330 802.11n 2.4G device */ +#define PCI_DEVID_BCM4330_D11N5G 0x4362 /* 4330 802.11n 5G device */ +#define PCI_DEVID_BCM4336_D11N 0x4343 /* 4336 802.11n 2.4GHz device */ +#define PCI_DEVID_BCM6362_D11N 0x435f /* 6362 802.11n dualband device */ +#define PCI_DEVID_BCM6362_D11N2G 0x433f /* 6362 802.11n 2.4Ghz band id */ +#define PCI_DEVID_BCM6362_D11N5G 0x434f /* 6362 802.11n 5Ghz band id */ +#define PCI_DEVID_BCM4331_D11N 0x4331 /* 4331 802.11n dualband id */ +#define PCI_DEVID_BCM4331_D11N2G 0x4332 /* 4331 802.11n 2.4Ghz band id */ +#define PCI_DEVID_BCM4331_D11N5G 0x4333 /* 4331 802.11n 5Ghz band id */ +#define PCI_DEVID_BCM43237_D11N 0x4355 /* 43237 802.11n dualband device */ +#define PCI_DEVID_BCM43237_D11N5G 0x4356 /* 43237 802.11n 5GHz device */ +#define PCI_DEVID_BCM43227_D11N2G 0x4358 /* 43228 802.11n 2.4GHz device */ +#define PCI_DEVID_BCM43228_D11N 0x4359 /* 43228 802.11n DualBand device */ +#define PCI_DEVID_BCM43228_D11N5G 0x435a /* 43228 802.11n 5GHz device */ +#define PCI_DEVID_BCM43362_D11N 0x4363 /* 43362 802.11n 2.4GHz device */ +#define PCI_DEVID_BCM43239_D11N 0x4370 /* 43239 802.11n dualband device */ +#define PCI_DEVID_BCM4324_D11N 0x4374 /* 4324 802.11n dualband device */ +#define PCI_DEVID_BCM43217_D11N2G 0x43a9 /* 43217 802.11n 2.4GHz device */ +#define PCI_DEVID_BCM43131_D11N2G 0x43aa /* 43131 802.11n 2.4GHz device */ +#define PCI_DEVID_BCM4314_D11N2G 0x4364 /* 4314 802.11n 2.4G device */ +#define PCI_DEVID_BCM43142_D11N2G 0x4365 /* 43142 802.11n 2.4G device */ +#define PCI_DEVID_BCM43143_D11N2G 0x4366 /* 43143 802.11n 2.4G device */ +#define PCI_DEVID_BCM4334_D11N 0x4380 /* 4334 802.11n dualband device */ +#define PCI_DEVID_BCM4334_D11N2G 0x4381 /* 4334 802.11n 2.4G device */ +#define PCI_DEVID_BCM4334_D11N5G 0x4382 /* 4334 802.11n 5G device */ +#define PCI_DEVID_BCM43342_D11N 0x4383 /* 43342 802.11n dualband device */ +#define PCI_DEVID_BCM43342_D11N2G 0x4384 /* 43342 802.11n 2.4G device */ +#define PCI_DEVID_BCM43342_D11N5G 0x4385 /* 43342 802.11n 5G device */ +#define PCI_DEVID_BCM43341_D11N 0x4386 /* 43341 802.11n dualband device */ +#define PCI_DEVID_BCM43341_D11N2G 0x4387 /* 43341 802.11n 2.4G device */ +#define PCI_DEVID_BCM43341_D11N5G 0x4388 /* 43341 802.11n 5G device */ +#define PCI_DEVID_BCM4360_D11AC 0x43a0 +#define PCI_DEVID_BCM4360_D11AC2G 0x43a1 +#define PCI_DEVID_BCM4360_D11AC5G 0x43a2 +#define PCI_DEVID_BCM4335_D11AC 0x43ae +#define PCI_DEVID_BCM4335_D11AC2G 0x43af +#define PCI_DEVID_BCM4335_D11AC5G 0x43b0 +#define PCI_DEVID_BCM4352_D11AC 0x43b1 /* 4352 802.11ac dualband device */ +#define PCI_DEVID_BCM4352_D11AC2G 0x43b2 /* 4352 802.11ac 2.4G device */ +#define PCI_DEVID_BCM4352_D11AC5G 0x43b3 /* 4352 802.11ac 5G device */ + +#define PCI_DEVID_PCIXX21_FLASHMEDIA0 0x8033 /* TI PCI xx21 Standard Host Controller */ +#define PCI_DEVID_PCIXX21_SDIOH0 0x8034 /* TI PCI xx21 Standard Host Controller */ + + +/* PCI Subsystem Vendor IDs */ +#define PCI_SUBVENDOR_BCM943228HMB 0x0607 +#define PCI_SUBVENDOR_BCM94313HMGBL 0x0608 +#define PCI_SUBVENDOR_BCM94313HMG 0x0609 +#define PCI_SUBVENDOR_BCM943142HM 0x0611 + + +/* PCI Subsystem Device IDs */ +#define PCI_SUBDEVID_BCM43143_D11N2G 0x4366 /* 43143 802.11n 2.4G device */ + +#define PCI_SUBDEVID_BCM43242_D11N 0x4367 /* 43242 802.11n dualband device */ +#define PCI_SUBDEVID_BCM43242_D11N2G 0x4368 /* 43242 802.11n 2.4G device */ +#define PCI_SUBDEVID_BCM43242_D11N5G 0x4369 /* 43242 802.11n 5G device */ + +#define PCI_SUBDEVID_BCM4350_D11AC 0x43a3 +#define PCI_SUBDEVID_BCM4350_D11AC2G 0x43a4 +#define PCI_SUBDEVID_BCM4350_D11AC5G 0x43a5 + +#define PCI_SUBDEVID_BCMGPRS_UART 0x4333 /* Uart id used by 4306/gprs card */ +#define PCI_SUBDEVID_BCMGPRS2_UART 0x4344 /* Uart id used by 4306/gprs card */ +#define PCI_SUBDEVID_BCM_FPGA_JTAGM 0x43f0 /* FPGA jtagm device id */ +#define PCI_SUBDEVID_BCM_JTAGM 0x43f1 /* BCM jtagm device id */ +#define PCI_SUBDEVID_BCM_SDIOH_FPGA 0x43f2 /* sdio host fpga */ +#define PCI_SUBDEVID_BCM_SDIOH 0x43f3 /* BCM sdio host id */ +#define PCI_SUBDEVID_BCM_SDIOD_FPGA 0x43f4 /* sdio device fpga */ +#define PCI_SUBDEVID_BCM_SPIH_FPGA 0x43f5 /* PCI SPI Host Controller FPGA */ +#define PCI_SUBDEVID_BCM_SPIH 0x43f6 /* Synopsis SPI Host Controller */ +#define PCI_SUBDEVID_BCM_MIMO_FPGA 0x43f8 /* FPGA mimo minimacphy device id */ +#define PCI_SUBDEVID_BCM_JTAGM2 0x43f9 /* PCI_SUBDEVID_BCM alternate jtagm device id */ +#define PCI_SUBDEVID_BCM_SDHCI_FPGA 0x43fa /* Standard SDIO Host Controller FPGA */ +#define PCI_SUBDEVID_BCM4402_ENET 0x4402 /* 4402 enet */ +#define PCI_SUBDEVID_BCM4402_V90 0x4403 /* 4402 v90 codec */ +#define PCI_SUBDEVID_BCM4410 0x4410 /* bcm44xx family pci iline */ +#define PCI_SUBDEVID_BCM4412 0x4412 /* bcm44xx family pci enet */ +#define PCI_SUBDEVID_BCM4430 0x4430 /* bcm44xx family cardbus iline */ +#define PCI_SUBDEVID_BCM4432 0x4432 /* bcm44xx family cardbus enet */ +#define PCI_SUBDEVID_BCM4704_ENET 0x4706 /* 4704 enet (Use 47XX_ENET_ID instead!) */ +#define PCI_SUBDEVID_BCM4710 0x4710 /* 4710 primary function 0 */ +#define PCI_SUBDEVID_BCM47XX_AUDIO 0x4711 /* 47xx audio codec */ +#define PCI_SUBDEVID_BCM47XX_V90 0x4712 /* 47xx v90 codec */ +#define PCI_SUBDEVID_BCM47XX_ENET 0x4713 /* 47xx enet */ +#define PCI_SUBDEVID_BCM47XX_EXT 0x4714 /* 47xx external i/f */ +#define PCI_SUBDEVID_BCM47XX_GMAC 0x4715 /* 47xx Unimac based GbE */ +#define PCI_SUBDEVID_BCM47XX_USBH 0x4716 /* 47xx usb host */ +#define PCI_SUBDEVID_BCM47XX_USBD 0x4717 /* 47xx usb device */ +#define PCI_SUBDEVID_BCM47XX_IPSEC 0x4718 /* 47xx ipsec */ +#define PCI_SUBDEVID_BCM47XX_ROBO 0x4719 /* 47xx/53xx roboswitch core */ +#define PCI_SUBDEVID_BCM47XX_USB20H 0x471a /* 47xx usb 2.0 host */ +#define PCI_SUBDEVID_BCM47XX_USB20D 0x471b /* 47xx usb 2.0 device */ +#define PCI_SUBDEVID_BCM47XX_ATA100 0x471d /* 47xx parallel ATA */ +#define PCI_SUBDEVID_BCM47XX_SATAXOR 0x471e /* 47xx serial ATA & XOR DMA */ +#define PCI_SUBDEVID_BCM47XX_GIGETH 0x471f /* 47xx GbE (5700) */ +#define PCI_SUBDEVID_BCM4712_MIPS 0x4720 /* 4712 base devid */ +#define PCI_SUBDEVID_BCM4716 0x4722 /* 4716 base devid */ +#define PCI_SUBDEVID_BCM47XX_USB30H 0x472a /* 47xx usb 3.0 host */ +#define PCI_SUBDEVID_BCM47XX_USB30D 0x472b /* 47xx usb 3.0 device */ +#define PCI_SUBDEVID_BCM47XX_SMBUS_EMU 0x47fe /* 47xx emulated SMBus device */ +#define PCI_SUBDEVID_BCM47XX_XOR_EMU 0x47ff /* 47xx emulated XOR engine */ +#define PCI_SUBDEVID_BCM_EPI41210 0xa0fa /* bcm4210 */ +#define PCI_SUBDEVID_BCM_EPI41230 0xa10e /* bcm4230 */ +#define PCI_SUBDEVID_BCM_JINVANI_SDIOH 0x4743 /* Jinvani SDIO Gold Host */ +#define PCI_SUBDEVID_BCM27XX_SDIOH 0x2702 /* PCI_SUBDEVID_BCM27xx Standard SDIO Host */ +#define PCI_SUBDEVID_BCM_PCIXX21_FLASHMEDIA 0x803b /* TI PCI xx21 Standard Host Controller */ +#define PCI_SUBDEVID_BCM_PCIXX21_SDIOH 0x803c /* TI PCI xx21 Standard Host Controller */ +#define PCI_SUBDEVID_BCM_R5C822_SDIOH 0x0822 /* Ricoh Co Ltd R5C822 SD/SDIO/MMC/MS/MSPro Host */ +#define PCI_SUBDEVID_BCM_JMICRON_SDIOH 0x2381 /* JMicron Standard SDIO Host Controller */ + + +/* Broadcom ChipCommon Chip IDs */ +#define BHND_CHIPID_BCM4306 0x4306 /* 4306 chipcommon chipid */ +#define BHND_CHIPID_BCM4311 0x4311 /* 4311 PCIe 802.11a/b/g */ +#define BHND_CHIPID_BCM43111 43111 /* 43111 chipcommon chipid (OTP chipid) */ +#define BHND_CHIPID_BCM43112 43112 /* 43112 chipcommon chipid (OTP chipid) */ +#define BHND_CHIPID_BCM4312 0x4312 /* 4312 chipcommon chipid */ +#define BHND_CHIPID_BCM4313 0x4313 /* 4313 chip id */ +#define BHND_CHIPID_BCM43131 43131 /* 43131 chip id (OTP chipid) */ +#define BHND_CHIPID_BCM4315 0x4315 /* 4315 chip id */ +#define BHND_CHIPID_BCM4318 0x4318 /* 4318 chipcommon chipid */ +#define BHND_CHIPID_BCM4319 0x4319 /* 4319 chip id */ +#define BHND_CHIPID_BCM4320 0x4320 /* 4320 chipcommon chipid */ +#define BHND_CHIPID_BCM4321 0x4321 /* 4321 chipcommon chipid */ +#define BHND_CHIPID_BCM43217 43217 /* 43217 chip id (OTP chipid) */ +#define BHND_CHIPID_BCM4322 0x4322 /* 4322 chipcommon chipid */ +#define BHND_CHIPID_BCM43221 43221 /* 43221 chipcommon chipid (OTP chipid) */ +#define BHND_CHIPID_BCM43222 43222 /* 43222 chipcommon chipid */ +#define BHND_CHIPID_BCM43224 43224 /* 43224 chipcommon chipid */ +#define BHND_CHIPID_BCM43225 43225 /* 43225 chipcommon chipid */ +#define BHND_CHIPID_BCM43227 43227 /* 43227 chipcommon chipid */ +#define BHND_CHIPID_BCM43228 43228 /* 43228 chipcommon chipid */ +#define BHND_CHIPID_BCM43226 43226 /* 43226 chipcommon chipid */ +#define BHND_CHIPID_BCM43231 43231 /* 43231 chipcommon chipid (OTP chipid) */ +#define BHND_CHIPID_BCM43234 43234 /* 43234 chipcommon chipid */ +#define BHND_CHIPID_BCM43235 43235 /* 43235 chipcommon chipid */ +#define BHND_CHIPID_BCM43236 43236 /* 43236 chipcommon chipid */ +#define BHND_CHIPID_BCM43237 43237 /* 43237 chipcommon chipid */ +#define BHND_CHIPID_BCM43238 43238 /* 43238 chipcommon chipid */ +#define BHND_CHIPID_BCM43239 43239 /* 43239 chipcommon chipid */ +#define BHND_CHIPID_BCM43420 43420 /* 43222 chipcommon chipid (OTP, RBBU) */ +#define BHND_CHIPID_BCM43421 43421 /* 43224 chipcommon chipid (OTP, RBBU) */ +#define BHND_CHIPID_BCM43428 43428 /* 43228 chipcommon chipid (OTP, RBBU) */ +#define BHND_CHIPID_BCM43431 43431 /* 4331 chipcommon chipid (OTP, RBBU) */ +#define BHND_CHIPID_BCM43460 43460 /* 4360 chipcommon chipid (OTP, RBBU) */ +#define BHND_CHIPID_BCM4325 0x4325 /* 4325 chip id */ +#define BHND_CHIPID_BCM4328 0x4328 /* 4328 chip id */ +#define BHND_CHIPID_BCM4329 0x4329 /* 4329 chipcommon chipid */ +#define BHND_CHIPID_BCM4331 0x4331 /* 4331 chipcommon chipid */ +#define BHND_CHIPID_BCM4336 0x4336 /* 4336 chipcommon chipid */ +#define BHND_CHIPID_BCM43362 43362 /* 43362 chipcommon chipid */ +#define BHND_CHIPID_BCM4330 0x4330 /* 4330 chipcommon chipid */ +#define BHND_CHIPID_BCM6362 0x6362 /* 6362 chipcommon chipid */ +#define BHND_CHIPID_BCM4314 0x4314 /* 4314 chipcommon chipid */ +#define BHND_CHIPID_BCM43142 43142 /* 43142 chipcommon chipid */ +#define BHND_CHIPID_BCM43143 43143 /* 43143 chipcommon chipid */ +#define BHND_CHIPID_BCM4324 0x4324 /* 4324 chipcommon chipid */ +#define BHND_CHIPID_BCM43242 43242 /* 43242 chipcommon chipid */ +#define BHND_CHIPID_BCM43243 43243 /* 43243 chipcommon chipid */ +#define BHND_CHIPID_BCM4334 0x4334 /* 4334 chipcommon chipid */ +#define BHND_CHIPID_BCM4335 0x4335 /* 4335 chipcommon chipid */ +#define BHND_CHIPID_BCM4360 0x4360 /* 4360 chipcommon chipid */ +#define BHND_CHIPID_BCM4352 0x4352 /* 4352 chipcommon chipid */ +#define BHND_CHIPID_BCM43526 0xAA06 +#define BHND_CHIPID_BCM43341 43341 /* 43341 chipcommon chipid */ +#define BHND_CHIPID_BCM43342 43342 /* 43342 chipcommon chipid */ +#define BHND_CHIPID_BCM4335 0x4335 +#define BHND_CHIPID_BCM4350 0x4350 /* 4350 chipcommon chipid */ + +#define BHND_CHIPID_BCM4342 4342 /* 4342 chipcommon chipid (OTP, RBBU) */ +#define BHND_CHIPID_BCM4402 0x4402 /* 4402 chipid */ +#define BHND_CHIPID_BCM4704 0x4704 /* 4704 chipcommon chipid */ +#define BHND_CHIPID_BCM4706 0x5300 /* 4706 chipcommon chipid */ +#define BHND_CHIPID_BCM4707 53010 /* 4707 chipcommon chipid */ +#define BHND_CHIPID_BCM53018 53018 /* 53018 chipcommon chipid */ +#define BHND_CHIPID_IS_BCM4707(chipid) \ + (((chipid) == BHND_CHIPID_BCM4707) || \ + ((chipid) == BHND_CHIPID_BCM53018)) +#define BHND_CHIPID_BCM4710 0x4710 /* 4710 chipid */ +#define BHND_CHIPID_BCM4712 0x4712 /* 4712 chipcommon chipid */ +#define BHND_CHIPID_BCM4716 0x4716 /* 4716 chipcommon chipid */ +#define BHND_CHIPID_BCM47162 47162 /* 47162 chipcommon chipid */ +#define BHND_CHIPID_BCM4748 0x4748 /* 4716 chipcommon chipid (OTP, RBBU) */ +#define BHND_CHIPID_BCM4749 0x4749 /* 5357 chipcommon chipid (OTP, RBBU) */ +#define BHND_CHIPID_BCM4785 0x4785 /* 4785 chipcommon chipid */ +#define BHND_CHIPID_BCM5350 0x5350 /* 5350 chipcommon chipid */ +#define BHND_CHIPID_BCM5352 0x5352 /* 5352 chipcommon chipid */ +#define BHND_CHIPID_BCM5354 0x5354 /* 5354 chipcommon chipid */ +#define BHND_CHIPID_BCM5365 0x5365 /* 5365 chipcommon chipid */ +#define BHND_CHIPID_BCM5356 0x5356 /* 5356 chipcommon chipid */ +#define BHND_CHIPID_BCM5357 0x5357 /* 5357 chipcommon chipid */ +#define BHND_CHIPID_BCM53572 53572 /* 53572 chipcommon chipid */ + + +/* Broadcom ChipCommon Package IDs */ +#define BHND_PKGID_BCM4303 2 /* 4303 package id */ +#define BHND_PKGID_BCM4309 1 /* 4309 package id */ +#define BHND_PKGID_BCM4712LARGE 0 /* 340pin 4712 package id */ +#define BHND_PKGID_BCM4712SMALL 1 /* 200pin 4712 package id */ +#define BHND_PKGID_BCM4712MID 2 /* 225pin 4712 package id */ +#define BHND_PKGID_BCM4328USBD11G 2 /* 4328 802.11g USB package id */ +#define BHND_PKGID_BCM4328USBDUAL 3 /* 4328 802.11a/g USB package id */ +#define BHND_PKGID_BCM4328SDIOD11G 4 /* 4328 802.11g SDIO package id */ +#define BHND_PKGID_BCM4328SDIODUAL 5 /* 4328 802.11a/g SDIO package id */ +#define BHND_PKGID_BCM4329_289PIN 0 /* 4329 289-pin package id */ +#define BHND_PKGID_BCM4329_182PIN 1 /* 4329N 182-pin package id */ +#define BHND_PKGID_BCM5354E 1 /* 5354E package id */ +#define BHND_PKGID_BCM4716 8 /* 4716 package id */ +#define BHND_PKGID_BCM4717 9 /* 4717 package id */ +#define BHND_PKGID_BCM4718 10 /* 4718 package id */ +#define BHND_PKGID_BCM5356_NONMODE 1 /* 5356 package without nmode suppport */ +#define BHND_PKGID_BCM5358U 8 /* 5358U package id */ +#define BHND_PKGID_BCM5358 9 /* 5358 package id */ +#define BHND_PKGID_BCM47186 10 /* 47186 package id */ +#define BHND_PKGID_BCM5357 11 /* 5357 package id */ +#define BHND_PKGID_BCM5356U 12 /* 5356U package id */ +#define BHND_PKGID_BCM53572 8 /* 53572 package id */ +#define BHND_PKGID_BCM5357C0 8 /* 5357c0 package id (the same as 53572) */ +#define BHND_PKGID_BCM47188 9 /* 47188 package id */ +#define BHND_PKGID_BCM5358C0 0xa /* 5358c0 package id */ +#define BHND_PKGID_BCM5356C0 0xb /* 5356c0 package id */ +#define BHND_PKGID_BCM4331TT 8 /* 4331 12x12 package id */ +#define BHND_PKGID_BCM4331TN 9 /* 4331 12x9 package id */ +#define BHND_PKGID_BCM4331TNA0 0xb /* 4331 12x9 package id */ +#define BHND_PKGID_BCM4706L 1 /* 4706L package id */ + +#define BHND_PKGID_HDLSIM5350 1 /* HDL simulator package id for a 5350 */ +#define BHND_PKGID_HDLSIM 14 /* HDL simulator package id */ +#define BHND_PKGID_HWSIM 15 /* Hardware simulator package id */ +#define BHND_PKGID_BCM43224_FAB_CSM 0x8 /* the chip is manufactured by CSM */ +#define BHND_PKGID_BCM43224_FAB_SMIC 0xa /* the chip is manufactured by SMIC */ +#define BHND_PKGID_BCM4336_WLBGA 0x8 +#define BHND_PKGID_BCM4330_WLBGA 0x0 +#define BHND_PKGID_BCM4314PCIE_ARM (8 | 0) /* 4314 QFN PCI package id, bit 3 tie high */ +#define BHND_PKGID_BCM4314SDIO (8 | 1) /* 4314 QFN SDIO package id */ +#define BHND_PKGID_BCM4314PCIE (8 | 2) /* 4314 QFN PCI (ARM-less) package id */ +#define BHND_PKGID_BCM4314SDIO_ARM (8 | 3) /* 4314 QFN SDIO (ARM-less) package id */ +#define BHND_PKGID_BCM4314SDIO_FPBGA (8 | 4) /* 4314 FpBGA SDIO package id */ +#define BHND_PKGID_BCM4314DEV (8 | 6) /* 4314 Developement package id */ + +#define BHND_PKGID_BCM4707 1 /* 4707 package id */ +#define BHND_PKGID_BCM4708 2 /* 4708 package id */ +#define BHND_PKGID_BCM4709 0 /* 4709 package id */ + +#define BHND_PKGID_BCM4335_WLCSP (0x0) /* WLCSP Module/Mobile SDIO/HSIC. */ +#define BHND_PKGID_BCM4335_FCBGA (0x1) /* FCBGA PC/Embeded/Media PCIE/SDIO */ +#define BHND_PKGID_BCM4335_WLBGA (0x2) /* WLBGA COB/Mobile SDIO/HSIC. */ +#define BHND_PKGID_BCM4335_FCBGAD (0x3) /* FCBGA Debug Debug/Dev All if's. */ +#define BHND_PKGID_PKG_MASK_BCM4335 (0x3) + + +/* Broadcom Core IDs */ +#define BHND_COREID_INVALID 0x700 /* Invalid coreid */ +#define BHND_COREID_CC 0x800 /* chipcommon core */ +#define BHND_COREID_ILINE20 0x801 /* iline20 core */ +#define BHND_COREID_SRAM 0x802 /* sram core */ +#define BHND_COREID_SDRAM 0x803 /* sdram core */ +#define BHND_COREID_PCI 0x804 /* pci core */ +#define BHND_COREID_MIPS 0x805 /* mips core */ +#define BHND_COREID_ENET 0x806 /* enet mac core */ +#define BHND_COREID_CODEC 0x807 /* v90 codec core */ +#define BHND_COREID_USB 0x808 /* usb 1.1 host/device core */ +#define BHND_COREID_ADSL 0x809 /* ADSL core */ +#define BHND_COREID_ILINE100 0x80a /* iline100 core */ +#define BHND_COREID_IPSEC 0x80b /* ipsec core */ +#define BHND_COREID_UTOPIA 0x80c /* utopia core */ +#define BHND_COREID_PCMCIA 0x80d /* pcmcia core */ +#define BHND_COREID_SOCRAM 0x80e /* internal memory core */ +#define BHND_COREID_MEMC 0x80f /* memc sdram core */ +#define BHND_COREID_OFDM 0x810 /* OFDM phy core */ +#define BHND_COREID_EXTIF 0x811 /* external interface core */ +#define BHND_COREID_D11 0x812 /* 802.11 MAC core */ +#define BHND_COREID_APHY 0x813 /* 802.11a phy core */ +#define BHND_COREID_BPHY 0x814 /* 802.11b phy core */ +#define BHND_COREID_GPHY 0x815 /* 802.11g phy core */ +#define BHND_COREID_MIPS33 0x816 /* mips3302 core */ +#define BHND_COREID_USB11H 0x817 /* usb 1.1 host core */ +#define BHND_COREID_USB11D 0x818 /* usb 1.1 device core */ +#define BHND_COREID_USB20H 0x819 /* usb 2.0 host core */ +#define BHND_COREID_USB20D 0x81a /* usb 2.0 device core */ +#define BHND_COREID_SDIOH 0x81b /* sdio host core */ +#define BHND_COREID_ROBO 0x81c /* roboswitch core */ +#define BHND_COREID_ATA100 0x81d /* parallel ATA core */ +#define BHND_COREID_SATAXOR 0x81e /* serial ATA & XOR DMA core */ +#define BHND_COREID_GIGETH 0x81f /* gigabit ethernet core */ +#define BHND_COREID_PCIE 0x820 /* pci express core */ +#define BHND_COREID_NPHY 0x821 /* 802.11n 2x2 phy core */ +#define BHND_COREID_SRAMC 0x822 /* SRAM controller core */ +#define BHND_COREID_MINIMAC 0x823 /* MINI MAC/phy core */ +#define BHND_COREID_ARM11 0x824 /* ARM 1176 core */ +#define BHND_COREID_ARM7S 0x825 /* ARM7tdmi-s core */ +#define BHND_COREID_LPPHY 0x826 /* 802.11a/b/g phy core */ +#define BHND_COREID_PMU 0x827 /* PMU core */ +#define BHND_COREID_SSNPHY 0x828 /* 802.11n single-stream phy core */ +#define BHND_COREID_SDIOD 0x829 /* SDIO device core */ +#define BHND_COREID_ARMCM3 0x82a /* ARM Cortex M3 core */ +#define BHND_COREID_HTPHY 0x82b /* 802.11n 4x4 phy core */ +#define BHND_COREID_MIPS74K 0x82c /* mips 74k core */ +#define BHND_COREID_GMAC 0x82d /* Gigabit MAC core */ +#define BHND_COREID_DMEMC 0x82e /* DDR1/2 memory controller core */ +#define BHND_COREID_PCIERC 0x82f /* PCIE Root Complex core */ +#define BHND_COREID_OCP 0x830 /* OCP2OCP bridge core */ +#define BHND_COREID_SC 0x831 /* shared common core */ +#define BHND_COREID_AHB 0x832 /* OCP2AHB bridge core */ +#define BHND_COREID_SPIH 0x833 /* SPI host core */ +#define BHND_COREID_I2S 0x834 /* I2S core */ +#define BHND_COREID_DMEMS 0x835 /* SDR/DDR1 memory controller core */ +#define BHND_COREID_UBUS_SHIM 0x837 /* SHIM component in ubus/6362 */ +#define BHND_COREID_PCIE2 0x83c /* pci express (gen2) core */ +/* ARM/AMBA Core IDs */ +#define BHND_COREID_APB_BRIDGE 0x135 /* BP135 AMBA AXI-APB bridge */ +#define BHND_COREID_PL301 0x301 /* PL301 AMBA AXI Interconnect */ +#define BHND_COREID_EROM 0x366 /* Enumeration ROM */ +#define BHND_COREID_OOB_ROUTER 0x367 /* OOB router core ID */ +#define BHND_COREID_AXI_UNMAPPED 0xfff /* AXI "Default Slave"; maps all unused address + * ranges, returning DECERR on read or write. */ +/* Northstar Plus and BCM4706 Core IDs */ +#define BHND_COREID_4706_CC 0x500 /* chipcommon core */ +#define BHND_COREID_NS_PCIE2 0x501 /* pci express (gen2) core */ +#define BHND_COREID_NS_DMA 0x502 /* dma core */ +#define BHND_COREID_NS_SDIO 0x503 /* sdio host core */ +#define BHND_COREID_NS_USB20H 0x504 /* usb 2.0 host core */ +#define BHND_COREID_NS_USB30H 0x505 /* usb 3.0 host core */ +#define BHND_COREID_NS_A9JTAG 0x506 /* ARM Cortex A9 JTAG core */ +#define BHND_COREID_NS_DDR23_MEMC 0x507 /* DDR2/3 cadence/denali memory controller core () */ +#define BHND_COREID_NS_ROM 0x508 /* device ROM core */ +#define BHND_COREID_NS_NAND 0x509 /* NAND flash controller core */ +#define BHND_COREID_NS_QSPI 0x50a /* QSPI flash controller core */ +#define BHND_COREID_NS_CC_B 0x50b /* chipcommon `b' (auxiliary) core */ +#define BHND_COREID_4706_SOCRAM 0x50e /* internal memory core */ +#define BHND_COREID_IHOST_ARMCA9 0x510 /* ARM Cortex A9 core */ +#define BHND_COREID_4706_GMAC_CMN 0x5dc /* Gigabit MAC common core */ +#define BHND_COREID_4706_GMAC 0x52d /* Gigabit MAC core */ +#define BHND_COREID_AMEMC 0x52e /* DDR1/2 cadence/denali memory controller core */ + + + +/* ARM PrimeCell Peripherial IDs. These were derived from inspection of the + * PrimeCell-compatible BCM4331 cores, but due to lack of documentation, the + * surmised core name/description may be incorrect. */ +#define BHND_PRIMEID_EROM 0x364 /* Enumeration ROM's primecell ID */ +#define BHND_PRIMEID_SWRAP 0x368 /* PL368 Device Management Interface (Slave) */ +#define BHND_PRIMEID_MWRAP 0x369 /* PL369 Device Management Interface (Master) */ + +/* Core HW Revision Numbers */ +#define BHND_HWREV_INVALID 0xFF /* Invalid hardware revision ID */ + +/* Chip Types */ +#define BHND_CHIPTYPE_SIBA 0 /**< siba(4) interconnect */ +#define BHND_CHIPTYPE_BCMA 1 /**< bcma(4) interconnect */ +#define BHND_CHIPTYPE_UBUS 2 /**< ubus interconnect found in bcm63xx devices */ +#define BHND_CHIPTYPE_BCMA_ALT 3 /**< bcma(4) interconnect */ + +/* Boardflags */ +#define BHND_BFL_BTC2WIRE 0x00000001 /* old 2wire Bluetooth coexistence, OBSOLETE */ +#define BHND_BFL_BTCOEX 0x00000001 /* Board supports BTCOEX */ +#define BHND_BFL_PACTRL 0x00000002 /* Board has gpio 9 controlling the PA */ +#define BHND_BFL_AIRLINEMODE 0x00000004 /* Board implements gpio 13 radio disable indication, UNUSED */ +#define BHND_BFL_ADCDIV 0x00000008 /* Board has the rssi ADC divider */ +#define BHND_BFL_DIS_256QAM 0x00000008 +#define BHND_BFL_ENETROBO 0x00000010 /* Board has robo switch or core */ +#define BHND_BFL_NOPLLDOWN 0x00000020 /* Not ok to power down the chip pll and oscillator */ +#define BHND_BFL_CCKHIPWR 0x00000040 /* Can do high-power CCK transmission */ +#define BHND_BFL_ENETADM 0x00000080 /* Board has ADMtek switch */ +#define BHND_BFL_ENETVLAN 0x00000100 /* Board has VLAN capability */ +#define BHND_BFL_LTECOEX 0x00000200 /* Board has LTE coex capability */ +#define BHND_BFL_NOPCI 0x00000400 /* Board leaves PCI floating */ +#define BHND_BFL_FEM 0x00000800 /* Board supports the Front End Module */ +#define BHND_BFL_EXTLNA 0x00001000 /* Board has an external LNA in 2.4GHz band */ +#define BHND_BFL_HGPA 0x00002000 /* Board has a high gain PA */ +#define BHND_BFL_BTC2WIRE_ALTGPIO 0x00004000 +/* Board's BTC 2wire is in the alternate gpios OBSLETE */ +#define BHND_BFL_ALTIQ 0x00008000 /* Alternate I/Q settings */ +#define BHND_BFL_NOPA 0x00010000 /* Board has no PA */ +#define BHND_BFL_RSSIINV 0x00020000 /* Board's RSSI uses positive slope(not TSSI) */ +#define BHND_BFL_PAREF 0x00040000 /* Board uses the PARef LDO */ +#define BHND_BFL_3TSWITCH 0x00080000 /* Board uses a triple throw switch shared with BT */ +#define BHND_BFL_PHASESHIFT 0x00100000 /* Board can support phase shifter */ +#define BHND_BFL_BUCKBOOST 0x00200000 /* Power topology uses BUCKBOOST */ +#define BHND_BFL_FEM_BT 0x00400000 /* Board has FEM and switch to share antenna w/ BT */ +#define BHND_BFL_RXCHAIN_OFF_BT 0x00400000 /* one rxchain is to be shut off when BT is active */ +#define BHND_BFL_NOCBUCK 0x00800000 /* Power topology doesn't use CBUCK */ +#define BHND_BFL_CCKFAVOREVM 0x01000000 /* Favor CCK EVM over spectral mask */ +#define BHND_BFL_PALDO 0x02000000 /* Power topology uses PALDO */ +#define BHND_BFL_LNLDO2_2P5 0x04000000 /* Select 2.5V as LNLDO2 output voltage */ +#define BHND_BFL_FASTPWR 0x08000000 +#define BHND_BFL_UCPWRCTL_MININDX 0x08000000 /* Enforce min power index to avoid FEM damage */ +#define BHND_BFL_EXTLNA_5GHz 0x10000000 /* Board has an external LNA in 5GHz band */ +#define BHND_BFL_TRSW_1by2 0x20000000 /* Board has 2 TRSW's in 1by2 designs */ +#define BHND_BFL_GAINBOOSTA01 0x20000000 /* 5g Gainboost for core0 and core1 */ +#define BHND_BFL_LO_TRSW_R_5GHz 0x40000000 /* In 5G do not throw TRSW to T for clipLO gain */ +#define BHND_BFL_ELNA_GAINDEF 0x80000000 /* Backoff InitGain based on elna_2g/5g field + * when this flag is set + */ +#define BHND_BFL_EXTLNA_TX 0x20000000 /* Temp boardflag to indicate to */ + + +/* Boardflags2 */ +#define BHND_BFL2_RXBB_INT_REG_DIS 0x00000001 /* Board has an external rxbb regulator */ +#define BHND_BFL2_APLL_WAR 0x00000002 /* Flag to implement alternative A-band PLL settings */ +#define BHND_BFL2_TXPWRCTRL_EN 0x00000004 /* Board permits enabling TX Power Control */ +#define BHND_BFL2_2X4_DIV 0x00000008 /* Board supports the 2X4 diversity switch */ +#define BHND_BFL2_5G_PWRGAIN 0x00000010 /* Board supports 5G band power gain */ +#define BHND_BFL2_PCIEWAR_OVR 0x00000020 /* Board overrides ASPM and Clkreq settings */ +#define BHND_BFL2_CAESERS_BRD 0x00000040 /* Board is Caesers brd (unused by sw) */ +#define BHND_BFL2_BTC3WIRE 0x00000080 /* Board support legacy 3 wire or 4 wire */ +#define BHND_BFL2_BTCLEGACY 0x00000080 /* Board support legacy 3/4 wire, to replace + * BHND_BFL2_BTC3WIRE + */ +#define BHND_BFL2_SKWRKFEM_BRD 0x00000100 /* 4321mcm93 board uses Skyworks FEM */ +#define BHND_BFL2_SPUR_WAR 0x00000200 /* Board has a WAR for clock-harmonic spurs */ +#define BHND_BFL2_GPLL_WAR 0x00000400 /* Flag to narrow G-band PLL loop b/w */ +#define BHND_BFL2_TRISTATE_LED 0x00000800 /* Tri-state the LED */ +#define BHND_BFL2_SINGLEANT_CCK 0x00001000 /* Tx CCK pkts on Ant 0 only */ +#define BHND_BFL2_2G_SPUR_WAR 0x00002000 /* WAR to reduce and avoid clock-harmonic spurs in 2G */ +#define BHND_BFL2_BPHY_ALL_TXCORES 0x00004000 /* Transmit bphy frames using all tx cores */ +#define BHND_BFL2_FCC_BANDEDGE_WAR 0x00008000 /* Activates WAR to improve FCC bandedge performance */ +#define BHND_BFL2_GPLL_WAR2 0x00010000 /* Flag to widen G-band PLL loop b/w */ +#define BHND_BFL2_IPALVLSHIFT_3P3 0x00020000 +#define BHND_BFL2_INTERNDET_TXIQCAL 0x00040000 /* Use internal envelope detector for TX IQCAL */ +#define BHND_BFL2_XTALBUFOUTEN 0x00080000 /* Keep the buffered Xtal output from radio on */ + /* Most drivers will turn it off without this flag */ + /* to save power. */ + +#define BHND_BFL2_ANAPACTRL_2G 0x00100000 /* 2G ext PAs are controlled by analog PA ctrl lines */ +#define BHND_BFL2_ANAPACTRL_5G 0x00200000 /* 5G ext PAs are controlled by analog PA ctrl lines */ +#define BHND_BFL2_ELNACTRL_TRSW_2G 0x00400000 /* AZW4329: 2G gmode_elna_gain controls TR Switch */ +#define BHND_BFL2_BT_SHARE_ANT0 0x00800000 /* WLAN/BT share antenna 0 */ +#define BHND_BFL2_BT_SHARE_BM_BIT0 0x00800000 /* bit 0 of WLAN/BT shared core bitmap */ +#define BHND_BFL2_TEMPSENSE_HIGHER 0x01000000 /* The tempsense threshold can sustain higher value + * than programmed. The exact delta is decided by + * driver per chip/boardtype. This can be used + * when tempsense qualification happens after shipment + */ +#define BHND_BFL2_BTC3WIREONLY 0x02000000 /* standard 3 wire btc only. 4 wire not supported */ +#define BHND_BFL2_PWR_NOMINAL 0x04000000 /* 0: power reduction on, 1: no power reduction */ +#define BHND_BFL2_EXTLNA_PWRSAVE 0x08000000 /* boardflag to enable ucode to apply power save + * ucode control of eLNA during Tx */ +#define BHND_BFL2_4313_RADIOREG 0x10000000 + /* board rework */ +#define BHND_BFL2_DYNAMIC_VMID 0x10000000 /* boardflag to enable dynamic Vmid idle TSSI CAL */ +#define BHND_BFL2_SDR_EN 0x20000000 /* SDR enabled or disabled */ +#define BHND_BFL2_LNA1BYPFORTR2G 0x40000000 /* acphy, enable lna1 bypass for clip gain, 2g */ +#define BHND_BFL2_LNA1BYPFORTR5G 0x80000000 /* acphy, enable lna1 bypass for clip gain, 5g */ + + +/* SROM 11 - 11ac boardflag definitions */ +#define BHND_BFL_SROM11_BTCOEX 0x00000001 /* Board supports BTCOEX */ +#define BHND_BFL_SROM11_WLAN_BT_SH_XTL 0x00000002 /* bluetooth and wlan share same crystal */ +#define BHND_BFL_SROM11_EXTLNA 0x00001000 /* Board has an external LNA in 2.4GHz band */ +#define BHND_BFL_SROM11_EXTLNA_5GHz 0x10000000 /* Board has an external LNA in 5GHz band */ +#define BHND_BFL_SROM11_GAINBOOSTA01 0x20000000 /* 5g Gainboost for core0 and core1 */ +#define BHND_BFL2_SROM11_APLL_WAR 0x00000002 /* Flag to implement alternative A-band PLL settings */ +#define BHND_BFL2_SROM11_ANAPACTRL_2G 0x00100000 /* 2G ext PAs are ctrl-ed by analog PA ctrl lines */ +#define BHND_BFL2_SROM11_ANAPACTRL_5G 0x00200000 /* 5G ext PAs are ctrl-ed by analog PA ctrl lines */ + + +/* Boardflags3 */ +#define BHND_BFL3_FEMCTRL_SUB 0x00000007 /* acphy, subrevs of femctrl on top of srom_femctrl */ +#define BHND_BFL3_RCAL_WAR 0x00000008 /* acphy, rcal war active on this board (4335a0) */ +#define BHND_BFL3_TXGAINTBLID 0x00000070 /* acphy, txgain table id */ +#define BHND_BFL3_TXGAINTBLID_SHIFT 0x4 /* acphy, txgain table id shift bit */ +#define BHND_BFL3_TSSI_DIV_WAR 0x00000080 /* acphy, Seperate paparam for 20/40/80 */ +#define BHND_BFL3_TSSI_DIV_WAR_SHIFT 0x7 /* acphy, Seperate paparam for 20/40/80 shift bit */ +#define BHND_BFL3_FEMTBL_FROM_NVRAM 0x00000100 /* acphy, femctrl table is read from nvram */ +#define BHND_BFL3_FEMTBL_FROM_NVRAM_SHIFT 0x8 /* acphy, femctrl table is read from nvram */ +#define BHND_BFL3_AGC_CFG_2G 0x00000200 /* acphy, gain control configuration for 2G */ +#define BHND_BFL3_AGC_CFG_5G 0x00000400 /* acphy, gain control configuration for 5G */ +#define BHND_BFL3_PPR_BIT_EXT 0x00000800 /* acphy, bit position for 1bit extension for ppr */ +#define BHND_BFL3_PPR_BIT_EXT_SHIFT 11 /* acphy, bit shift for 1bit extension for ppr */ +#define BHND_BFL3_BBPLL_SPR_MODE_DIS 0x00001000 /* acphy, disables bbpll spur modes */ +#define BHND_BFL3_RCAL_OTP_VAL_EN 0x00002000 /* acphy, to read rcal_trim value from otp */ +#define BHND_BFL3_2GTXGAINTBL_BLANK 0x00004000 /* acphy, blank the first X ticks of 2g gaintbl */ +#define BHND_BFL3_2GTXGAINTBL_BLANK_SHIFT 14 /* acphy, blank the first X ticks of 2g gaintbl */ +#define BHND_BFL3_5GTXGAINTBL_BLANK 0x00008000 /* acphy, blank the first X ticks of 5g gaintbl */ +#define BHND_BFL3_5GTXGAINTBL_BLANK_SHIFT 15 /* acphy, blank the first X ticks of 5g gaintbl */ +#define BHND_BFL3_BT_SHARE_BM_BIT1 0x40000000 /* bit 1 of WLAN/BT shared core bitmap */ +#define BHND_BFL3_PHASETRACK_MAX_ALPHABETA 0x00010000 /* acphy, to max out alpha,beta to 511 */ +#define BHND_BFL3_PHASETRACK_MAX_ALPHABETA_SHIFT 16 /* acphy, to max out alpha,beta to 511 */ +#define BHND_BFL3_BT_SHARE_BM_BIT1 0x40000000 /* bit 1 of WLAN/BT shared core bitmap */ +#define BHND_BFL3_EN_NONBRCM_TXBF 0x10000000 /* acphy, enable non-brcm TXBF */ +#define BHND_BFL3_EN_P2PLINK_TXBF 0x20000000 /* acphy, enable TXBF in p2p links */ + + +/* board specific GPIO assignment, gpio 0-3 are also customer-configurable led */ +#define BHND_BOARD_GPIO_BTC3W_IN 0x850 /* bit 4 is RF_ACTIVE, bit 6 is STATUS, bit 11 is PRI */ +#define BHND_BOARD_GPIO_BTC3W_OUT 0x020 /* bit 5 is TX_CONF */ +#define BHND_BOARD_GPIO_BTCMOD_IN 0x010 /* bit 4 is the alternate BT Coexistence Input */ +#define BHND_BOARD_GPIO_BTCMOD_OUT 0x020 /* bit 5 is the alternate BT Coexistence Out */ +#define BHND_BOARD_GPIO_BTC_IN 0x080 /* bit 7 is BT Coexistence Input */ +#define BHND_BOARD_GPIO_BTC_OUT 0x100 /* bit 8 is BT Coexistence Out */ +#define BHND_BOARD_GPIO_PACTRL 0x200 /* bit 9 controls the PA on new 4306 boards */ +#define BHND_BOARD_GPIO_12 0x1000 /* gpio 12 */ +#define BHND_BOARD_GPIO_13 0x2000 /* gpio 13 */ +#define BHND_BOARD_GPIO_BTC4_IN 0x0800 /* gpio 11, coex4, in */ +#define BHND_BOARD_GPIO_BTC4_BT 0x2000 /* gpio 12, coex4, bt active */ +#define BHND_BOARD_GPIO_BTC4_STAT 0x4000 /* gpio 14, coex4, status */ +#define BHND_BOARD_GPIO_BTC4_WLAN 0x8000 /* gpio 15, coex4, wlan active */ +#define BHND_BOARD_GPIO_1_WLAN_PWR 0x02 /* throttle WLAN power on X21 board */ +#define BHND_BOARD_GPIO_3_WLAN_PWR 0x08 /* throttle WLAN power on X28 board */ +#define BHND_BOARD_GPIO_4_WLAN_PWR 0x10 /* throttle WLAN power on X19 board */ + +#define BHND_GPIO_BTC4W_OUT_4312 0x010 /* bit 4 is BT_IODISABLE */ +#define BHND_GPIO_BTC4W_OUT_43224 0x020 /* bit 5 is BT_IODISABLE */ +#define BHND_GPIO_BTC4W_OUT_43224_SHARED 0x0e0 /* bit 5 is BT_IODISABLE */ +#define BHND_GPIO_BTC4W_OUT_43225 0x0e0 /* bit 5 BT_IODISABLE, bit 6 SW_BT, bit 7 SW_WL */ +#define BHND_GPIO_BTC4W_OUT_43421 0x020 /* bit 5 is BT_IODISABLE */ +#define BHND_GPIO_BTC4W_OUT_4313 0x060 /* bit 5 SW_BT, bit 6 SW_WL */ +#define BHND_GPIO_BTC4W_OUT_4331_SHARED 0x010 /* GPIO 4 */ + +/* Power Control Defines */ +#define BHND_CHIPC_PLL_DELAY 150 /* us pll on delay */ +#define BHND_CHIPC_FREF_DELAY 200 /* us fref change delay */ +#define BHND_CHIPC_MIN_SLOW_CLK 32 /* us Slow clock period */ +#define BHND_CHIPC_XTAL_ON_DELAY 1000 /* us crystal power-on delay */ + +/* 43341 Boards */ +#define BCM943341WLABGS_SSID 0x062d + +/* 43342 Boards */ +#define BCM943342FCAGBI_SSID 0x0641 + +/* # of GPIO pins */ +#define BHND_BCM43XX_GPIO_NUMPINS 32 + +/* These values are used by dhd USB host driver. */ +#define BHND_USB_RDL_RAM_BASE_4319 0x60000000 +#define BHND_USB_RDL_RAM_BASE_4329 0x60000000 +#define BHND_USB_RDL_RAM_SIZE_4319 0x48000 +#define BHND_USB_RDL_RAM_SIZE_4329 0x48000 +#define BHND_USB_RDL_RAM_SIZE_43236 0x70000 +#define BHND_USB_RDL_RAM_BASE_43236 0x60000000 +#define BHND_USB_RDL_RAM_SIZE_4328 0x60000 +#define BHND_USB_RDL_RAM_BASE_4328 0x80000000 +#define BHND_USB_RDL_RAM_SIZE_4322 0x60000 +#define BHND_USB_RDL_RAM_BASE_4322 0x60000000 +#define BHND_USB_RDL_RAM_SIZE_4360 0xA0000 +#define BHND_USB_RDL_RAM_BASE_4360 0x60000000 +#define BHND_USB_RDL_RAM_SIZE_43242 0x90000 +#define BHND_USB_RDL_RAM_BASE_43242 0x60000000 +#define BHND_USB_RDL_RAM_SIZE_43143 0x70000 +#define BHND_USB_RDL_RAM_BASE_43143 0x60000000 +#define BHND_USB_RDL_RAM_SIZE_4350 0xC0000 +#define BHND_USB_RDL_RAM_BASE_4350 0x180800 + +/* generic defs for nvram "muxenab" bits +* Note: these differ for 4335a0. refer bcmchipc.h for specific mux options. +*/ +#define BHND_NVRAM_MUXENAB_UART 0x00000001 +#define BHND_NVRAM_MUXENAB_GPIO 0x00000002 +#define BHND_NVRAM_MUXENAB_ERCX 0x00000004 /* External Radio BT coex */ +#define BHND_NVRAM_MUXENAB_JTAG 0x00000008 +#define BHND_NVRAM_MUXENAB_HOST_WAKE 0x00000010 /* configure GPIO for SDIO host_wake */ +#define BHND_NVRAM_MUXENAB_I2S_EN 0x00000020 +#define BHND_NVRAM_MUXENAB_I2S_MASTER 0x00000040 +#define BHND_NVRAM_MUXENAB_I2S_FULL 0x00000080 +#define BHND_NVRAM_MUXENAB_SFLASH 0x00000100 +#define BHND_NVRAM_MUXENAB_RFSWCTRL0 0x00000200 +#define BHND_NVRAM_MUXENAB_RFSWCTRL1 0x00000400 +#define BHND_NVRAM_MUXENAB_RFSWCTRL2 0x00000800 +#define BHND_NVRAM_MUXENAB_SECI 0x00001000 +#define BHND_NVRAM_MUXENAB_BT_LEGACY 0x00002000 +#define BHND_NVRAM_MUXENAB_HOST_WAKE1 0x00004000 /* configure alternative GPIO for SDIO host_wake */ + +/* Boot flags */ +#define BHND_BOOTFLAG_FLASH_KERNEL_NFLASH 0x00000001 +#define BHND_BOOTFLAG_FLASH_BOOT_NFLASH 0x00000002 + +#endif /* _BHND_BHND_IDS_H_ */ diff --git a/sys/dev/bhnd/bhnd_subr.c b/sys/dev/bhnd/bhnd_subr.c new file mode 100644 index 000000000000..3d79845cc9a8 --- /dev/null +++ b/sys/dev/bhnd/bhnd_subr.c @@ -0,0 +1,648 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include +#include +#include + +#include + +#include "bhndreg.h" +#include "bhndvar.h" + +/* BHND core device description table. */ +static const struct bhnd_core_desc { + uint16_t vendor; + uint16_t device; + bhnd_devclass_t class; + const char *desc; +} bhnd_core_descs[] = { + #define BHND_CDESC(_mfg, _cid, _cls, _desc) \ + { BHND_MFGID_ ## _mfg, BHND_COREID_ ## _cid, \ + BHND_DEVCLASS_ ## _cls, _desc } + + BHND_CDESC(BCM, CC, CC, "ChipCommon I/O Controller"), + BHND_CDESC(BCM, ILINE20, OTHER, "iLine20 HPNA"), + BHND_CDESC(BCM, SRAM, RAM, "SRAM"), + BHND_CDESC(BCM, SDRAM, RAM, "SDRAM"), + BHND_CDESC(BCM, PCI, PCI, "PCI Bridge"), + BHND_CDESC(BCM, MIPS, CPU, "MIPS Core"), + BHND_CDESC(BCM, ENET, ENET_MAC, "Fast Ethernet MAC"), + BHND_CDESC(BCM, CODEC, OTHER, "V.90 Modem Codec"), + BHND_CDESC(BCM, USB, OTHER, "USB 1.1 Device/Host Controller"), + BHND_CDESC(BCM, ADSL, OTHER, "ADSL Core"), + BHND_CDESC(BCM, ILINE100, OTHER, "iLine100 HPNA"), + BHND_CDESC(BCM, IPSEC, OTHER, "IPsec Accelerator"), + BHND_CDESC(BCM, UTOPIA, OTHER, "UTOPIA ATM Core"), + BHND_CDESC(BCM, PCMCIA, PCCARD, "PCMCIA Bridge"), + BHND_CDESC(BCM, SOCRAM, RAM, "Internal Memory"), + BHND_CDESC(BCM, MEMC, MEMC, "MEMC SDRAM Controller"), + BHND_CDESC(BCM, OFDM, OTHER, "OFDM PHY"), + BHND_CDESC(BCM, EXTIF, OTHER, "External Interface"), + BHND_CDESC(BCM, D11, WLAN, "802.11 MAC/PHY/Radio"), + BHND_CDESC(BCM, APHY, WLAN_PHY, "802.11a PHY"), + BHND_CDESC(BCM, BPHY, WLAN_PHY, "802.11b PHY"), + BHND_CDESC(BCM, GPHY, WLAN_PHY, "802.11g PHY"), + BHND_CDESC(BCM, MIPS33, CPU, "MIPS 3302 Core"), + BHND_CDESC(BCM, USB11H, OTHER, "USB 1.1 Host Controller"), + BHND_CDESC(BCM, USB11D, OTHER, "USB 1.1 Device Core"), + BHND_CDESC(BCM, USB20H, OTHER, "USB 2.0 Host Controller"), + BHND_CDESC(BCM, USB20D, OTHER, "USB 2.0 Device Core"), + BHND_CDESC(BCM, SDIOH, OTHER, "SDIO Host Controller"), + BHND_CDESC(BCM, ROBO, OTHER, "RoboSwitch"), + BHND_CDESC(BCM, ATA100, OTHER, "Parallel ATA Controller"), + BHND_CDESC(BCM, SATAXOR, OTHER, "SATA DMA/XOR Controller"), + BHND_CDESC(BCM, GIGETH, ENET_MAC, "Gigabit Ethernet MAC"), + BHND_CDESC(BCM, PCIE, PCIE, "PCIe Bridge"), + BHND_CDESC(BCM, NPHY, WLAN_PHY, "802.11n 2x2 PHY"), + BHND_CDESC(BCM, SRAMC, MEMC, "SRAM Controller"), + BHND_CDESC(BCM, MINIMAC, OTHER, "MINI MAC/PHY"), + BHND_CDESC(BCM, ARM11, CPU, "ARM1176 CPU"), + BHND_CDESC(BCM, ARM7S, CPU, "ARM7TDMI-S CPU"), + BHND_CDESC(BCM, LPPHY, WLAN_PHY, "802.11a/b/g PHY"), + BHND_CDESC(BCM, PMU, PMU, "PMU"), + BHND_CDESC(BCM, SSNPHY, WLAN_PHY, "802.11n Single-Stream PHY"), + BHND_CDESC(BCM, SDIOD, OTHER, "SDIO Device Core"), + BHND_CDESC(BCM, ARMCM3, CPU, "ARM Cortex-M3 CPU"), + BHND_CDESC(BCM, HTPHY, WLAN_PHY, "802.11n 4x4 PHY"), + BHND_CDESC(BCM, MIPS74K, CPU, "MIPS74k CPU"), + BHND_CDESC(BCM, GMAC, ENET_MAC, "Gigabit MAC core"), + BHND_CDESC(BCM, DMEMC, MEMC, "DDR1/DDR2 Memory Controller"), + BHND_CDESC(BCM, PCIERC, OTHER, "PCIe Root Complex"), + BHND_CDESC(BCM, OCP, SOC_BRIDGE, "OCP to OCP Bridge"), + BHND_CDESC(BCM, SC, OTHER, "Shared Common Core"), + BHND_CDESC(BCM, AHB, SOC_BRIDGE, "OCP to AHB Bridge"), + BHND_CDESC(BCM, SPIH, OTHER, "SPI Host Controller"), + BHND_CDESC(BCM, I2S, OTHER, "I2S Digital Audio Interface"), + BHND_CDESC(BCM, DMEMS, MEMC, "SDR/DDR1 Memory Controller"), + BHND_CDESC(BCM, UBUS_SHIM, OTHER, "BCM6362/UBUS WLAN SHIM"), + BHND_CDESC(BCM, PCIE2, PCIE, "PCIe Bridge (Gen2)"), + + BHND_CDESC(ARM, APB_BRIDGE, SOC_BRIDGE, "BP135 AMBA3 AXI to APB Bridge"), + BHND_CDESC(ARM, PL301, SOC_ROUTER, "PL301 AMBA3 Interconnect"), + BHND_CDESC(ARM, EROM, EROM, "PL366 Device Enumeration ROM"), + BHND_CDESC(ARM, OOB_ROUTER, OTHER, "PL367 OOB Interrupt Router"), + BHND_CDESC(ARM, AXI_UNMAPPED, OTHER, "Unmapped Address Ranges"), + + BHND_CDESC(BCM, 4706_CC, CC, "ChipCommon I/O Controller"), + BHND_CDESC(BCM, NS_PCIE2, PCIE, "PCIe Bridge (Gen2)"), + BHND_CDESC(BCM, NS_DMA, OTHER, "DMA engine"), + BHND_CDESC(BCM, NS_SDIO, OTHER, "SDIO 3.0 Host Controller"), + BHND_CDESC(BCM, NS_USB20H, OTHER, "USB 2.0 Host Controller"), + BHND_CDESC(BCM, NS_USB30H, OTHER, "USB 3.0 Host Controller"), + BHND_CDESC(BCM, NS_A9JTAG, OTHER, "ARM Cortex A9 JTAG Interface"), + BHND_CDESC(BCM, NS_DDR23_MEMC, MEMC, "Denali DDR2/DD3 Memory Controller"), + BHND_CDESC(BCM, NS_ROM, NVRAM, "System ROM"), + BHND_CDESC(BCM, NS_NAND, NVRAM, "NAND Flash Controller"), + BHND_CDESC(BCM, NS_QSPI, NVRAM, "QSPI Flash Controller"), + BHND_CDESC(BCM, NS_CC_B, CC_B, "ChipCommon B Auxiliary I/O Controller"), + BHND_CDESC(BCM, 4706_SOCRAM, RAM, "Internal Memory"), + BHND_CDESC(BCM, IHOST_ARMCA9, CPU, "ARM Cortex A9 CPU"), + BHND_CDESC(BCM, 4706_GMAC_CMN, ENET, "Gigabit MAC (Common)"), + BHND_CDESC(BCM, 4706_GMAC, ENET_MAC, "Gigabit MAC"), + BHND_CDESC(BCM, AMEMC, MEMC, "Denali DDR1/DDR2 Memory Controller"), +#undef BHND_CDESC + + /* Derived from inspection of the BCM4331 cores that provide PrimeCell + * IDs. Due to lack of documentation, the surmised device name/purpose + * provided here may be incorrect. */ + { BHND_MFGID_ARM, BHND_PRIMEID_EROM, BHND_DEVCLASS_OTHER, + "PL364 Device Enumeration ROM" }, + { BHND_MFGID_ARM, BHND_PRIMEID_SWRAP, BHND_DEVCLASS_OTHER, + "PL368 Device Management Interface" }, + { BHND_MFGID_ARM, BHND_PRIMEID_MWRAP, BHND_DEVCLASS_OTHER, + "PL369 Device Management Interface" }, + + { 0, 0, 0, NULL } +}; + +/** + * Return the name for a given JEP106 manufacturer ID. + * + * @param vendor A JEP106 Manufacturer ID, including the non-standard ARM 4-bit + * JEP106 continuation code. + */ +const char * +bhnd_vendor_name(uint16_t vendor) +{ + switch (vendor) { + case BHND_MFGID_ARM: + return "ARM"; + case BHND_MFGID_BCM: + return "Broadcom"; + case BHND_MFGID_MIPS: + return "MIPS"; + default: + return "unknown"; + } +} + +/** + * Return the name of a port type. + */ +const char * +bhnd_port_type_name(bhnd_port_type port_type) +{ + switch (port_type) { + case BHND_PORT_DEVICE: + return ("device"); + case BHND_PORT_BRIDGE: + return ("bridge"); + case BHND_PORT_AGENT: + return ("agent"); + } +} + + +static const struct bhnd_core_desc * +bhnd_find_core_desc(uint16_t vendor, uint16_t device) +{ + for (u_int i = 0; bhnd_core_descs[i].desc != NULL; i++) { + if (bhnd_core_descs[i].vendor != vendor) + continue; + + if (bhnd_core_descs[i].device != device) + continue; + + return (&bhnd_core_descs[i]); + } + + return (NULL); +} + +/** + * Return a human-readable name for a BHND core. + * + * @param vendor The core designer's JEDEC-106 Manufacturer ID + * @param device The core identifier. + */ +const char * +bhnd_find_core_name(uint16_t vendor, uint16_t device) +{ + const struct bhnd_core_desc *desc; + + if ((desc = bhnd_find_core_desc(vendor, device)) == NULL) + return ("unknown"); + + return desc->desc; +} + +/** + * Return the device class for a BHND core. + * + * @param vendor The core designer's JEDEC-106 Manufacturer ID + * @param device The core identifier. + */ +bhnd_devclass_t +bhnd_find_core_class(uint16_t vendor, uint16_t device) +{ + const struct bhnd_core_desc *desc; + + if ((desc = bhnd_find_core_desc(vendor, device)) == NULL) + return (BHND_DEVCLASS_OTHER); + + return desc->class; +} + +/** + * Return a human-readable name for a BHND core. + * + * @param ci The core's info record. + */ +const char * +bhnd_core_name(const struct bhnd_core_info *ci) +{ + return bhnd_find_core_name(ci->vendor, ci->device); +} + +/** + * Return the device class for a BHND core. + * + * @param ci The core's info record. + */ +bhnd_devclass_t +bhnd_core_class(const struct bhnd_core_info *ci) +{ + return bhnd_find_core_class(ci->vendor, ci->device); +} + +/** + * Initialize a core info record with data from from a bhnd-attached @p dev. + * + * @param dev A bhnd device. + * @param core The record to be initialized. + */ +struct bhnd_core_info +bhnd_get_core_info(device_t dev) { + return (struct bhnd_core_info) { + .vendor = bhnd_get_vendor(dev), + .device = bhnd_get_device(dev), + .hwrev = bhnd_get_hwrev(dev), + .core_idx = bhnd_get_core_index(dev), + .unit = bhnd_get_core_unit(dev) + }; +} + +/** + * Find a @p class child device with @p unit on @p dev. + * + * @param parent The bhnd-compatible bus to be searched. + * @param class The device class to match on. + * @param unit The device unit number; specify -1 to return the first match + * regardless of unit number. + * + * @retval device_t if a matching child device is found. + * @retval NULL if no matching child device is found. + */ +device_t +bhnd_find_child(device_t dev, bhnd_devclass_t class, int unit) +{ + struct bhnd_core_match md = { + .vendor = BHND_MFGID_INVALID, + .device = BHND_COREID_INVALID, + .hwrev.start = BHND_HWREV_INVALID, + .hwrev.end = BHND_HWREV_INVALID, + .class = class, + .unit = unit + }; + + return bhnd_match_child(dev, &md); +} + +/** + * Find the first child device on @p dev that matches @p desc. + * + * @param parent The bhnd-compatible bus to be searched. + * @param desc A match descriptor. + * + * @retval device_t if a matching child device is found. + * @retval NULL if no matching child device is found. + */ +device_t +bhnd_match_child(device_t dev, const struct bhnd_core_match *desc) +{ + device_t *devlistp; + device_t match; + int devcnt; + int error; + + error = device_get_children(dev, &devlistp, &devcnt); + if (error != 0) + return (NULL); + + match = NULL; + for (int i = 0; i < devcnt; i++) { + device_t dev = devlistp[i]; + if (bhnd_device_matches(dev, desc)) { + match = dev; + goto done; + } + } + +done: + free(devlistp, M_TEMP); + return match; +} + +/** + * Find the first core in @p cores that matches @p desc. + * + * @param cores The table to search. + * @param num_cores The length of @p cores. + * @param desc A match descriptor. + * + * @retval bhnd_core_info if a matching core is found. + * @retval NULL if no matching core is found. + */ +const struct bhnd_core_info * +bhnd_match_core(const struct bhnd_core_info *cores, u_int num_cores, + const struct bhnd_core_match *desc) +{ + for (u_int i = 0; i < num_cores; i++) { + if (bhnd_core_matches(&cores[i], desc)) + return &cores[i]; + } + + return (NULL); +} + + +/** + * Find the first core in @p cores with the given @p class. + * + * @param cores The table to search. + * @param num_cores The length of @p cores. + * @param desc A match descriptor. + * + * @retval bhnd_core_info if a matching core is found. + * @retval NULL if no matching core is found. + */ +const struct bhnd_core_info * +bhnd_find_core(const struct bhnd_core_info *cores, u_int num_cores, + bhnd_devclass_t class) +{ + struct bhnd_core_match md = { + .vendor = BHND_MFGID_INVALID, + .device = BHND_COREID_INVALID, + .hwrev.start = BHND_HWREV_INVALID, + .hwrev.end = BHND_HWREV_INVALID, + .class = class, + .unit = -1 + }; + + return bhnd_match_core(cores, num_cores, &md); +} + +/** + * Return true if the @p core matches @p desc. + * + * @param core A bhnd core descriptor. + * @param desc A match descriptor to compare against @p core. + * + * @retval true if @p core matches @p match + * @retval false if @p core does not match @p match. + */ +bool +bhnd_core_matches(const struct bhnd_core_info *core, + const struct bhnd_core_match *desc) +{ + if (desc->vendor != BHND_MFGID_INVALID && + desc->vendor != core->vendor) + return (false); + + if (desc->device != BHND_COREID_INVALID && + desc->device != core->device) + return (false); + + if (desc->unit != -1 && desc->unit != core->unit) + return (false); + + if (!bhnd_hwrev_matches(core->hwrev, &desc->hwrev)) + return (false); + + if (desc->hwrev.end != BHND_HWREV_INVALID && + desc->hwrev.end < core->hwrev) + return (false); + + if (desc->class != BHND_DEVCLASS_INVALID && + desc->class != bhnd_core_class(core)) + return (false); + + return true; +} + +/** + * Return true if the @p hwrev matches @p desc. + * + * @param hwrev A bhnd hardware revision. + * @param desc A match descriptor to compare against @p core. + * + * @retval true if @p hwrev matches @p match + * @retval false if @p hwrev does not match @p match. + */ +bool +bhnd_hwrev_matches(uint16_t hwrev, const struct bhnd_hwrev_match *desc) +{ + if (desc->start != BHND_HWREV_INVALID && + desc->start > hwrev) + return false; + + if (desc->end != BHND_HWREV_INVALID && + desc->end < hwrev) + return false; + + return true; +} + +/** + * Return true if the @p dev matches @p desc. + * + * @param dev A bhnd device. + * @param desc A match descriptor to compare against @p dev. + * + * @retval true if @p dev matches @p match + * @retval false if @p dev does not match @p match. + */ +bool +bhnd_device_matches(device_t dev, const struct bhnd_core_match *desc) +{ + struct bhnd_core_info ci = { + .vendor = bhnd_get_vendor(dev), + .device = bhnd_get_device(dev), + .unit = bhnd_get_core_unit(dev), + .hwrev = bhnd_get_hwrev(dev) + }; + + return bhnd_core_matches(&ci, desc); +} + +/** + * Allocate bhnd(4) resources defined in @p rs from a parent bus. + * + * @param dev The device requesting ownership of the resources. + * @param rs A standard bus resource specification. This will be updated + * with the allocated resource's RIDs. + * @param res On success, the allocated bhnd resources. + * + * @retval 0 success + * @retval non-zero if allocation of any non-RF_OPTIONAL resource fails, + * all allocated resources will be released and a regular + * unix error code will be returned. + */ +int +bhnd_alloc_resources(device_t dev, struct resource_spec *rs, + struct bhnd_resource **res) +{ + /* Initialize output array */ + for (u_int i = 0; rs[i].type != -1; i++) + res[i] = NULL; + + for (u_int i = 0; rs[i].type != -1; i++) { + res[i] = bhnd_alloc_resource_any(dev, rs[i].type, &rs[i].rid, + rs[i].flags); + + /* Clean up all allocations on failure */ + if (res[i] == NULL && !(rs[i].flags & RF_OPTIONAL)) { + bhnd_release_resources(dev, rs, res); + return (ENXIO); + } + } + + return (0); +}; + +/** + * Release bhnd(4) resources defined in @p rs from a parent bus. + * + * @param dev The device that owns the resources. + * @param rs A standard bus resource specification previously initialized + * by @p bhnd_alloc_resources. + * @param res The bhnd resources to be released. + */ +void +bhnd_release_resources(device_t dev, const struct resource_spec *rs, + struct bhnd_resource **res) +{ + for (u_int i = 0; rs[i].type != -1; i++) { + if (res[i] == NULL) + continue; + + bhnd_release_resource(dev, rs[i].type, rs[i].rid, res[i]); + res[i] = NULL; + } +} + +/** + * Parse the CHIPC_ID_* fields from the ChipCommon CHIPC_ID + * register, returning its bhnd_chipid representation. + * + * @param idreg The CHIPC_ID register value. + * @param enum_addr The enumeration address to include in the result. + * + * @warning + * On early siba(4) devices, the ChipCommon core does not provide + * a valid CHIPC_ID_NUMCORE field. On these ChipCommon revisions + * (see CHIPC_NCORES_MIN_HWREV()), this function will parse and return + * an invalid `ncores` value. + */ +struct bhnd_chipid +bhnd_parse_chipid(uint32_t idreg, bhnd_addr_t enum_addr) +{ + struct bhnd_chipid result; + + /* Fetch the basic chip info */ + result.chip_id = CHIPC_GET_ATTR(idreg, ID_CHIP); + result.chip_pkg = CHIPC_GET_ATTR(idreg, ID_PKG); + result.chip_rev = CHIPC_GET_ATTR(idreg, ID_REV); + result.chip_type = CHIPC_GET_ATTR(idreg, ID_BUS); + result.ncores = CHIPC_GET_ATTR(idreg, ID_NUMCORE); + + result.enum_addr = enum_addr; + + return (result); +} + +/** + * Allocate the resource defined by @p rs via @p dev, use it + * to read the ChipCommon ID register relative to @p chipc_offset, + * then release the resource. + * + * @param dev The device owning @p rs. + * @param rs A resource spec that encompasses the ChipCommon register block. + * @param chipc_offset The offset of the ChipCommon registers within @p rs. + * @param[out] result the chip identification data. + * + * @retval 0 success + * @retval non-zero if the ChipCommon identification data could not be read. + */ +int +bhnd_read_chipid(device_t dev, struct resource_spec *rs, + bus_size_t chipc_offset, struct bhnd_chipid *result) +{ + struct resource *res; + uint32_t reg; + int error, rid, rtype; + + /* Allocate the ChipCommon window resource and fetch the chipid data */ + rid = rs->rid; + rtype = rs->type; + res = bus_alloc_resource_any(dev, rtype, &rid, RF_ACTIVE); + if (res == NULL) { + device_printf(dev, + "failed to allocate bhnd chipc resource\n"); + return (ENXIO); + } + + /* Fetch the basic chip info */ + reg = bus_read_4(res, chipc_offset + CHIPC_ID); + *result = bhnd_parse_chipid(reg, 0x0); + + /* Fetch the enum base address */ + error = 0; + switch (result->chip_type) { + case BHND_CHIPTYPE_SIBA: + result->enum_addr = BHND_DEFAULT_CHIPC_ADDR; + break; + case BHND_CHIPTYPE_BCMA: + case BHND_CHIPTYPE_BCMA_ALT: + result->enum_addr = bus_read_4(res, chipc_offset + + CHIPC_EROMPTR); + break; + case BHND_CHIPTYPE_UBUS: + device_printf(dev, "unsupported ubus/bcm63xx chip type"); + error = ENODEV; + goto cleanup; + default: + device_printf(dev, "unknown chip type %hhu\n", + result->chip_type); + error = ENODEV; + goto cleanup; + } + +cleanup: + /* Clean up */ + bus_release_resource(dev, rtype, rid, res); + return (error); +} + +/** + * Using the bhnd(4) bus-level core information, populate @p dev's device + * description. + * + * @param dev A bhnd-bus attached device. + */ +void +bhnd_set_generic_core_desc(device_t dev) +{ + const char *dev_name; + const char *vendor_name; + char *desc; + + vendor_name = bhnd_get_vendor_name(dev); + dev_name = bhnd_get_device_name(dev); + + asprintf(&desc, M_BHND, "%s %s, rev %hhu", + bhnd_get_vendor_name(dev), + bhnd_get_device_name(dev), + bhnd_get_hwrev(dev)); + + if (desc != NULL) { + device_set_desc_copy(dev, desc); + free(desc, M_BHND); + } else { + device_set_desc(dev, dev_name); + } +} diff --git a/sys/dev/bhnd/bhnd_types.h b/sys/dev/bhnd/bhnd_types.h new file mode 100644 index 000000000000..d31c00b07e28 --- /dev/null +++ b/sys/dev/bhnd/bhnd_types.h @@ -0,0 +1,97 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $FreeBSD$ + */ + +#ifndef _BHND_BHND_TYPES_H_ +#define _BHND_BHND_TYPES_H_ + +#include + +/** bhnd(4) device classes. */ +typedef enum { + BHND_DEVCLASS_CC, /**< chipcommon i/o controller */ + BHND_DEVCLASS_CC_B, /**< chipcommon auxiliary controller */ + BHND_DEVCLASS_PMU, /**< pmu controller */ + BHND_DEVCLASS_PCI, /**< pci host/device bridge */ + BHND_DEVCLASS_PCIE, /**< pcie host/device bridge */ + BHND_DEVCLASS_PCCARD, /**< pcmcia host/device bridge */ + BHND_DEVCLASS_RAM, /**< internal RAM/SRAM */ + BHND_DEVCLASS_MEMC, /**< memory controller */ + BHND_DEVCLASS_ENET, /**< 802.3 MAC/PHY */ + BHND_DEVCLASS_ENET_MAC, /**< 802.3 MAC */ + BHND_DEVCLASS_ENET_PHY, /**< 802.3 PHY */ + BHND_DEVCLASS_WLAN, /**< 802.11 MAC/PHY/Radio */ + BHND_DEVCLASS_WLAN_MAC, /**< 802.11 MAC */ + BHND_DEVCLASS_WLAN_PHY, /**< 802.11 PHY */ + BHND_DEVCLASS_CPU, /**< cpu core */ + BHND_DEVCLASS_SOC_ROUTER, /**< interconnect router */ + BHND_DEVCLASS_SOC_BRIDGE, /**< interconnect host bridge */ + BHND_DEVCLASS_EROM, /**< bus device enumeration ROM */ + BHND_DEVCLASS_NVRAM, /**< nvram/flash controller */ + BHND_DEVCLASS_OTHER, /**< other / unknown */ + + BHND_DEVCLASS_INVALID /**< no/invalid class */ +} bhnd_devclass_t; + + +/** + * bhnd(4) port types. + * + * Only BHND_PORT_DEVICE is guaranteed to be supported by all bhnd(4) bus + * implementations. + */ +typedef enum { + BHND_PORT_DEVICE = 0, /**< device memory */ + BHND_PORT_BRIDGE = 1, /**< bridge memory */ + BHND_PORT_AGENT = 2, /**< interconnect agent/wrapper */ +} bhnd_port_type; + + +/** Evaluates to true if @p cls is a device class that can be configured + * as a host bridge device. */ +#define BHND_DEVCLASS_SUPPORTS_HOSTB(cls) \ + ((cls) == BHND_DEVCLASS_PCI || (cls) == BHND_DEVCLASS_PCIE || \ + (cls) == BHND_DEVCLASS_PCCARD) + +/** + * BHND bus address. + * + * @note While the interconnect may support 64-bit addressing, not + * all bridges and SoC CPUs will. + */ +typedef uint64_t bhnd_addr_t; +#define BHND_ADDR_MAX UINT64_MAX /**< Maximum bhnd_addr_t value */ + +/** BHND bus size. */ +typedef uint64_t bhnd_size_t; +#define BHND_SIZE_MAX UINT64_MAX /**< Maximum bhnd_size_t value */ + + +#endif /* _BHND_BHND_TYPES_H_ */ diff --git a/sys/dev/bhnd/bhndb/bhndb.c b/sys/dev/bhnd/bhndb/bhndb.c new file mode 100644 index 000000000000..238d4ee63184 --- /dev/null +++ b/sys/dev/bhnd/bhndb/bhndb.c @@ -0,0 +1,1943 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * Abstract BHND Bridge Device Driver + * + * Provides generic support for bridging from a parent bus (such as PCI) to + * a BHND-compatible bus (e.g. bcma or siba). + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include + +#include "bhndbvar.h" +#include "bhndb_bus_if.h" +#include "bhndb_hwdata.h" +#include "bhndb_private.h" + +/* Debugging flags */ +static u_long bhndb_debug = 0; +TUNABLE_ULONG("hw.bhndb.debug", &bhndb_debug); + +enum { + BHNDB_DEBUG_PRIO = 1 << 0, +}; + +#define BHNDB_DEBUG(_type) (BHNDB_DEBUG_ ## _type & bhndb_debug) + +static bool bhndb_hw_matches(device_t *devlist, + int num_devs, + const struct bhndb_hw *hw); + +static int bhndb_initialize_region_cfg( + struct bhndb_softc *sc, device_t *devs, + int ndevs, + const struct bhndb_hw_priority *table, + struct bhndb_resources *r); + +static int bhndb_find_hwspec(struct bhndb_softc *sc, + device_t *devs, int ndevs, + const struct bhndb_hw **hw); + +static int bhndb_read_chipid(struct bhndb_softc *sc, + const struct bhndb_hwcfg *cfg, + struct bhnd_chipid *result); + +static struct rman *bhndb_get_rman(struct bhndb_softc *sc, + int type); + +static int bhndb_init_child_resource(struct resource *r, + struct resource *parent, + bhnd_size_t offset, + bhnd_size_t size); + +static int bhndb_activate_static_region( + struct bhndb_softc *sc, + struct bhndb_region *region, + device_t child, int type, int rid, + struct resource *r); + +static int bhndb_try_activate_resource( + struct bhndb_softc *sc, device_t child, + int type, int rid, struct resource *r, + bool *indirect); + + +/** + * Default bhndb(4) implementation of DEVICE_PROBE(). + * + * This function provides the default bhndb implementation of DEVICE_PROBE(), + * and is compatible with bhndb(4) bridges attached via bhndb_attach_bridge(). + */ +int +bhndb_generic_probe(device_t dev) +{ + return (BUS_PROBE_NOWILDCARD); +} + +static void +bhndb_probe_nomatch(device_t dev, device_t child) +{ + const char *name; + + name = device_get_name(child); + if (name == NULL) + name = "unknown device"; + + device_printf(dev, "<%s> (no driver attached)\n", name); +} + +static int +bhndb_print_child(device_t dev, device_t child) +{ + struct bhndb_softc *sc; + struct resource_list *rl; + int retval = 0; + + sc = device_get_softc(dev); + + retval += bus_print_child_header(dev, child); + + rl = BUS_GET_RESOURCE_LIST(dev, child); + if (rl != NULL) { + retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, + "%#lx"); + retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, + "%ld"); + } + + retval += bus_print_child_domain(dev, child); + retval += bus_print_child_footer(dev, child); + + return (retval); +} + +static int +bhndb_child_pnpinfo_str(device_t bus, device_t child, char *buf, + size_t buflen) +{ + *buf = '\0'; + return (0); +} + +static int +bhndb_child_location_str(device_t dev, device_t child, char *buf, + size_t buflen) +{ + struct bhndb_softc *sc; + + sc = device_get_softc(dev); + + snprintf(buf, buflen, "base=0x%llx", + (unsigned long long) sc->chipid.enum_addr); + return (0); +} + +/** + * Return true if @p devlist matches the @p hw specification. + * + * @param devlist A device table to match against. + * @param num_devs The number of devices in @p devlist. + * @param hw The hardware description to be matched against. + */ +static bool +bhndb_hw_matches(device_t *devlist, int num_devs, const struct bhndb_hw *hw) +{ + for (u_int i = 0; i < hw->num_hw_reqs; i++) { + const struct bhnd_core_match *match; + bool found; + + match = &hw->hw_reqs[i]; + found = false; + + for (int d = 0; d < num_devs; d++) { + if (!bhnd_device_matches(devlist[d], match)) + continue; + + found = true; + break; + } + + if (!found) + return (false); + } + + return (true); +} + +/** + * Initialize the region maps and priority configuration in @p r using + * the provided priority @p table and the set of devices attached to + * the bridged @p bus_dev . + * + * @param sc The bhndb device state. + * @param devs All devices enumerated on the bridged bhnd bus. + * @param ndevs The length of @p devs. + * @param table Hardware priority table to be used to determine the relative + * priorities of per-core port resources. + * @param r The resource state to be configured. + */ +static int +bhndb_initialize_region_cfg(struct bhndb_softc *sc, device_t *devs, int ndevs, + const struct bhndb_hw_priority *table, struct bhndb_resources *r) +{ + const struct bhndb_hw_priority *hp; + bhnd_addr_t addr; + bhnd_size_t size; + size_t prio_low, prio_default, prio_high; + int error; + + /* The number of port regions per priority band that must be accessible + * via dynamic register windows */ + prio_low = 0; + prio_default = 0; + prio_high = 0; + + /* + * Register bridge regions covering all statically mapped ports. + */ + for (int i = 0; i < ndevs; i++) { + const struct bhndb_regwin *regw; + device_t child; + + child = devs[i]; + + for (regw = r->cfg->register_windows; + regw->win_type != BHNDB_REGWIN_T_INVALID; regw++) + { + /* Only core windows are supported */ + if (regw->win_type != BHNDB_REGWIN_T_CORE) + continue; + + /* Skip non-applicable register windows. */ + if (!bhndb_regwin_matches_device(regw, child)) + continue; + + /* Fetch the base address of the mapped port. */ + error = bhnd_get_region_addr(child, + regw->core.port_type, regw->core.port, + regw->core.region, &addr, &size); + if (error) + return (error); + + /* + * Always defer to the register window's size. + * + * If the port size is smaller than the window size, + * this ensures that we fully utilize register windows + * larger than the referenced port. + * + * If the port size is larger than the window size, this + * ensures that we do not directly map the allocations + * within the region to a too-small window. + */ + size = regw->win_size; + + /* + * Add to the bus region list. + * + * The window priority for a statically mapped + * region is always HIGH. + */ + error = bhndb_add_resource_region(r, addr, size, + BHNDB_PRIORITY_HIGH, regw); + if (error) + return (error); + } + } + + /* + * Perform priority accounting and register bridge regions for all + * ports defined in the priority table + */ + for (int i = 0; i < ndevs; i++) { + struct bhndb_region *region; + device_t child; + + child = devs[i]; + + /* + * Skip priority accounting for cores that ... + */ + + /* ... do not require bridge resources */ + if (bhnd_is_hw_disabled(child) || !device_is_enabled(child)) + continue; + + /* ... do not have a priority table entry */ + hp = bhndb_hw_priority_find_device(table, child); + if (hp == NULL) + continue; + + /* ... are explicitly disabled in the priority table. */ + if (hp->priority == BHNDB_PRIORITY_NONE) + continue; + + /* Determine the number of dynamic windows required and + * register their bus_region entries. */ + for (u_int i = 0; i < hp->num_ports; i++) { + const struct bhndb_port_priority *pp; + + pp = &hp->ports[i]; + + /* Skip ports not defined on this device */ + if (!bhnd_is_region_valid(child, pp->type, pp->port, + pp->region)) + { + continue; + } + + /* Fetch the address+size of the mapped port. */ + error = bhnd_get_region_addr(child, pp->type, pp->port, + pp->region, &addr, &size); + if (error) + return (error); + + /* Skip ports with an existing static mapping */ + region = bhndb_find_resource_region(r, addr, size); + if (region != NULL && region->static_regwin != NULL) + continue; + + /* Define a dynamic region for this port */ + error = bhndb_add_resource_region(r, addr, size, + pp->priority, NULL); + if (error) + return (error); + + /* Update port mapping counts */ + switch (pp->priority) { + case BHNDB_PRIORITY_NONE: + break; + case BHNDB_PRIORITY_LOW: + prio_low++; + break; + case BHNDB_PRIORITY_DEFAULT: + prio_default++; + break; + case BHNDB_PRIORITY_HIGH: + prio_high++; + break; + } + } + } + + /* Determine the minimum priority at which we'll allocate direct + * register windows from our dynamic pool */ + size_t prio_total = prio_low + prio_default + prio_high; + if (prio_total <= r->dwa_count) { + /* low+default+high priority regions get windows */ + r->min_prio = BHNDB_PRIORITY_LOW; + + } else if (prio_default + prio_high <= r->dwa_count) { + /* default+high priority regions get windows */ + r->min_prio = BHNDB_PRIORITY_DEFAULT; + + } else { + /* high priority regions get windows */ + r->min_prio = BHNDB_PRIORITY_HIGH; + } + + if (BHNDB_DEBUG(PRIO)) { + struct bhndb_region *region; + const char *direct_msg, *type_msg; + bhndb_priority_t prio, prio_min; + + prio_min = r->min_prio; + device_printf(sc->dev, "min_prio: %d\n", prio_min); + + STAILQ_FOREACH(region, &r->bus_regions, link) { + prio = region->priority; + + direct_msg = prio >= prio_min ? "direct" : "indirect"; + type_msg = region->static_regwin ? "static" : "dynamic"; + + device_printf(sc->dev, "region 0x%llx+0x%llx priority " + "%u %s/%s\n", + (unsigned long long) region->addr, + (unsigned long long) region->size, + region->priority, + direct_msg, type_msg); + } + } + + return (0); +} + +/** + * Find a hardware specification for @p dev. + * + * @param sc The bhndb device state. + * @param devs All devices enumerated on the bridged bhnd bus. + * @param ndevs The length of @p devs. + * @param[out] hw On success, the matched hardware specification. + * with @p dev. + * + * @retval 0 success + * @retval non-zero if an error occurs fetching device info for comparison. + */ +static int +bhndb_find_hwspec(struct bhndb_softc *sc, device_t *devs, int ndevs, + const struct bhndb_hw **hw) +{ + const struct bhndb_hw *next, *hw_table; + + /* Search for the first matching hardware config. */ + hw_table = BHNDB_BUS_GET_HARDWARE_TABLE(sc->parent_dev, sc->dev); + for (next = hw_table; next->hw_reqs != NULL; next++) { + if (!bhndb_hw_matches(devs, ndevs, next)) + continue; + + /* Found */ + *hw = next; + return (0); + } + + return (ENOENT); +} + +/** + * Read the ChipCommon identification data for this device. + * + * @param sc bhndb device state. + * @param cfg The hardware configuration to use when mapping the ChipCommon + * registers. + * @param[out] result the chip identification data. + * + * @retval 0 success + * @retval non-zero if the ChipCommon identification data could not be read. + */ +static int +bhndb_read_chipid(struct bhndb_softc *sc, const struct bhndb_hwcfg *cfg, + struct bhnd_chipid *result) +{ + const struct bhnd_chipid *parent_cid; + const struct bhndb_regwin *cc_win; + struct resource_spec rs; + int error; + + /* Let our parent device override the discovery process */ + parent_cid = BHNDB_BUS_GET_CHIPID(sc->parent_dev, sc->dev); + if (parent_cid != NULL) { + *result = *parent_cid; + return (0); + } + + /* Find a register window we can use to map the first CHIPC_CHIPID_SIZE + * of ChipCommon registers. */ + cc_win = bhndb_regwin_find_best(cfg->register_windows, + BHND_DEVCLASS_CC, 0, BHND_PORT_DEVICE, 0, 0, CHIPC_CHIPID_SIZE); + if (cc_win == NULL) { + device_printf(sc->dev, "no chipcommon register window\n"); + return (0); + } + + /* We can assume a device without a static ChipCommon window uses the + * default ChipCommon address. */ + if (cc_win->win_type == BHNDB_REGWIN_T_DYN) { + error = BHNDB_SET_WINDOW_ADDR(sc->dev, cc_win, + BHND_DEFAULT_CHIPC_ADDR); + + if (error) { + device_printf(sc->dev, "failed to set chipcommon " + "register window\n"); + return (error); + } + } + + /* Let the default bhnd implemenation alloc/release the resource and + * perform the read */ + rs.type = cc_win->res.type; + rs.rid = cc_win->res.rid; + rs.flags = RF_ACTIVE; + + return (bhnd_read_chipid(sc->parent_dev, &rs, cc_win->win_offset, + result)); +} + +/** + * Helper function that must be called by subclass bhndb(4) drivers + * when implementing DEVICE_ATTACH() before calling any bhnd(4) or bhndb(4) + * APIs on the bridge device. + * + * @param dev The bridge device to attach. + * @param bridge_devclass The device class of the bridging core. This is used + * to automatically detect the bridge core, and to disable additional bridge + * cores (e.g. PCMCIA on a PCIe device). + */ +int +bhndb_attach(device_t dev, bhnd_devclass_t bridge_devclass) +{ + struct bhndb_softc *sc; + const struct bhndb_hwcfg *cfg; + int error; + + sc = device_get_softc(dev); + sc->dev = dev; + sc->parent_dev = device_get_parent(dev); + sc->bridge_class = bridge_devclass; + + BHNDB_LOCK_INIT(sc); + + /* Read our chip identification data */ + cfg = BHNDB_BUS_GET_GENERIC_HWCFG(sc->parent_dev, sc->dev); + if ((error = bhndb_read_chipid(sc, cfg, &sc->chipid))) + return (error); + + /* Set up a resource manager for the device's address space. */ + sc->mem_rman.rm_start = 0; + sc->mem_rman.rm_end = BUS_SPACE_MAXADDR_32BIT; + sc->mem_rman.rm_type = RMAN_ARRAY; + sc->mem_rman.rm_descr = "BHND I/O memory addresses"; + + if ((error = rman_init(&sc->mem_rman))) { + device_printf(dev, "could not initialize mem_rman\n"); + return (error); + } + + error = rman_manage_region(&sc->mem_rman, 0, BUS_SPACE_MAXADDR_32BIT); + if (error) { + device_printf(dev, "could not configure mem_rman\n"); + goto failed; + } + + /* Initialize basic resource allocation state. */ + sc->bus_res = bhndb_alloc_resources(dev, sc->parent_dev, cfg); + if (sc->bus_res == NULL) { + error = ENXIO; + goto failed; + } + + /* Attach our bridged bus device */ + sc->bus_dev = device_add_child(dev, devclass_get_name(bhnd_devclass), + -1); + if (sc->bus_dev == NULL) { + error = ENXIO; + goto failed; + } + + return (bus_generic_attach(dev)); + +failed: + BHNDB_LOCK_DESTROY(sc); + + rman_fini(&sc->mem_rman); + + if (sc->bus_res != NULL) + bhndb_free_resources(sc->bus_res); + + return (error); +} + +/** + * Default bhndb(4) implementation of BHNDB_INIT_FULL_CONFIG(). + * + * This function provides the default bhndb implementation of + * BHNDB_INIT_FULL_CONFIG(), and must be called by any subclass driver + * overriding BHNDB_INIT_FULL_CONFIG(). + * + * As documented by BHNDB_INIT_FULL_CONFIG, this function performs final + * bridge configuration based on the hardware information enumerated by the + * child bus, and will reset all resource allocation state on the bridge. + * + * When calling this method: + * - Any bus resources previously allocated by @p child must be deallocated. + * - The @p child bus must have performed initial enumeration -- but not + * probe or attachment -- of its children. + */ +int +bhndb_generic_init_full_config(device_t dev, device_t child, + const struct bhndb_hw_priority *hw_prio_table) +{ + struct bhndb_softc *sc; + const struct bhndb_hw *hw; + struct bhndb_resources *r; + device_t *devs; + device_t hostb; + int ndevs; + int error; + + sc = device_get_softc(dev); + hostb = NULL; + + /* Fetch the full set of attached devices */ + if ((error = device_get_children(sc->bus_dev, &devs, &ndevs))) + return (error); + + /* Find our host bridge device */ + for (int i = 0; i < ndevs; i++) { + if (bhnd_is_hostb_device(devs[i])) { + hostb = devs[i]; + break; + } + } + + if (hostb == NULL) { + device_printf(sc->dev, "no host bridge core found\n"); + error = ENODEV; + goto cleanup; + } + + /* Find our full register window configuration */ + if ((error = bhndb_find_hwspec(sc, devs, ndevs, &hw))) { + device_printf(sc->dev, "unable to identify device, " + " using generic bridge resource definitions\n"); + error = 0; + goto cleanup; + } + + if (bootverbose) + device_printf(sc->dev, "%s resource configuration\n", hw->name); + + /* Release existing resource state */ + BHNDB_LOCK(sc); + bhndb_free_resources(sc->bus_res); + sc->bus_res = NULL; + BHNDB_UNLOCK(sc); + + /* Allocate new resource state */ + r = bhndb_alloc_resources(dev, sc->parent_dev, hw->cfg); + if (r == NULL) { + error = ENXIO; + goto cleanup; + } + + /* Initialize our resource priority configuration */ + error = bhndb_initialize_region_cfg(sc, devs, ndevs, hw_prio_table, r); + if (error) { + bhndb_free_resources(r); + goto cleanup; + } + + /* Update our bridge state */ + BHNDB_LOCK(sc); + sc->bus_res = r; + sc->hostb_dev = hostb; + BHNDB_UNLOCK(sc); + +cleanup: + free(devs, M_TEMP); + return (error); +} + +/** + * Default bhndb(4) implementation of DEVICE_DETACH(). + * + * This function detaches any child devices, and if successful, releases all + * resources held by the bridge device. + */ +int +bhndb_generic_detach(device_t dev) +{ + struct bhndb_softc *sc; + int error; + + sc = device_get_softc(dev); + + /* Detach children */ + if ((error = bus_generic_detach(dev))) + return (error); + + /* Clean up our driver state. */ + rman_fini(&sc->mem_rman); + bhndb_free_resources(sc->bus_res); + + BHNDB_LOCK_DESTROY(sc); + + return (0); +} + +/** + * Default bhndb(4) implementation of DEVICE_SUSPEND(). + * + * This function calls bus_generic_suspend() (or implements equivalent + * behavior). + */ +int +bhndb_generic_suspend(device_t dev) +{ + return (bus_generic_suspend(dev)); +} + +/** + * Default bhndb(4) implementation of DEVICE_RESUME(). + * + * This function calls bus_generic_resume() (or implements equivalent + * behavior). + */ +int +bhndb_generic_resume(device_t dev) +{ + struct bhndb_softc *sc; + struct bhndb_resources *bus_res; + struct bhndb_dw_alloc *dwa; + int error; + + sc = device_get_softc(dev); + bus_res = sc->bus_res; + + /* Guarantee that all in-use dynamic register windows are mapped to + * their previously configured target address. */ + BHNDB_LOCK(sc); + for (size_t i = 0; i < bus_res->dwa_count; i++) { + dwa = &bus_res->dw_alloc[i]; + + /* Skip regions that were not previously used */ + if (bhndb_dw_is_free(bus_res, dwa) && dwa->target == 0x0) + continue; + + /* Otherwise, ensure the register window is correct before + * any children attempt MMIO */ + error = BHNDB_SET_WINDOW_ADDR(dev, dwa->win, dwa->target); + if (error) + break; + } + BHNDB_UNLOCK(sc); + + /* Error restoring hardware state; children cannot be safely resumed */ + if (error) { + device_printf(dev, "Unable to restore hardware configuration; " + "cannot resume: %d\n", error); + return (error); + } + + return (bus_generic_resume(dev)); +} + +/** + * Default implementation of BHNDB_SUSPEND_RESOURCE. + */ +static void +bhndb_suspend_resource(device_t dev, device_t child, int type, + struct resource *r) +{ + struct bhndb_softc *sc; + struct bhndb_dw_alloc *dwa; + + sc = device_get_softc(dev); + + // TODO: IRQs? + if (type != SYS_RES_MEMORY) + return; + + BHNDB_LOCK(sc); + dwa = bhndb_dw_find_resource(sc->bus_res, r); + if (dwa == NULL) { + BHNDB_UNLOCK(sc); + return; + } + + if (BHNDB_DEBUG(PRIO)) + device_printf(child, "suspend resource type=%d 0x%lx+0x%lx\n", + type, rman_get_start(r), rman_get_size(r)); + + /* Release the resource's window reference */ + bhndb_dw_release(sc->bus_res, dwa, r); + BHNDB_UNLOCK(sc); +} + +/** + * Default implementation of BHNDB_RESUME_RESOURCE. + */ +static int +bhndb_resume_resource(device_t dev, device_t child, int type, + struct resource *r) +{ + struct bhndb_softc *sc; + + sc = device_get_softc(dev); + + // TODO: IRQs? + if (type != SYS_RES_MEMORY) + return (0); + + /* Inactive resources don't require reallocation of bridge resources */ + if (!(rman_get_flags(r) & RF_ACTIVE)) + return (0); + + if (BHNDB_DEBUG(PRIO)) + device_printf(child, "resume resource type=%d 0x%lx+0x%lx\n", + type, rman_get_start(r), rman_get_size(r)); + + return (bhndb_try_activate_resource(sc, rman_get_device(r), type, + rman_get_rid(r), r, NULL)); +} + + +/** + * Default bhndb(4) implementation of BUS_READ_IVAR(). + */ +static int +bhndb_read_ivar(device_t dev, device_t child, int index, + uintptr_t *result) +{ + return (ENOENT); +} + +/** + * Default bhndb(4) implementation of BUS_WRITE_IVAR(). + */ +static int +bhndb_write_ivar(device_t dev, device_t child, int index, + uintptr_t value) +{ + return (ENOENT); +} + +/** + * Return the rman instance for a given resource @p type, if any. + * + * @param sc The bhndb device state. + * @param type The resource type (e.g. SYS_RES_MEMORY, SYS_RES_IRQ, ...) + */ +static struct rman * +bhndb_get_rman(struct bhndb_softc *sc, int type) +{ + switch (type) { + case SYS_RES_MEMORY: + return &sc->mem_rman; + case SYS_RES_IRQ: + // TODO + // return &sc->irq_rman; + return (NULL); + default: + return (NULL); + }; +} + +/** + * Default implementation of BUS_ADD_CHILD() + */ +static device_t +bhndb_add_child(device_t dev, u_int order, const char *name, int unit) +{ + struct bhndb_devinfo *dinfo; + device_t child; + + child = device_add_child_ordered(dev, order, name, unit); + if (child == NULL) + return (NULL); + + dinfo = malloc(sizeof(struct bhndb_devinfo), M_BHND, M_NOWAIT); + if (dinfo == NULL) { + device_delete_child(dev, child); + return (NULL); + } + + resource_list_init(&dinfo->resources); + + device_set_ivars(child, dinfo); + + return (child); +} + +/** + * Default implementation of BUS_CHILD_DELETED(). + */ +static void +bhndb_child_deleted(device_t dev, device_t child) +{ + struct bhndb_devinfo *dinfo = device_get_ivars(child); + if (dinfo != NULL) { + resource_list_free(&dinfo->resources); + free(dinfo, M_BHND); + } + + device_set_ivars(child, NULL); +} + +/** + * Default implementation of BHNDB_GET_CHIPID(). + */ +static const struct bhnd_chipid * +bhndb_get_chipid(device_t dev, device_t child) +{ + struct bhndb_softc *sc = device_get_softc(dev); + return (&sc->chipid); +} + + +/** + * Default implementation of BHNDB_IS_HW_DISABLED(). + */ +static bool +bhndb_is_hw_disabled(device_t dev, device_t child) { + struct bhndb_softc *sc; + struct bhnd_core_info core; + + sc = device_get_softc(dev); + + /* Requestor must be attached to the bhnd bus */ + if (device_get_parent(child) != sc->bus_dev) { + return (BHND_BUS_IS_HW_DISABLED(device_get_parent(dev), child)); + } + + /* Fetch core info */ + core = bhnd_get_core_info(child); + + /* Try to defer to the bhndb bus parent */ + if (BHNDB_BUS_IS_CORE_DISABLED(sc->parent_dev, dev, &core)) + return (true); + + /* Otherwise, we treat bridge-capable cores as unpopulated if they're + * not the configured host bridge */ + if (BHND_DEVCLASS_SUPPORTS_HOSTB(bhnd_core_class(&core))) + return (!BHND_BUS_IS_HOSTB_DEVICE(dev, child)); + + /* Otherwise, assume the core is populated */ + return (false); +} + +/* ascending core index comparison used by bhndb_is_hostb_device() */ +static int +compare_core_index(const void *lhs, const void *rhs) +{ + u_int left = bhnd_get_core_index(*(const device_t *) lhs); + u_int right = bhnd_get_core_index(*(const device_t *) rhs); + + if (left < right) + return (-1); + else if (left > right) + return (1); + else + return (0); +} + +/** + * Default bhndb(4) implementation of BHND_BUS_IS_HOSTB_DEVICE(). + * + * This function uses a heuristic valid on all known PCI/PCIe/PCMCIA-bridged + * bhnd(4) devices to determine the hostb core: + * + * - The core must have a Broadcom vendor ID. + * - The core devclass must match the bridge type. + * - The core must be the first device on the bus with the bridged device + * class. + * + * @param sc The bridge device state. + * @param cores The table of bridge-enumerated cores. + * @param num_cores The length of @p cores. + * @param core The core to check. + */ +static bool +bhndb_is_hostb_device(device_t dev, device_t child) +{ + struct bhndb_softc *sc; + struct bhnd_core_match md; + device_t hostb_dev, *devlist; + int devcnt, error; + + + sc = device_get_softc(dev); + + /* Requestor must be attached to the bhnd bus */ + if (device_get_parent(child) != sc->bus_dev) + return (BHND_BUS_IS_HOSTB_DEVICE(device_get_parent(dev), + child)); + + /* Determine required device class and set up a match descriptor. */ + md = (struct bhnd_core_match) { + .vendor = BHND_MFGID_BCM, + .device = BHND_COREID_INVALID, + .hwrev = { BHND_HWREV_INVALID, BHND_HWREV_INVALID }, + .class = sc->bridge_class, + .unit = 0 + }; + + /* Pre-screen the device before searching over the full device list. */ + if (!bhnd_device_matches(child, &md)) + return (false); + + /* Must be the absolute first matching device on the bus. */ + if ((error = device_get_children(sc->bus_dev, &devlist, &devcnt))) + return (false); + + /* Sort by core index value, ascending */ + qsort(devlist, devcnt, sizeof(*devlist), compare_core_index); + + /* Find the actual hostb device */ + hostb_dev = NULL; + for (int i = 0; i < devcnt; i++) { + if (bhnd_device_matches(devlist[i], &md)) { + hostb_dev = devlist[i]; + break; + } + } + + /* Clean up */ + free(devlist, M_TEMP); + + return (child == hostb_dev); +} + +/** + * Default bhndb(4) implementation of BUS_ALLOC_RESOURCE(). + */ +static struct resource * +bhndb_alloc_resource(device_t dev, device_t child, int type, + int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) +{ + struct bhndb_softc *sc; + struct resource_list_entry *rle; + struct resource *rv; + struct rman *rm; + int error; + bool immed_child, defaults; + + sc = device_get_softc(dev); + immed_child = (device_get_parent(child) == dev); + defaults = (start == 0UL && end == ~0UL); + rle = NULL; + + /* Populate defaults */ + if (immed_child && defaults) { + /* Fetch the resource list entry. */ + rle = resource_list_find(BUS_GET_RESOURCE_LIST(dev, child), + type, *rid); + if (rle == NULL) { + device_printf(dev, + "default resource %#x type %d for child %s " + "not found\n", *rid, type, + device_get_nameunit(child)); + + return (NULL); + } + + if (rle->res != NULL) { + device_printf(dev, + "resource entry %#x type %d for child %s is busy\n", + *rid, type, device_get_nameunit(child)); + + return (NULL); + } + + start = rle->start; + end = rle->end; + count = ulmax(count, rle->count); + } + + /* Validate resource addresses */ + if (start > end || end < start || count > ((end - start) + 1)) + return (NULL); + + /* Fetch the resource manager */ + rm = bhndb_get_rman(sc, type); + if (rm == NULL) + return (NULL); + + /* Make our reservation */ + rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE, + child); + if (rv == NULL) + return (NULL); + + rman_set_rid(rv, *rid); + + /* Activate */ + if (flags & RF_ACTIVE) { + error = bus_activate_resource(child, type, *rid, rv); + if (error) { + device_printf(dev, + "failed to activate entry %#x type %d for " + "child %s\n", + *rid, type, device_get_nameunit(child)); + + rman_release_resource(rv); + + return (NULL); + } + } + + /* Update child's resource list entry */ + if (rle != NULL) { + rle->res = rv; + rle->start = rman_get_start(rv); + rle->end = rman_get_end(rv); + rle->count = rman_get_size(rv); + } + + return (rv); +} + +/** + * Default bhndb(4) implementation of BUS_RELEASE_RESOURCE(). + */ +static int +bhndb_release_resource(device_t dev, device_t child, int type, int rid, + struct resource *r) +{ + int error; + + /* Deactivate resources */ + if (rman_get_flags(r) & RF_ACTIVE) { + error = BUS_DEACTIVATE_RESOURCE(dev, child, type, rid, r); + if (error) + return (error); + } + + if ((error = rman_release_resource(r))) + return (error); + + return (0); +} + +/** + * Default bhndb(4) implementation of BUS_ADJUST_RESOURCE(). + */ +static int +bhndb_adjust_resource(device_t dev, device_t child, int type, + struct resource *r, rman_res_t start, rman_res_t end) +{ + struct bhndb_softc *sc; + struct rman *rm; + int error; + + sc = device_get_softc(dev); + error = 0; + + /* Fetch resource manager */ + rm = bhndb_get_rman(sc, type); + if (rm == NULL) + return (ENXIO); + + if (!rman_is_region_manager(r, rm)) + return (ENXIO); + + /* If active, adjustment is limited by the assigned window. */ + BHNDB_LOCK(sc); + + // TODO: Currently unsupported + error = ENODEV; + + BHNDB_UNLOCK(sc); + if (!error) + error = rman_adjust_resource(r, start, end); + + return (error); +} + +/** + * Initialize child resource @p r with a virtual address, tag, and handle + * copied from @p parent, adjusted to contain only the range defined by @p win. + * + * @param r The register to be initialized. + * @param parent The parent bus resource that fully contains the subregion. + * @param offset The subregion offset within @p parent. + * @param size The subregion size. + * @p r. + */ +static int +bhndb_init_child_resource(struct resource *r, + struct resource *parent, bhnd_size_t offset, bhnd_size_t size) +{ + + bus_space_handle_t bh, child_bh; + bus_space_tag_t bt; + uintptr_t vaddr; + int error; + + /* Fetch the parent resource's real bus values */ + vaddr = (uintptr_t) rman_get_virtual(parent); + bt = rman_get_bustag(parent); + bh = rman_get_bushandle(parent); + + /* Configure child resource with window-adjusted real bus values */ + vaddr += offset; + error = bus_space_subregion(bt, bh, offset, size, &child_bh); + if (error) + return (error); + + rman_set_virtual(r, (void *) vaddr); + rman_set_bustag(r, bt); + rman_set_bushandle(r, child_bh); + + return (0); +} + +/** + * Attempt activation of a fixed register window mapping for @p child. + * + * @param sc BHNDB device state. + * @param region The static region definition capable of mapping @p r. + * @param child A child requesting resource activation. + * @param type Resource type. + * @param rid Resource identifier. + * @param r Resource to be activated. + * + * @retval 0 if @p r was activated successfully + * @retval ENOENT if no fixed register window was found. + * @retval non-zero if @p r could not be activated. + */ +static int +bhndb_activate_static_region(struct bhndb_softc *sc, + struct bhndb_region *region, device_t child, int type, int rid, + struct resource *r) +{ + struct resource *bridge_res; + const struct bhndb_regwin *win; + bhnd_size_t parent_offset; + rman_res_t r_start, r_size; + int error; + + win = region->static_regwin; + + KASSERT(win != NULL && BHNDB_REGWIN_T_IS_STATIC(win->win_type), + ("can't activate non-static region")); + + r_start = rman_get_start(r); + r_size = rman_get_size(r); + + /* Find the corresponding bridge resource */ + bridge_res = bhndb_find_regwin_resource(sc->bus_res, win); + if (bridge_res == NULL) + return (ENXIO); + + /* Calculate subregion offset within the parent resource */ + parent_offset = r_start - region->addr; + parent_offset += win->win_offset; + + /* Configure resource with its real bus values. */ + error = bhndb_init_child_resource(r, bridge_res, parent_offset, r_size); + if (error) + return (error); + + /* Mark active */ + if ((error = rman_activate_resource(r))) + return (error); + + return (0); +} + +/** + * Attempt to allocate/retain a dynamic register window for @p r, returning + * the retained window. + * + * @param sc The bhndb driver state. + * @param r The resource for which a window will be retained. + */ +static struct bhndb_dw_alloc * +bhndb_retain_dynamic_window(struct bhndb_softc *sc, struct resource *r) +{ + struct bhndb_dw_alloc *dwa; + rman_res_t r_start, r_size; + int error; + + BHNDB_LOCK_ASSERT(sc, MA_OWNED); + + r_start = rman_get_start(r); + r_size = rman_get_size(r); + + /* Look for an existing dynamic window we can reference */ + dwa = bhndb_dw_find_mapping(sc->bus_res, r_start, r_size); + if (dwa != NULL) { + if (bhndb_dw_retain(sc->bus_res, dwa, r) == 0) + return (dwa); + + return (NULL); + } + + /* Otherwise, try to reserve a free window */ + dwa = bhndb_dw_next_free(sc->bus_res); + if (dwa == NULL) { + /* No free windows */ + return (NULL); + } + + /* Set the window target */ + error = bhndb_dw_set_addr(sc->dev, sc->bus_res, dwa, rman_get_start(r), + rman_get_size(r)); + if (error) { + device_printf(sc->dev, "dynamic window initialization " + "for 0x%llx-0x%llx failed\n", + (unsigned long long) r_start, + (unsigned long long) r_start + r_size - 1); + return (NULL); + } + + /* Add our reservation */ + if (bhndb_dw_retain(sc->bus_res, dwa, r)) + return (NULL); + + return (dwa); +} + +/** + * Activate a resource using any viable static or dynamic register window. + * + * @param sc The bhndb driver state. + * @param child The child holding ownership of @p r. + * @param type The type of the resource to be activated. + * @param rid The resource ID of @p r. + * @param r The resource to be activated + * @param[out] indirect On error and if not NULL, will be set to 'true' if + * the caller should instead use an indirect resource mapping. + * + * @retval 0 success + * @retval non-zero activation failed. + */ +static int +bhndb_try_activate_resource(struct bhndb_softc *sc, device_t child, int type, + int rid, struct resource *r, bool *indirect) +{ + struct bhndb_region *region; + struct bhndb_dw_alloc *dwa; + bhndb_priority_t dw_priority; + rman_res_t r_start, r_size; + rman_res_t parent_offset; + int error; + + BHNDB_LOCK_ASSERT(sc, MA_NOTOWNED); + + // TODO - IRQs + if (type != SYS_RES_MEMORY) + return (ENXIO); + + if (indirect) + *indirect = false; + + /* Default to low priority */ + dw_priority = BHNDB_PRIORITY_LOW; + + /* Look for a bus region matching the resource's address range */ + r_start = rman_get_start(r); + r_size = rman_get_size(r); + region = bhndb_find_resource_region(sc->bus_res, r_start, r_size); + if (region != NULL) + dw_priority = region->priority; + + /* Prefer static mappings over consuming a dynamic windows. */ + if (region && region->static_regwin) { + error = bhndb_activate_static_region(sc, region, child, type, + rid, r); + if (error) + device_printf(sc->dev, "static window allocation " + "for 0x%llx-0x%llx failed\n", + (unsigned long long) r_start, + (unsigned long long) r_start + r_size - 1); + return (error); + } + + /* A dynamic window will be required; is this resource high enough + * priority to be reserved a dynamic window? */ + if (dw_priority < sc->bus_res->min_prio) { + if (indirect) + *indirect = true; + + return (ENOMEM); + } + + /* Find and retain a usable window */ + BHNDB_LOCK(sc); { + dwa = bhndb_retain_dynamic_window(sc, r); + } BHNDB_UNLOCK(sc); + + if (dwa == NULL) { + if (indirect) + *indirect = true; + return (ENOMEM); + } + + /* Configure resource with its real bus values. */ + parent_offset = dwa->win->win_offset; + parent_offset += r_start - dwa->target; + + error = bhndb_init_child_resource(r, dwa->parent_res, parent_offset, + dwa->win->win_size); + if (error) + goto failed; + + /* Mark active */ + if ((error = rman_activate_resource(r))) + goto failed; + + return (0); + +failed: + /* Release our region allocation. */ + BHNDB_LOCK(sc); + bhndb_dw_release(sc->bus_res, dwa, r); + BHNDB_UNLOCK(sc); + + return (error); +} + +/** + * Default bhndb(4) implementation of BUS_ACTIVATE_RESOURCE(). + * + * Maps resource activation requests to a viable static or dynamic + * register window, if any. + */ +static int +bhndb_activate_resource(device_t dev, device_t child, int type, int rid, + struct resource *r) +{ + struct bhndb_softc *sc = device_get_softc(dev); + + return (bhndb_try_activate_resource(sc, child, type, rid, r, NULL)); +} + +/** + * Default bhndb(4) implementation of BUS_DEACTIVATE_RESOURCE(). + */ +static int +bhndb_deactivate_resource(device_t dev, device_t child, int type, + int rid, struct resource *r) +{ + struct bhndb_dw_alloc *dwa; + struct bhndb_softc *sc; + struct rman *rm; + int error; + + sc = device_get_softc(dev); + + if ((rm = bhndb_get_rman(sc, type)) == NULL) + return (EINVAL); + + /* Mark inactive */ + if ((error = rman_deactivate_resource(r))) + return (error); + + /* Free any dynamic window allocation. */ + BHNDB_LOCK(sc); + dwa = bhndb_dw_find_resource(sc->bus_res, r); + if (dwa != NULL) + bhndb_dw_release(sc->bus_res, dwa, r); + BHNDB_UNLOCK(sc); + + return (0); +} + +/** + * Default bhndb(4) implementation of BUS_GET_RESOURCE_LIST(). + */ +static struct resource_list * +bhndb_get_resource_list(device_t dev, device_t child) +{ + struct bhndb_devinfo *dinfo = device_get_ivars(child); + return (&dinfo->resources); +} + +/** + * Default bhndb(4) implementation of BHND_BUS_ALLOC_RESOURCE(). + */ +static struct bhnd_resource * +bhndb_alloc_bhnd_resource(device_t dev, device_t child, int type, + int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) +{ + struct bhndb_softc *sc; + struct bhnd_resource *br; + + sc = device_get_softc(dev); + + /* Allocate resource wrapper */ + br = malloc(sizeof(struct bhnd_resource), M_BHND, M_NOWAIT|M_ZERO); + if (br == NULL) + return (NULL); + + /* Configure */ + br->direct = false; + br->res = bus_alloc_resource(child, type, rid, start, end, count, + flags & ~RF_ACTIVE); + if (br->res == NULL) + goto failed; + + + if (flags & RF_ACTIVE) { + if (bhnd_activate_resource(child, type, *rid, br)) + goto failed; + } + + return (br); + +failed: + if (br->res != NULL) + bus_release_resource(child, type, *rid, br->res); + + free(br, M_BHND); + return (NULL); +} + +/** + * Default bhndb(4) implementation of BHND_BUS_RELEASE_RESOURCE(). + */ +static int +bhndb_release_bhnd_resource(device_t dev, device_t child, + int type, int rid, struct bhnd_resource *r) +{ + int error; + + if ((error = bus_release_resource(child, type, rid, r->res))) + return (error); + + free(r, M_BHND); + return (0); +} + +/** + * Default bhndb(4) implementation of BHND_BUS_ACTIVATE_RESOURCE(). + * + * Attempts to activate a static register window, a dynamic register window, + * or configures @p r as an indirect resource -- in that order. + */ +static int +bhndb_activate_bhnd_resource(device_t dev, device_t child, + int type, int rid, struct bhnd_resource *r) +{ + struct bhndb_softc *sc; + struct bhndb_region *region; + bhndb_priority_t r_prio; + rman_res_t r_start, r_size; + int error; + bool indirect; + + KASSERT(!r->direct, + ("direct flag set on inactive resource")); + + KASSERT(!(rman_get_flags(r->res) & RF_ACTIVE), + ("RF_ACTIVE set on inactive resource")); + + sc = device_get_softc(dev); + + /* Fetch the address range's resource priority */ + r_start = rman_get_start(r->res); + r_size = rman_get_size(r->res); + r_prio = BHNDB_PRIORITY_NONE; + + region = bhndb_find_resource_region(sc->bus_res, r_start, r_size); + if (region != NULL) + r_prio = region->priority; + + /* If less than the minimum dynamic window priority, this + * resource should always be indirect. */ + if (r_prio < sc->bus_res->min_prio) + return (0); + + /* Attempt direct activation */ + error = bhndb_try_activate_resource(sc, child, type, rid, r->res, + &indirect); + if (!error) { + r->direct = true; + } else if (indirect) { + /* The request was valid, but no viable register window is + * available; indirection must be employed. */ + error = 0; + r->direct = false; + } + + if (BHNDB_DEBUG(PRIO)) { + device_printf(child, "activated 0x%llx-0x%llx as %s " + "resource\n", + (unsigned long long) r_start, + (unsigned long long) r_start + r_size - 1, + r->direct ? "direct" : "indirect"); + } + + return (error); +}; + +/** + * Default bhndb(4) implementation of BHND_BUS_DEACTIVATE_RESOURCE(). + */ +static int +bhndb_deactivate_bhnd_resource(device_t dev, device_t child, + int type, int rid, struct bhnd_resource *r) +{ + int error; + + /* Indirect resources don't require activation */ + if (!r->direct) + return (0); + + KASSERT(rman_get_flags(r->res) & RF_ACTIVE, + ("RF_ACTIVE not set on direct resource")); + + /* Perform deactivation */ + error = bus_deactivate_resource(child, type, rid, r->res); + if (!error) + r->direct = false; + + return (error); +}; + +/** + * Slow path for bhndb_io_resource(). + * + * Iterates over the existing allocated dynamic windows looking for a viable + * in-use region; the first matching region is returned. + */ +static struct bhndb_dw_alloc * +bhndb_io_resource_slow(struct bhndb_softc *sc, bus_addr_t addr, + bus_size_t size, bus_size_t *offset) +{ + struct bhndb_resources *br; + struct bhndb_dw_alloc *dwa; + + BHNDB_LOCK_ASSERT(sc, MA_OWNED); + + br = sc->bus_res; + + /* Search for an existing dynamic mapping of this address range. + * Static regions are not searched, as a statically mapped + * region would never be allocated as an indirect resource. */ + for (size_t i = 0; i < br->dwa_count; i++) { + const struct bhndb_regwin *win; + + dwa = &br->dw_alloc[i]; + win = dwa->win; + + KASSERT(win->win_type == BHNDB_REGWIN_T_DYN, + ("invalid register window type")); + + /* Verify the range */ + if (addr < dwa->target) + continue; + + if (addr + size > dwa->target + win->win_size) + continue; + + /* Found */ + *offset = dwa->win->win_offset; + *offset += addr - dwa->target; + + return (dwa); + } + + /* not found */ + return (NULL); +} + +/** + * Find the bridge resource to be used for I/O requests. + * + * @param sc Bridge driver state. + * @param addr The I/O target address. + * @param size The size of the I/O operation to be performed at @p addr. + * @param[out] offset The offset within the returned resource at which + * to perform the I/O request. + */ +static inline struct bhndb_dw_alloc * +bhndb_io_resource(struct bhndb_softc *sc, bus_addr_t addr, bus_size_t size, + bus_size_t *offset) +{ + struct bhndb_resources *br; + struct bhndb_dw_alloc *dwa; + int error; + + BHNDB_LOCK_ASSERT(sc, MA_OWNED); + + br = sc->bus_res; + + /* Try to fetch a free window */ + dwa = bhndb_dw_next_free(br); + + /* + * If no dynamic windows are available, look for an existing + * region that maps the target range. + * + * If none are found, this is a child driver bug -- our window + * over-commit should only fail in the case where a child driver leaks + * resources, or perform operations out-of-order. + * + * Broadcom HND chipsets are designed to not require register window + * swapping during execution; as long as the child devices are + * attached/detached correctly, using the hardware's required order + * of operations, there should always be a window available for the + * current operation. + */ + if (dwa == NULL) { + dwa = bhndb_io_resource_slow(sc, addr, size, offset); + if (dwa == NULL) { + panic("register windows exhausted attempting to map " + "0x%llx-0x%llx\n", + (unsigned long long) addr, + (unsigned long long) addr+size-1); + } + + return (dwa); + } + + /* Adjust the window if the I/O request won't fit in the current + * target range. */ + if (addr < dwa->target || + (dwa->target + dwa->win->win_size) - addr < size) + { + error = bhndb_dw_set_addr(sc->dev, sc->bus_res, dwa, addr, + size); + if (error) { + panic("failed to set register window target mapping " + "0x%llx-0x%llx\n", + (unsigned long long) addr, + (unsigned long long) addr+size-1); + } + } + + /* Calculate the offset and return */ + *offset = (addr - dwa->target) + dwa->win->win_offset; + return (dwa); +} + +/* + * BHND_BUS_(READ|WRITE_* implementations + */ + +/* bhndb_bus_(read|write) common implementation */ +#define BHNDB_IO_COMMON_SETUP(_io_size) \ + struct bhndb_softc *sc; \ + struct bhndb_dw_alloc *dwa; \ + struct resource *io_res; \ + bus_size_t io_offset; \ + \ + sc = device_get_softc(dev); \ + \ + BHNDB_LOCK(sc); \ + dwa = bhndb_io_resource(sc, rman_get_start(r->res) + \ + offset, _io_size, &io_offset); \ + io_res = dwa->parent_res; \ + \ + KASSERT(!r->direct, \ + ("bhnd_bus slow path used for direct resource")); \ + \ + KASSERT(rman_get_flags(io_res) & RF_ACTIVE, \ + ("i/o resource is not active")); + +#define BHNDB_IO_COMMON_TEARDOWN() \ + BHNDB_UNLOCK(sc); + +/* Defines a bhndb_bus_read_* method implementation */ +#define BHNDB_IO_READ(_type, _size) \ +static _type \ +bhndb_bus_read_ ## _size (device_t dev, device_t child, \ + struct bhnd_resource *r, bus_size_t offset) \ +{ \ + _type v; \ + BHNDB_IO_COMMON_SETUP(sizeof(_type)); \ + v = bus_read_ ## _size (io_res, io_offset); \ + BHNDB_IO_COMMON_TEARDOWN(); \ + \ + return (v); \ +} + +/* Defines a bhndb_bus_write_* method implementation */ +#define BHNDB_IO_WRITE(_type, _size) \ +static void \ +bhndb_bus_write_ ## _size (device_t dev, device_t child, \ + struct bhnd_resource *r, bus_size_t offset, _type value) \ +{ \ + BHNDB_IO_COMMON_SETUP(sizeof(_type)); \ + bus_write_ ## _size (io_res, io_offset, value); \ + BHNDB_IO_COMMON_TEARDOWN(); \ +} + +BHNDB_IO_READ(uint8_t, 1); +BHNDB_IO_READ(uint16_t, 2); +BHNDB_IO_READ(uint32_t, 4); + +BHNDB_IO_WRITE(uint8_t, 1); +BHNDB_IO_WRITE(uint16_t, 2); +BHNDB_IO_WRITE(uint32_t, 4); + +/** + * Default bhndb(4) implementation of BHND_BUS_BARRIER(). + */ +static void +bhndb_bus_barrier(device_t dev, device_t child, struct bhnd_resource *r, + bus_size_t offset, bus_size_t length, int flags) +{ + bus_size_t remain; + + BHNDB_IO_COMMON_SETUP(length); + + /* TODO: It's unclear whether we need a barrier implementation, + * and if we do, what it needs to actually do. This may need + * revisiting once we have a better idea of requirements after + * porting the core drivers. */ + panic("implementation incorrect"); + + /* Use 4-byte reads where possible */ + remain = length % sizeof(uint32_t); + for (bus_size_t i = 0; i < (length - remain); i += 4) + bus_read_4(io_res, io_offset + offset + i); + + /* Use 1 byte reads for the remainder */ + for (bus_size_t i = 0; i < remain; i++) + bus_read_1(io_res, io_offset + offset + length + i); + + BHNDB_IO_COMMON_TEARDOWN(); +} + +/** + * Default bhndb(4) implementation of BUS_SETUP_INTR(). + */ +static int +bhndb_setup_intr(device_t dev, device_t child, struct resource *r, + int flags, driver_filter_t filter, driver_intr_t handler, void *arg, + void **cookiep) +{ + // TODO + return (EOPNOTSUPP); +} + +/** + * Default bhndb(4) implementation of BUS_TEARDOWN_INTR(). + */ +static int +bhndb_teardown_intr(device_t dev, device_t child, struct resource *r, + void *cookie) +{ + // TODO + return (EOPNOTSUPP); +} + +/** + * Default bhndb(4) implementation of BUS_CONFIG_INTR(). + */ +static int +bhndb_config_intr(device_t dev, int irq, enum intr_trigger trig, + enum intr_polarity pol) +{ + // TODO + return (EOPNOTSUPP); +} + +/** + * Default bhndb(4) implementation of BUS_BIND_INTR(). + */ +static int +bhndb_bind_intr(device_t dev, device_t child, struct resource *r, int cpu) +{ + // TODO + return (EOPNOTSUPP); +} + +/** + * Default bhndb(4) implementation of BUS_DESCRIBE_INTR(). + */ +static int +bhndb_describe_intr(device_t dev, device_t child, struct resource *irq, void *cookie, + const char *descr) +{ + // TODO + return (EOPNOTSUPP); +} + +/** + * Default bhndb(4) implementation of BUS_GET_DMA_TAG(). + */ +static bus_dma_tag_t +bhndb_get_dma_tag(device_t dev, device_t child) +{ + // TODO + return (NULL); +} + +static device_method_t bhndb_methods[] = { + /* Device interface */ \ + DEVMETHOD(device_probe, bhndb_generic_probe), + DEVMETHOD(device_detach, bhndb_generic_detach), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + DEVMETHOD(device_suspend, bhndb_generic_suspend), + DEVMETHOD(device_resume, bhndb_generic_resume), + + /* Bus interface */ + DEVMETHOD(bus_probe_nomatch, bhndb_probe_nomatch), + DEVMETHOD(bus_print_child, bhndb_print_child), + DEVMETHOD(bus_child_pnpinfo_str, bhndb_child_pnpinfo_str), + DEVMETHOD(bus_child_location_str, bhndb_child_location_str), + DEVMETHOD(bus_add_child, bhndb_add_child), + DEVMETHOD(bus_child_deleted, bhndb_child_deleted), + + DEVMETHOD(bus_alloc_resource, bhndb_alloc_resource), + DEVMETHOD(bus_release_resource, bhndb_release_resource), + DEVMETHOD(bus_activate_resource, bhndb_activate_resource), + DEVMETHOD(bus_deactivate_resource, bhndb_deactivate_resource), + + DEVMETHOD(bus_setup_intr, bhndb_setup_intr), + DEVMETHOD(bus_teardown_intr, bhndb_teardown_intr), + DEVMETHOD(bus_config_intr, bhndb_config_intr), + DEVMETHOD(bus_bind_intr, bhndb_bind_intr), + DEVMETHOD(bus_describe_intr, bhndb_describe_intr), + + DEVMETHOD(bus_get_dma_tag, bhndb_get_dma_tag), + + DEVMETHOD(bus_adjust_resource, bhndb_adjust_resource), + DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), + DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), + DEVMETHOD(bus_delete_resource, bus_generic_rl_delete_resource), + DEVMETHOD(bus_get_resource_list, bhndb_get_resource_list), + + DEVMETHOD(bus_read_ivar, bhndb_read_ivar), + DEVMETHOD(bus_write_ivar, bhndb_write_ivar), + + /* BHNDB interface */ + DEVMETHOD(bhndb_get_chipid, bhndb_get_chipid), + DEVMETHOD(bhndb_init_full_config, bhndb_generic_init_full_config), + DEVMETHOD(bhndb_suspend_resource, bhndb_suspend_resource), + DEVMETHOD(bhndb_resume_resource, bhndb_resume_resource), + + /* BHND interface */ + DEVMETHOD(bhnd_bus_is_hw_disabled, bhndb_is_hw_disabled), + DEVMETHOD(bhnd_bus_is_hostb_device, bhndb_is_hostb_device), + DEVMETHOD(bhnd_bus_get_chipid, bhndb_get_chipid), + DEVMETHOD(bhnd_bus_alloc_resource, bhndb_alloc_bhnd_resource), + DEVMETHOD(bhnd_bus_release_resource, bhndb_release_bhnd_resource), + DEVMETHOD(bhnd_bus_activate_resource, bhndb_activate_bhnd_resource), + DEVMETHOD(bhnd_bus_activate_resource, bhndb_deactivate_bhnd_resource), + DEVMETHOD(bhnd_bus_read_1, bhndb_bus_read_1), + DEVMETHOD(bhnd_bus_read_2, bhndb_bus_read_2), + DEVMETHOD(bhnd_bus_read_4, bhndb_bus_read_4), + DEVMETHOD(bhnd_bus_write_1, bhndb_bus_write_1), + DEVMETHOD(bhnd_bus_write_2, bhndb_bus_write_2), + DEVMETHOD(bhnd_bus_write_4, bhndb_bus_write_4), + DEVMETHOD(bhnd_bus_barrier, bhndb_bus_barrier), + + DEVMETHOD_END +}; + +devclass_t bhndb_devclass; + +DEFINE_CLASS_0(bhndb, bhndb_driver, bhndb_methods, sizeof(struct bhndb_softc)); + +MODULE_VERSION(bhndb, 1); +MODULE_DEPEND(bhndb, bhnd, 1, 1, 1); +MODULE_DEPEND(bhndb, bhnd_chipc, 1, 1, 1); diff --git a/sys/dev/bhnd/bhndb/bhndb.h b/sys/dev/bhnd/bhndb/bhndb.h new file mode 100644 index 000000000000..7ece8ae4dc8e --- /dev/null +++ b/sys/dev/bhnd/bhndb/bhndb.h @@ -0,0 +1,173 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $FreeBSD$ + */ + +#ifndef _BHND_BHNDB_H_ +#define _BHND_BHNDB_H_ + +#include +#include + +#include +#include +#include + +#include + +#include "bhndb_bus_if.h" + +extern devclass_t bhndb_devclass; + +int bhndb_attach_bridge(device_t parent, device_t *bhndb, int unit); + +/** + * bhndb register window types. + */ +typedef enum { + BHNDB_REGWIN_T_CORE, /**< Fixed mapping of a core port region. */ + BHNDB_REGWIN_T_SPROM, /**< Fixed mapping of device SPROM */ + BHNDB_REGWIN_T_DYN, /**< A dynamically configurable window */ + BHNDB_REGWIN_T_INVALID /**< Invalid type */ +} bhndb_regwin_type_t; + +/** + * Evaluates to true if @p _rt defines a static mapping. + * + * @param _rt A bhndb_regwin_type_t value. + */ +#define BHNDB_REGWIN_T_IS_STATIC(_rt) \ + ((_rt) == BHNDB_REGWIN_T_CORE || \ + (_rt) == BHNDB_REGWIN_T_SPROM) + +/** + * bhndb register window definition. + */ +struct bhndb_regwin { + bhndb_regwin_type_t win_type; /**< window type */ + bus_size_t win_offset; /**< offset of the window within the resource */ + bus_size_t win_size; /**< size of the window */ + + /** Resource identification */ + struct { + int type; /**< resource type */ + int rid; /**< resource id */ + } res; + + + union { + /** Core-specific register window (BHNDB_REGWIN_T_CORE). */ + struct { + bhnd_devclass_t class; /**< mapped core's class */ + u_int unit; /**< mapped core's unit */ + bhnd_port_type port_type; /**< mapped port type */ + u_int port; /**< mapped port number */ + u_int region; /**< mapped region number */ + } core; + + /** SPROM register window (BHNDB_REGWIN_T_SPROM). */ + struct {} sprom; + + /** Dynamic register window (BHNDB_REGWIN_T_DYN). */ + struct { + bus_size_t cfg_offset; /**< window address config offset. */ + } dyn; + }; +}; + +#define BHNDB_REGWIN_TABLE_END { BHNDB_REGWIN_T_INVALID, 0, 0, { 0, 0 } } + +/** + * Bridge hardware configuration. + * + * Provides the bridge's register/address mappings, and the resources + * via which those mappings may be accessed. + */ +struct bhndb_hwcfg { + const struct resource_spec *resource_specs; + const struct bhndb_regwin *register_windows; +}; + +/** + * Hardware specification entry. + * + * Defines a set of match criteria that may be used to determine the + * register map and resource configuration for a bhndb bridge device. + */ +struct bhndb_hw { + const char *name; /**< configuration name */ + const struct bhnd_core_match *hw_reqs; /**< match requirements */ + u_int num_hw_reqs; /**< number of match requirements */ + const struct bhndb_hwcfg *cfg; /**< associated hardware configuration */ +}; + + +/** + * bhndb resource allocation priorities. + */ +typedef enum { + /** No direct resources should ever be allocated for this device. */ + BHNDB_PRIORITY_NONE = 0, + + /** Allocate a direct resource if available after serving all other + * higher-priority requests. */ + BHNDB_PRIORITY_LOW = 1, + + /** Direct resource allocation is preferred, but not necessary + * for reasonable runtime performance. */ + BHNDB_PRIORITY_DEFAULT = 2, + + /** Indirect resource allocation would incur high runtime overhead. */ + BHNDB_PRIORITY_HIGH = 3 +} bhndb_priority_t; + +/** + * Port resource priority descriptor. + */ +struct bhndb_port_priority { + bhnd_port_type type; /**< port type. */ + u_int port; /**< port */ + u_int region; /**< region */ + bhndb_priority_t priority; /**< port priority */ +}; + +/** + * Core resource priority descriptor. + */ +struct bhndb_hw_priority { + struct bhnd_core_match match; /**< core match descriptor */ + bhndb_priority_t priority; /**< core-level priority */ + const struct bhndb_port_priority *ports; /**< port priorities */ + u_int num_ports; /**< number of port priority records. */ +}; + +#define BHNDB_HW_PRIORITY_TABLE_END { {}, BHNDB_PRIORITY_NONE, NULL, 0 } + + +#endif /* _BHND_BHNDB_H_ */ \ No newline at end of file diff --git a/sys/dev/bhnd/bhndb/bhndb_bus_if.m b/sys/dev/bhnd/bhndb/bhndb_bus_if.m new file mode 100644 index 000000000000..2546da1d357c --- /dev/null +++ b/sys/dev/bhnd/bhndb/bhndb_bus_if.m @@ -0,0 +1,127 @@ +#- +# Copyright (c) 2015 Landon Fuller +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# $FreeBSD$ + +#include +#include + +# +# Parent bus interface required by attached bhndb bridge devices. +# + +INTERFACE bhndb_bus; + +HEADER { + struct bhnd_core_info; + struct bhndb_hwcfg; + struct bhndb_hw; +}; + +CODE { + #include + + static const struct bhnd_chipid * + bhndb_null_get_chipid(device_t dev, device_t child) + { + return (NULL); + } + + static const struct bhndb_hwcfg * + bhndb_null_get_generic_hwcfg(device_t dev, device_t child) + { + panic("bhndb_get_generic_hwcfg unimplemented"); + } + + static const struct bhndb_hw * + bhndb_null_get_hardware_table(device_t dev, device_t child) + { + panic("bhndb_get_hardware_table unimplemented"); + } + + static bool + bhndb_null_is_core_disabled(device_t dev, device_t child, + struct bhnd_core_info *core) + { + return (true); + } +} + +/** + * Return a generic hardware configuration to be used by + * the bhndb bridge device to enumerate attached devices. + * + * @param dev The parent device. + * @param child The attached bhndb device. + * + * @retval bhndb_hwcfg The configuration to use for bus enumeration. + */ +METHOD const struct bhndb_hwcfg * get_generic_hwcfg { + device_t dev; + device_t child; +} DEFAULT bhndb_null_get_generic_hwcfg; + +/** + * Provide chip identification information to be used by a @p child during + * device enumeration. + * + * May return NULL if the device includes a ChipCommon core. + * + * @param dev The parent device. + * @param child The attached bhndb device. + */ +METHOD const struct bhnd_chipid * get_chipid { + device_t dev; + device_t child; +} DEFAULT bhndb_null_get_chipid; + +/** + * Return the hardware specification table to be used when identifying the + * bridge's full hardware configuration. + * + * @param dev The parent device. + * @param child The attached bhndb device. + */ +METHOD const struct bhndb_hw * get_hardware_table { + device_t dev; + device_t child; +} DEFAULT bhndb_null_get_hardware_table; + +/** + * Return true if the hardware required by @p core is unpopulated or + * otherwise unusable. + * + * In some cases, the core's pins may be left floating, or the hardware + * may otherwise be non-functional; this method allows the parent device + * to explicitly specify whether @p core should be disabled. + * + * @param dev The parent device. + * @param child The attached bhndb device. + * @param core A core discovered on @p child. + */ +METHOD bool is_core_disabled { + device_t dev; + device_t child; + struct bhnd_core_info *core; +} DEFAULT bhndb_null_is_core_disabled; diff --git a/sys/dev/bhnd/bhndb/bhndb_hwdata.c b/sys/dev/bhnd/bhndb/bhndb_hwdata.c new file mode 100644 index 000000000000..dd973e96b3ba --- /dev/null +++ b/sys/dev/bhnd/bhndb/bhndb_hwdata.c @@ -0,0 +1,195 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include + +#include +#include +#include + +#include "bhndb_hwdata.h" + +/* + * Resource priority specifications shared by all bhndb(4) bridge + * implementations. + */ + +/* + * Define a bhndb_port_priority table. + */ +#define BHNDB_PORTS(...) \ + .ports = _BHNDB_PORT_ARRAY(__VA_ARGS__), \ + .num_ports = nitems(_BHNDB_PORT_ARRAY(__VA_ARGS__)) + +#define _BHNDB_PORT_ARRAY(...) (const struct bhndb_port_priority[]) { \ + __VA_ARGS__ \ +} + +/* + * Define a core priority record for all cores matching @p devclass and + * @p unit. + * + * If a devclass of BHNDB_DEVCLASS_INVALID is specified, this will match + * on all device classes. + * + * If a unit number of -1 is specified, this will match on all units. + */ +#define BHNDB_CLASS_PRIO(_devclass, _unit, _priority, ...) { \ + .match = { \ + .vendor = BHND_MFGID_INVALID, \ + .device = BHND_COREID_INVALID, \ + .hwrev = { BHND_HWREV_INVALID, BHND_HWREV_INVALID }, \ + .class = (BHND_DEVCLASS_ ## _devclass), \ + .unit = (_unit) \ + }, \ + .priority = (BHNDB_PRIORITY_ ## _priority), \ + BHNDB_PORTS(__VA_ARGS__) \ +} + +/* Define a port priority record for the type/port/region + * triplet. */ +#define BHNDB_PORT_PRIO(_type, _port, _region, _priority) { \ + .type = (BHND_PORT_ ## _type), \ + .port = _port, \ + .region = _region, \ + .priority = (BHNDB_PRIORITY_ ## _priority) \ +} + +/* Define a port priority record for the default (_type, 0, 0) type/port/region + * triplet. */ +#define BHNDB_PORT0_PRIO(_type, _priority) \ + BHNDB_PORT_PRIO(_type, 0, 0, _priority) + +/** + * Generic resource priority configuration usable with all currently supported + * bcma(4)-based PCI devices. + */ +const struct bhndb_hw_priority bhndb_bcma_priority_table[] = { + /* + * Ignorable device classes. + * + * Runtime access to these cores is not required, and no register + * windows should be reserved for these device types. + */ + BHNDB_CLASS_PRIO(SOC_ROUTER, -1, NONE), + BHNDB_CLASS_PRIO(SOC_BRIDGE, -1, NONE), + BHNDB_CLASS_PRIO(EROM, -1, NONE), + BHNDB_CLASS_PRIO(OTHER, -1, NONE), + + /* + * Low priority device classes. + * + * These devices do not sit in a performance-critical path and can be + * treated as a low allocation priority. + */ + BHNDB_CLASS_PRIO(CC, -1, LOW, + /* Device Block */ + BHNDB_PORT0_PRIO(DEVICE, LOW), + + /* CC agent registers are not accessed via the bridge. */ + BHNDB_PORT0_PRIO(AGENT, NONE) + ), + + BHNDB_CLASS_PRIO(PMU, -1, LOW, + /* Device Block */ + BHNDB_PORT0_PRIO(DEVICE, LOW), + + /* PMU agent registers are not accessed via the bridge. */ + BHNDB_PORT0_PRIO(AGENT, NONE) + ), + + /* + * Default Core Behavior + * + * All other cores are assumed to require effecient runtime access to + * the default device port, and if supported by the bus, an agent port. + */ + BHNDB_CLASS_PRIO(INVALID, -1, DEFAULT, + /* Device Block */ + BHNDB_PORT0_PRIO(DEVICE, HIGH), + + /* Agent Block */ + BHNDB_PORT0_PRIO(AGENT, DEFAULT) + ), + + BHNDB_HW_PRIORITY_TABLE_END +}; + +/** + * Generic resource priority configuration usable with all currently supported + * siba(4)-based PCI devices. + */ +const struct bhndb_hw_priority bhndb_siba_priority_table[] = { + /* + * Ignorable device classes. + * + * Runtime access to these cores is not required, and no register + * windows should be reserved for these device types. + */ + BHNDB_CLASS_PRIO(SOC_ROUTER, -1, NONE), + BHNDB_CLASS_PRIO(SOC_BRIDGE, -1, NONE), + BHNDB_CLASS_PRIO(EROM, -1, NONE), + BHNDB_CLASS_PRIO(OTHER, -1, NONE), + + /* + * Low priority device classes. + * + * These devices do not sit in a performance-critical path and can be + * treated as a low allocation priority. + * + * Agent ports are marked as 'NONE' on siba(4) devices, as they + * will be fully mappable via register windows shared with the + * device0.0 port. + */ + BHNDB_CLASS_PRIO(CC, -1, LOW, + /* Device Block */ + BHNDB_PORT_PRIO(DEVICE, 0, 0, LOW) + ), + + BHNDB_CLASS_PRIO(PMU, -1, LOW, + /* Device Block */ + BHNDB_PORT_PRIO(DEVICE, 0, 0, LOW) + ), + + /* + * Default Core Behavior + * + * All other cores are assumed to require effecient runtime access to + * the device port. + */ + BHNDB_CLASS_PRIO(INVALID, -1, DEFAULT, + /* Device Block */ + BHNDB_PORT_PRIO(DEVICE, 0, 0, HIGH) + ), + + BHNDB_HW_PRIORITY_TABLE_END +}; \ No newline at end of file diff --git a/sys/dev/bhnd/bhndb/bhndb_hwdata.h b/sys/dev/bhnd/bhndb/bhndb_hwdata.h new file mode 100644 index 000000000000..0dda5404b3bf --- /dev/null +++ b/sys/dev/bhnd/bhndb/bhndb_hwdata.h @@ -0,0 +1,40 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $FreeBSD$ + */ + +#ifndef _BHND_BHNDB_HWDATA_H_ +#define _BHND_BHNDB_HWDATA_H_ + +#include "bhndb.h" + +extern const struct bhndb_hw_priority bhndb_bcma_priority_table[]; +extern const struct bhndb_hw_priority bhndb_siba_priority_table[]; + +#endif /* _BHND_BHNDB_HWDATA_H_ */ \ No newline at end of file diff --git a/sys/dev/bhnd/bhndb/bhndb_if.m b/sys/dev/bhnd/bhndb/bhndb_if.m new file mode 100644 index 000000000000..110925b4d334 --- /dev/null +++ b/sys/dev/bhnd/bhndb/bhndb_if.m @@ -0,0 +1,184 @@ +#- +# Copyright (c) 2015 Landon Fuller +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# $FreeBSD$ + +#include +#include + +#include +#include +#include + +#include + +# +# bhndb bridge device interface. +# + +INTERFACE bhndb; + +HEADER { + struct bhndb_regwin; + struct bhndb_hw; + struct bhndb_hw_priority; +} + +CODE { + #include + #include + + static const struct bhnd_chipid * + bhndb_null_get_chipid(device_t dev, device_t child) + { + panic("bhndb_get_chipid unimplemented"); + } + + static int + bhndb_null_init_full_config(device_t dev, device_t child, + const struct bhndb_hw_priority *priority_table) + { + panic("bhndb_init_full_config unimplemented"); + } + + static void + bhndb_null_suspend_resource(device_t dev, device_t child, int type, + struct resource *r) + { + panic("bhndb_suspend_resource unimplemented"); + } + + static int + bhndb_null_resume_resource(device_t dev, device_t child, int type, + struct resource *r) + { + panic("bhndb_resume_resource unimplemented"); + } + + static int + bhndb_null_set_window_addr(device_t dev, + const struct bhndb_regwin *rw, bhnd_addr_t addr) + { + panic("bhndb_set_window_addr unimplemented"); + } +} + +/** + * Return the chip identification information for @p child. + * + * @param dev The parent device of @p child. + * @param child The bhndb-attached device. + */ +METHOD const struct bhnd_chipid * get_chipid { + device_t dev; + device_t child; +} DEFAULT bhndb_null_get_chipid; + +/** + * Perform final bridge hardware configuration after @p child has fully + * enumerated its children. + * + * This must be called by any bhndb-attached bus device; this allows the + * bridge to perform final configuration based on the hardware information + * enumerated by the child bus. + * + * When calling this method: + * - Any bus resources previously allocated by @p child must be deallocated. + * - The @p child bus must have performed initial enumeration -- but not + * probe or attachment -- of its children. + * + * @param dev The bridge device. + * @param child The bhnd bus device attached to @p dev. + * @param hw_priority The hardware priority table to be used when determining + * the bridge resource allocation strategy. + */ +METHOD int init_full_config { + device_t dev; + device_t child; + const struct bhndb_hw_priority *priority_table; +} DEFAULT bhndb_null_init_full_config; + +/** + * Mark a resource as 'suspended', gauranteeing to the bridge that no + * further use of the resource will be made until BHNDB_RESUME_RESOURCE() + * is called. + * + * Bridge resources consumed by the reference may be released; these will + * be reacquired if BHNDB_RESUME_RESOURCE() completes successfully. + * + * Requests to suspend a suspended resource will be ignored. + * + * @param dev The bridge device. + * @param child The child device requesting resource suspension. This does + * not need to be the owner of @p r. + * @param type The resource type. + * @param r The resource to be suspended. + */ +METHOD void suspend_resource { + device_t dev; + device_t child; + int type; + struct resource *r; +} DEFAULT bhndb_null_suspend_resource; + +/** + * Attempt to re-enable a resource previously suspended by + * BHNDB_SUSPEND_RESOURCE(). + * + * Bridge resources required by the reference may not be available, in which + * case an error will be returned and the resource mapped by @p r must not be + * used in any capacity. + * + * Requests to resume a non-suspended resource will be ignored. + * + * @param dev The bridge device. + * @param child The child device requesting resource suspension. This does + * not need to be the owner of @p r. + * @param type The resource type. + * @param r The resource to be suspended. + */ +METHOD int resume_resource { + device_t dev; + device_t child; + int type; + struct resource *r; +} DEFAULT bhndb_null_resume_resource; + +/** + * Set a given register window's base address. + * + * @param dev The bridge device. + * @param win The register window. + * @param addr The address to be configured for @p win. + * + * @retval 0 success + * @retval ENODEV The provided @p win is not memory-mapped on the bus or does + * not support setting a base address. + * @retval non-zero failure + */ +METHOD int set_window_addr { + device_t dev; + const struct bhndb_regwin *win; + bhnd_addr_t addr; +} DEFAULT bhndb_null_set_window_addr; diff --git a/sys/dev/bhnd/bhndb/bhndb_pci.c b/sys/dev/bhnd/bhndb/bhndb_pci.c new file mode 100644 index 000000000000..03a09968d84c --- /dev/null +++ b/sys/dev/bhnd/bhndb/bhndb_pci.c @@ -0,0 +1,1096 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * PCI-specific implementation for the BHNDB bridge driver. + * + * Provides support for bridging from a PCI parent bus to a BHND-compatible + * bus (e.g. bcma or siba) via a Broadcom PCI core configured in end-point + * mode. + * + * This driver handles all interactions with the PCI bridge core. On the + * bridged bhnd bus, the PCI core device will be claimed by a simple + * bhnd_hostb driver. + */ + +// Quirk TODO +// WARs for the following are not yet implemented: +// - BHND_PCI_QUIRK_SBINTVEC +// - BHND_PCIE_QUIRK_ASPM_OVR +// - BHND_PCIE_QUIRK_SERDES_NOPLLDOWN +// Quirks (and WARs) for the following are not yet defined: +// - Power savings via MDIO BLK1/PWR_MGMT3 on PCIe hwrev 15-20, 21-22 +// - WOWL PME enable/disable +// - 4360 PCIe SerDes Tx amplitude/deemphasis (vendor Apple, boards +// BCM94360X51P2, BCM94360X51A). +// - PCI latency timer (boards CB2_4321_BOARD, CB2_4321_AG_BOARD) +// - Max SerDes TX drive strength (vendor Apple, pcie >= rev10, +// board BCM94322X9) +// - 700mV SerDes TX drive strength (chipid BCM4331, boards BCM94331X19, +// BCM94331X28, BCM94331X29B, BCM94331X19C) + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#include "bhndb_pcireg.h" +#include "bhndb_pcivar.h" +#include "bhndb_private.h" + +static int bhndb_enable_pci_clocks(struct bhndb_pci_softc *sc); +static int bhndb_disable_pci_clocks(struct bhndb_pci_softc *sc); + +static int bhndb_pci_compat_setregwin(struct bhndb_pci_softc *, + const struct bhndb_regwin *, bhnd_addr_t); +static int bhndb_pci_fast_setregwin(struct bhndb_pci_softc *, + const struct bhndb_regwin *, bhnd_addr_t); + +static uint32_t bhndb_pcie_read_proto_reg(struct bhndb_pci_softc *sc, + uint32_t addr); +static void bhndb_pcie_write_proto_reg(struct bhndb_pci_softc *sc, + uint32_t addr, uint32_t val); + +static void bhndb_init_sromless_pci_config(struct bhndb_pci_softc *sc); + +static int bhndb_pci_wars_register_access(struct bhndb_pci_softc *sc); +static int bhndb_pci_wars_early_once(struct bhndb_pci_softc *sc); +static int bhndb_pci_wars_hwup(struct bhndb_pci_softc *sc); +static int bhndb_pci_wars_hwdown(struct bhndb_pci_softc *sc); + +static uint32_t bhndb_pci_discover_quirks(struct bhndb_pci_softc *, + const struct bhndb_pci_id *); + +static const struct bhndb_pci_id *bhndb_pci_find_core_id( + struct bhnd_core_info *core); +/* + * Supported PCI bridge cores. + * + * This table defines quirks specific to core hwrev ranges; see also + * bhndb_pci_discover_quirks() for additional quirk detection. + */ +static const struct bhndb_pci_id bhndb_pci_ids[] = { + /* PCI */ + BHNDB_PCI_ID(PCI, + BHND_QUIRK_HWREV_GTE (0, + BHNDB_PCI_QUIRK_EXT_CLOCK_GATING | + BHNDB_PCI_QUIRK_SBTOPCI2_PREF_BURST), + + BHND_QUIRK_HWREV_RANGE (0, 5, + BHNDB_PCI_QUIRK_SBINTVEC), + + BHND_QUIRK_HWREV_GTE (11, + BHNDB_PCI_QUIRK_SBTOPCI2_READMULTI | + BHNDB_PCI_QUIRK_CLKRUN_DSBL), + + BHND_QUIRK_HWREV_END + ), + + /* PCI Gen 1 */ + BHNDB_PCI_ID(PCIE, + BHND_QUIRK_HWREV_EQ (0, + BHNDB_PCIE_QUIRK_SDR9_L0s_HANG), + + BHND_QUIRK_HWREV_RANGE (0, 1, + BHNDB_PCIE_QUIRK_UR_STATUS_FIX), + + BHND_QUIRK_HWREV_EQ (1, + BHNDB_PCIE_QUIRK_PCIPM_REQEN), + + BHND_QUIRK_HWREV_RANGE (3, 5, + BHNDB_PCIE_QUIRK_ASPM_OVR | + BHNDB_PCIE_QUIRK_SDR9_POLARITY | + BHNDB_PCIE_QUIRK_SDR9_NO_FREQRETRY), + + BHND_QUIRK_HWREV_LTE (6, + BHNDB_PCIE_QUIRK_L1_IDLE_THRESH), + + BHND_QUIRK_HWREV_GTE (6, + BHNDB_PCIE_QUIRK_SPROM_L23_PCI_RESET), + + BHND_QUIRK_HWREV_EQ (7, + BHNDB_PCIE_QUIRK_SERDES_NOPLLDOWN), + + BHND_QUIRK_HWREV_GTE (8, + BHNDB_PCIE_QUIRK_L1_TIMER_PERF), + + BHND_QUIRK_HWREV_GTE (10, + BHNDB_PCIE_QUIRK_SD_C22_EXTADDR), + + BHND_QUIRK_HWREV_END + ), + + { BHND_COREID_INVALID, BHND_PCI_REGFMT_PCI, NULL } +}; + + +/* quirk flag convenience macros */ +#define BHNDB_PCI_QUIRK(_sc, _name) \ + ((_sc)->quirks & BHNDB_PCI_QUIRK_ ## _name) +#define BHNDB_PCIE_QUIRK(_sc, _name) \ + ((_sc)->quirks & BHNDB_PCIE_QUIRK_ ## _name) + +#define BHNDB_PCI_ASSERT_QUIRK(_sc, name) \ + KASSERT(BHNDB_PCI_QUIRK((_sc), name), ("quirk " __STRING(_name) " not set")) +#define BHNDB_PCIE_ASSERT_QUIRK(_sc, name) \ + KASSERT(BHNDB_PCIE_QUIRK((_sc), name), ("quirk " __STRING(_name) " not set")) + + +/* bus_(read|write)_* convenience macros */ +#define BHNDB_PCI_READ_2(_sc, _reg) \ + bus_read_2((_sc)->mem_res, (_sc)->mem_off + (_reg)) +#define BHNDB_PCI_READ_4(_sc, _reg) \ + bus_read_4((_sc)->mem_res, (_sc)->mem_off + (_reg)) + +#define BHNDB_PCI_WRITE_2(_sc, _reg, _val) \ + bus_write_2((_sc)->mem_res, (_sc)->mem_off + (_reg), (_val)) +#define BHNDB_PCI_WRITE_4(_sc, _reg, _val) \ + bus_write_4((_sc)->mem_res, (_sc)->mem_off + (_reg), (_val)) + + +/* BHNDB_PCI_REG_* convenience macros */ +#define BPCI_REG_EXTRACT(_rv, _a) BHND_PCI_REG_EXTRACT(_rv, BHND_ ## _a) +#define BPCI_REG_INSERT(_rv, _a, _v) BHND_PCI_REG_INSERT(_rv, BHND_ ## _a, _v) + +#define BPCI_COMMON_REG_EXTRACT(_r, _a) \ + BHND_PCI_COMMON_REG_EXTRACT(sc->regfmt, _r, _a) + +#define BPCI_COMMON_REG_INSERT(_r, _a, _v) \ + BHND_PCI_COMMON_REG_INSERT(sc->regfmt, _r, _a, _v) + +#define BPCI_COMMON_REG(_name) \ + BHND_PCI_COMMON_REG(sc->regfmt, _name) + +#define BPCI_COMMON_REG_OFFSET(_base, _offset) \ + (BPCI_COMMON_REG(_base) + BPCI_COMMON_REG(_offset)) + +/** + * Default bhndb_pci implementation of device_probe(). + * + * Verifies that the parent is a PCI/PCIe device. + */ +static int +bhndb_pci_probe(device_t dev) +{ + device_t parent; + devclass_t parent_bus; + devclass_t pci; + + /* Our parent must be a PCI/PCIe device. */ + pci = devclass_find("pci"); + parent = device_get_parent(dev); + parent_bus = device_get_devclass(device_get_parent(parent)); + + if (parent_bus != pci) + return (ENXIO); + + device_set_desc(dev, "PCI-BHND bridge"); + + return (BUS_PROBE_DEFAULT); +} + +static int +bhndb_pci_attach(device_t dev) +{ + struct bhndb_pci_softc *sc; + int error, reg; + + sc = device_get_softc(dev); + sc->dev = dev; + + /* Enable PCI bus mastering */ + pci_enable_busmaster(device_get_parent(dev)); + + /* Determine our bridge device class */ + sc->pci_devclass = BHND_DEVCLASS_PCI; + if (pci_find_cap(device_get_parent(dev), PCIY_EXPRESS, ®) == 0) + sc->pci_devclass = BHND_DEVCLASS_PCIE; + + /* Determine the basic set of applicable quirks. This will be updated + * in bhndb_pci_init_full_config() once the PCI device core has + * been enumerated. */ + sc->quirks = bhndb_pci_discover_quirks(sc, NULL); + + /* Using the discovered quirks, apply any WARs required for basic + * register access. */ + if ((error = bhndb_pci_wars_register_access(sc))) + return (error); + + /* Use siba(4)-compatible regwin handling until we know + * what kind of bus is attached */ + sc->set_regwin = bhndb_pci_compat_setregwin; + + /* Perform full bridge attach. This should call back into our + * bhndb_pci_init_full_config() implementation once the bridged + * bhnd(4) bus has been enumerated, but before any devices have been + * probed or attached. */ + if ((error = bhndb_attach(dev, sc->pci_devclass))) + return (error); + + /* If supported, switch to the faster regwin handling */ + if (sc->bhndb.chipid.chip_type != BHND_CHIPTYPE_SIBA) { + atomic_store_rel_ptr((volatile void *) &sc->set_regwin, + (uintptr_t) &bhndb_pci_fast_setregwin); + } + + return (0); +} + +/** + * Initialize the full bridge configuration. + * + * This is called during the DEVICE_ATTACH() process by the bridged bhndb(4) + * bus, prior to probe/attachment of child cores. + * + * At this point, we can introspect the enumerated cores, find our host + * bridge device, and apply any bridge-level hardware workarounds required + * for proper operation of the bridged device cores. + */ +static int +bhndb_pci_init_full_config(device_t dev, device_t child, + const struct bhndb_hw_priority *prio_table) +{ + struct bhnd_core_info core; + const struct bhndb_pci_id *id; + struct bhndb_pci_softc *sc; + struct bhndb_region *pcir; + bhnd_addr_t pcir_addr; + bhnd_size_t pcir_size; + int error; + + sc = device_get_softc(dev); + + /* Let bhndb perform full discovery and initialization of the + * available register windows and bridge resources. */ + if ((error = bhndb_generic_init_full_config(dev, child, prio_table))) + return (error); + + /* + * Identify our PCI bridge core, its register family, and any + * applicable hardware quirks. + */ + KASSERT(sc->bhndb.hostb_dev, + ("missing hostb device\n")); + + core = bhnd_get_core_info(sc->bhndb.hostb_dev); + id = bhndb_pci_find_core_id(&core); + if (id == NULL) { + device_printf(dev, "%s %s hostb core is not recognized\n", + bhnd_vendor_name(core.vendor), bhnd_core_name(&core)); + } + + sc->regfmt = id->regfmt; + + /* Now that we've identified the PCI bridge core, we can determine the + * full set of device quirks */ + sc->quirks = bhndb_pci_discover_quirks(sc, id); + + /* + * Determine and save a reference to the bhndb resource and offset + * at which the bridge core's device registers are mapped. + * + * All known bhnd(4) hardware provides a fixed static mapping of + * the PCI core's registers. If this changes in the future -- which + * is unlikely -- this driver will need to be adjusted to use + * dynamic register windows. + */ + + /* Find base address and size of the PCI core's register block. */ + error = bhnd_get_region_addr(sc->bhndb.hostb_dev, BHND_PORT_DEVICE, 0, + 0, &pcir_addr, &pcir_size); + if (error) { + device_printf(dev, + "failed to locate PCI core registers\n"); + return (error); + } + + /* Find the bhndb_region that statically maps this block */ + pcir = bhndb_find_resource_region(sc->bhndb.bus_res, pcir_addr, + pcir_size); + if (pcir == NULL || pcir->static_regwin == NULL) { + device_printf(dev, + "missing static PCI core register window\n"); + return (ENXIO); + } + + /* Save borrowed reference to the mapped PCI core registers */ + sc->mem_off = pcir->static_regwin->win_offset; + sc->mem_res = bhndb_find_regwin_resource(sc->bhndb.bus_res, + pcir->static_regwin); + if (sc->mem_res == NULL || !(rman_get_flags(sc->mem_res) & RF_ACTIVE)) { + device_printf(dev, + "no active resource maps the PCI core register window\n"); + return (ENXIO); + } + + /* Configure a direct bhnd_resource wrapper that we can pass to + * bhnd_resource APIs */ + sc->bhnd_mem_res = (struct bhnd_resource) { + .res = sc->mem_res, + .direct = true + }; + + /* + * Attach MMIO device (if this is a PCIe device), which is used for + * access to the PCIe SerDes required by the quirk workarounds. + */ + if (sc->pci_devclass == BHND_DEVCLASS_PCIE) { + sc->mdio = device_add_child(dev, + devclass_get_name(bhnd_mdio_pci_devclass), 0); + if (sc->mdio == NULL) + return (ENXIO); + + if ((error = device_probe_and_attach(sc->mdio))) { + device_printf(dev, "failed to attach MDIO device\n"); + return (error); + } + } + + /* Apply any early one-time quirk workarounds */ + if ((error = bhndb_pci_wars_early_once(sc))) + return (error); + + /* Apply attach-time quirk workarounds, required before the bridged + * bhnd(4) bus itself performs a full attach(). */ + if ((error = bhndb_pci_wars_hwup(sc))) + return (error); + + return (0); +} + +/** + * Apply any hardware workarounds that must be executed prior to attempting + * register access on the bridged chipset. + * + * This must be called very early in attach() or resume(), after the basic + * set of applicable device quirks has been determined. + */ +static int +bhndb_pci_wars_register_access(struct bhndb_pci_softc *sc) +{ + int error; + + if (BHNDB_PCI_QUIRK(sc, EXT_CLOCK_GATING)) { + if ((error = bhndb_enable_pci_clocks(sc))) { + device_printf(sc->dev, "failed to enable clocks\n"); + return (error); + } + } + + return (0); +} + +/** + * Apply any hardware work-arounds that must be executed exactly once, early in + * the attach process. + * + * This must be called after core enumeration and discovery of all applicable + * quirks, but prior to probe/attach of any cores, parsing of + * SPROM, etc. + */ +static int +bhndb_pci_wars_early_once(struct bhndb_pci_softc *sc) +{ + /* Determine correct polarity by observing the attach-time PCIe PHY + * link status. This is used later to reset/force the SerDes + * polarity */ + if (BHNDB_PCIE_QUIRK(sc, SDR9_POLARITY)) { + uint32_t st; + bool inv; + + + st = bhndb_pcie_read_proto_reg(sc, BHND_PCIE_PLP_STATUSREG); + inv = ((st & BHND_PCIE_PLP_POLARITY_INV) != 0); + sc->sdr9_quirk_polarity.inv = inv; + } + + return (0); +} + +/** + * Apply any hardware workarounds that are required upon attach or resume + * of the bridge device. + */ +static int +bhndb_pci_wars_hwup(struct bhndb_pci_softc *sc) +{ + /* Note that the order here matters; these work-arounds + * should not be re-ordered without careful review of their + * interdependencies */ + + /* Fix up any PoR defaults on SROMless devices */ + bhndb_init_sromless_pci_config(sc); + + /* Enable PCI prefetch/burst/readmulti flags */ + if (BHNDB_PCI_QUIRK(sc, SBTOPCI2_PREF_BURST) || + BHNDB_PCI_QUIRK(sc, SBTOPCI2_READMULTI)) + { + uint32_t sbp2; + sbp2 = BHNDB_PCI_READ_4(sc, BHND_PCI_SBTOPCI2); + + if (BHNDB_PCI_QUIRK(sc, SBTOPCI2_PREF_BURST)) + sbp2 |= (BHND_PCI_SBTOPCI_PREF|BHND_PCI_SBTOPCI_BURST); + + if (BHNDB_PCI_QUIRK(sc, SBTOPCI2_READMULTI)) + sbp2 |= BHND_PCI_SBTOPCI_RC_READMULTI; + + BHNDB_PCI_WRITE_4(sc, BHND_PCI_SBTOPCI2, sbp2); + } + + /* Disable PCI CLKRUN# */ + if (BHNDB_PCI_QUIRK(sc, CLKRUN_DSBL)) { + uint32_t ctl; + + ctl = BHNDB_PCI_READ_4(sc, BHND_PCI_CLKRUN_CTL); + ctl |= BHND_PCI_CLKRUN_DSBL; + BHNDB_PCI_WRITE_4(sc, BHND_PCI_CLKRUN_CTL, ctl); + } + + /* Enable TLP unmatched address handling work-around */ + if (BHNDB_PCIE_QUIRK(sc, UR_STATUS_FIX)) { + uint32_t wrs; + wrs = bhndb_pcie_read_proto_reg(sc, BHND_PCIE_TLP_WORKAROUNDSREG); + wrs |= BHND_PCIE_TLP_WORKAROUND_URBIT; + bhndb_pcie_write_proto_reg(sc, BHND_PCIE_TLP_WORKAROUNDSREG, wrs); + } + + /* Adjust SerDes CDR tuning to ensure that CDR is stable before sending + * data during L0s to L0 exit transitions. */ + if (BHNDB_PCIE_QUIRK(sc, SDR9_L0s_HANG)) { + uint16_t sdv; + + /* Set RX track/acquire timers to 2.064us/40.96us */ + sdv = BPCI_REG_INSERT(0, PCIE_SDR9_RX_TIMER1_LKTRK, (2064/16)); + sdv = BPCI_REG_INSERT(sdv, PCIE_SDR9_RX_TIMER1_LKACQ, + (40960/1024)); + MDIO_WRITEREG(sc->mdio, BHND_PCIE_PHY_SDR9_TXRX, + BHND_PCIE_SDR9_RX_TIMER1, sdv); + + /* Apply CDR frequency workaround */ + sdv = BHND_PCIE_SDR9_RX_CDR_FREQ_OVR_EN; + sdv = BPCI_REG_INSERT(sdv, PCIE_SDR9_RX_CDR_FREQ_OVR, 0x0); + MDIO_WRITEREG(sc->mdio, BHND_PCIE_PHY_SDR9_TXRX, + BHND_PCIE_SDR9_RX_CDR, sdv); + + /* Apply CDR BW tunings */ + sdv = 0; + sdv = BPCI_REG_INSERT(sdv, PCIE_SDR9_RX_CDRBW_INTGTRK, 0x2); + sdv = BPCI_REG_INSERT(sdv, PCIE_SDR9_RX_CDRBW_INTGACQ, 0x4); + sdv = BPCI_REG_INSERT(sdv, PCIE_SDR9_RX_CDRBW_PROPTRK, 0x6); + sdv = BPCI_REG_INSERT(sdv, PCIE_SDR9_RX_CDRBW_PROPACQ, 0x6); + MDIO_WRITEREG(sc->mdio, BHND_PCIE_PHY_SDR9_TXRX, + BHND_PCIE_SDR9_RX_CDRBW, sdv); + } + + /* Force correct SerDes polarity */ + if (BHNDB_PCIE_QUIRK(sc, SDR9_POLARITY)) { + uint16_t rxctl; + + rxctl = MDIO_READREG(sc->mdio, BHND_PCIE_PHY_SDR9_TXRX, + BHND_PCIE_SDR9_RX_CTRL); + + rxctl |= BHND_PCIE_SDR9_RX_CTRL_FORCE; + if (sc->sdr9_quirk_polarity.inv) + rxctl |= BHND_PCIE_SDR9_RX_CTRL_POLARITY_INV; + else + rxctl &= ~BHND_PCIE_SDR9_RX_CTRL_POLARITY_INV; + + MDIO_WRITEREG(sc->mdio, BHND_PCIE_PHY_SDR9_TXRX, + BHND_PCIE_SDR9_RX_CTRL, rxctl); + } + + /* Disable startup retry on PLL frequency detection failure */ + if (BHNDB_PCIE_QUIRK(sc, SDR9_NO_FREQRETRY)) { + uint16_t pctl; + + pctl = MDIO_READREG(sc->mdio, BHND_PCIE_PHY_SDR9_PLL, + BHND_PCIE_SDR9_PLL_CTRL); + + pctl &= ~BHND_PCIE_SDR9_PLL_CTRL_FREQDET_EN; + MDIO_WRITEREG(sc->mdio, BHND_PCIE_PHY_SDR9_PLL, + BHND_PCIE_SDR9_PLL_CTRL, pctl); + } + + /* Explicitly enable PCI-PM */ + if (BHNDB_PCIE_QUIRK(sc, PCIPM_REQEN)) { + uint32_t lcreg; + lcreg = bhndb_pcie_read_proto_reg(sc, BHND_PCIE_DLLP_LCREG); + lcreg |= BHND_PCIE_DLLP_LCREG_PCIPM_EN; + bhndb_pcie_write_proto_reg(sc, BHND_PCIE_DLLP_LCREG, lcreg); + } + + /* Adjust L1 timer to fix slow L1->L0 transitions */ + if (BHNDB_PCIE_QUIRK(sc, L1_IDLE_THRESH)) { + uint32_t pmt; + pmt = bhndb_pcie_read_proto_reg(sc, BHND_PCIE_DLLP_PMTHRESHREG); + pmt = BPCI_REG_INSERT(pmt, PCIE_L1THRESHOLDTIME, + BHND_PCIE_L1THRESHOLD_WARVAL); + bhndb_pcie_write_proto_reg(sc, BHND_PCIE_DLLP_PMTHRESHREG, pmt); + } + + /* Extend L1 timer for better performance. + * TODO: We could enable/disable this on demand for better power + * savings if we tie this to HT clock request handling */ + if (BHNDB_PCIE_QUIRK(sc, L1_TIMER_PERF)) { + uint32_t pmt; + pmt = bhndb_pcie_read_proto_reg(sc, BHND_PCIE_DLLP_PMTHRESHREG); + pmt |= BHND_PCIE_ASPMTIMER_EXTEND; + bhndb_pcie_write_proto_reg(sc, BHND_PCIE_DLLP_PMTHRESHREG, pmt); + } + + /* Enable L23READY_EXIT_NOPRST if not already set in SPROM. */ + if (BHNDB_PCIE_QUIRK(sc, SPROM_L23_PCI_RESET)) { + bus_size_t reg; + uint16_t cfg; + + /* Fetch the misc cfg flags from SPROM */ + reg = BHND_PCIE_SPROM_SHADOW + BHND_PCIE_SRSH_PCIE_MISC_CONFIG; + cfg = BHNDB_PCI_READ_2(sc, reg); + + /* Write EXIT_NOPRST flag if not already set in SPROM */ + if (!(cfg & BHND_PCIE_SRSH_L23READY_EXIT_NOPRST)) { + cfg |= BHND_PCIE_SRSH_L23READY_EXIT_NOPRST; + BHNDB_PCI_WRITE_2(sc, reg, cfg); + } + } + + return (0); +} + +/** + * Apply any hardware workarounds that are required upon resume of the + * bridge device. + * + * This must be called before any bridged bhnd(4) cores have been resumed. + */ +static int +bhndb_pci_wars_hwresume(struct bhndb_pci_softc *sc) +{ + int error; + + /* Nothing is possible without register access */ + if ((error = bhndb_pci_wars_register_access(sc))) + return (error); + + /* Apply the general hwup workarounds */ + return (bhndb_pci_wars_hwup(sc)); +} + +/** + * Apply any hardware workarounds that are required upon detach or suspend + * of the bridge device. + */ +static int +bhndb_pci_wars_hwdown(struct bhndb_pci_softc *sc) +{ + int error; + + /* Reduce L1 timer for better power savings. + * TODO: We could enable/disable this on demand for better power + * savings if we tie this to HT clock request handling */ + if (BHNDB_PCIE_QUIRK(sc, L1_TIMER_PERF)) { + uint32_t pmt; + pmt = bhndb_pcie_read_proto_reg(sc, BHND_PCIE_DLLP_PMTHRESHREG); + pmt &= ~BHND_PCIE_ASPMTIMER_EXTEND; + bhndb_pcie_write_proto_reg(sc, BHND_PCIE_DLLP_PMTHRESHREG, pmt); + } + + /* Disable clocks */ + if (BHNDB_PCI_QUIRK(sc, EXT_CLOCK_GATING)) { + if ((error = bhndb_disable_pci_clocks(sc))) { + device_printf(sc->dev, "failed to disable clocks\n"); + return (error); + } + } + + return (0); +} + +/* + * On devices without a SROM, the PCI(e) cores will be initialized with + * their Power-on-Reset defaults; this can leave the the BAR0 PCI windows + * potentially mapped to the wrong core index. + * + * This function updates the PCI core's BAR0 PCI configuration to point at the + * current PCI core. + * + * Applies to all PCI/PCIe revisions. Must be applied before bus devices + * are probed/attached or the SPROM is parsed. + */ +static void +bhndb_init_sromless_pci_config(struct bhndb_pci_softc *sc) +{ + bus_size_t sprom_addr; + u_int sprom_core_idx; + u_int pci_core_idx; + uint16_t val; + + /* Fetch the SPROM's configured core index */ + sprom_addr = BPCI_COMMON_REG_OFFSET(SPROM_SHADOW, SRSH_PI_OFFSET); + val = BHNDB_PCI_READ_2(sc, sprom_addr); + + /* If it doesn't match host bridge's core index, update the index + * value */ + sprom_core_idx = BPCI_COMMON_REG_EXTRACT(val, SRSH_PI); + pci_core_idx = bhnd_get_core_index(sc->bhndb.hostb_dev); + + if (sprom_core_idx != pci_core_idx) { + val = BPCI_COMMON_REG_INSERT(val, SRSH_PI, pci_core_idx); + BHNDB_PCI_WRITE_2(sc, sprom_addr, val); + } +} + +static int +bhndb_pci_detach(device_t dev) +{ + struct bhndb_pci_softc *sc; + int error; + + sc = device_get_softc(dev); + + if ((error = bhndb_generic_detach(dev))) + return (error); + + /* Apply any hardware workarounds. This may disable the clock, and + * thus must be called *after* any children have been detached. */ + if ((error = bhndb_pci_wars_hwdown(sc))) + return (error); + + /* Disable PCI bus mastering */ + pci_disable_busmaster(device_get_parent(dev)); + + return (0); +} + +static int +bhndb_pci_suspend(device_t dev) +{ + struct bhndb_pci_softc *sc; + int error; + + sc = device_get_softc(dev); + + if ((error = bhndb_generic_suspend(dev))) + return (error); + + /* Apply any hardware workarounds. This may disable the clock, and + * thus must be called *after* any children have been suspended. */ + if ((error = bhndb_pci_wars_hwdown(sc))) + return (error); + + return (0); +} + +static int +bhndb_pci_resume(device_t dev) +{ + struct bhndb_pci_softc *sc; + int error; + + sc = device_get_softc(dev); + + /* Apply any resume workarounds; these may be required for bridged + * device access, and thus must be called *before* any children are + * resumed. */ + if ((error = bhndb_pci_wars_hwresume(sc))) + return (error); + + if ((error = bhndb_generic_resume(dev))) + return (error); + + return (0); +} + +static int +bhndb_pci_set_window_addr(device_t dev, const struct bhndb_regwin *rw, + bhnd_addr_t addr) +{ + struct bhndb_pci_softc *sc = device_get_softc(dev); + return (sc->set_regwin(sc, rw, addr)); +} + +/** + * A siba(4) and bcma(4)-compatible bhndb_set_window_addr implementation. + * + * On siba(4) devices, it's possible that writing a PCI window register may + * not succeed; it's necessary to immediately read the configuration register + * and retry if not set to the desired value. + * + * This is not necessary on bcma(4) devices, but other than the overhead of + * validating the register, there's no harm in performing the verification. + */ +static int +bhndb_pci_compat_setregwin(struct bhndb_pci_softc *sc, + const struct bhndb_regwin *rw, bhnd_addr_t addr) +{ + device_t parent; + int error; + + parent = sc->bhndb.parent_dev; + + if (rw->win_type != BHNDB_REGWIN_T_DYN) + return (ENODEV); + + for (u_int i = 0; i < BHNDB_PCI_BARCTRL_WRITE_RETRY; i++) { + if ((error = bhndb_pci_fast_setregwin(sc, rw, addr))) + return (error); + + if (pci_read_config(parent, rw->dyn.cfg_offset, 4) == addr) + return (0); + + DELAY(10); + } + + /* Unable to set window */ + return (ENODEV); +} + +/** + * A bcma(4)-only bhndb_set_window_addr implementation. + */ +static int +bhndb_pci_fast_setregwin(struct bhndb_pci_softc *sc, + const struct bhndb_regwin *rw, bhnd_addr_t addr) +{ + device_t parent = sc->bhndb.parent_dev; + + /* The PCI bridge core only supports 32-bit addressing, regardless + * of the bus' support for 64-bit addressing */ + if (addr > UINT32_MAX) + return (ERANGE); + + switch (rw->win_type) { + case BHNDB_REGWIN_T_DYN: + /* Addresses must be page aligned */ + if (addr % rw->win_size != 0) + return (EINVAL); + + pci_write_config(parent, rw->dyn.cfg_offset, addr, 4); + break; + default: + return (ENODEV); + } + + return (0); +} + + +/** + * Read a 32-bit PCIe TLP/DLLP/PLP protocol register. + * + * @param sc The bhndb_pci driver state. + * @param addr The protocol register offset. + */ +static uint32_t +bhndb_pcie_read_proto_reg(struct bhndb_pci_softc *sc, uint32_t addr) +{ + uint32_t val; + + KASSERT(bhnd_get_class(sc->bhndb.hostb_dev) == BHND_DEVCLASS_PCIE, + ("not a pcie device!")); + + BHNDB_LOCK(&sc->bhndb); + BHNDB_PCI_WRITE_4(sc, BHND_PCIE_IND_ADDR, addr); + val = BHNDB_PCI_READ_4(sc, BHND_PCIE_IND_DATA); + BHNDB_UNLOCK(&sc->bhndb); + + return (val); +} + +/** + * Write a 32-bit PCIe TLP/DLLP/PLP protocol register value. + * + * @param sc The bhndb_pci driver state. + * @param addr The protocol register offset. + * @param val The value to write to @p addr. + */ +static void +bhndb_pcie_write_proto_reg(struct bhndb_pci_softc *sc, uint32_t addr, + uint32_t val) +{ + KASSERT(bhnd_get_class(sc->bhndb.hostb_dev) == BHND_DEVCLASS_PCIE, + ("not a pcie device!")); + + BHNDB_LOCK(&sc->bhndb); + BHNDB_PCI_WRITE_4(sc, BHND_PCIE_IND_ADDR, addr); + BHNDB_PCI_WRITE_4(sc, BHND_PCIE_IND_DATA, val); + BHNDB_UNLOCK(&sc->bhndb); +} + + +/** + * Enable externally managed clocks. + * + * Quirk Required: EXT_CLOCK_GATING + * + * @param sc Bridge driver state. + */ +static int +bhndb_enable_pci_clocks(struct bhndb_pci_softc *sc) +{ + device_t pci_parent; + uint32_t gpio_in, gpio_out, gpio_en; + uint32_t gpio_flags; + uint16_t pci_status; + + BHNDB_PCI_ASSERT_QUIRK(sc, EXT_CLOCK_GATING); + + pci_parent = device_get_parent(sc->dev); + + /* Read state of XTAL pin */ + gpio_in = pci_read_config(pci_parent, BHNDB_PCI_GPIO_IN, 4); + if (gpio_in & BHNDB_PCI_GPIO_XTAL_ON) + return (0); /* already enabled */ + + /* Fetch current config */ + gpio_out = pci_read_config(pci_parent, BHNDB_PCI_GPIO_OUT, 4); + gpio_en = pci_read_config(pci_parent, BHNDB_PCI_GPIO_OUTEN, 4); + + /* Set PLL_OFF/XTAL_ON pins to HIGH and enable both pins */ + gpio_flags = (BHNDB_PCI_GPIO_PLL_OFF|BHNDB_PCI_GPIO_XTAL_ON); + gpio_out |= gpio_flags; + gpio_en |= gpio_flags; + + pci_write_config(pci_parent, BHNDB_PCI_GPIO_OUT, gpio_out, 4); + pci_write_config(pci_parent, BHNDB_PCI_GPIO_OUTEN, gpio_en, 4); + DELAY(1000); + + /* Reset PLL_OFF */ + gpio_out &= ~BHNDB_PCI_GPIO_PLL_OFF; + pci_write_config(pci_parent, BHNDB_PCI_GPIO_OUT, gpio_out, 4); + DELAY(5000); + + /* Clear any PCI 'sent target-abort' flag. */ + pci_status = pci_read_config(pci_parent, PCIR_STATUS, 2); + pci_status &= ~PCIM_STATUS_STABORT; + pci_write_config(pci_parent, PCIR_STATUS, pci_status, 2); + + return (0); +} + +/** + * Disable externally managed clocks. + * + * Quirk Required: EXT_CLOCK_GATING + * + * @param sc Bridge driver state. + */ +static int +bhndb_disable_pci_clocks(struct bhndb_pci_softc *sc) +{ + device_t parent_dev; + uint32_t gpio_out, gpio_en; + + BHNDB_PCI_ASSERT_QUIRK(sc, EXT_CLOCK_GATING); + + parent_dev = device_get_parent(sc->dev); + + // TODO: Check board flags for BFL2_XTALBUFOUTEN? + // TODO: Check PCI core revision? + // TODO: Switch to 'slow' clock? + + /* Fetch current config */ + gpio_out = pci_read_config(parent_dev, BHNDB_PCI_GPIO_OUT, 4); + gpio_en = pci_read_config(parent_dev, BHNDB_PCI_GPIO_OUTEN, 4); + + /* Set PLL_OFF to HIGH, XTAL_ON to LOW. */ + gpio_out &= ~BHNDB_PCI_GPIO_XTAL_ON; + gpio_out |= BHNDB_PCI_GPIO_PLL_OFF; + pci_write_config(parent_dev, BHNDB_PCI_GPIO_OUT, gpio_out, 4); + + /* Enable both output pins */ + gpio_en |= (BHNDB_PCI_GPIO_PLL_OFF|BHNDB_PCI_GPIO_XTAL_ON); + pci_write_config(parent_dev, BHNDB_PCI_GPIO_OUTEN, gpio_en, 4); + + return (0); +} + + +/** + * Find the identification table entry for a core descriptor. + * + * @param sc bhndb PCI driver state. + */ +static const struct bhndb_pci_id * +bhndb_pci_find_core_id(struct bhnd_core_info *core) +{ + const struct bhndb_pci_id *id; + + for (id = bhndb_pci_ids; id->device != BHND_COREID_INVALID; id++) { + if (core->vendor == BHND_MFGID_BCM && + core->device == id->device) + return (id); + } + + return (NULL); +} + +/** + * Return all quirks known to be applicable to the host bridge. + * + * If the PCI bridge core has not yet been identified, no core-specific + * quirk flags will be returned. This function may be called again to + * rediscover applicable quirks after the host bridge core has been + * identified. + * + * @param sc bhndb PCI driver state. + * @param id The host bridge core's identification table entry, or NULL + * if the host bridge core has not yet been identified. + * + * @return Returns the set of quirks applicable to the current hardware. + */ +static uint32_t +bhndb_pci_discover_quirks(struct bhndb_pci_softc *sc, + const struct bhndb_pci_id *id) +{ + struct bhnd_device_quirk *qt; + uint32_t quirks; + uint8_t hwrev; + + quirks = BHNDB_PCI_QUIRK_NONE; + + /* Determine any device class-specific quirks */ + switch (sc->pci_devclass) { + case BHND_DEVCLASS_PCI: + /* All PCI devices require external clock gating */ + sc->quirks |= BHNDB_PCI_QUIRK_EXT_CLOCK_GATING; + break; + default: + break; + } + + // TODO: Additional quirk matching + + /* Determine any PCI core hwrev-specific device quirks */ + if (id != NULL) { + hwrev = bhnd_get_hwrev(sc->bhndb.hostb_dev); + for (qt = id->quirks; qt->quirks != 0; qt++) { + if (bhnd_hwrev_matches(hwrev, &qt->hwrev)) + quirks |= qt->quirks; + }; + } + + + return (quirks); +} + +/* + * Support for attaching the PCIe-Gen1 MDIO driver to a parent bhndb PCIe + * bridge device. + */ +static int +bhndb_mdio_pcie_probe(device_t dev) +{ + struct bhndb_softc *psc; + device_t parent; + + /* Parent must be a bhndb_pcie instance */ + parent = device_get_parent(dev); + if (device_get_driver(parent) != &bhndb_pci_driver) + return (ENXIO); + + /* Parent must have PCIe-Gen1 hostb device */ + psc = device_get_softc(parent); + if (psc->hostb_dev == NULL) + return (ENXIO); + + if (bhnd_get_vendor(psc->hostb_dev) != BHND_MFGID_BCM || + bhnd_get_device(psc->hostb_dev) != BHND_COREID_PCIE) + { + return (ENXIO); + } + + device_quiet(dev); + return (BUS_PROBE_NOWILDCARD); +} + +static int +bhndb_mdio_pcie_attach(device_t dev) +{ + struct bhndb_pci_softc *psc; + + psc = device_get_softc(device_get_parent(dev)); + + return (bhnd_mdio_pcie_attach(dev, + &psc->bhnd_mem_res, -1, + psc->mem_off + BHND_PCIE_MDIO_CTL, + (psc->quirks & BHNDB_PCIE_QUIRK_SD_C22_EXTADDR) != 0)); + + return (ENXIO); +} + +static device_method_t bhnd_mdio_pcie_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, bhndb_mdio_pcie_probe), + DEVMETHOD(device_attach, bhndb_mdio_pcie_attach), + DEVMETHOD_END +}; + +static device_method_t bhndb_pci_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, bhndb_pci_probe), + DEVMETHOD(device_attach, bhndb_pci_attach), + DEVMETHOD(device_detach, bhndb_pci_detach), + DEVMETHOD(device_suspend, bhndb_pci_suspend), + DEVMETHOD(device_resume, bhndb_pci_resume), + + /* BHNDB interface */ + DEVMETHOD(bhndb_init_full_config, bhndb_pci_init_full_config), + DEVMETHOD(bhndb_set_window_addr, bhndb_pci_set_window_addr), + + DEVMETHOD_END +}; + +DEFINE_CLASS_1(bhndb, bhndb_pci_driver, bhndb_pci_methods, + sizeof(struct bhndb_pci_softc), bhndb_driver); + +DEFINE_CLASS_1(bhnd_mdio_pci, bhndb_mdio_pcie_driver, bhnd_mdio_pcie_methods, + sizeof(struct bhnd_mdio_pcie_softc), bhnd_mdio_pcie_driver); + +DRIVER_MODULE(bhnd_mdio_pcie, bhndb, bhndb_mdio_pcie_driver, + bhnd_mdio_pci_devclass, NULL, NULL); + +MODULE_VERSION(bhndb_pci, 1); +MODULE_DEPEND(bhndb_pci, bhnd_pci, 1, 1, 1); +MODULE_DEPEND(bhndb_pci, pci, 1, 1, 1); +MODULE_DEPEND(bhndb_pci, bhndb, 1, 1, 1); diff --git a/sys/dev/bhnd/bhndb/bhndb_pci_hwdata.c b/sys/dev/bhnd/bhndb/bhndb_pci_hwdata.c new file mode 100644 index 000000000000..0ebb2cb8f7c4 --- /dev/null +++ b/sys/dev/bhnd/bhndb/bhndb_pci_hwdata.c @@ -0,0 +1,616 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * Resource specifications and register maps for Broadcom PCI/PCIe cores + * configured as PCI-BHND bridges. + */ + +#include +#include + +#include +#include +#include + +#include +#include + +#include "bhndbvar.h" +#include "bhndb_pcireg.h" + +static const struct bhndb_hwcfg bhndb_pci_hwcfg_v0; +static const struct bhndb_hwcfg bhndb_pci_hwcfg_v1_pci; +static const struct bhndb_hwcfg bhndb_pci_hwcfg_v1_pcie; +static const struct bhndb_hwcfg bhndb_pci_hwcfg_v2; +static const struct bhndb_hwcfg bhndb_pci_hwcfg_v3; + +/** + * Define a bhndb_hw match entry. + * + * @param _name The entry name. + * @param _vers The configuration version associated with this entry. + */ +#define BHNDB_HW_MATCH(_name, _vers, ...) { \ + .name = _name, \ + .hw_reqs = _BHNDB_HW_REQ_ARRAY(__VA_ARGS__), \ + .num_hw_reqs = (sizeof(_BHNDB_HW_REQ_ARRAY(__VA_ARGS__)) / \ + sizeof(_BHNDB_HW_REQ_ARRAY(__VA_ARGS__)[0])), \ + .cfg = &bhndb_pci_hwcfg_ ## _vers \ +} + +#define _BHNDB_HW_REQ_ARRAY(...) (struct bhnd_core_match[]) { __VA_ARGS__ } + +/** + * Generic PCI-SIBA bridge configuration usable with all known siba(4)-based + * PCI devices; this configuration is adequate for enumerating a bridged + * siba(4) bus to determine the full hardware configuration. + * + * @par Compatibility + * - Compatible with PCI_V0, PCI_V1, PCI_V2, and PCI_V3 devices. + * - Compatible with siba(4) bus enumeration. + * - Compatible with bcma(4) bus enumeration if the ChipCommon core is mapped + * at the default enumeration address (0x18000000). + */ +const struct bhndb_hwcfg bhndb_pci_siba_generic_hwcfg = { + .resource_specs = (const struct resource_spec[]) { + { SYS_RES_MEMORY, PCIR_BAR(0), RF_ACTIVE }, + { -1, 0, 0 } + }, + + .register_windows = (const struct bhndb_regwin[]) { + /* bar0+0x0000: configurable backplane window */ + { + .win_type = BHNDB_REGWIN_T_DYN, + .win_offset = BHNDB_PCI_V1_BAR0_WIN0_OFFSET, + .win_size = BHNDB_PCI_V1_BAR0_WIN0_SIZE, + .dyn.cfg_offset = BHNDB_PCI_V1_BAR0_WIN0_CONTROL, + .res = { SYS_RES_MEMORY, PCIR_BAR(0) } + }, + BHNDB_REGWIN_TABLE_END + }, +}; + + +/** + * Generic PCI-BCMA bridge configuration usable with all known bcma(4)-based + * PCI devices; this configuration is adequate for enumerating a bridged + * bcma(4) bus to determine the full hardware configuration. + * + * @par Compatibility + * - Compatible with PCI_V1, PCI_V2, and PCI_V3 devices. + * - Compatible with both siba(4) and bcma(4) bus enumeration. + */ +const struct bhndb_hwcfg bhndb_pci_bcma_generic_hwcfg = { + .resource_specs = (const struct resource_spec[]) { + { SYS_RES_MEMORY, PCIR_BAR(0), RF_ACTIVE }, + { -1, 0, 0 } + }, + + .register_windows = (const struct bhndb_regwin[]) { + /* bar0+0x0000: configurable backplane window */ + { + .win_type = BHNDB_REGWIN_T_DYN, + .win_offset = BHNDB_PCI_V1_BAR0_WIN0_OFFSET, + .win_size = BHNDB_PCI_V1_BAR0_WIN0_SIZE, + .dyn.cfg_offset = BHNDB_PCI_V1_BAR0_WIN0_CONTROL, + .res = { SYS_RES_MEMORY, PCIR_BAR(0) } + }, + + /* bar0+0x3000: chipc core registers */ + { + .win_type = BHNDB_REGWIN_T_CORE, + .win_offset = BHNDB_PCI_V1_BAR0_CCREGS_OFFSET, + .win_size = BHNDB_PCI_V1_BAR0_CCREGS_SIZE, + .core = { + .class = BHND_DEVCLASS_CC, + .unit = 0, + .port = 0, + .region = 0, + .port_type = BHND_PORT_DEVICE + }, + .res = { SYS_RES_MEMORY, PCIR_BAR(0) } + }, + + BHNDB_REGWIN_TABLE_END + }, +}; + +/** + * Hardware configuration tables for Broadcom HND PCI NICs. + */ +const struct bhndb_hw bhndb_pci_generic_hw_table[] = { + /* PCI/V0 WLAN */ + BHNDB_HW_MATCH("PCI/v0 WLAN", v0, + /* PCI Core */ + { + .vendor = BHND_MFGID_BCM, + .device = BHND_COREID_PCI, + .hwrev = { + .start = 0, + .end = BHNDB_PCI_V0_MAX_PCI_HWREV + }, + .class = BHND_DEVCLASS_PCI, + .unit = 0 + }, + + /* 802.11 Core */ + { + .vendor = BHND_MFGID_BCM, + .device = BHND_COREID_INVALID, + .hwrev = { + .start = 0, + .end = BHND_HWREV_INVALID + }, + .class = BHND_DEVCLASS_WLAN, + .unit = 0 + } + ), + + /* PCI/V1 WLAN */ + BHNDB_HW_MATCH("PCI/v1 WLAN", v1_pci, + /* PCI Core */ + { + .vendor = BHND_MFGID_BCM, + .device = BHND_COREID_PCI, + .hwrev = { + .start = BHNDB_PCI_V1_MIN_PCI_HWREV, + .end = BHND_HWREV_INVALID + }, + .class = BHND_DEVCLASS_PCI, + .unit = 0 + }, + + /* 802.11 Core */ + { + .vendor = BHND_MFGID_BCM, + .device = BHND_COREID_INVALID, + .hwrev = { + .start = 0, + .end = BHND_HWREV_INVALID + }, + .class = BHND_DEVCLASS_WLAN, + .unit = 0 + } + ), + + /* PCIE/V1 WLAN */ + BHNDB_HW_MATCH("PCIe/v1 WLAN", v1_pcie, + /* PCIe Core */ + { + .vendor = BHND_MFGID_BCM, + .device = BHND_COREID_PCIE, + .hwrev = { + .start = 0, + .end = BHND_HWREV_INVALID + }, + .class = BHND_DEVCLASS_PCIE, + .unit = 0 + }, + + /* ChipCommon (revision <= 31) */ + { + .vendor = BHND_MFGID_BCM, + .device = BHND_COREID_CC, + .hwrev = { + .start = 0, + .end = BHNDB_PCI_V1_MAX_CHIPC_HWREV + }, + .class = BHND_DEVCLASS_CC, + .unit = 0 + }, + + /* 802.11 Core */ + { + .vendor = BHND_MFGID_BCM, + .device = BHND_COREID_INVALID, + .hwrev = { + .start = 0, + .end = BHND_HWREV_INVALID + }, + .class = BHND_DEVCLASS_WLAN, + .unit = 0 + } + ), + + /* PCIE/V2 WLAN */ + BHNDB_HW_MATCH("PCIe/v2 WLAN", v2, + /* PCIe Core */ + { + .vendor = BHND_MFGID_BCM, + .device = BHND_COREID_PCIE, + .hwrev = { 0, BHND_HWREV_INVALID }, + .class = BHND_DEVCLASS_PCIE, + .unit = 0 + }, + + /* ChipCommon (revision >= 32) */ + { + .vendor = BHND_MFGID_BCM, + .device = BHND_COREID_CC, + .hwrev = { + .start = BHNDB_PCI_V2_MIN_CHIPC_HWREV, + .end = BHND_HWREV_INVALID + }, + .class = BHND_DEVCLASS_CC, + .unit = 0 + }, + + /* 802.11 Core */ + { + .vendor = BHND_MFGID_BCM, + .device = BHND_COREID_INVALID, + .hwrev = { + .start = 0, + .end = BHND_HWREV_INVALID + }, + .class = BHND_DEVCLASS_WLAN, + .unit = 0 + } + ), + + + /* PCIE/V3 WLAN */ + BHNDB_HW_MATCH("PCIe-Gen2/v3 WLAN", v3, + /* PCIe Gen2 Core */ + { + .vendor = BHND_MFGID_BCM, + .device = BHND_COREID_PCIE2, + .hwrev = { + .start = 0, + .end = BHND_HWREV_INVALID + }, + .class = BHND_DEVCLASS_PCIE, + .unit = 0 + }, + + /* 802.11 Core */ + { + .vendor = BHND_MFGID_BCM, + .device = BHND_COREID_INVALID, + .hwrev = { + .start = 0, + .end = BHND_HWREV_INVALID + }, + .class = BHND_DEVCLASS_WLAN, + .unit = 0 + } + ), + + { NULL, NULL, 0, NULL } +}; + +/** + * PCI_V0 hardware configuration. + * + * Applies to: + * - PCI (cid=0x804, revision <= 12) + */ +static const struct bhndb_hwcfg bhndb_pci_hwcfg_v0 = { + .resource_specs = (const struct resource_spec[]) { + { SYS_RES_MEMORY, PCIR_BAR(0), RF_ACTIVE }, + { -1, 0, 0 } + }, + + .register_windows = (const struct bhndb_regwin[]) { + /* bar0+0x0000: configurable backplane window */ + { + .win_type = BHNDB_REGWIN_T_DYN, + .win_offset = BHNDB_PCI_V0_BAR0_WIN0_OFFSET, + .win_size = BHNDB_PCI_V0_BAR0_WIN0_SIZE, + .dyn.cfg_offset = BHNDB_PCI_V0_BAR0_WIN0_CONTROL, + .res = { SYS_RES_MEMORY, PCIR_BAR(0) } + }, + + /* bar0+0x1000: sprom shadow */ + { + .win_type = BHNDB_REGWIN_T_SPROM, + .win_offset = BHNDB_PCI_V0_BAR0_SPROM_OFFSET, + .win_size = BHNDB_PCI_V0_BAR0_SPROM_SIZE, + .res = { SYS_RES_MEMORY, PCIR_BAR(0) } + }, + + /* bar0+0x1800: pci core registers */ + { + .win_type = BHNDB_REGWIN_T_CORE, + .win_offset = BHNDB_PCI_V0_BAR0_PCIREG_OFFSET, + .win_size = BHNDB_PCI_V0_BAR0_PCIREG_SIZE, + .core = { + .class = BHND_DEVCLASS_PCI, + .unit = 0, + .port = 0, + .region = 0, + .port_type = BHND_PORT_DEVICE + }, + .res = { SYS_RES_MEMORY, PCIR_BAR(0) } + }, + BHNDB_REGWIN_TABLE_END + }, +}; + +/** + * PCI_V1 (PCI-only) hardware configuration (PCI version) + * + * Applies to: + * - PCI (cid=0x804, revision >= 13) + */ +static const struct bhndb_hwcfg bhndb_pci_hwcfg_v1_pci = { + .resource_specs = (const struct resource_spec[]) { + { SYS_RES_MEMORY, PCIR_BAR(0), RF_ACTIVE }, + { -1, 0, 0 } + }, + + .register_windows = (const struct bhndb_regwin[]) { + /* bar0+0x0000: configurable backplane window */ + { + .win_type = BHNDB_REGWIN_T_DYN, + .win_offset = BHNDB_PCI_V1_BAR0_WIN0_OFFSET, + .win_size = BHNDB_PCI_V1_BAR0_WIN0_SIZE, + .dyn.cfg_offset = BHNDB_PCI_V1_BAR0_WIN0_CONTROL, + .res = { SYS_RES_MEMORY, PCIR_BAR(0) } + }, + + /* bar0+0x1000: sprom shadow */ + { + .win_type = BHNDB_REGWIN_T_SPROM, + .win_offset = BHNDB_PCI_V1_BAR0_SPROM_OFFSET, + .win_size = BHNDB_PCI_V1_BAR0_SPROM_SIZE, + .res = { SYS_RES_MEMORY, PCIR_BAR(0) } + }, + + /* bar0+0x2000: pci core registers */ + { + .win_type = BHNDB_REGWIN_T_CORE, + .win_offset = BHNDB_PCI_V1_BAR0_PCIREG_OFFSET, + .win_size = BHNDB_PCI_V1_BAR0_PCIREG_SIZE, + .core = { + .class = BHND_DEVCLASS_PCI, + .unit = 0, + .port = 0, + .region = 0, + .port_type = BHND_PORT_DEVICE + }, + .res = { SYS_RES_MEMORY, PCIR_BAR(0) } + }, + + /* bar0+0x3000: chipc core registers */ + { + .win_type = BHNDB_REGWIN_T_CORE, + .win_offset = BHNDB_PCI_V1_BAR0_CCREGS_OFFSET, + .win_size = BHNDB_PCI_V1_BAR0_CCREGS_SIZE, + .core = { + .class = BHND_DEVCLASS_CC, + .unit = 0, + .port = 0, + .region = 0, + .port_type = BHND_PORT_DEVICE + }, + .res = { SYS_RES_MEMORY, PCIR_BAR(0) } + }, + + BHNDB_REGWIN_TABLE_END + }, +}; + +/** + * PCI_V1 hardware configuration (PCIE version). + * + * Applies to: + * - PCIE (cid=0x820) with ChipCommon (revision <= 31) + */ +static const struct bhndb_hwcfg bhndb_pci_hwcfg_v1_pcie = { + .resource_specs = (const struct resource_spec[]) { + { SYS_RES_MEMORY, PCIR_BAR(0), RF_ACTIVE }, + { -1, 0, 0 } + }, + + .register_windows = (const struct bhndb_regwin[]) { + /* bar0+0x0000: configurable backplane window */ + { + .win_type = BHNDB_REGWIN_T_DYN, + .win_offset = BHNDB_PCI_V1_BAR0_WIN0_OFFSET, + .win_size = BHNDB_PCI_V1_BAR0_WIN0_SIZE, + .dyn.cfg_offset = BHNDB_PCI_V1_BAR0_WIN0_CONTROL, + .res = { SYS_RES_MEMORY, PCIR_BAR(0) } + }, + + /* bar0+0x1000: sprom shadow */ + { + .win_type = BHNDB_REGWIN_T_SPROM, + .win_offset = BHNDB_PCI_V1_BAR0_SPROM_OFFSET, + .win_size = BHNDB_PCI_V1_BAR0_SPROM_SIZE, + .res = { SYS_RES_MEMORY, PCIR_BAR(0) } + }, + + /* bar0+0x2000: pci core registers */ + { + .win_type = BHNDB_REGWIN_T_CORE, + .win_offset = BHNDB_PCI_V1_BAR0_PCIREG_OFFSET, + .win_size = BHNDB_PCI_V1_BAR0_PCIREG_SIZE, + .core = { + .class = BHND_DEVCLASS_PCIE, + .unit = 0, + .port = 0, + .region = 0, + .port_type = BHND_PORT_DEVICE + }, + .res = { SYS_RES_MEMORY, PCIR_BAR(0) } + }, + + /* bar0+0x3000: chipc core registers */ + { + .win_type = BHNDB_REGWIN_T_CORE, + .win_offset = BHNDB_PCI_V1_BAR0_CCREGS_OFFSET, + .win_size = BHNDB_PCI_V1_BAR0_CCREGS_SIZE, + .core = { + .class = BHND_DEVCLASS_CC, + .unit = 0, + .port = 0, + .region = 0, + .port_type = BHND_PORT_DEVICE + }, + .res = { SYS_RES_MEMORY, PCIR_BAR(0) } + }, + + BHNDB_REGWIN_TABLE_END + }, +}; + +/** + * PCI_V2 hardware configuration. + * + * Applies to: + * - PCIE (cid=0x820) with ChipCommon (revision >= 32) + */ +static const struct bhndb_hwcfg bhndb_pci_hwcfg_v2 = { + .resource_specs = (const struct resource_spec[]) { + { SYS_RES_MEMORY, PCIR_BAR(0), RF_ACTIVE }, + { -1, 0, 0 } + }, + + .register_windows = (const struct bhndb_regwin[]) { + /* bar0+0x0000: configurable backplane window */ + { + .win_type = BHNDB_REGWIN_T_DYN, + .win_offset = BHNDB_PCI_V2_BAR0_WIN0_OFFSET, + .win_size = BHNDB_PCI_V2_BAR0_WIN0_SIZE, + .dyn.cfg_offset = BHNDB_PCI_V2_BAR0_WIN0_CONTROL, + .res = { SYS_RES_MEMORY, PCIR_BAR(0) } + }, + + /* bar0+0x1000: configurable backplane window */ + { + .win_type = BHNDB_REGWIN_T_DYN, + .win_offset = BHNDB_PCI_V2_BAR0_WIN1_OFFSET, + .win_size = BHNDB_PCI_V2_BAR0_WIN1_SIZE, + .dyn.cfg_offset = BHNDB_PCI_V2_BAR0_WIN1_CONTROL, + .res = { SYS_RES_MEMORY, PCIR_BAR(0) } + }, + + /* bar0+0x2000: pcie core registers */ + { + .win_type = BHNDB_REGWIN_T_CORE, + .win_offset = BHNDB_PCI_V2_BAR0_PCIREG_OFFSET, + .win_size = BHNDB_PCI_V2_BAR0_PCIREG_SIZE, + .core = { + .class = BHND_DEVCLASS_PCIE, + .unit = 0, + .port = 0, + .region = 0, + .port_type = BHND_PORT_DEVICE + }, + .res = { SYS_RES_MEMORY, PCIR_BAR(0) } + }, + + /* bar0+0x3000: chipc core registers */ + { + .win_type = BHNDB_REGWIN_T_CORE, + .win_offset = BHNDB_PCI_V2_BAR0_CCREGS_OFFSET, + .win_size = BHNDB_PCI_V2_BAR0_CCREGS_SIZE, + .core = { + .class = BHND_DEVCLASS_CC, + .unit = 0, + .port = 0, + .region = 0, + .port_type = BHND_PORT_DEVICE + }, + .res = { SYS_RES_MEMORY, PCIR_BAR(0) } + }, + + BHNDB_REGWIN_TABLE_END + }, +}; + +/** + * PCI_V3 hardware configuration. + * + * Applies to: + * - PCIE2 (cid=0x83c) + */ +static const struct bhndb_hwcfg bhndb_pci_hwcfg_v3 = { + .resource_specs = (const struct resource_spec[]) { + { SYS_RES_MEMORY, PCIR_BAR(0), RF_ACTIVE }, + { -1, 0, 0 } + }, + + .register_windows = (const struct bhndb_regwin[]) { + /* bar0+0x0000: configurable backplane window */ + { + .win_type = BHNDB_REGWIN_T_DYN, + .win_offset = BHNDB_PCI_V3_BAR0_WIN0_OFFSET, + .win_size = BHNDB_PCI_V3_BAR0_WIN0_SIZE, + .dyn.cfg_offset = BHNDB_PCI_V3_BAR0_WIN0_CONTROL, + .res = { SYS_RES_MEMORY, PCIR_BAR(0) } + }, + + /* bar0+0x1000: configurable backplane window */ + { + .win_type = BHNDB_REGWIN_T_DYN, + .win_offset = BHNDB_PCI_V3_BAR0_WIN1_OFFSET, + .win_size = BHNDB_PCI_V3_BAR0_WIN1_SIZE, + .dyn.cfg_offset = BHNDB_PCI_V3_BAR0_WIN1_CONTROL, + .res = { SYS_RES_MEMORY, PCIR_BAR(0) } + }, + + /* bar0+0x2000: pcie core registers */ + { + .win_type = BHNDB_REGWIN_T_CORE, + .win_offset = BHNDB_PCI_V3_BAR0_PCIREG_OFFSET, + .win_size = BHNDB_PCI_V3_BAR0_PCIREG_SIZE, + .core = { + .class = BHND_DEVCLASS_PCIE, + .unit = 0, + .port = 0, + .region = 0, + .port_type = BHND_PORT_DEVICE + }, + .res = { SYS_RES_MEMORY, PCIR_BAR(0) } + }, + + /* bar0+0x3000: chipc core registers */ + { + .win_type = BHNDB_REGWIN_T_CORE, + .win_offset = BHNDB_PCI_V3_BAR0_CCREGS_OFFSET, + .win_size = BHNDB_PCI_V3_BAR0_CCREGS_SIZE, + .core = { + .class = BHND_DEVCLASS_CC, + .unit = 0, + .port = 0, + .region = 0, + .port_type = BHND_PORT_DEVICE + }, + .res = { SYS_RES_MEMORY, PCIR_BAR(0) } + }, + + BHNDB_REGWIN_TABLE_END + }, +}; diff --git a/sys/dev/bhnd/bhndb/bhndb_pci_hwdata.h b/sys/dev/bhnd/bhndb/bhndb_pci_hwdata.h new file mode 100644 index 000000000000..68d03b70099c --- /dev/null +++ b/sys/dev/bhnd/bhndb/bhndb_pci_hwdata.h @@ -0,0 +1,42 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $FreeBSD$ + */ + +#ifndef _BHND_BHNDB_PCI_HWDATA_H_ +#define _BHND_BHNDB_PCI_HWDATA_H_ + +#include "bhndb.h" + +extern struct bhndb_hw bhndb_pci_generic_hw_table[]; + +extern const struct bhndb_hwcfg bhndb_pci_bcma_generic_hwcfg; +extern const struct bhndb_hwcfg bhndb_pci_siba_generic_hwcfg; + +#endif /* _BHND_BHNDB_PCI_HWDATA_H_ */ \ No newline at end of file diff --git a/sys/dev/bhnd/bhndb/bhndb_pcireg.h b/sys/dev/bhnd/bhndb/bhndb_pcireg.h new file mode 100644 index 000000000000..6f431acdcc3c --- /dev/null +++ b/sys/dev/bhnd/bhndb/bhndb_pcireg.h @@ -0,0 +1,223 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * Copyright (c) 2010 Broadcom Corporation + * + * Portions of this file were derived from the bcmdevs.h header contributed by + * Broadcom to Android's bcmdhd driver module, and the pcicfg.h header + * distributed with Broadcom's initial brcm80211 Linux driver release. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef _BHND_BHNDB_PCIREG_H_ +#define _BHND_BHNDB_PCIREG_H_ + +/* + * Common PCI/PCIE Bridge Configuration Registers. + * + * = MAJOR CORE REVISIONS = + * + * There have been four revisions to the BAR0/BAR1 memory mappings used + * in BHND PCI/PCIE bridge cores: + * + * == PCI_V0 == + * Applies to: + * - PCI (cid=0x804, revision <= 12) + * BAR size: 8KB + * Address Map: + * [offset+ size] type description + * [0x0000+0x1000] dynamic mapped backplane address space (window 0). + * [0x1000+0x0800] fixed SPROM shadow + * [0x1800+0x0800] fixed pci core registers + * + * == PCI_V1 == + * Applies to: + * - PCI (cid=0x804, revision >= 13) + * - PCIE (cid=0x820) with ChipCommon (revision <= 31) + * BAR size: 16KB + * Address Map: + * [offset+ size] type description + * [0x0000+0x1000] dynamic mapped backplane address space (window 0). + * [0x1000+0x1000] fixed SPROM shadow + * [0x2000+0x1000] fixed pci/pcie core registers + * [0x3000+0x1000] fixed chipcommon core registers + * + * == PCI_V2 == + * Applies to: + * - PCIE (cid=0x820) with ChipCommon (revision >= 32) + * BAR size: 16KB + * Address Map: + * [offset+ size] type description + * [0x0000+0x1000] dynamic mapped backplane address space (window 0). + * [0x1000+0x1000] dynamic mapped backplane address space (window 1). + * [0x2000+0x1000] fixed pci/pcie core registers + * [0x3000+0x1000] fixed chipcommon core registers + * + * == PCI_V3 == + * Applies to: + * - PCIE Gen 2 (cid=0x83c) + * BAR size: 32KB? + * Address Map: + * [offset+ size] type description + * [0x0000+0x1000] dynamic mapped backplane address space (window 0). + * [0x1000+0x1000] dynamic mapped backplane address space (window 1). + * [0x2000+0x1000] fixed pci/pcie core registers + * [0x3000+0x1000] fixed chipcommon core registers + * [???] + * + * = MINOR CORE REVISIONS = + * + * == PCI Cores Revision >= 3 == + * - Mapped GPIO CSRs into the PCI config space. Refer to + * BHND_PCI_GPIO_*. + * + * == PCI/PCIE Cores Revision >= 14 == + * - Mapped the clock CSR into the PCI config space. Refer to + * BHND_PCI_CLK_CTL_ST + * + * = Hardware Bugs = + * == BAR1 == + * + * The BHND PCI(e) cores hypothetically support an additional memory mapping + * of the backplane address space via BAR1, but this appears to be subject + * to a hardware bug in which BAR1 is initially configured with a 4 byte + * length. + * + * A work-around for this bug may be possible by writing to the PCI core's + * BAR1 config register (0x4e0), but this requires further research -- I've + * found three sources for information on the BAR1 PCI core configuration that + * may be relevant: + * - The QLogix NetXTreme 10GB PCIe NIC seems to use the same PCIE + * core IP block as is used in other BHND devices. The bxe(4) driver + * contains example initialization code and register constants + * that may apply (e.g. GRC_BAR2_CONFIG/PCI_CONFIG_2_BAR2_SIZE). + * - The publicly available Broadcom BCM440X data sheet (440X-PG02-R) + * appears to (partially) document a Broadcom PCI(e) core that has a + * seemingly compatible programming model. + * - The Android bcmdhd driver sources include a possible work-around + * implementation (writing to 0x4e0) in dhd_pcie.c + */ + +/* Common PCI/PCIE Config Registers */ +#define BHNDB_PCI_SPROM_CONTROL 0x88 /* sprom property control */ +#define BHNDB_PCI_BAR1_CONTROL 0x8c /* BAR1 region prefetch/burst control */ +#define BHNDB_PCI_INT_STATUS 0x90 /* PCI and other cores interrupts */ +#define BHNDB_PCI_INT_MASK 0x94 /* mask of PCI and other cores interrupts */ +#define BHNDB_PCI_TO_SB_MB 0x98 /* signal backplane interrupts */ +#define BHNDB_PCI_BACKPLANE_ADDR 0xa0 /* address an arbitrary location on the system backplane */ +#define BHNDB_PCI_BACKPLANE_DATA 0xa4 /* data at the location specified by above address */ + +/* PCI (non-PCIe) GPIO/Clock Config Registers */ +#define BHNDB_PCI_CLK_CTL 0xa8 /* clock control/status (pci >=rev14) */ +#define BHNDB_PCI_GPIO_IN 0xb0 /* gpio input (pci >=rev3) */ +#define BHNDB_PCI_GPIO_OUT 0xb4 /* gpio output (pci >=rev3) */ +#define BHNDB_PCI_GPIO_OUTEN 0xb8 /* gpio output enable (pci >=rev3) */ + +/* Hardware revisions used to determine PCI revision */ +#define BHNDB_PCI_V0_MAX_PCI_HWREV 12 +#define BHNDB_PCI_V1_MIN_PCI_HWREV 13 +#define BHNDB_PCI_V1_MAX_CHIPC_HWREV 31 +#define BHNDB_PCI_V2_MIN_CHIPC_HWREV 32 + +/** + * Number of times to retry writing to a PCI window address register. + * + * On siba(4) devices, it's possible that writing a PCI window register may + * not succeed; it's necessary to immediately read the configuration register + * and retry if not set to the desired value. + */ +#define BHNDB_PCI_BARCTRL_WRITE_RETRY 50 + +/* PCI_V0 */ +#define BHNDB_PCI_V0_BAR0_WIN0_CONTROL 0x80 /* backplane address space accessed by BAR0/WIN0 */ +#define BHNDB_PCI_V0_BAR1_WIN0_CONTROL 0x84 /* backplane address space accessed by BAR1/WIN0. */ + +#define BHNDB_PCI_V0_BAR0_SIZE 0x2000 /* 8KB BAR0 */ +#define BHNDB_PCI_V0_BAR0_WIN0_OFFSET 0x0 /* bar0 + 0x0 accesses configurable 4K region of backplane address space */ +#define BHNDB_PCI_V0_BAR0_WIN0_SIZE 0x1000 +#define BHNDB_PCI_V0_BAR0_SPROM_OFFSET 0x1000 /* bar0 + 4K accesses sprom shadow (in pci core) */ +#define BHNDB_PCI_V0_BAR0_SPROM_SIZE 0x0800 +#define BHNDB_PCI_V0_BAR0_PCIREG_OFFSET 0x1800 /* bar0 + 6K accesses pci core registers */ +#define BHNDB_PCI_V0_BAR0_PCIREG_SIZE 0x0800 + +/* PCI_V1 */ +#define BHNDB_PCI_V1_BAR0_WIN0_CONTROL 0x80 /* backplane address space accessed by BAR0/WIN0 */ +#define BHNDB_PCI_V1_BAR1_WIN0_CONTROL 0x84 /* backplane address space accessed by BAR1/WIN0. */ + +#define BHNDB_PCI_V1_BAR0_SIZE 0x4000 /* 16KB BAR0 */ +#define BHNDB_PCI_V1_BAR0_WIN0_OFFSET 0x0 /* bar0 + 0x0 accesses configurable 4K region of backplane address space */ +#define BHNDB_PCI_V1_BAR0_WIN0_SIZE 0x1000 +#define BHNDB_PCI_V1_BAR0_SPROM_OFFSET 0x1000 /* bar0 + 4K accesses sprom shadow (in pci core) */ +#define BHNDB_PCI_V1_BAR0_SPROM_SIZE 0x1000 +#define BHNDB_PCI_V1_BAR0_PCIREG_OFFSET 0x2000 /* bar0 + 8K accesses pci/pcie core registers */ +#define BHNDB_PCI_V1_BAR0_PCIREG_SIZE 0x1000 +#define BHNDB_PCI_V1_BAR0_CCREGS_OFFSET 0x3000 /* bar0 + 12K accesses chipc core registers */ +#define BHNDB_PCI_V1_BAR0_CCREGS_SIZE 0x1000 + +/* PCI_V2 */ +#define BHNDB_PCI_V2_BAR0_WIN0_CONTROL 0x80 /* backplane address space accessed by BAR0/WIN0 */ +#define BHNDB_PCI_V2_BAR1_WIN0_CONTROL 0x84 /* backplane address space accessed by BAR1/WIN0. */ +#define BHNDB_PCI_V2_BAR0_WIN1_CONTROL 0xAC /* backplane address space accessed by BAR0/WIN1 */ + +#define BHNDB_PCI_V2_BAR0_SIZE 0x4000 /* 16KB BAR0 */ +#define BHNDB_PCI_V2_BAR0_WIN0_OFFSET 0x0 /* bar0 + 0x0 accesses configurable 4K region of backplane address space */ +#define BHNDB_PCI_V2_BAR0_WIN0_SIZE 0x1000 +#define BHNDB_PCI_V2_BAR0_WIN1_OFFSET 0x1000 /* bar0 + 4K accesses second 4K window */ +#define BHNDB_PCI_V2_BAR0_WIN1_SIZE 0x1000 +#define BHNDB_PCI_V2_BAR0_PCIREG_OFFSET 0x2000 /* bar0 + 8K accesses pci/pcie core registers */ +#define BHNDB_PCI_V2_BAR0_PCIREG_SIZE 0x1000 +#define BHNDB_PCI_V2_BAR0_CCREGS_OFFSET 0x3000 /* bar0 + 12K accesses chipc core registers */ +#define BHNDB_PCI_V2_BAR0_CCREGS_SIZE 0x1000 + +/* PCI_V3 */ +#define BHNDB_PCI_V3_BAR0_WIN0_CONTROL 0x80 /* backplane address space accessed by BAR0/WIN0 */ +#define BHNDB_PCI_V3_BAR1_WIN0_CONTROL 0x84 /* backplane address space accessed by BAR1/WIN0. */ +#define BHNDB_PCI_V3_BAR0_WIN1_CONTROL 0x70 /* backplane address space accessed by BAR0/WIN1 */ + +#define BHNDB_PCI_V3_BAR0_SIZE 0x8000 /* 32KB BAR0 (?) */ +#define BHNDB_PCI_V3_BAR0_WIN0_OFFSET 0x0 /* bar0 + 0x0 accesses configurable 4K region of backplane address space */ +#define BHNDB_PCI_V3_BAR0_WIN0_SIZE 0x1000 +#define BHNDB_PCI_V3_BAR0_WIN1_OFFSET 0x1000 /* bar0 + 4K accesses second 4K window */ +#define BHNDB_PCI_V3_BAR0_WIN1_SIZE 0x1000 +#define BHNDB_PCI_V3_BAR0_PCIREG_OFFSET 0x2000 /* bar0 + 8K accesses pci/pcie core registers */ +#define BHNDB_PCI_V3_BAR0_PCIREG_SIZE 0x1000 +#define BHNDB_PCI_V3_BAR0_CCREGS_OFFSET 0x3000 /* bar0 + 12K accesses chipc core registers */ +#define BHNDB_PCI_V3_BAR0_CCREGS_SIZE 0x1000 + +/* BHNDB_PCI_INT_STATUS */ +#define BHNDB_PCI_SBIM_STATUS_SERR 0x4 /* backplane SBErr interrupt status */ + +/* BHNDB_PCI_INT_MASK */ +#define BHNDB_PCI_SBIM_SHIFT 8 /* backplane core interrupt mask bits offset */ +#define BHNDB_PCI_SBIM_MASK 0xff00 /* backplane core interrupt mask */ +#define BHNDB_PCI_SBIM_MASK_SERR 0x4 /* backplane SBErr interrupt mask */ + +/* BHNDB_PCI_SPROM_CONTROL */ +#define BHNDB_PCI_SPROM_SZ_MSK 0x02 /* SPROM Size Mask */ +#define BHNDB_PCI_SPROM_LOCKED 0x08 /* SPROM Locked */ +#define BHNDB_PCI_SPROM_BLANK 0x04 /* indicating a blank SPROM */ +#define BHNDB_PCI_SPROM_WRITEEN 0x10 /* SPROM write enable */ +#define BHNDB_PCI_SPROM_BOOTROM_WE 0x20 /* external bootrom write enable */ +#define BHNDB_PCI_SPROM_BACKPLANE_EN 0x40 /* Enable indirect backplane access */ +#define BHNDB_PCI_SPROM_OTPIN_USE 0x80 /* device OTP In use */ + + +/* PCI (non-PCIe) BHNDB_PCI_GPIO_OUTEN */ +#define BHNDB_PCI_GPIO_SCS 0x10 /* PCI config space bit 4 for 4306c0 slow clock source */ +#define BHNDB_PCI_GPIO_HWRAD_OFF 0x20 /* PCI config space GPIO 13 for hw radio disable */ +#define BHNDB_PCI_GPIO_XTAL_ON 0x40 /* PCI config space GPIO 14 for Xtal power-up */ +#define BHNDB_PCI_GPIO_PLL_OFF 0x80 /* PCI config space GPIO 15 for PLL power-down */ + +#endif /* _BHND_BHNDB_PCIREG_H_ */ diff --git a/sys/dev/bhnd/bhndb/bhndb_pcivar.h b/sys/dev/bhnd/bhndb/bhndb_pcivar.h new file mode 100644 index 000000000000..0549bcc8fee4 --- /dev/null +++ b/sys/dev/bhnd/bhndb/bhndb_pcivar.h @@ -0,0 +1,251 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $FreeBSD$ + */ + +#ifndef _BHND_BHNDB_PCIVAR_H_ +#define _BHND_BHNDB_PCIVAR_H_ + +#include + +#include + +#include "bhndbvar.h" + +/* + * bhndb(4) PCI driver subclass. + */ + +DECLARE_CLASS(bhndb_pci_driver); + +struct bhndb_pci_softc; + +/* + * An interconnect-specific function implementing BHNDB_SET_WINDOW_ADDR + */ +typedef int (*bhndb_pci_set_regwin_t)(struct bhndb_pci_softc *sc, + const struct bhndb_regwin *rw, bhnd_addr_t addr); + + +/** + * PCI bridge core identification table. + */ +struct bhndb_pci_id { + uint16_t device; /**< bhnd device ID */ + bhnd_pci_regfmt_t regfmt; /**< register format */ + struct bhnd_device_quirk *quirks; /**< quirks table */ +}; + +struct bhndb_pci_softc { + struct bhndb_softc bhndb; /**< parent softc */ + device_t dev; /**< bridge device */ + bhnd_devclass_t pci_devclass; /**< PCI core's devclass */ + bhndb_pci_set_regwin_t set_regwin; /**< regwin handler */ + + /* + * Initialized in BHNDB_INIT_FULL_CONFIG() + */ + + device_t mdio; /**< PCIe MDIO device. NULL if not PCIe. */ + bhnd_pci_regfmt_t regfmt; /**< device register format */ + + struct resource *mem_res; /**< pci core's registers (borrowed reference) */ + bus_size_t mem_off; /**< offset to the PCI core's registers within `mem_res` . */ + + struct bhnd_resource bhnd_mem_res; /**< bhnd resource representation of mem_res. + this is a simple 'direct' resource mapping */ + + uint32_t quirks; /**< BHNDB_PCI(E)_QUIRK flags */ + + /** + * Driver state specific to BHNDB_PCIE_QUIRK_SDR9_POLARITY. + */ + struct { + /** + * PCIe SerDes RX polarity. + * + * Initialized to the PCIe link's RX polarity + * at attach time. This is used to restore the + * correct polarity on resume */ + bool inv; + } sdr9_quirk_polarity; +}; + +/* Declare a bhndb_pci_id entry */ +#define BHNDB_PCI_ID(_device, _desc, ...) { \ + BHND_COREID_ ## _device, \ + BHND_PCI_REGFMT_ ## _device, \ + (struct bhnd_device_quirk[]) { \ + __VA_ARGS__ \ + } \ +} + +/* + * PCI/PCIe-Gen1 endpoint-mode device quirks + */ +enum { + /** No quirks */ + BHNDB_PCI_QUIRK_NONE = 0, + + /** + * BCM4306 chips (and possibly others) do not support the idle + * low-power clock. Clocking must be bootstrapped at attach/resume by + * directly adjusting GPIO registers exposed in the PCI config space, + * and correspondingly, explicitly shutdown at detach/suspend. + */ + BHNDB_PCI_QUIRK_EXT_CLOCK_GATING = (1<<1), + + /** + * SBTOPCI_PREF and SBTOPCI_BURST must be set on the + * SSB_PCICORE_SBTOPCI2 register. + */ + BHNDB_PCI_QUIRK_SBTOPCI2_PREF_BURST = (1<<2), + + /** + * SBTOPCI_RC_READMULTI must be set on the SSB_PCICORE_SBTOPCI2 + * register. + */ + BHNDB_PCI_QUIRK_SBTOPCI2_READMULTI = (1<<3), + + /** + * Interrupt masking is handled via the interconnect configuration + * registers (SBINTVEC on siba), rather than the PCI_INT_MASK + * config register. + */ + BHNDB_PCI_QUIRK_SBINTVEC = (1<<4), + + /** + * PCI CLKRUN# should be disabled on attach (via CLKRUN_DSBL). + * + * The purpose of this work-around is unclear; there is some + * documentation regarding earlier Broadcom drivers supporting + * a "force CLKRUN#" *enable* registry key for use on mobile + * hardware. + */ + BHNDB_PCI_QUIRK_CLKRUN_DSBL = (1<<5), + + /** + * TLP workaround for unmatched address handling is required. + * + * This TLP workaround will enable setting of the PCIe UR status bit + * on memory access to an unmatched address. + */ + BHNDB_PCIE_QUIRK_UR_STATUS_FIX = (1<<6), + + /** + * PCI-PM power management must be explicitly enabled via + * the data link control register. + */ + BHNDB_PCIE_QUIRK_PCIPM_REQEN = (1<<7), + + /** + * Fix L0s to L0 exit transition on SerDes <= rev9 devices. + * + * On these devices, PCIe/SerDes symbol lock can be lost if the + * reference clock has not fully stabilized during the L0s to L0 + * exit transition, triggering an internal reset of the chip. + * + * The SerDes RX CDR phase lock timers and proportional/integral + * filters must be tweaked to ensure the CDR has fully stabilized + * before asserting receive sequencer completion. + */ + BHNDB_PCIE_QUIRK_SDR9_L0s_HANG = (1<<8), + + /** + * The idle time for entering L1 low-power state must be + * explicitly set (to 114ns) to fix slow L1->L0 transition issues. + */ + BHNDB_PCIE_QUIRK_L1_IDLE_THRESH = (1<<9), + + /** + * The ASPM L1 entry timer should be extended for better performance, + * and restored for better power savings. + */ + BHNDB_PCIE_QUIRK_L1_TIMER_PERF = (1<<10), + + /** + * ASPM and ECPM settings must be overridden manually. + * + * The override behavior is controlled by the BHND_BFL2_PCIEWAR_OVR + * flag. If this flag is set, ASPM/CLKREQ should be overridden as + * enabled; otherwise, they should be overridden as disabled. + * + * Attach/Resume: + * - Set SRSH_ASPM_ENB flag in the SPROM ASPM register. + * - Set ASPM L0S/L1 in the PCIER_LINK_CTL register. + * - Set SRSH_CLKREQ_ENB flag in the SPROM CLKREQ_REV5 register. + * - Clear ECPM in the PCIER_LINK_CTL register. + * + * Detach/Suspend: + * - + * - When the device enters D3 state, or system enters S3/S4 state, + * clear ASPM L1 in the PCIER_LINK_CTL register. + */ + BHNDB_PCIE_QUIRK_ASPM_OVR = (1<<11), + + /** + * Fix SerDes polarity on SerDes <= rev9 devices. + * + * The SerDes polarity must be saved at device attachment, and + * restored on suspend/resume. + */ + BHNDB_PCIE_QUIRK_SDR9_POLARITY = (1<<12), + + /** + * The SerDes PLL override flag (CHIPCTRL_4321_PLL_DOWN) must be set on + * the ChipCommon core on resume. + */ + BHNDB_PCIE_QUIRK_SERDES_NOPLLDOWN = (1<<13), + + /** + * On attach and resume, consult the SPROM to determine whether + * the L2/L3-Ready w/o PCI RESET work-around must be applied. + * + * If L23READY_EXIT_NOPRST is not already set in the SPROM, set it + */ + BHNDB_PCIE_QUIRK_SPROM_L23_PCI_RESET = (1<<14), + + /** + * The PCIe SerDes supports non-standard extended MDIO register access. + * + * The PCIe SerDes supports access to extended MDIO registers via + * a non-standard Clause 22 address extension mechanism. + */ + BHNDB_PCIE_QUIRK_SD_C22_EXTADDR = (1<<15), + + /** + * The PCIe SerDes PLL must be configured to not retry the startup + * sequence upon frequency detection failure on SerDes <= rev9 devices + * + * The issue this workaround resolves has not be determined. + */ + BHNDB_PCIE_QUIRK_SDR9_NO_FREQRETRY = (1<<16), +}; + +#endif /* _BHND_BHNDB_PCIVAR_H_ */ \ No newline at end of file diff --git a/sys/dev/bhnd/bhndb/bhndb_private.h b/sys/dev/bhnd/bhndb/bhndb_private.h new file mode 100644 index 000000000000..c5dc2ff6137b --- /dev/null +++ b/sys/dev/bhnd/bhndb/bhndb_private.h @@ -0,0 +1,239 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $FreeBSD$ + */ + +#ifndef _BHND_BHNDB_PRIVATE_H_ +#define _BHND_BHNDB_PRIVATE_H_ + +#include +#include +#include + +#include +#include +#include + +#include "bhndbvar.h" + +/* + * Private bhndb(4) driver definitions. + */ + +struct bhndb_dw_alloc; +struct bhndb_region; +struct bhndb_resources; + +struct resource *bhndb_find_regwin_resource( + struct bhndb_resources *br, + const struct bhndb_regwin *win); + +struct bhndb_resources *bhndb_alloc_resources(device_t dev, + device_t parent_dev, + const struct bhndb_hwcfg *cfg); + +void bhndb_free_resources( + struct bhndb_resources *br); + +int bhndb_add_resource_region( + struct bhndb_resources *br, + bhnd_addr_t addr, bhnd_size_t size, + bhndb_priority_t priority, + const struct bhndb_regwin *static_regwin); + +struct bhndb_region *bhndb_find_resource_region( + struct bhndb_resources *br, + bhnd_addr_t addr, bhnd_size_t size); + +struct bhndb_dw_alloc *bhndb_dw_find_resource( + struct bhndb_resources *dr, + struct resource *r); + +struct bhndb_dw_alloc *bhndb_dw_find_mapping( + struct bhndb_resources *br, + bhnd_addr_t addr, bhnd_size_t size); + +int bhndb_dw_retain( + struct bhndb_resources *br, + struct bhndb_dw_alloc *dwa, + struct resource *res); + +void bhndb_dw_release( + struct bhndb_resources *br, + struct bhndb_dw_alloc *dwa, + struct resource *res); + +int bhndb_dw_set_addr(device_t dev, + struct bhndb_resources *br, + struct bhndb_dw_alloc *dwa, + bus_addr_t addr, bus_size_t size); + +size_t bhndb_regwin_count( + const struct bhndb_regwin *table, + bhndb_regwin_type_t type); + +const struct bhndb_regwin *bhndb_regwin_find_type( + const struct bhndb_regwin *table, + bhndb_regwin_type_t type, + bus_size_t min_size); + +const struct bhndb_regwin *bhndb_regwin_find_core( + const struct bhndb_regwin *table, + bhnd_devclass_t class, int unit, + bhnd_port_type port_type, u_int port, + u_int region); + + +const struct bhndb_regwin *bhndb_regwin_find_best( + const struct bhndb_regwin *table, + bhnd_devclass_t class, int unit, + bhnd_port_type port_type, u_int port, + u_int region, bus_size_t min_size); + +bool bhndb_regwin_matches_device( + const struct bhndb_regwin *regw, + device_t dev); + +const struct bhndb_hw_priority *bhndb_hw_priority_find_device( + const struct bhndb_hw_priority *table, + device_t device); + + +/** + * Dynamic register window allocation reference. + */ +struct bhndb_dw_rentry { + struct resource *dw_res; /**< child resource */ + LIST_ENTRY(bhndb_dw_rentry) dw_link; +}; + +/** + * A dynamic register window allocation record. + */ +struct bhndb_dw_alloc { + const struct bhndb_regwin *win; /**< window definition */ + struct resource *parent_res; /**< enclosing resource */ + u_int rnid; /**< region identifier */ + rman_res_t target; /**< the current window address, or 0x0 if unknown */ + + LIST_HEAD(, bhndb_dw_rentry) refs; /**< references */ +}; + +/** + * A bus address region description. + */ +struct bhndb_region { + bhnd_addr_t addr; /**< start of mapped range */ + bhnd_size_t size; /**< size of mapped range */ + bhndb_priority_t priority; /**< direct resource allocation priority */ + const struct bhndb_regwin *static_regwin; /**< fixed mapping regwin, if any */ + + STAILQ_ENTRY(bhndb_region) link; +}; + +/** + * BHNDB resource allocation state. + */ +struct bhndb_resources { + device_t dev; /**< bridge device */ + const struct bhndb_hwcfg *cfg; /**< hardware configuration */ + + device_t parent_dev; /**< parent device */ + struct resource_spec *res_spec; /**< parent bus resource specs */ + struct resource **res; /**< parent bus resources */ + + STAILQ_HEAD(, bhndb_region) bus_regions; /**< bus region descriptors */ + + struct bhndb_dw_alloc *dw_alloc; /**< dynamic window allocation records */ + size_t dwa_count; /**< number of dynamic windows available. */ + uint32_t dwa_freelist; /**< dynamic window free list */ + bhndb_priority_t min_prio; /**< minimum resource priority required to + allocate a dynamic window */ +}; + +/** + * Returns true if the all dynamic windows have been exhausted, false + * otherwise. + * + * @param br The resource state to check. + */ +static inline bool +bhndb_dw_exhausted(struct bhndb_resources *br) +{ + return (br->dwa_freelist == 0); +} + +/** + * Find the next free dynamic window region in @p br. + * + * @param br The resource state to search. + */ +static inline struct bhndb_dw_alloc * +bhndb_dw_next_free(struct bhndb_resources *br) +{ + struct bhndb_dw_alloc *dw_free; + + if (bhndb_dw_exhausted(br)) + return (NULL); + + dw_free = &br->dw_alloc[__builtin_ctz(br->dwa_freelist)]; + + KASSERT(LIST_EMPTY(&dw_free->refs), + ("free list out of sync with refs")); + + return (dw_free); +} + +/** + * Returns true if a dynamic window allocation is marked as free. + * + * @param br The resource state owning @p dwa. + * @param dwa The dynamic window allocation record to be checked. + */ +static inline bool +bhndb_dw_is_free(struct bhndb_resources *br, struct bhndb_dw_alloc *dwa) +{ + bool is_free = LIST_EMPTY(&dwa->refs); + + KASSERT(is_free == ((br->dwa_freelist & (1 << dwa->rnid)) != 0), + ("refs out of sync with free list")); + + return (is_free); +} + + +#define BHNDB_LOCK_INIT(sc) \ + mtx_init(&(sc)->sc_mtx, device_get_nameunit((sc)->dev), \ + "bhndb resource allocator lock", MTX_DEF) +#define BHNDB_LOCK(sc) mtx_lock(&(sc)->sc_mtx) +#define BHNDB_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) +#define BHNDB_LOCK_ASSERT(sc, what) mtx_assert(&(sc)->sc_mtx, what) +#define BHNDB_LOCK_DESTROY(sc) mtx_destroy(&(sc)->sc_mtx) + +#endif /* _BHND_BHNDB_PRIVATE_H_ */ diff --git a/sys/dev/bhnd/bhndb/bhndb_subr.c b/sys/dev/bhnd/bhndb/bhndb_subr.c new file mode 100644 index 000000000000..932b4cc4cae2 --- /dev/null +++ b/sys/dev/bhnd/bhndb/bhndb_subr.c @@ -0,0 +1,889 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include + +#include "bhndb_private.h" +#include "bhndbvar.h" + +/** + * Attach a BHND bridge device to @p parent. + * + * @param parent A parent PCI device. + * @param[out] bhndb On success, the probed and attached bhndb bridge device. + * @param unit The device unit number, or -1 to select the next available unit + * number. + * + * @retval 0 success + * @retval non-zero Failed to attach the bhndb device. + */ +int +bhndb_attach_bridge(device_t parent, device_t *bhndb, int unit) +{ + int error; + + *bhndb = device_add_child(parent, devclass_get_name(bhndb_devclass), + unit); + if (*bhndb == NULL) + return (ENXIO); + + if (!(error = device_probe_and_attach(*bhndb))) + return (0); + + if ((device_delete_child(parent, *bhndb))) + device_printf(parent, "failed to detach bhndb child\n"); + + return (error); +} + +/* + * Call BHNDB_SUSPEND_RESOURCE() for all resources in @p rl. + */ +static void +bhndb_do_suspend_resources(device_t dev, struct resource_list *rl) +{ + struct resource_list_entry *rle; + + /* Suspend all child resources. */ + STAILQ_FOREACH(rle, rl, link) { + /* Skip non-allocated resources */ + if (rle->res == NULL) + continue; + + BHNDB_SUSPEND_RESOURCE(device_get_parent(dev), dev, rle->type, + rle->res); + } +} + +/** + * Helper function for implementing BUS_RESUME_CHILD() on bridged + * bhnd(4) buses. + * + * This implementation of BUS_RESUME_CHILD() uses BUS_GET_RESOURCE_LIST() + * to find the child's resources and call BHNDB_SUSPEND_RESOURCE() for all + * child resources, ensuring that the device's allocated bridge resources + * will be available to other devices during bus resumption. + * + * Before suspending any resources, @p child is suspended by + * calling bhnd_generic_suspend_child(). + * + * If @p child is not a direct child of @p dev, suspension is delegated to + * the @p dev parent. + */ +int +bhnd_generic_br_suspend_child(device_t dev, device_t child) +{ + struct resource_list *rl; + int error; + + if (device_get_parent(child) != dev) + BUS_SUSPEND_CHILD(device_get_parent(dev), child); + + if (device_is_suspended(child)) + return (EBUSY); + + /* Suspend the child device */ + if ((error = bhnd_generic_suspend_child(dev, child))) + return (error); + + /* Fetch the resource list. If none, there's nothing else to do */ + rl = BUS_GET_RESOURCE_LIST(device_get_parent(child), child); + if (rl == NULL) + return (0); + + /* Suspend all child resources. */ + bhndb_do_suspend_resources(dev, rl); + + return (0); +} + +/** + * Helper function for implementing BUS_RESUME_CHILD() on bridged + * bhnd(4) bus devices. + * + * This implementation of BUS_RESUME_CHILD() uses BUS_GET_RESOURCE_LIST() + * to find the child's resources and call BHNDB_RESUME_RESOURCE() for all + * child resources, before delegating to bhnd_generic_resume_child(). + * + * If resource resumption fails, @p child will not be resumed. + * + * If @p child is not a direct child of @p dev, suspension is delegated to + * the @p dev parent. + */ +int +bhnd_generic_br_resume_child(device_t dev, device_t child) +{ + struct resource_list *rl; + struct resource_list_entry *rle; + int error; + + if (device_get_parent(child) != dev) + BUS_RESUME_CHILD(device_get_parent(dev), child); + + if (!device_is_suspended(child)) + return (EBUSY); + + /* Fetch the resource list. If none, there's nothing else to do */ + rl = BUS_GET_RESOURCE_LIST(device_get_parent(child), child); + if (rl == NULL) + return (bhnd_generic_resume_child(dev, child)); + + /* Resume all resources */ + STAILQ_FOREACH(rle, rl, link) { + /* Skip non-allocated resources */ + if (rle->res == NULL) + continue; + + error = BHNDB_RESUME_RESOURCE(device_get_parent(dev), dev, + rle->type, rle->res); + if (error) { + /* Put all resources back into a suspend state */ + bhndb_do_suspend_resources(dev, rl); + return (error); + } + } + + /* Now that all resources are resumed, resume child */ + if ((error = bhnd_generic_resume_child(dev, child))) { + /* Put all resources back into a suspend state */ + bhndb_do_suspend_resources(dev, rl); + } + + return (error); +} + +/** + * Find the resource containing @p win. + * + * @param br The bhndb resource state to search. + * @param win A register window. + * + * @retval resource the resource containing @p win. + * @retval NULL if no resource containing @p win can be found. + */ +struct resource * +bhndb_find_regwin_resource(struct bhndb_resources *br, + const struct bhndb_regwin *win) +{ + const struct resource_spec *rspecs; + + rspecs = br->cfg->resource_specs; + for (u_int i = 0; rspecs[i].type != -1; i++) { + if (win->res.type != rspecs[i].type) + continue; + + if (win->res.rid != rspecs[i].rid) + continue; + + /* Found declared resource */ + return (br->res[i]); + } + + device_printf(br->dev, + "missing regwin resource spec (type=%d, rid=%d)\n", + win->res.type, win->res.rid); + + return (NULL); +} + +/** + * Allocate and initialize a new resource state structure, allocating + * bus resources from @p parent_dev according to @p cfg. + * + * @param dev The bridge device. + * @param parent_dev The parent device from which resources will be allocated. + * @param cfg The hardware configuration to be used. + */ +struct bhndb_resources * +bhndb_alloc_resources(device_t dev, device_t parent_dev, + const struct bhndb_hwcfg *cfg) +{ + struct bhndb_resources *r; + const struct bhndb_regwin *win; + bus_size_t last_window_size; + size_t res_num; + u_int rnid; + int error; + bool free_parent_res; + + free_parent_res = false; + + r = malloc(sizeof(*r), M_BHND, M_NOWAIT|M_ZERO); + if (r == NULL) + return (NULL); + + /* Basic initialization */ + r->dev = dev; + r->parent_dev = parent_dev; + r->cfg = cfg; + r->min_prio = BHNDB_PRIORITY_NONE; + STAILQ_INIT(&r->bus_regions); + + /* Determine our bridge resource count from the hardware config. */ + res_num = 0; + for (size_t i = 0; cfg->resource_specs[i].type != -1; i++) + res_num++; + + /* Allocate space for a non-const copy of our resource_spec + * table; this will be updated with the RIDs assigned by + * bus_alloc_resources. */ + r->res_spec = malloc(sizeof(r->res_spec[0]) * (res_num + 1), M_BHND, + M_NOWAIT); + if (r->res_spec == NULL) + goto failed; + + /* Initialize and terminate the table */ + for (size_t i = 0; i < res_num; i++) + r->res_spec[i] = cfg->resource_specs[i]; + + r->res_spec[res_num].type = -1; + + /* Allocate space for our resource references */ + r->res = malloc(sizeof(r->res[0]) * res_num, M_BHND, M_NOWAIT); + if (r->res == NULL) + goto failed; + + /* Allocate resources */ + error = bus_alloc_resources(r->parent_dev, r->res_spec, r->res); + if (error) { + device_printf(r->dev, + "could not allocate bridge resources on %s: %d\n", + device_get_nameunit(r->parent_dev), error); + goto failed; + } else { + free_parent_res = true; + } + + /* Fetch the dynamic regwin count and verify that it does not exceed + * what is representable via our freelist bitmask. */ + r->dwa_count = bhndb_regwin_count(cfg->register_windows, + BHNDB_REGWIN_T_DYN); + if (r->dwa_count >= (8 * sizeof(r->dwa_freelist))) { + device_printf(r->dev, "max dynamic regwin count exceeded\n"); + goto failed; + } + + /* Allocate the dynamic window allocation table. */ + r->dw_alloc = malloc(sizeof(r->dw_alloc[0]) * r->dwa_count, M_BHND, + M_NOWAIT); + if (r->dw_alloc == NULL) + goto failed; + + /* Initialize the dynamic window table and freelist. */ + r->dwa_freelist = 0; + rnid = 0; + last_window_size = 0; + for (win = cfg->register_windows; + win->win_type != BHNDB_REGWIN_T_INVALID; win++) + { + struct bhndb_dw_alloc *dwa; + + /* Skip non-DYN windows */ + if (win->win_type != BHNDB_REGWIN_T_DYN) + continue; + + /* Validate the window size */ + if (win->win_size == 0) { + device_printf(r->dev, "ignoring zero-length dynamic " + "register window\n"); + continue; + } else if (last_window_size == 0) { + last_window_size = win->win_size; + } else if (last_window_size != win->win_size) { + /* + * No existing hardware should trigger this. + * + * If you run into this in the future, the dynamic + * window allocator and the resource priority system + * will need to be extended to support multiple register + * window allocation pools. + */ + device_printf(r->dev, "devices that vend multiple " + "dynamic register window sizes are not currently " + "supported\n"); + goto failed; + } + + dwa = &r->dw_alloc[rnid]; + dwa->win = win; + dwa->parent_res = NULL; + dwa->rnid = rnid; + dwa->target = 0x0; + + LIST_INIT(&dwa->refs); + + /* Find and validate corresponding resource. */ + dwa->parent_res = bhndb_find_regwin_resource(r, win); + if (dwa->parent_res == NULL) + goto failed; + + if (rman_get_size(dwa->parent_res) < win->win_offset + + win->win_size) + { + device_printf(r->dev, "resource %d too small for " + "register window with offset %llx and size %llx\n", + rman_get_rid(dwa->parent_res), + (unsigned long long) win->win_offset, + (unsigned long long) win->win_size); + + error = EINVAL; + goto failed; + } + + /* Add to freelist */ + r->dwa_freelist |= (1 << rnid); + + rnid++; + } + + return (r); + +failed: + if (free_parent_res) + bus_release_resources(r->parent_dev, r->res_spec, r->res); + + if (r->res != NULL) + free(r->res, M_BHND); + + if (r->res_spec != NULL) + free(r->res_spec, M_BHND); + + if (r->dw_alloc != NULL) + free(r->dw_alloc, M_BHND); + + free (r, M_BHND); + + return (NULL); +} + +/** + * Deallocate the given bridge resource structure and any associated resources. + * + * @param br Resource state to be deallocated. + */ +void +bhndb_free_resources(struct bhndb_resources *br) +{ + struct bhndb_region *region, *r_next; + struct bhndb_dw_alloc *dwa; + struct bhndb_dw_rentry *dwr, *dwr_next; + + /* No window regions may still be held */ + if (__builtin_popcount(br->dwa_freelist) != br->dwa_count) { + device_printf(br->dev, "leaked %llu dynamic register regions\n", + (unsigned long long) br->dwa_count - br->dwa_freelist); + } + + /* Release resources allocated through our parent. */ + bus_release_resources(br->parent_dev, br->res_spec, br->res); + + /* Clean up resource reservations */ + for (size_t i = 0; i < br->dwa_count; i++) { + dwa = &br->dw_alloc[i]; + + LIST_FOREACH_SAFE(dwr, &dwa->refs, dw_link, dwr_next) { + LIST_REMOVE(dwr, dw_link); + free(dwr, M_BHND); + } + } + + /* Release bus regions */ + STAILQ_FOREACH_SAFE(region, &br->bus_regions, link, r_next) { + STAILQ_REMOVE(&br->bus_regions, region, bhndb_region, link); + free(region, M_BHND); + } + + /* Free backing resource state structures */ + free(br->res, M_BHND); + free(br->res_spec, M_BHND); + free(br->dw_alloc, M_BHND); +} + +/** + * Add a bus region entry to @p r for the given base @p addr and @p size. + * + * @param br The resource state to which the bus region entry will be added. + * @param addr The base address of this region. + * @param size The size of this region. + * @param priority The resource priority to be assigned to allocations + * made within this bus region. + * @param static_regwin If available, a static register window mapping this + * bus region entry. If not available, NULL. + * + * @retval 0 success + * @retval non-zero if adding the bus region fails. + */ +int +bhndb_add_resource_region(struct bhndb_resources *br, bhnd_addr_t addr, + bhnd_size_t size, bhndb_priority_t priority, + const struct bhndb_regwin *static_regwin) +{ + struct bhndb_region *reg; + + /* Insert in the bus resource list */ + reg = malloc(sizeof(*reg), M_BHND, M_NOWAIT); + if (reg == NULL) + return (ENOMEM); + + *reg = (struct bhndb_region) { + .addr = addr, + .size = size, + .priority = priority, + .static_regwin = static_regwin + }; + + STAILQ_INSERT_HEAD(&br->bus_regions, reg, link); + + return (0); +} + +/** + * Find a bus region that maps @p size bytes at @p addr. + * + * @param br The resource state to search. + * @param addr The requested starting address. + * @param size The requested size. + * + * @retval bhndb_region A region that fully contains the requested range. + * @retval NULL If no mapping region can be found. + */ +struct bhndb_region * +bhndb_find_resource_region(struct bhndb_resources *br, bhnd_addr_t addr, + bhnd_size_t size) +{ + struct bhndb_region *region; + + STAILQ_FOREACH(region, &br->bus_regions, link) { + /* Request must fit within the region's mapping */ + if (addr < region->addr) + continue; + + if (addr + size > region->addr + region->size) + continue; + + return (region); + } + + /* Not found */ + return (NULL); +} + +/** + * Find the entry matching @p r in @p dwa's references, if any. + * + * @param dwa The dynamic window allocation to search + * @param r The resource to search for in @p dwa. + */ +static struct bhndb_dw_rentry * +bhndb_dw_find_resource_entry(struct bhndb_dw_alloc *dwa, struct resource *r) +{ + struct bhndb_dw_rentry *rentry; + + LIST_FOREACH(rentry, &dwa->refs, dw_link) { + struct resource *dw_res = rentry->dw_res; + + /* Match dev/rid/addr/size */ + if (rman_get_device(dw_res) != rman_get_device(r) || + rman_get_rid(dw_res) != rman_get_rid(r) || + rman_get_start(dw_res) != rman_get_start(r) || + rman_get_size(dw_res) != rman_get_size(r)) + { + continue; + } + + /* Matching allocation found */ + return (rentry); + } + + return (NULL); +} + +/** + * Find the dynamic region allocated for @p r, if any. + * + * @param br The resource state to search. + * @param r The resource to search for. + * + * @retval bhndb_dw_alloc The allocation record for @p r. + * @retval NULL if no dynamic window is allocated for @p r. + */ +struct bhndb_dw_alloc * +bhndb_dw_find_resource(struct bhndb_resources *br, struct resource *r) +{ + struct bhndb_dw_alloc *dwa; + + for (size_t i = 0; i < br->dwa_count; i++) { + dwa = &br->dw_alloc[i]; + + /* Skip free dynamic windows */ + if (bhndb_dw_is_free(br, dwa)) + continue; + + /* Matching allocation found? */ + if (bhndb_dw_find_resource_entry(dwa, r) != NULL) + return (dwa); + } + + return (NULL); +} + +/** + * Find an existing dynamic window mapping @p size bytes + * at @p addr. The window may or may not be free. + * + * @param br The resource state to search. + * @param addr The requested starting address. + * @param size The requested size. + * + * @retval bhndb_dw_alloc A window allocation that fully contains the requested + * range. + * @retval NULL If no mapping region can be found. + */ +struct bhndb_dw_alloc * +bhndb_dw_find_mapping(struct bhndb_resources *br, bhnd_addr_t addr, + bhnd_size_t size) +{ + struct bhndb_dw_alloc *dwr; + const struct bhndb_regwin *win; + + /* Search for an existing dynamic mapping of this address range. */ + for (size_t i = 0; i < br->dwa_count; i++) { + dwr = &br->dw_alloc[i]; + win = dwr->win; + + /* Verify the range */ + if (addr < dwr->target) + continue; + + if (addr + size > dwr->target + win->win_size) + continue; + + /* Found a usable mapping */ + return (dwr); + } + + /* not found */ + return (NULL); +} + +/** + * Retain a reference to @p dwa for use by @p res. + * + * @param br The resource state owning @p dwa. + * @param dwa The allocation record to be retained. + * @param res The resource that will own a reference to @p dwa. + * + * @retval 0 success + * @retval ENOMEM Failed to allocate a new reference structure. + */ +int +bhndb_dw_retain(struct bhndb_resources *br, struct bhndb_dw_alloc *dwa, + struct resource *res) +{ + struct bhndb_dw_rentry *rentry; + + KASSERT(bhndb_dw_find_resource_entry(dwa, res) == NULL, + ("double-retain of dynamic window for same resource")); + + /* Insert a reference entry; we use M_NOWAIT to allow use from + * within a non-sleepable lock */ + rentry = malloc(sizeof(*rentry), M_BHND, M_NOWAIT); + if (rentry == NULL) + return (ENOMEM); + + rentry->dw_res = res; + LIST_INSERT_HEAD(&dwa->refs, rentry, dw_link); + + /* Update the free list */ + br->dwa_freelist &= ~(1 << (dwa->rnid)); + + return (0); +} + +/** + * Release a reference to @p dwa previously retained by @p res. If the + * reference count of @p dwa reaches zero, it will be added to the + * free list. + * + * @param br The resource state owning @p dwa. + * @param dwa The allocation record to be released. + * @param res The resource that currently owns a reference to @p dwa. + */ +void +bhndb_dw_release(struct bhndb_resources *br, struct bhndb_dw_alloc *dwa, + struct resource *r) +{ + struct bhndb_dw_rentry *rentry; + + /* Find the rentry */ + rentry = bhndb_dw_find_resource_entry(dwa, r); + KASSERT(rentry != NULL, ("over release of resource entry")); + + LIST_REMOVE(rentry, dw_link); + free(rentry, M_BHND); + + /* If this was the last reference, update the free list */ + if (LIST_EMPTY(&dwa->refs)) + br->dwa_freelist |= (1 << (dwa->rnid)); +} + +/** + * Attempt to set (or reset) the target address of @p dwa to map @p size bytes + * at @p addr. + * + * This will apply any necessary window alignment and verify that + * the window is capable of mapping the requested range prior to modifying + * therecord. + * + * @param dev The device on which to issue the BHNDB_SET_WINDOW_ADDR() request. + * @param br The resource state owning @p dwa. + * @param dwa The allocation record to be configured. + * @param addr The address to be mapped via @p dwa. + * @param size The number of bytes to be mapped at @p addr. + * + * @retval 0 success + * @retval non-zero no usable register window available. + */ +int +bhndb_dw_set_addr(device_t dev, struct bhndb_resources *br, + struct bhndb_dw_alloc *dwa, bus_addr_t addr, bus_size_t size) +{ + const struct bhndb_regwin *rw; + bus_addr_t offset; + int error; + + rw = dwa->win; + + KASSERT(bhndb_dw_is_free(br, dwa), + ("attempting to set the target address on an in-use window")); + + /* Page-align the target address */ + offset = addr % rw->win_size; + dwa->target = addr - offset; + + /* Verify that the window is large enough for the full target */ + if (rw->win_size - offset < size) + return (ENOMEM); + + /* Update the window target */ + error = BHNDB_SET_WINDOW_ADDR(dev, dwa->win, dwa->target); + if (error) { + dwa->target = 0x0; + return (error); + } + + return (0); +} + +/** + * Return the count of @p type register windows in @p table. + * + * @param table The table to search. + * @param type The required window type, or BHNDB_REGWIN_T_INVALID to + * count all register window types. + */ +size_t +bhndb_regwin_count(const struct bhndb_regwin *table, + bhndb_regwin_type_t type) +{ + const struct bhndb_regwin *rw; + size_t count; + + count = 0; + for (rw = table; rw->win_type != BHNDB_REGWIN_T_INVALID; rw++) { + if (type == BHNDB_REGWIN_T_INVALID || rw->win_type == type) + count++; + } + + return (count); +} + +/** + * Search @p table for the first window with the given @p type. + * + * @param table The table to search. + * @param type The required window type. + * @param min_size The minimum window size. + * + * @retval bhndb_regwin The first matching window. + * @retval NULL If no window of the requested type could be found. + */ +const struct bhndb_regwin * +bhndb_regwin_find_type(const struct bhndb_regwin *table, + bhndb_regwin_type_t type, bus_size_t min_size) +{ + const struct bhndb_regwin *rw; + + for (rw = table; rw->win_type != BHNDB_REGWIN_T_INVALID; rw++) + { + if (rw->win_type == type && rw->win_size >= min_size) + return (rw); + } + + return (NULL); +} + +/** + * Search @p windows for the first matching core window. + * + * @param table The table to search. + * @param class The required core class. + * @param unit The required core unit, or -1. + * @param port_type The required port type. + * @param port The required port. + * @param region The required region. + * + * @retval bhndb_regwin The first matching window. + * @retval NULL If no matching window was found. + */ +const struct bhndb_regwin * +bhndb_regwin_find_core(const struct bhndb_regwin *table, bhnd_devclass_t class, + int unit, bhnd_port_type port_type, u_int port, u_int region) +{ + const struct bhndb_regwin *rw; + + for (rw = table; rw->win_type != BHNDB_REGWIN_T_INVALID; rw++) + { + if (rw->win_type != BHNDB_REGWIN_T_CORE) + continue; + + if (rw->core.class != class) + continue; + + if (unit != -1 && rw->core.unit != unit) + continue; + + if (rw->core.port_type != port_type) + continue; + + if (rw->core.port != port) + continue; + + if (rw->core.region != region) + continue; + + return (rw); + } + + return (NULL); +} + +/** + * Search @p windows for the best available window of at least @p min_size. + * + * Search order: + * - BHND_REGWIN_T_CORE + * - BHND_REGWIN_T_DYN + * + * @param table The table to search. + * @param class The required core class. + * @param unit The required core unit, or -1. + * @param port_type The required port type. + * @param port The required port. + * @param region The required region. + * @param min_size The minimum window size. + * + * @retval bhndb_regwin The first matching window. + * @retval NULL If no matching window was found. + */ +const struct bhndb_regwin * +bhndb_regwin_find_best(const struct bhndb_regwin *table, + bhnd_devclass_t class, int unit, bhnd_port_type port_type, u_int port, + u_int region, bus_size_t min_size) +{ + const struct bhndb_regwin *rw; + + /* Prefer a fixed core mapping */ + rw = bhndb_regwin_find_core(table, class, unit, port_type, + port, region); + if (rw != NULL) + return (rw); + + /* Fall back on a generic dynamic window */ + return (bhndb_regwin_find_type(table, BHNDB_REGWIN_T_DYN, min_size)); +} + +/** + * Return true if @p regw defines a static port register window, and + * the mapped port is actually defined on @p dev. + * + * @param regw A register window to match against. + * @param dev A bhnd(4) bus device. + */ +bool +bhndb_regwin_matches_device(const struct bhndb_regwin *regw, device_t dev) +{ + /* Only core windows are supported */ + if (regw->win_type != BHNDB_REGWIN_T_CORE) + return (false); + + /* Device class must match */ + if (bhnd_get_class(dev) != regw->core.class) + return (false); + + /* Device unit must match */ + if (bhnd_get_core_unit(dev) != regw->core.unit) + return (false); + + /* The regwin port/region must be defined. */ + if (!bhnd_is_region_valid(dev, regw->core.port_type, regw->core.port, + regw->core.region)) + { + return (false); + } + + /* Matches */ + return (true); +} + +/** + * Search for a core resource priority descriptor in @p table that matches + * @p device. + * + * @param table The table to search. + * @param device A bhnd(4) bus device. + */ +const struct bhndb_hw_priority * +bhndb_hw_priority_find_device(const struct bhndb_hw_priority *table, + device_t device) +{ + const struct bhndb_hw_priority *hp; + + for (hp = table; hp->ports != NULL; hp++) { + if (bhnd_device_matches(device, &hp->match)) + return (hp); + } + + /* not found */ + return (NULL); +} diff --git a/sys/dev/bhnd/bhndb/bhndbvar.h b/sys/dev/bhnd/bhndb/bhndbvar.h new file mode 100644 index 000000000000..f993e7ce76d3 --- /dev/null +++ b/sys/dev/bhnd/bhndb/bhndbvar.h @@ -0,0 +1,94 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $FreeBSD$ + */ + +#ifndef _BHND_BHNDBVAR_H_ +#define _BHND_BHNDBVAR_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include "bhndb.h" + +#include "bhndb_if.h" + +/* + * Definitions shared by bhndb(4) driver implementations. + */ + +DECLARE_CLASS(bhndb_driver); + +struct bhndb_resources; + +int bhndb_attach(device_t dev, bhnd_devclass_t bridge_devclass); + +int bhndb_generic_probe(device_t dev); +int bhndb_generic_detach(device_t dev); +int bhndb_generic_suspend(device_t dev); +int bhndb_generic_resume(device_t dev); +int bhndb_generic_init_full_config(device_t dev, device_t child, + const struct bhndb_hw_priority *hw_prio_table); + +int bhnd_generic_br_suspend_child(device_t dev, device_t child); +int bhnd_generic_br_resume_child(device_t dev, device_t child); + +/** bhndb child instance state */ +struct bhndb_devinfo { + struct resource_list resources; /**< child resources. */ +}; + +/** + * bhndb driver instance state. Must be first member of all subclass + * softc structures. + */ +struct bhndb_softc { + device_t dev; /**< bridge device */ + struct bhnd_chipid chipid; /**< chip identification */ + bhnd_devclass_t bridge_class; /**< bridge core type */ + + device_t parent_dev; /**< parent device */ + device_t bus_dev; /**< child bhnd(4) bus */ + device_t hostb_dev; /**< child host bridge device, or NULL + if the @p bus_dev has not yet + called BHNDB_INIT_FULL_CONFIG() */ + + struct rman mem_rman; /**< bridged bus memory manager */ + struct mtx sc_mtx; /**< resource lock. */ + + struct bhndb_resources *bus_res; /**< bus resource state */ +}; + +#endif /* _BHND_BHNDBVAR_H_ */ diff --git a/sys/dev/bhnd/bhndreg.h b/sys/dev/bhnd/bhndreg.h new file mode 100644 index 000000000000..6463d1b5f5a2 --- /dev/null +++ b/sys/dev/bhnd/bhndreg.h @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $FreeBSD$ + */ + +#ifndef _BHND_BHNDREG_H_ +#define _BHND_BHNDREG_H_ + +/** + * The default address at which the ChipCommon core is mapped on all siba(4) + * devices, and most bcma(4) devices. + */ +#define BHND_DEFAULT_CHIPC_ADDR 0x18000000 + +/** + * The standard size of a primary BHND_PORT_DEVICE or BHND_PORT_AGENT + * register block. + */ +#define BHND_DEFAULT_CORE_SIZE 0x1000 + + +#endif /* _BHND_BHNDREG_H_ */ \ No newline at end of file diff --git a/sys/dev/bhnd/bhndvar.h b/sys/dev/bhnd/bhndvar.h new file mode 100644 index 000000000000..4b18ba40b0eb --- /dev/null +++ b/sys/dev/bhnd/bhndvar.h @@ -0,0 +1,106 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $FreeBSD$ + */ + +#ifndef _BHND_BHNDVAR_H_ +#define _BHND_BHNDVAR_H_ + +#include +#include +#include + +#include "bhnd.h" + +/* + * Definitions shared by bhnd(4) bus and bhndb(4) bridge driver implementations. + */ + +MALLOC_DECLARE(M_BHND); +DECLARE_CLASS(bhnd_driver); + +/** + * bhnd driver instance state. Must be first member of all subclass + * softc structures. + */ +struct bhnd_softc {}; + + +int bhnd_generic_attach(device_t dev); +int bhnd_generic_detach(device_t dev); +int bhnd_generic_shutdown(device_t dev); +int bhnd_generic_resume(device_t dev); +int bhnd_generic_suspend(device_t dev); + +int bhnd_generic_get_probe_order(device_t dev, + device_t child); + +int bhnd_generic_print_child(device_t dev, + device_t child); +void bhnd_generic_probe_nomatch(device_t dev, + device_t child); + +int bhnd_generic_suspend_child(device_t dev, + device_t child); +int bhnd_generic_resume_child(device_t dev, + device_t child); + +bool bhnd_generic_is_hostb_device(device_t dev, + device_t child); +bool bhnd_generic_is_hw_disabled(device_t dev, + device_t child); +bool bhnd_generic_is_region_valid(device_t dev, + device_t child, bhnd_port_type type, u_int port, + u_int region); + +int bhnd_generic_read_nvram_var(device_t dev, + device_t child, const char *name, void *buf, + size_t *size); + +const struct bhnd_chipid *bhnd_generic_get_chipid(device_t dev, device_t child); + +struct bhnd_resource *bhnd_generic_alloc_bhnd_resource (device_t dev, + device_t child, int type, int *rid, + rman_res_t start, rman_res_t end, rman_res_t count, + u_int flags); + +int bhnd_generic_release_bhnd_resource (device_t dev, + device_t child, int type, int rid, + struct bhnd_resource *r); + +int bhnd_generic_activate_bhnd_resource (device_t dev, + device_t child, int type, int rid, + struct bhnd_resource *r); + +int bhnd_generic_deactivate_bhnd_resource (device_t dev, + device_t child, int type, int rid, + struct bhnd_resource *r); + + +#endif /* _BHND_BHNDVAR_H_ */ diff --git a/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m b/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m new file mode 100644 index 000000000000..0ecaba5b1987 --- /dev/null +++ b/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m @@ -0,0 +1,46 @@ +#- +# Copyright (c) 2016 Landon Fuller +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# $FreeBSD$ + +#include +#include + +#include +#include + +INTERFACE bhnd_chipc; + +# +# bhnd(4) ChipCommon interface. +# + +/** + * Return the preferred NVRAM data source. + * + * @param dev A bhnd(4) ChipCommon device. + */ +METHOD bhnd_nvram_src_t nvram_src { + device_t dev; +} \ No newline at end of file diff --git a/sys/dev/bhnd/cores/chipc/chipc.c b/sys/dev/bhnd/cores/chipc/chipc.c new file mode 100644 index 000000000000..f47a8f2bdc75 --- /dev/null +++ b/sys/dev/bhnd/cores/chipc/chipc.c @@ -0,0 +1,319 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * Broadcom ChipCommon driver. + * + * With the exception of some very early chipsets, the ChipCommon core + * has been included in all HND SoCs and chipsets based on the siba(4) + * and bcma(4) interconnects, providing a common interface to chipset + * identification, bus enumeration, UARTs, clocks, watchdog interrupts, GPIO, + * flash, etc. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "chipcreg.h" +#include "chipcvar.h" + +devclass_t bhnd_chipc_devclass; /**< bhnd(4) chipcommon device class */ + +static const struct resource_spec chipc_rspec[CHIPC_MAX_RSPEC] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { -1, -1, 0 } +}; + +/* Supported device identifiers */ +static const struct chipc_device { + uint16_t device; +} chipc_devices[] = { + { BHND_COREID_CC }, + { BHND_COREID_INVALID } +}; + +/* Device quirks table */ +static struct bhnd_device_quirk chipc_quirks[] = { + BHND_QUIRK_HWREV_RANGE (0, 21, CHIPC_QUIRK_ALWAYS_HAS_SPROM), + BHND_QUIRK_HWREV_EQ (22, CHIPC_QUIRK_SPROM_CHECK_CST_R22), + BHND_QUIRK_HWREV_RANGE (23, 31, CHIPC_QUIRK_SPROM_CHECK_CST_R23), + BHND_QUIRK_HWREV_GTE (35, CHIPC_QUIRK_SUPPORTS_NFLASH), + BHND_QUIRK_HWREV_END +}; + +/* quirk and capability flag convenience macros */ +#define CHIPC_QUIRK(_sc, _name) \ + ((_sc)->quirks & CHIPC_QUIRK_ ## _name) + +#define CHIPC_CAP(_sc, _name) \ + ((_sc)->caps & CHIPC_ ## _name) + +#define CHIPC_ASSERT_QUIRK(_sc, name) \ + KASSERT(CHIPC_QUIRK((_sc), name), ("quirk " __STRING(_name) " not set")) + +#define CHIPC_ASSERT_CAP(_sc, name) \ + KASSERT(CHIPC_CAP((_sc), name), ("capability " __STRING(_name) " not set")) + +static int +chipc_probe(device_t dev) +{ + const struct chipc_device *id; + + for (id = chipc_devices; id->device != BHND_COREID_INVALID; id++) + { + if (bhnd_get_vendor(dev) == BHND_MFGID_BCM && + bhnd_get_device(dev) == id->device) + { + bhnd_set_generic_core_desc(dev); + return (BUS_PROBE_DEFAULT); + } + } + + return (ENXIO); +} + +static int +chipc_attach(device_t dev) +{ + struct bhnd_device_quirk *dq; + struct chipc_softc *sc; + bhnd_addr_t enum_addr; + uint32_t ccid_reg; + uint8_t chip_type; + int error; + + sc = device_get_softc(dev); + sc->dev = dev; + + /* Allocate bus resources */ + memcpy(sc->rspec, chipc_rspec, sizeof(sc->rspec)); + if ((error = bhnd_alloc_resources(dev, sc->rspec, sc->res))) + return (error); + + sc->core = sc->res[0]; + + /* Fetch our chipset identification data */ + ccid_reg = bhnd_bus_read_4(sc->core, CHIPC_ID); + chip_type = CHIPC_GET_ATTR(ccid_reg, ID_BUS); + + switch (chip_type) { + case BHND_CHIPTYPE_SIBA: + /* enumeration space starts at the ChipCommon register base. */ + enum_addr = rman_get_start(sc->core->res); + break; + case BHND_CHIPTYPE_BCMA: + case BHND_CHIPTYPE_BCMA_ALT: + enum_addr = bhnd_bus_read_4(sc->core, CHIPC_EROMPTR); + break; + default: + device_printf(dev, "unsupported chip type %hhu\n", chip_type); + error = ENODEV; + goto cleanup; + } + + sc->ccid = bhnd_parse_chipid(ccid_reg, enum_addr); + + /* Fetch capability and status register values */ + sc->caps = bhnd_bus_read_4(sc->core, CHIPC_CAPABILITIES); + sc->cst = bhnd_bus_read_4(sc->core, CHIPC_CHIPST); + + /* Populate the set of applicable quirk flags */ + sc->quirks = 0; + for (dq = chipc_quirks; dq->quirks != 0; dq++) { + if (bhnd_hwrev_matches(bhnd_get_hwrev(dev), &dq->hwrev)) + sc->quirks |= dq->quirks; + }; + + // TODO + switch (bhnd_chipc_nvram_src(dev)) { + case BHND_NVRAM_SRC_CIS: + device_printf(dev, "NVRAM source: CIS\n"); + break; + case BHND_NVRAM_SRC_SPROM: + device_printf(dev, "NVRAM source: SPROM\n"); + break; + case BHND_NVRAM_SRC_OTP: + device_printf(dev, "NVRAM source: OTP\n"); + break; + case BHND_NVRAM_SRC_NFLASH: + device_printf(dev, "NVRAM source: NFLASH\n"); + break; + case BHND_NVRAM_SRC_NONE: + device_printf(dev, "NVRAM source: NONE\n"); + break; + } + + return (0); + +cleanup: + bhnd_release_resources(dev, sc->rspec, sc->res); + return (error); +} + +static int +chipc_detach(device_t dev) +{ + struct chipc_softc *sc; + + sc = device_get_softc(dev); + bhnd_release_resources(dev, sc->rspec, sc->res); + + return (0); +} + +static int +chipc_suspend(device_t dev) +{ + return (0); +} + +static int +chipc_resume(device_t dev) +{ + return (0); +} + +/** + * Use device-specific ChipStatus flags to determine the preferred NVRAM + * data source. + */ +static bhnd_nvram_src_t +chipc_nvram_src_chipst(struct chipc_softc *sc) +{ + uint8_t nvram_sel; + + CHIPC_ASSERT_QUIRK(sc, SPROM_CHECK_CHIPST); + + if (CHIPC_QUIRK(sc, SPROM_CHECK_CST_R22)) { + // TODO: On these devices, the official driver code always + // assumes SPROM availability if CHIPC_CST_OTP_SEL is not + // set; we must review against the actual behavior of our + // BCM4312 hardware + nvram_sel = CHIPC_GET_ATTR(sc->cst, CST_SPROM_OTP_SEL_R22); + } else if (CHIPC_QUIRK(sc, SPROM_CHECK_CST_R23)) { + nvram_sel = CHIPC_GET_ATTR(sc->cst, CST_SPROM_OTP_SEL_R23); + } else { + panic("invalid CST OTP/SPROM chipc quirk flags"); + } + device_printf(sc->dev, "querying chipst for 0x%x, 0x%x\n", sc->ccid.chip_id, sc->cst); + + switch (nvram_sel) { + case CHIPC_CST_DEFCIS_SEL: + return (BHND_NVRAM_SRC_CIS); + + case CHIPC_CST_SPROM_SEL: + case CHIPC_CST_OTP_PWRDN: + return (BHND_NVRAM_SRC_SPROM); + + case CHIPC_CST_OTP_SEL: + return (BHND_NVRAM_SRC_OTP); + + default: + device_printf(sc->dev, "unrecognized OTP/SPROM type 0x%hhx", + nvram_sel); + return (BHND_NVRAM_SRC_NONE); + } +} + +/** + * Determine the preferred NVRAM data source. + */ +static bhnd_nvram_src_t +chipc_nvram_src(device_t dev) +{ + struct chipc_softc *sc; + uint32_t srom_ctrl; + + sc = device_get_softc(dev); + + /* Very early devices always included a SPROM */ + if (CHIPC_QUIRK(sc, ALWAYS_HAS_SPROM)) + return (BHND_NVRAM_SRC_SPROM); + + /* Most other early devices require checking ChipStatus flags */ + if (CHIPC_QUIRK(sc, SPROM_CHECK_CHIPST)) + return (chipc_nvram_src_chipst(sc)); + + /* + * Later chipset revisions standardized the NVRAM capability flags and + * register interfaces. + * + * We check for hardware presence in order of precedence. For example, + * SPROM is is always used in preference to internal OTP if found. + */ + if (CHIPC_CAP(sc, CAP_SPROM)) { + srom_ctrl = bhnd_bus_read_4(sc->core, CHIPC_SPROM_CTRL); + if (srom_ctrl & CHIPC_SRC_PRESENT) + return (BHND_NVRAM_SRC_SPROM); + } + + /* Check for OTP */ + if (CHIPC_CAP(sc, CAP_OTP_SIZE)) + return (BHND_NVRAM_SRC_OTP); + + /* + * Finally, Northstar chipsets (and possibly other chipsets?) support + * external NAND flash. + */ + if (CHIPC_QUIRK(sc, SUPPORTS_NFLASH) && CHIPC_CAP(sc, CAP_NFLASH)) + return (BHND_NVRAM_SRC_NFLASH); + + /* No NVRAM hardware capability declared */ + return (BHND_NVRAM_SRC_NONE); +} + +static device_method_t chipc_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, chipc_probe), + DEVMETHOD(device_attach, chipc_attach), + DEVMETHOD(device_detach, chipc_detach), + DEVMETHOD(device_suspend, chipc_suspend), + DEVMETHOD(device_resume, chipc_resume), + + /* ChipCommon interface */ + DEVMETHOD(bhnd_chipc_nvram_src, chipc_nvram_src), + + DEVMETHOD_END +}; + +DEFINE_CLASS_0(bhnd_chipc, chipc_driver, chipc_methods, sizeof(struct chipc_softc)); +DRIVER_MODULE(bhnd_chipc, bhnd, chipc_driver, bhnd_chipc_devclass, 0, 0); +MODULE_VERSION(bhnd_chipc, 1); diff --git a/sys/dev/bhnd/cores/chipc/chipc.h b/sys/dev/bhnd/cores/chipc/chipc.h new file mode 100644 index 000000000000..2757f7965c76 --- /dev/null +++ b/sys/dev/bhnd/cores/chipc/chipc.h @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 2015-2016 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $FreeBSD$ + */ + +#ifndef _BHND_CORES_CHIPC_CHIPC_H_ +#define _BHND_CORES_CHIPC_CHIPC_H_ + +#include +#include + +#include "bhnd_chipc_if.h" + +/** + * Query a ChipCommon device and return the preferred NVRAM data source. + * + * @param dev A bhnd(4) ChipCommon device. + */ +static inline bhnd_nvram_src_t +bhnd_chipc_nvram_src(device_t dev) +{ + return (BHND_CHIPC_NVRAM_SRC(dev)); +} + +#endif /* _BHND_CORES_CHIPC_CHIPC_H_ */ \ No newline at end of file diff --git a/sys/dev/bhnd/cores/chipc/chipcreg.h b/sys/dev/bhnd/cores/chipc/chipcreg.h new file mode 100644 index 000000000000..502468481bf6 --- /dev/null +++ b/sys/dev/bhnd/cores/chipc/chipcreg.h @@ -0,0 +1,1395 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * Copyright (c) 2010 Broadcom Corporation + * All rights reserved. + * + * This file is derived from the sbchipc.h header distributed with + * Broadcom's initial brcm80211 Linux driver release, as + * contributed to the Linux staging repository. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef _BHND_CORES_CHIPC_CHIPCREG_H_ +#define _BHND_CORES_CHIPC_CHIPCREG_H_ + +#define CHIPC_CHIPID_SIZE 0x100 /**< size of the register block + containing the chip + identification registers. */ + +/** Evaluates to true if the given ChipCommon core revision provides + * the core count via the chip identification register. */ +#define CHIPC_NCORES_MIN_HWREV(hwrev) ((hwrev) == 4 || (hwrev) >= 6) + +#define CHIPC_GET_ATTR(_entry, _attr) \ + ((_entry & CHIPC_ ## _attr ## _MASK) >> CHIPC_ ## _attr ## _SHIFT) + +#define CHIPC_ID 0x0 +#define CHIPC_CAPABILITIES 0x04 +#define CHIPC_CHIPST 0x2c +#define CHIPC_EROMPTR 0xfc /**< 32-bit EROM base address + * on BCMA devices */ + +/** chipid */ +#define CHIPC_ID 0x0 /**< identification register */ +#define CHIPC_ID_CHIP_MASK 0x0000FFFF /**< chip id */ +#define CHIPC_ID_CHIP_SHIFT 0 +#define CHIPC_ID_REV_MASK 0x000F0000 /**< chip revision */ +#define CHIPC_ID_REV_SHIFT 16 +#define CHIPC_ID_PKG_MASK 0x00F00000 /**< physical package ID */ +#define CHIPC_ID_PKG_SHIFT 20 +#define CHIPC_ID_NUMCORE_MASK 0x0F000000 /**< number of cores on chip (rev >= 4) */ +#define CHIPC_ID_NUMCORE_SHIFT 24 +#define CHIPC_ID_BUS_MASK 0xF0000000 /**< chip/interconnect type (BHND_CHIPTYPE_*) */ +#define CHIPC_ID_BUS_SHIFT 28 + +#define CHIPC_OTPST 0x10 +#define CHIPC_JTAGCMD 0x30 +#define CHIPC_JTAGIR 0x34 +#define CHIPC_JTAGDR 0x38 +#define CHIPC_JTAGCTRL 0x3c +#define CHIPC_GPIOPU 0x58 +#define CHIPC_GPIOPD 0x5c +#define CHIPC_GPIOIN 0x60 +#define CHIPC_GPIOOUT 0x64 +#define CHIPC_GPIOOUTEN 0x68 +#define CHIPC_GPIOCTRL 0x6c +#define CHIPC_GPIOPOL 0x70 +#define CHIPC_GPIOINTM 0x74 +#define CHIPC_WATCHDOG 0x80 +#define CHIPC_CLKC_N 0x90 +#define CHIPC_CLKC_M0 0x94 +#define CHIPC_CLKC_M1 0x98 +#define CHIPC_CLKC_M2 0x9c +#define CHIPC_CLKC_M3 0xa0 +#define CHIPC_CLKDIV 0xa4 +#define CHIPC_SYS_CLK_CTL 0xc0 +#define CHIPC_SPROM_CTRL 0x190 /**< SPROM interface (rev >= 32) */ +#define CHIPC_SPROM_ADDR 0x194 +#define CHIPC_SPROM_DATA 0x198 +#define CHIPC_CLK_CTL_ST SI_CLK_CTL_ST +#define CHIPC_PMU_CTL 0x600 +#define CHIPC_PMU_CAP 0x604 +#define CHIPC_PMU_ST 0x608 +#define CHIPC_PMU_RES_STATE 0x60c +#define CHIPC_PMU_TIMER 0x614 +#define CHIPC_PMU_MIN_RES_MASK 0x618 +#define CHIPC_PMU_MAX_RES_MASK 0x61c +#define CHIPC_CHIPCTL_ADDR 0x650 +#define CHIPC_CHIPCTL_DATA 0x654 +#define CHIPC_PMU_REG_CONTROL_ADDR 0x658 +#define CHIPC_PMU_REG_CONTROL_DATA 0x65C +#define CHIPC_PMU_PLL_CONTROL_ADDR 0x660 +#define CHIPC_PMU_PLL_CONTROL_DATA 0x664 +#define CHIPC_SPROM_OTP 0x800 /* SPROM/OTP address space */ + +/* capabilities */ +#define CHIPC_CAP_UARTS_MASK 0x00000003 /* Number of UARTs */ +#define CHIPC_CAP_MIPSEB 0x00000004 /* MIPS is in big-endian mode */ +#define CHIPC_CAP_UCLKSEL 0x00000018 /* UARTs clock select */ +#define CHIPC_CAP_UINTCLK 0x00000008 /* UARTs are driven by internal divided clock */ +#define CHIPC_CAP_UARTGPIO 0x00000020 /* UARTs own GPIOs 15:12 */ +#define CHIPC_CAP_EXTBUS_MASK 0x000000c0 /* External bus mask */ +#define CHIPC_CAP_EXTBUS_NONE 0x00000000 /* No ExtBus present */ +#define CHIPC_CAP_EXTBUS_FULL 0x00000040 /* ExtBus: PCMCIA, IDE & Prog */ +#define CHIPC_CAP_EXTBUS_PROG 0x00000080 /* ExtBus: ProgIf only */ +#define CHIPC_CAP_FLASH_MASK 0x00000700 /* Type of flash */ +#define CHIPC_CAP_PLL_MASK 0x00038000 /* Type of PLL */ +#define CHIPC_CAP_PWR_CTL 0x00040000 /* Power control */ +#define CHIPC_CAP_OTP_SIZE 0x00380000 /* OTP Size (0 = none) */ +#define CHIPC_CAP_OTP_SIZE_SHIFT 19 /* OTP Size shift */ +#define CHIPC_CAP_OTP_SIZE_BASE 5 /* OTP Size base */ +#define CHIPC_CAP_JTAGP 0x00400000 /* JTAG Master Present */ +#define CHIPC_CAP_ROM 0x00800000 /* Internal boot rom active */ +#define CHIPC_CAP_BKPLN64 0x08000000 /* 64-bit backplane */ +#define CHIPC_CAP_PMU 0x10000000 /* PMU Present, rev >= 20 */ +#define CHIPC_CAP_SPROM 0x40000000 /* SPROM Present, rev >= 32 */ +#define CHIPC_CAP_NFLASH 0x80000000 /* Nand flash present, rev >= 35 */ + +#define CHIPC_CAP2_SECI 0x00000001 /* SECI Present, rev >= 36 */ +#define CHIPC_CAP2_GSIO 0x00000002 /* GSIO (spi/i2c) present, rev >= 37 */ + +/* + * ChipStatus (Common) + */ + +/** ChipStatus CIS/OTP/SPROM values used to advertise OTP/SPROM availability in + * chipcommon revs 11-31. */ +enum { + CHIPC_CST_DEFCIS_SEL = 0, /**< OTP is powered up, use default CIS, no SPROM */ + CHIPC_CST_SPROM_SEL = 1, /**< OTP is powered up, SPROM is present */ + CHIPC_CST_OTP_SEL = 2, /**< OTP is powered up, no SPROM */ + CHIPC_CST_OTP_PWRDN = 3 /**< OTP is powered down, SPROM is present (rev <= 22 only) */ +}; + + +#define CHIPC_CST_SPROM_OTP_SEL_R22_MASK 0x00000003 /**< chipstatus OTP/SPROM SEL value (rev 22) */ +#define CHIPC_CST_SPROM_OTP_SEL_R22_SHIFT 0 +#define CHIPC_CST_SPROM_OTP_SEL_R23_MASK 0x000000c0 /**< chipstatus OTP/SPROM SEL value (revs 23-31) + * + * it is unknown whether this is supported on + * any CC revs >= 32 that also vend CHIPC_CAP_* + * constants for OTP/SPROM/NVRAM availability. + */ +#define CHIPC_CST_SPROM_OTP_SEL_R23_SHIFT 6 + +/* PLL type */ +#define CHIPC_PLL_NONE 0x00000000 +#define CHIPC_PLL_TYPE1 0x00010000 /* 48MHz base, 3 dividers */ +#define CHIPC_PLL_TYPE2 0x00020000 /* 48MHz, 4 dividers */ +#define CHIPC_PLL_TYPE3 0x00030000 /* 25MHz, 2 dividers */ +#define CHIPC_PLL_TYPE4 0x00008000 /* 48MHz, 4 dividers */ +#define CHIPC_PLL_TYPE5 0x00018000 /* 25MHz, 4 dividers */ +#define CHIPC_PLL_TYPE6 0x00028000 /* 100/200 or 120/240 only */ +#define CHIPC_PLL_TYPE7 0x00038000 /* 25MHz, 4 dividers */ + +/* ILP clock */ +#define CHIPC_ILP_CLOCK 32000 + +/* ALP clock on pre-PMU chips */ +#define CHIPC_ALP_CLOCK 20000000 + +/* HT clock */ +#define CHIPC_HT_CLOCK 80000000 + +/* corecontrol */ +#define CHIPC_UARTCLKO 0x00000001 /* Drive UART with internal clock */ +#define CHIPC_SE 0x00000002 /* sync clk out enable (corerev >= 3) */ +#define CHIPC_UARTCLKEN 0x00000008 /* enable UART Clock (corerev > = 21 */ + +/* chipcontrol */ +#define CHIPCTRL_4321A0_DEFAULT 0x3a4 +#define CHIPCTRL_4321A1_DEFAULT 0x0a4 +#define CHIPCTRL_4321_PLL_DOWN 0x800000 /* serdes PLL down override */ + +/* Fields in the otpstatus register in rev >= 21 */ +#define CHIPC_OTPS_OL_MASK 0x000000ff +#define CHIPC_OTPS_OL_MFG 0x00000001 /* manuf row is locked */ +#define CHIPC_OTPS_OL_OR1 0x00000002 /* otp redundancy row 1 is locked */ +#define CHIPC_OTPS_OL_OR2 0x00000004 /* otp redundancy row 2 is locked */ +#define CHIPC_OTPS_OL_GU 0x00000008 /* general use region is locked */ +#define CHIPC_OTPS_GUP_MASK 0x00000f00 +#define CHIPC_OTPS_GUP_SHIFT 8 +#define CHIPC_OTPS_GUP_HW 0x00000100 /* h/w subregion is programmed */ +#define CHIPC_OTPS_GUP_SW 0x00000200 /* s/w subregion is programmed */ +#define CHIPC_OTPS_GUP_CI 0x00000400 /* chipid/pkgopt subregion is programmed */ +#define CHIPC_OTPS_GUP_FUSE 0x00000800 /* fuse subregion is programmed */ +#define CHIPC_OTPS_READY 0x00001000 +#define CHIPC_OTPS_RV(x) (1 << (16 + (x))) /* redundancy entry valid */ +#define CHIPC_OTPS_RV_MASK 0x0fff0000 + +/* Fields in the otpcontrol register in rev >= 21 */ +#define CHIPC_OTPC_PROGSEL 0x00000001 +#define CHIPC_OTPC_PCOUNT_MASK 0x0000000e +#define CHIPC_OTPC_PCOUNT_SHIFT 1 +#define CHIPC_OTPC_VSEL_MASK 0x000000f0 +#define CHIPC_OTPC_VSEL_SHIFT 4 +#define CHIPC_OTPC_TMM_MASK 0x00000700 +#define CHIPC_OTPC_TMM_SHIFT 8 +#define CHIPC_OTPC_ODM 0x00000800 +#define CHIPC_OTPC_PROGEN 0x80000000 + +/* Fields in otpprog in rev >= 21 and HND OTP */ +#define CHIPC_OTPP_COL_MASK 0x000000ff +#define CHIPC_OTPP_COL_SHIFT 0 +#define CHIPC_OTPP_ROW_MASK 0x0000ff00 +#define CHIPC_OTPP_ROW_SHIFT 8 +#define CHIPC_OTPP_OC_MASK 0x0f000000 +#define CHIPC_OTPP_OC_SHIFT 24 +#define CHIPC_OTPP_READERR 0x10000000 +#define CHIPC_OTPP_VALUE_MASK 0x20000000 +#define CHIPC_OTPP_VALUE_SHIFT 29 +#define CHIPC_OTPP_START_BUSY 0x80000000 +#define CHIPC_OTPP_READ 0x40000000 /* HND OTP */ + +/* otplayout reg corerev >= 36 */ +#define CHIPC_OTP_CISFORMAT_NEW 0x80000000 + +/* Opcodes for OTPP_OC field */ +#define CHIPC_OTPPOC_READ 0 +#define CHIPC_OTPPOC_BIT_PROG 1 +#define CHIPC_OTPPOC_VERIFY 3 +#define CHIPC_OTPPOC_INIT 4 +#define CHIPC_OTPPOC_SET 5 +#define CHIPC_OTPPOC_RESET 6 +#define CHIPC_OTPPOC_OCST 7 +#define CHIPC_OTPPOC_ROW_LOCK 8 +#define CHIPC_OTPPOC_PRESCN_TEST 9 + +/* Jtagm characteristics that appeared at a given corerev */ +#define CHIPC_JTAGM_CREV_OLD 10 /* Old command set, 16bit max IR */ +#define CHIPC_JTAGM_CREV_IRP 22 /* Able to do pause-ir */ +#define CHIPC_JTAGM_CREV_RTI 28 /* Able to do return-to-idle */ + +/* jtagcmd */ +#define CHIPC_JCMD_START 0x80000000 +#define CHIPC_JCMD_BUSY 0x80000000 +#define CHIPC_JCMD_STATE_MASK 0x60000000 +#define CHIPC_JCMD_STATE_TLR 0x00000000 /* Test-logic-reset */ +#define CHIPC_JCMD_STATE_PIR 0x20000000 /* Pause IR */ +#define CHIPC_JCMD_STATE_PDR 0x40000000 /* Pause DR */ +#define CHIPC_JCMD_STATE_RTI 0x60000000 /* Run-test-idle */ +#define CHIPC_JCMD0_ACC_MASK 0x0000f000 +#define CHIPC_JCMD0_ACC_IRDR 0x00000000 +#define CHIPC_JCMD0_ACC_DR 0x00001000 +#define CHIPC_JCMD0_ACC_IR 0x00002000 +#define CHIPC_JCMD0_ACC_RESET 0x00003000 +#define CHIPC_JCMD0_ACC_IRPDR 0x00004000 +#define CHIPC_JCMD0_ACC_PDR 0x00005000 +#define CHIPC_JCMD0_IRW_MASK 0x00000f00 +#define CHIPC_JCMD_ACC_MASK 0x000f0000 /* Changes for corerev 11 */ +#define CHIPC_JCMD_ACC_IRDR 0x00000000 +#define CHIPC_JCMD_ACC_DR 0x00010000 +#define CHIPC_JCMD_ACC_IR 0x00020000 +#define CHIPC_JCMD_ACC_RESET 0x00030000 +#define CHIPC_JCMD_ACC_IRPDR 0x00040000 +#define CHIPC_JCMD_ACC_PDR 0x00050000 +#define CHIPC_JCMD_ACC_PIR 0x00060000 +#define CHIPC_JCMD_ACC_IRDR_I 0x00070000 /* rev 28: return to run-test-idle */ +#define CHIPC_JCMD_ACC_DR_I 0x00080000 /* rev 28: return to run-test-idle */ +#define CHIPC_JCMD_IRW_MASK 0x00001f00 +#define CHIPC_JCMD_IRW_SHIFT 8 +#define CHIPC_JCMD_DRW_MASK 0x0000003f + +/* jtagctrl */ +#define CHIPC_JCTRL_FORCE_CLK 4 /* Force clock */ +#define CHIPC_JCTRL_EXT_EN 2 /* Enable external targets */ +#define CHIPC_JCTRL_EN 1 /* Enable Jtag master */ + +/* Fields in clkdiv */ +#define CHIPC_CLKD_SFLASH 0x0f000000 +#define CHIPC_CLKD_SFLASH_SHIFT 24 +#define CHIPC_CLKD_OTP 0x000f0000 +#define CHIPC_CLKD_OTP_SHIFT 16 +#define CHIPC_CLKD_JTAG 0x00000f00 +#define CHIPC_CLKD_JTAG_SHIFT 8 +#define CHIPC_CLKD_UART 0x000000ff + +#define CHIPC_CLKD2_SPROM 0x00000003 + +/* intstatus/intmask */ +#define CHIPC_CI_GPIO 0x00000001 /* gpio intr */ +#define CHIPC_CI_EI 0x00000002 /* extif intr (corerev >= 3) */ +#define CHIPC_CI_TEMP 0x00000004 /* temp. ctrl intr (corerev >= 15) */ +#define CHIPC_CI_SIRQ 0x00000008 /* serial IRQ intr (corerev >= 15) */ +#define CHIPC_CI_PMU 0x00000020 /* pmu intr (corerev >= 21) */ +#define CHIPC_CI_UART 0x00000040 /* uart intr (corerev >= 21) */ +#define CHIPC_CI_WDRESET 0x80000000 /* watchdog reset occurred */ + +/* slow_clk_ctl */ +#define CHIPC_SCC_SS_MASK 0x00000007 /* slow clock source mask */ +#define CHIPC_SCC_SS_LPO 0x00000000 /* source of slow clock is LPO */ +#define CHIPC_SCC_SS_XTAL 0x00000001 /* source of slow clock is crystal */ +#define CHIPC_SCC_SS_PCI 0x00000002 /* source of slow clock is PCI */ +#define CHIPC_SCC_LF 0x00000200 /* LPOFreqSel, 1: 160Khz, 0: 32KHz */ +#define CHIPC_SCC_LP 0x00000400 /* LPOPowerDown, 1: LPO is disabled, + * 0: LPO is enabled + */ +#define CHIPC_SCC_FS 0x00000800 /* ForceSlowClk, 1: sb/cores running on slow clock, + * 0: power logic control + */ +#define CHIPC_SCC_IP 0x00001000 /* IgnorePllOffReq, 1/0: power logic ignores/honors + * PLL clock disable requests from core + */ +#define CHIPC_SCC_XC 0x00002000 /* XtalControlEn, 1/0: power logic does/doesn't + * disable crystal when appropriate + */ +#define CHIPC_SCC_XP 0x00004000 /* XtalPU (RO), 1/0: crystal running/disabled */ +#define CHIPC_SCC_CD_MASK 0xffff0000 /* ClockDivider (SlowClk = 1/(4+divisor)) */ +#define CHIPC_SCC_CD_SHIFT 16 + +/* system_clk_ctl */ +#define CHIPC_SYCC_IE 0x00000001 /* ILPen: Enable Idle Low Power */ +#define CHIPC_SYCC_AE 0x00000002 /* ALPen: Enable Active Low Power */ +#define CHIPC_SYCC_FP 0x00000004 /* ForcePLLOn */ +#define CHIPC_SYCC_AR 0x00000008 /* Force ALP (or HT if ALPen is not set */ +#define CHIPC_SYCC_HR 0x00000010 /* Force HT */ +#define CHIPC_SYCC_CD_MASK 0xffff0000 /* ClkDiv (ILP = 1/(4 * (divisor + 1)) */ +#define CHIPC_SYCC_CD_SHIFT 16 + +/* Indirect backplane access */ +#define CHIPC_BPIA_BYTEEN 0x0000000f +#define CHIPC_BPIA_SZ1 0x00000001 +#define CHIPC_BPIA_SZ2 0x00000003 +#define CHIPC_BPIA_SZ4 0x00000007 +#define CHIPC_BPIA_SZ8 0x0000000f +#define CHIPC_BPIA_WRITE 0x00000100 +#define CHIPC_BPIA_START 0x00000200 +#define CHIPC_BPIA_BUSY 0x00000200 +#define CHIPC_BPIA_ERROR 0x00000400 + +/* pcmcia/prog/flash_config */ +#define CHIPC_CF_EN 0x00000001 /* enable */ +#define CHIPC_CF_EM_MASK 0x0000000e /* mode */ +#define CHIPC_CF_EM_SHIFT 1 +#define CHIPC_CF_EM_FLASH 0 /* flash/asynchronous mode */ +#define CHIPC_CF_EM_SYNC 2 /* synchronous mode */ +#define CHIPC_CF_EM_PCMCIA 4 /* pcmcia mode */ +#define CHIPC_CF_DS 0x00000010 /* destsize: 0=8bit, 1=16bit */ +#define CHIPC_CF_BS 0x00000020 /* byteswap */ +#define CHIPC_CF_CD_MASK 0x000000c0 /* clock divider */ +#define CHIPC_CF_CD_SHIFT 6 +#define CHIPC_CF_CD_DIV2 0x00000000 /* backplane/2 */ +#define CHIPC_CF_CD_DIV3 0x00000040 /* backplane/3 */ +#define CHIPC_CF_CD_DIV4 0x00000080 /* backplane/4 */ +#define CHIPC_CF_CE 0x00000100 /* clock enable */ +#define CHIPC_CF_SB 0x00000200 /* size/bytestrobe (synch only) */ + +/* pcmcia_memwait */ +#define CHIPC_PM_W0_MASK 0x0000003f /* waitcount0 */ +#define CHIPC_PM_W1_MASK 0x00001f00 /* waitcount1 */ +#define CHIPC_PM_W1_SHIFT 8 +#define CHIPC_PM_W2_MASK 0x001f0000 /* waitcount2 */ +#define CHIPC_PM_W2_SHIFT 16 +#define CHIPC_PM_W3_MASK 0x1f000000 /* waitcount3 */ +#define CHIPC_PM_W3_SHIFT 24 + +/* pcmcia_attrwait */ +#define CHIPC_PA_W0_MASK 0x0000003f /* waitcount0 */ +#define CHIPC_PA_W1_MASK 0x00001f00 /* waitcount1 */ +#define CHIPC_PA_W1_SHIFT 8 +#define CHIPC_PA_W2_MASK 0x001f0000 /* waitcount2 */ +#define CHIPC_PA_W2_SHIFT 16 +#define CHIPC_PA_W3_MASK 0x1f000000 /* waitcount3 */ +#define CHIPC_PA_W3_SHIFT 24 + +/* pcmcia_iowait */ +#define CHIPC_PI_W0_MASK 0x0000003f /* waitcount0 */ +#define CHIPC_PI_W1_MASK 0x00001f00 /* waitcount1 */ +#define CHIPC_PI_W1_SHIFT 8 +#define CHIPC_PI_W2_MASK 0x001f0000 /* waitcount2 */ +#define CHIPC_PI_W2_SHIFT 16 +#define CHIPC_PI_W3_MASK 0x1f000000 /* waitcount3 */ +#define CHIPC_PI_W3_SHIFT 24 + +/* prog_waitcount */ +#define CHIPC_PW_W0_MASK 0x0000001f /* waitcount0 */ +#define CHIPC_PW_W1_MASK 0x00001f00 /* waitcount1 */ +#define CHIPC_PW_W1_SHIFT 8 +#define CHIPC_PW_W2_MASK 0x001f0000 /* waitcount2 */ +#define CHIPC_PW_W2_SHIFT 16 +#define CHIPC_PW_W3_MASK 0x1f000000 /* waitcount3 */ +#define CHIPC_PW_W3_SHIFT 24 + +#define CHIPC_PW_W0 0x0000000c +#define CHIPC_PW_W1 0x00000a00 +#define CHIPC_PW_W2 0x00020000 +#define CHIPC_PW_W3 0x01000000 + +/* flash_waitcount */ +#define CHIPC_FW_W0_MASK 0x0000003f /* waitcount0 */ +#define CHIPC_FW_W1_MASK 0x00001f00 /* waitcount1 */ +#define CHIPC_FW_W1_SHIFT 8 +#define CHIPC_FW_W2_MASK 0x001f0000 /* waitcount2 */ +#define CHIPC_FW_W2_SHIFT 16 +#define CHIPC_FW_W3_MASK 0x1f000000 /* waitcount3 */ +#define CHIPC_FW_W3_SHIFT 24 + +/* When SPROM support present, fields in spromcontrol */ +#define CHIPC_SRC_START 0x80000000 +#define CHIPC_SRC_BUSY 0x80000000 +#define CHIPC_SRC_OPCODE 0x60000000 +#define CHIPC_SRC_OP_READ 0x00000000 +#define CHIPC_SRC_OP_WRITE 0x20000000 +#define CHIPC_SRC_OP_WRDIS 0x40000000 +#define CHIPC_SRC_OP_WREN 0x60000000 +#define CHIPC_SRC_OTPSEL 0x00000010 +#define CHIPC_SRC_LOCK 0x00000008 +#define CHIPC_SRC_SIZE_MASK 0x00000006 +#define CHIPC_SRC_SIZE_1K 0x00000000 +#define CHIPC_SRC_SIZE_4K 0x00000002 +#define CHIPC_SRC_SIZE_16K 0x00000004 +#define CHIPC_SRC_SIZE_SHIFT 1 +#define CHIPC_SRC_PRESENT 0x00000001 + +/* Fields in pmucontrol */ +#define CHIPC_PCTL_ILP_DIV_MASK 0xffff0000 +#define CHIPC_PCTL_ILP_DIV_SHIFT 16 +#define CHIPC_PCTL_PLL_PLLCTL_UPD 0x00000400 /* rev 2 */ +#define CHIPC_PCTL_NOILP_ON_WAIT 0x00000200 /* rev 1 */ +#define CHIPC_PCTL_HT_REQ_EN 0x00000100 +#define CHIPC_PCTL_ALP_REQ_EN 0x00000080 +#define CHIPC_PCTL_XTALFREQ_MASK 0x0000007c +#define CHIPC_PCTL_XTALFREQ_SHIFT 2 +#define CHIPC_PCTL_ILP_DIV_EN 0x00000002 +#define CHIPC_PCTL_LPO_SEL 0x00000001 + +/* Fields in clkstretch */ +#define CHIPC_CSTRETCH_HT 0xffff0000 +#define CHIPC_CSTRETCH_ALP 0x0000ffff + +/* gpiotimerval */ +#define CHIPC_GPIO_ONTIME_SHIFT 16 + +/* clockcontrol_n */ +#define CHIPC_CN_N1_MASK 0x3f /* n1 control */ +#define CHIPC_CN_N2_MASK 0x3f00 /* n2 control */ +#define CHIPC_CN_N2_SHIFT 8 +#define CHIPC_CN_PLLC_MASK 0xf0000 /* pll control */ +#define CHIPC_CN_PLLC_SHIFT 16 + +/* clockcontrol_sb/pci/uart */ +#define CHIPC_M1_MASK 0x3f /* m1 control */ +#define CHIPC_M2_MASK 0x3f00 /* m2 control */ +#define CHIPC_M2_SHIFT 8 +#define CHIPC_M3_MASK 0x3f0000 /* m3 control */ +#define CHIPC_M3_SHIFT 16 +#define CHIPC_MC_MASK 0x1f000000 /* mux control */ +#define CHIPC_MC_SHIFT 24 + +/* N3M Clock control magic field values */ +#define CHIPC_F6_2 0x02 /* A factor of 2 in */ +#define CHIPC_F6_3 0x03 /* 6-bit fields like */ +#define CHIPC_F6_4 0x05 /* N1, M1 or M3 */ +#define CHIPC_F6_5 0x09 +#define CHIPC_F6_6 0x11 +#define CHIPC_F6_7 0x21 + +#define CHIPC_F5_BIAS 5 /* 5-bit fields get this added */ + +#define CHIPC_MC_BYPASS 0x08 +#define CHIPC_MC_M1 0x04 +#define CHIPC_MC_M1M2 0x02 +#define CHIPC_MC_M1M2M3 0x01 +#define CHIPC_MC_M1M3 0x11 + +/* Type 2 Clock control magic field values */ +#define CHIPC_T2_BIAS 2 /* n1, n2, m1 & m3 bias */ +#define CHIPC_T2M2_BIAS 3 /* m2 bias */ + +#define CHIPC_T2MC_M1BYP 1 +#define CHIPC_T2MC_M2BYP 2 +#define CHIPC_T2MC_M3BYP 4 + +/* Type 6 Clock control magic field values */ +#define CHIPC_T6_MMASK 1 /* bits of interest in m */ +#define CHIPC_T6_M0 120000000 /* sb clock for m = 0 */ +#define CHIPC_T6_M1 100000000 /* sb clock for m = 1 */ +#define CHIPC_SB2MIPS_T6(sb) (2 * (sb)) + +/* Common clock base */ +#define CHIPC_CLOCK_BASE1 24000000 /* Half the clock freq */ +#define CHIPC_CLOCK_BASE2 12500000 /* Alternate crystal on some PLLs */ + +/* Clock control values for 200MHz in 5350 */ +#define CHIPC_CLKC_5350_N 0x0311 +#define CHIPC_CLKC_5350_M 0x04020009 + +/* Flash types in the chipcommon capabilities register */ +#define CHIPC_FLASH_NONE 0x000 /* No flash */ +#define CHIPC_SFLASH_ST 0x100 /* ST serial flash */ +#define CHIPC_SFLASH_AT 0x200 /* Atmel serial flash */ +#define CHIPC_PFLASH 0x700 /* Parallel flash */ + +/* Bits in the ExtBus config registers */ +#define CHIPC_CFG_EN 0x0001 /* Enable */ +#define CHIPC_CFG_EM_MASK 0x000e /* Extif Mode */ +#define CHIPC_CFG_EM_ASYNC 0x0000 /* Async/Parallel flash */ +#define CHIPC_CFG_EM_SYNC 0x0002 /* Synchronous */ +#define CHIPC_CFG_EM_PCMCIA 0x0004 /* PCMCIA */ +#define CHIPC_CFG_EM_IDE 0x0006 /* IDE */ +#define CHIPC_CFG_DS 0x0010 /* Data size, 0=8bit, 1=16bit */ +#define CHIPC_CFG_CD_MASK 0x00e0 /* Sync: Clock divisor, rev >= 20 */ +#define CHIPC_CFG_CE 0x0100 /* Sync: Clock enable, rev >= 20 */ +#define CHIPC_CFG_SB 0x0200 /* Sync: Size/Bytestrobe, rev >= 20 */ +#define CHIPC_CFG_IS 0x0400 /* Extif Sync Clk Select, rev >= 20 */ + +/* ExtBus address space */ +#define CHIPC_EB_BASE 0x1a000000 /* Chipc ExtBus base address */ +#define CHIPC_EB_PCMCIA_MEM 0x1a000000 /* PCMCIA 0 memory base address */ +#define CHIPC_EB_PCMCIA_IO 0x1a200000 /* PCMCIA 0 I/O base address */ +#define CHIPC_EB_PCMCIA_CFG 0x1a400000 /* PCMCIA 0 config base address */ +#define CHIPC_EB_IDE 0x1a800000 /* IDE memory base */ +#define CHIPC_EB_PCMCIA1_MEM 0x1a800000 /* PCMCIA 1 memory base address */ +#define CHIPC_EB_PCMCIA1_IO 0x1aa00000 /* PCMCIA 1 I/O base address */ +#define CHIPC_EB_PCMCIA1_CFG 0x1ac00000 /* PCMCIA 1 config base address */ +#define CHIPC_EB_PROGIF 0x1b000000 /* ProgIF Async/Sync base address */ + +/* Start/busy bit in flashcontrol */ +#define CHIPC_SFLASH_OPCODE 0x000000ff +#define CHIPC_SFLASH_ACTION 0x00000700 +#define CHIPC_SFLASH_CS_ACTIVE 0x00001000 /* Chip Select Active, rev >= 20 */ +#define CHIPC_SFLASH_START 0x80000000 +#define CHIPC_SFLASH_BUSY SFLASH_START + +/* flashcontrol action codes */ +#define CHIPC_SFLASH_ACT_OPONLY 0x0000 /* Issue opcode only */ +#define CHIPC_SFLASH_ACT_OP1D 0x0100 /* opcode + 1 data byte */ +#define CHIPC_SFLASH_ACT_OP3A 0x0200 /* opcode + 3 addr bytes */ +#define CHIPC_SFLASH_ACT_OP3A1D 0x0300 /* opcode + 3 addr & 1 data bytes */ +#define CHIPC_SFLASH_ACT_OP3A4D 0x0400 /* opcode + 3 addr & 4 data bytes */ +#define CHIPC_SFLASH_ACT_OP3A4X4D 0x0500 /* opcode + 3 addr, 4 don't care & 4 data bytes */ +#define CHIPC_SFLASH_ACT_OP3A1X4D 0x0700 /* opcode + 3 addr, 1 don't care & 4 data bytes */ + +/* flashcontrol action+opcodes for ST flashes */ +#define CHIPC_SFLASH_ST_WREN 0x0006 /* Write Enable */ +#define CHIPC_SFLASH_ST_WRDIS 0x0004 /* Write Disable */ +#define CHIPC_SFLASH_ST_RDSR 0x0105 /* Read Status Register */ +#define CHIPC_SFLASH_ST_WRSR 0x0101 /* Write Status Register */ +#define CHIPC_SFLASH_ST_READ 0x0303 /* Read Data Bytes */ +#define CHIPC_SFLASH_ST_PP 0x0302 /* Page Program */ +#define CHIPC_SFLASH_ST_SE 0x02d8 /* Sector Erase */ +#define CHIPC_SFLASH_ST_BE 0x00c7 /* Bulk Erase */ +#define CHIPC_SFLASH_ST_DP 0x00b9 /* Deep Power-down */ +#define CHIPC_SFLASH_ST_RES 0x03ab /* Read Electronic Signature */ +#define CHIPC_SFLASH_ST_CSA 0x1000 /* Keep chip select asserted */ +#define CHIPC_SFLASH_ST_SSE 0x0220 /* Sub-sector Erase */ + +/* Status register bits for ST flashes */ +#define CHIPC_SFLASH_ST_WIP 0x01 /* Write In Progress */ +#define CHIPC_SFLASH_ST_WEL 0x02 /* Write Enable Latch */ +#define CHIPC_SFLASH_ST_BP_MASK 0x1c /* Block Protect */ +#define CHIPC_SFLASH_ST_BP_SHIFT 2 +#define CHIPC_SFLASH_ST_SRWD 0x80 /* Status Register Write Disable */ + +/* flashcontrol action+opcodes for Atmel flashes */ +#define CHIPC_SFLASH_AT_READ 0x07e8 +#define CHIPC_SFLASH_AT_PAGE_READ 0x07d2 +#define CHIPC_SFLASH_AT_BUF1_READ +#define CHIPC_SFLASH_AT_BUF2_READ +#define CHIPC_SFLASH_AT_STATUS 0x01d7 +#define CHIPC_SFLASH_AT_BUF1_WRITE 0x0384 +#define CHIPC_SFLASH_AT_BUF2_WRITE 0x0387 +#define CHIPC_SFLASH_AT_BUF1_ERASE_PROGRAM 0x0283 +#define CHIPC_SFLASH_AT_BUF2_ERASE_PROGRAM 0x0286 +#define CHIPC_SFLASH_AT_BUF1_PROGRAM 0x0288 +#define CHIPC_SFLASH_AT_BUF2_PROGRAM 0x0289 +#define CHIPC_SFLASH_AT_PAGE_ERASE 0x0281 +#define CHIPC_SFLASH_AT_BLOCK_ERASE 0x0250 +#define CHIPC_SFLASH_AT_BUF1_WRITE_ERASE_PROGRAM 0x0382 +#define CHIPC_SFLASH_AT_BUF2_WRITE_ERASE_PROGRAM 0x0385 +#define CHIPC_SFLASH_AT_BUF1_LOAD 0x0253 +#define CHIPC_SFLASH_AT_BUF2_LOAD 0x0255 +#define CHIPC_SFLASH_AT_BUF1_COMPARE 0x0260 +#define CHIPC_SFLASH_AT_BUF2_COMPARE 0x0261 +#define CHIPC_SFLASH_AT_BUF1_REPROGRAM 0x0258 +#define CHIPC_SFLASH_AT_BUF2_REPROGRAM 0x0259 + +/* Status register bits for Atmel flashes */ +#define CHIPC_SFLASH_AT_READY 0x80 +#define CHIPC_SFLASH_AT_MISMATCH 0x40 +#define CHIPC_SFLASH_AT_ID_MASK 0x38 +#define CHIPC_SFLASH_AT_ID_SHIFT 3 + +/* + * These are the UART port assignments, expressed as offsets from the base + * register. These assignments should hold for any serial port based on + * a 8250, 16450, or 16550(A). + */ + +#define CHIPC_UART_RX 0 /* In: Receive buffer (DLAB=0) */ +#define CHIPC_UART_TX 0 /* Out: Transmit buffer (DLAB=0) */ +#define CHIPC_UART_DLL 0 /* Out: Divisor Latch Low (DLAB=1) */ +#define CHIPC_UART_IER 1 /* In/Out: Interrupt Enable Register (DLAB=0) */ +#define CHIPC_UART_DLM 1 /* Out: Divisor Latch High (DLAB=1) */ +#define CHIPC_UART_IIR 2 /* In: Interrupt Identity Register */ +#define CHIPC_UART_FCR 2 /* Out: FIFO Control Register */ +#define CHIPC_UART_LCR 3 /* Out: Line Control Register */ +#define CHIPC_UART_MCR 4 /* Out: Modem Control Register */ +#define CHIPC_UART_LSR 5 /* In: Line Status Register */ +#define CHIPC_UART_MSR 6 /* In: Modem Status Register */ +#define CHIPC_UART_SCR 7 /* I/O: Scratch Register */ +#define CHIPC_UART_LCR_DLAB 0x80 /* Divisor latch access bit */ +#define CHIPC_UART_LCR_WLEN8 0x03 /* Word length: 8 bits */ +#define CHIPC_UART_MCR_OUT2 0x08 /* MCR GPIO out 2 */ +#define CHIPC_UART_MCR_LOOP 0x10 /* Enable loopback test mode */ +#define CHIPC_UART_LSR_RX_FIFO 0x80 /* Receive FIFO error */ +#define CHIPC_UART_LSR_TDHR 0x40 /* Data-hold-register empty */ +#define CHIPC_UART_LSR_THRE 0x20 /* Transmit-hold-register empty */ +#define CHIPC_UART_LSR_BREAK 0x10 /* Break interrupt */ +#define CHIPC_UART_LSR_FRAMING 0x08 /* Framing error */ +#define CHIPC_UART_LSR_PARITY 0x04 /* Parity error */ +#define CHIPC_UART_LSR_OVERRUN 0x02 /* Overrun error */ +#define CHIPC_UART_LSR_RXRDY 0x01 /* Receiver ready */ +#define CHIPC_UART_FCR_FIFO_ENABLE 1 /* FIFO control register bit controlling FIFO enable/disable */ + +/* Interrupt Identity Register (IIR) bits */ +#define CHIPC_UART_IIR_FIFO_MASK 0xc0 /* IIR FIFO disable/enabled mask */ +#define CHIPC_UART_IIR_INT_MASK 0xf /* IIR interrupt ID source */ +#define CHIPC_UART_IIR_MDM_CHG 0x0 /* Modem status changed */ +#define CHIPC_UART_IIR_NOINT 0x1 /* No interrupt pending */ +#define CHIPC_UART_IIR_THRE 0x2 /* THR empty */ +#define CHIPC_UART_IIR_RCVD_DATA 0x4 /* Received data available */ +#define CHIPC_UART_IIR_RCVR_STATUS 0x6 /* Receiver status */ +#define CHIPC_UART_IIR_CHAR_TIME 0xc /* Character time */ + +/* Interrupt Enable Register (IER) bits */ +#define CHIPC_UART_IER_EDSSI 8 /* enable modem status interrupt */ +#define CHIPC_UART_IER_ELSI 4 /* enable receiver line status interrupt */ +#define CHIPC_UART_IER_ETBEI 2 /* enable transmitter holding register empty interrupt */ +#define CHIPC_UART_IER_ERBFI 1 /* enable data available interrupt */ + +/* pmustatus */ +#define CHIPC_PST_EXTLPOAVAIL 0x0100 +#define CHIPC_PST_WDRESET 0x0080 +#define CHIPC_PST_INTPEND 0x0040 +#define CHIPC_PST_SBCLKST 0x0030 +#define CHIPC_PST_SBCLKST_ILP 0x0010 +#define CHIPC_PST_SBCLKST_ALP 0x0020 +#define CHIPC_PST_SBCLKST_HT 0x0030 +#define CHIPC_PST_ALPAVAIL 0x0008 +#define CHIPC_PST_HTAVAIL 0x0004 +#define CHIPC_PST_RESINIT 0x0003 + +/* pmucapabilities */ +#define CHIPC_PCAP_REV_MASK 0x000000ff +#define CHIPC_PCAP_RC_MASK 0x00001f00 +#define CHIPC_PCAP_RC_SHIFT 8 +#define CHIPC_PCAP_TC_MASK 0x0001e000 +#define CHIPC_PCAP_TC_SHIFT 13 +#define CHIPC_PCAP_PC_MASK 0x001e0000 +#define CHIPC_PCAP_PC_SHIFT 17 +#define CHIPC_PCAP_VC_MASK 0x01e00000 +#define CHIPC_PCAP_VC_SHIFT 21 +#define CHIPC_PCAP_CC_MASK 0x1e000000 +#define CHIPC_PCAP_CC_SHIFT 25 +#define CHIPC_PCAP5_PC_MASK 0x003e0000 /* PMU corerev >= 5 */ +#define CHIPC_PCAP5_PC_SHIFT 17 +#define CHIPC_PCAP5_VC_MASK 0x07c00000 +#define CHIPC_PCAP5_VC_SHIFT 22 +#define CHIPC_PCAP5_CC_MASK 0xf8000000 +#define CHIPC_PCAP5_CC_SHIFT 27 + +/* PMU Resource Request Timer registers */ +/* This is based on PmuRev0 */ +#define CHIPC_PRRT_TIME_MASK 0x03ff +#define CHIPC_PRRT_INTEN 0x0400 +#define CHIPC_PRRT_REQ_ACTIVE 0x0800 +#define CHIPC_PRRT_ALP_REQ 0x1000 +#define CHIPC_PRRT_HT_REQ 0x2000 + +/* PMU resource bit position */ +#define CHIPC_PMURES_BIT(bit) (1 << (bit)) + +/* PMU resource number limit */ +#define CHIPC_PMURES_MAX_RESNUM 30 + +/* PMU chip control0 register */ +#define CHIPC_PMU_CHIPCTL0 0 + +/* PMU chip control1 register */ +#define CHIPC_PMU_CHIPCTL1 1 +#define CHIPC_PMU_CC1_RXC_DLL_BYPASS 0x00010000 + +#define CHIPC_PMU_CC1_IF_TYPE_MASK 0x00000030 +#define CHIPC_PMU_CC1_IF_TYPE_RMII 0x00000000 +#define CHIPC_PMU_CC1_IF_TYPE_MII 0x00000010 +#define CHIPC_PMU_CC1_IF_TYPE_RGMII 0x00000020 + +#define CHIPC_PMU_CC1_SW_TYPE_MASK 0x000000c0 +#define CHIPC_PMU_CC1_SW_TYPE_EPHY 0x00000000 +#define CHIPC_PMU_CC1_SW_TYPE_EPHYMII 0x00000040 +#define CHIPC_PMU_CC1_SW_TYPE_EPHYRMII 0x00000080 +#define CHIPC_PMU_CC1_SW_TYPE_RGMII 0x000000c0 + +/* PMU corerev and chip specific PLL controls. + * PMU_PLL_XX where is PMU corerev and is an arbitrary number + * to differentiate different PLLs controlled by the same PMU rev. + */ +/* pllcontrol registers */ +/* PDIV, div_phy, div_arm, div_adc, dith_sel, ioff, kpd_scale, lsb_sel, mash_sel, lf_c & lf_r */ +#define CHIPC_PMU0_PLL0_PLLCTL0 0 +#define CHIPC_PMU0_PLL0_PC0_PDIV_MASK 1 +#define CHIPC_PMU0_PLL0_PC0_PDIV_FREQ 25000 +#define CHIPC_PMU0_PLL0_PC0_DIV_ARM_MASK 0x00000038 +#define CHIPC_PMU0_PLL0_PC0_DIV_ARM_SHIFT 3 +#define CHIPC_PMU0_PLL0_PC0_DIV_ARM_BASE 8 + +/* PC0_DIV_ARM for PLLOUT_ARM */ +#define CHIPC_PMU0_PLL0_PC0_DIV_ARM_110MHZ 0 +#define CHIPC_PMU0_PLL0_PC0_DIV_ARM_97_7MHZ 1 +#define CHIPC_PMU0_PLL0_PC0_DIV_ARM_88MHZ 2 +#define CHIPC_PMU0_PLL0_PC0_DIV_ARM_80MHZ 3 /* Default */ +#define CHIPC_PMU0_PLL0_PC0_DIV_ARM_73_3MHZ 4 +#define CHIPC_PMU0_PLL0_PC0_DIV_ARM_67_7MHZ 5 +#define CHIPC_PMU0_PLL0_PC0_DIV_ARM_62_9MHZ 6 +#define CHIPC_PMU0_PLL0_PC0_DIV_ARM_58_6MHZ 7 + +/* Wildcard base, stop_mod, en_lf_tp, en_cal & lf_r2 */ +#define CHIPC_PMU0_PLL0_PLLCTL1 1 +#define CHIPC_PMU0_PLL0_PC1_WILD_INT_MASK 0xf0000000 +#define CHIPC_PMU0_PLL0_PC1_WILD_INT_SHIFT 28 +#define CHIPC_PMU0_PLL0_PC1_WILD_FRAC_MASK 0x0fffff00 +#define CHIPC_PMU0_PLL0_PC1_WILD_FRAC_SHIFT 8 +#define CHIPC_PMU0_PLL0_PC1_STOP_MOD 0x00000040 + +/* Wildcard base, vco_calvar, vco_swc, vco_var_selref, vso_ical & vco_sel_avdd */ +#define CHIPC_PMU0_PLL0_PLLCTL2 2 +#define CHIPC_PMU0_PLL0_PC2_WILD_INT_MASK 0xf +#define CHIPC_PMU0_PLL0_PC2_WILD_INT_SHIFT 4 + +/* pllcontrol registers */ +/* ndiv_pwrdn, pwrdn_ch, refcomp_pwrdn, dly_ch, p1div, p2div, _bypass_sdmod */ +#define CHIPC_PMU1_PLL0_PLLCTL0 0 +#define CHIPC_PMU1_PLL0_PC0_P1DIV_MASK 0x00f00000 +#define CHIPC_PMU1_PLL0_PC0_P1DIV_SHIFT 20 +#define CHIPC_PMU1_PLL0_PC0_P2DIV_MASK 0x0f000000 +#define CHIPC_PMU1_PLL0_PC0_P2DIV_SHIFT 24 + +/* mdiv */ +#define CHIPC_PMU1_PLL0_PLLCTL1 1 +#define CHIPC_PMU1_PLL0_PC1_M1DIV_MASK 0x000000ff +#define CHIPC_PMU1_PLL0_PC1_M1DIV_SHIFT 0 +#define CHIPC_PMU1_PLL0_PC1_M2DIV_MASK 0x0000ff00 +#define CHIPC_PMU1_PLL0_PC1_M2DIV_SHIFT 8 +#define CHIPC_PMU1_PLL0_PC1_M3DIV_MASK 0x00ff0000 +#define CHIPC_PMU1_PLL0_PC1_M3DIV_SHIFT 16 +#define CHIPC_PMU1_PLL0_PC1_M4DIV_MASK 0xff000000 +#define CHIPC_PMU1_PLL0_PC1_M4DIV_SHIFT 24 + +#define CHIPC_DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT 8 +#define CHIPC_DOT11MAC_880MHZ_CLK_DIVISOR_MASK (0xFF << DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT) +#define CHIPC_DOT11MAC_880MHZ_CLK_DIVISOR_VAL (0xE << DOT11MAC_880MHZ_CLK_DIVISOR_SHIFT) + +/* mdiv, ndiv_dither_mfb, ndiv_mode, ndiv_int */ +#define CHIPC_PMU1_PLL0_PLLCTL2 2 +#define CHIPC_PMU1_PLL0_PC2_M5DIV_MASK 0x000000ff +#define CHIPC_PMU1_PLL0_PC2_M5DIV_SHIFT 0 +#define CHIPC_PMU1_PLL0_PC2_M6DIV_MASK 0x0000ff00 +#define CHIPC_PMU1_PLL0_PC2_M6DIV_SHIFT 8 +#define CHIPC_PMU1_PLL0_PC2_NDIV_MODE_MASK 0x000e0000 +#define CHIPC_PMU1_PLL0_PC2_NDIV_MODE_SHIFT 17 +#define CHIPC_PMU1_PLL0_PC2_NDIV_MODE_MASH 1 +#define CHIPC_PMU1_PLL0_PC2_NDIV_MODE_MFB 2 /* recommended for 4319 */ +#define CHIPC_PMU1_PLL0_PC2_NDIV_INT_MASK 0x1ff00000 +#define CHIPC_PMU1_PLL0_PC2_NDIV_INT_SHIFT 20 + +/* ndiv_frac */ +#define CHIPC_PMU1_PLL0_PLLCTL3 3 +#define CHIPC_PMU1_PLL0_PC3_NDIV_FRAC_MASK 0x00ffffff +#define CHIPC_PMU1_PLL0_PC3_NDIV_FRAC_SHIFT 0 + +/* pll_ctrl */ +#define CHIPC_PMU1_PLL0_PLLCTL4 4 + +/* pll_ctrl, vco_rng, clkdrive_ch */ +#define CHIPC_PMU1_PLL0_PLLCTL5 5 +#define CHIPC_PMU1_PLL0_PC5_CLK_DRV_MASK 0xffffff00 +#define CHIPC_PMU1_PLL0_PC5_CLK_DRV_SHIFT 8 + +/* PMU rev 2 control words */ +#define CHIPC_PMU2_PHY_PLL_PLLCTL 4 +#define CHIPC_PMU2_SI_PLL_PLLCTL 10 + +/* PMU rev 2 */ +/* pllcontrol registers */ +/* ndiv_pwrdn, pwrdn_ch, refcomp_pwrdn, dly_ch, p1div, p2div, _bypass_sdmod */ +#define CHIPC_PMU2_PLL_PLLCTL0 0 +#define CHIPC_PMU2_PLL_PC0_P1DIV_MASK 0x00f00000 +#define CHIPC_PMU2_PLL_PC0_P1DIV_SHIFT 20 +#define CHIPC_PMU2_PLL_PC0_P2DIV_MASK 0x0f000000 +#define CHIPC_PMU2_PLL_PC0_P2DIV_SHIFT 24 + +/* mdiv */ +#define CHIPC_PMU2_PLL_PLLCTL1 1 +#define CHIPC_PMU2_PLL_PC1_M1DIV_MASK 0x000000ff +#define CHIPC_PMU2_PLL_PC1_M1DIV_SHIFT 0 +#define CHIPC_PMU2_PLL_PC1_M2DIV_MASK 0x0000ff00 +#define CHIPC_PMU2_PLL_PC1_M2DIV_SHIFT 8 +#define CHIPC_PMU2_PLL_PC1_M3DIV_MASK 0x00ff0000 +#define CHIPC_PMU2_PLL_PC1_M3DIV_SHIFT 16 +#define CHIPC_PMU2_PLL_PC1_M4DIV_MASK 0xff000000 +#define CHIPC_PMU2_PLL_PC1_M4DIV_SHIFT 24 + +/* mdiv, ndiv_dither_mfb, ndiv_mode, ndiv_int */ +#define CHIPC_PMU2_PLL_PLLCTL2 2 +#define CHIPC_PMU2_PLL_PC2_M5DIV_MASK 0x000000ff +#define CHIPC_PMU2_PLL_PC2_M5DIV_SHIFT 0 +#define CHIPC_PMU2_PLL_PC2_M6DIV_MASK 0x0000ff00 +#define CHIPC_PMU2_PLL_PC2_M6DIV_SHIFT 8 +#define CHIPC_PMU2_PLL_PC2_NDIV_MODE_MASK 0x000e0000 +#define CHIPC_PMU2_PLL_PC2_NDIV_MODE_SHIFT 17 +#define CHIPC_PMU2_PLL_PC2_NDIV_INT_MASK 0x1ff00000 +#define CHIPC_PMU2_PLL_PC2_NDIV_INT_SHIFT 20 + +/* ndiv_frac */ +#define CHIPC_PMU2_PLL_PLLCTL3 3 +#define CHIPC_PMU2_PLL_PC3_NDIV_FRAC_MASK 0x00ffffff +#define CHIPC_PMU2_PLL_PC3_NDIV_FRAC_SHIFT 0 + +/* pll_ctrl */ +#define CHIPC_PMU2_PLL_PLLCTL4 4 + +/* pll_ctrl, vco_rng, clkdrive_ch */ +#define CHIPC_PMU2_PLL_PLLCTL5 5 +#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH1_MASK 0x00000f00 +#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH1_SHIFT 8 +#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH2_MASK 0x0000f000 +#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH2_SHIFT 12 +#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH3_MASK 0x000f0000 +#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH3_SHIFT 16 +#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH4_MASK 0x00f00000 +#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH4_SHIFT 20 +#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH5_MASK 0x0f000000 +#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH5_SHIFT 24 +#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH6_MASK 0xf0000000 +#define CHIPC_PMU2_PLL_PC5_CLKDRIVE_CH6_SHIFT 28 + +/* PMU rev 5 (& 6) */ +#define CHIPC_PMU5_PLL_P1P2_OFF 0 +#define CHIPC_PMU5_PLL_P1_MASK 0x0f000000 +#define CHIPC_PMU5_PLL_P1_SHIFT 24 +#define CHIPC_PMU5_PLL_P2_MASK 0x00f00000 +#define CHIPC_PMU5_PLL_P2_SHIFT 20 +#define CHIPC_PMU5_PLL_M14_OFF 1 +#define CHIPC_PMU5_PLL_MDIV_MASK 0x000000ff +#define CHIPC_PMU5_PLL_MDIV_WIDTH 8 +#define CHIPC_PMU5_PLL_NM5_OFF 2 +#define CHIPC_PMU5_PLL_NDIV_MASK 0xfff00000 +#define CHIPC_PMU5_PLL_NDIV_SHIFT 20 +#define CHIPC_PMU5_PLL_NDIV_MODE_MASK 0x000e0000 +#define CHIPC_PMU5_PLL_NDIV_MODE_SHIFT 17 +#define CHIPC_PMU5_PLL_FMAB_OFF 3 +#define CHIPC_PMU5_PLL_MRAT_MASK 0xf0000000 +#define CHIPC_PMU5_PLL_MRAT_SHIFT 28 +#define CHIPC_PMU5_PLL_ABRAT_MASK 0x08000000 +#define CHIPC_PMU5_PLL_ABRAT_SHIFT 27 +#define CHIPC_PMU5_PLL_FDIV_MASK 0x07ffffff +#define CHIPC_PMU5_PLL_PLLCTL_OFF 4 +#define CHIPC_PMU5_PLL_PCHI_OFF 5 +#define CHIPC_PMU5_PLL_PCHI_MASK 0x0000003f + +/* pmu XtalFreqRatio */ +#define CHIPC_PMU_XTALFREQ_REG_ILPCTR_MASK 0x00001FFF +#define CHIPC_PMU_XTALFREQ_REG_MEASURE_MASK 0x80000000 +#define CHIPC_PMU_XTALFREQ_REG_MEASURE_SHIFT 31 + +/* Divider allocation in 4716/47162/5356/5357 */ +#define CHIPC_PMU5_MAINPLL_CPU 1 +#define CHIPC_PMU5_MAINPLL_MEM 2 +#define CHIPC_PMU5_MAINPLL_SI 3 + +#define CHIPC_PMU7_PLL_PLLCTL7 7 +#define CHIPC_PMU7_PLL_PLLCTL8 8 +#define CHIPC_PMU7_PLL_PLLCTL11 11 + +/* PLL usage in 4716/47162 */ +#define CHIPC_PMU4716_MAINPLL_PLL0 12 + +/* PLL usage in 5356/5357 */ +#define CHIPC_PMU5356_MAINPLL_PLL0 0 +#define CHIPC_PMU5357_MAINPLL_PLL0 0 + +/* 4716/47162 resources */ +#define CHIPC_RES4716_PROC_PLL_ON 0x00000040 +#define CHIPC_RES4716_PROC_HT_AVAIL 0x00000080 + +/* 4716/4717/4718 Chip specific ChipControl register bits */ +#define CHIPC_CCTRL471X_I2S_PINS_ENABLE 0x0080 /* I2S pins off by default, shared with pflash */ + +/* 5354 resources */ +#define CHIPC_RES5354_EXT_SWITCHER_PWM 0 /* 0x00001 */ +#define CHIPC_RES5354_BB_SWITCHER_PWM 1 /* 0x00002 */ +#define CHIPC_RES5354_BB_SWITCHER_BURST 2 /* 0x00004 */ +#define CHIPC_RES5354_BB_EXT_SWITCHER_BURST 3 /* 0x00008 */ +#define CHIPC_RES5354_ILP_REQUEST 4 /* 0x00010 */ +#define CHIPC_RES5354_RADIO_SWITCHER_PWM 5 /* 0x00020 */ +#define CHIPC_RES5354_RADIO_SWITCHER_BURST 6 /* 0x00040 */ +#define CHIPC_RES5354_ROM_SWITCH 7 /* 0x00080 */ +#define CHIPC_RES5354_PA_REF_LDO 8 /* 0x00100 */ +#define CHIPC_RES5354_RADIO_LDO 9 /* 0x00200 */ +#define CHIPC_RES5354_AFE_LDO 10 /* 0x00400 */ +#define CHIPC_RES5354_PLL_LDO 11 /* 0x00800 */ +#define CHIPC_RES5354_BG_FILTBYP 12 /* 0x01000 */ +#define CHIPC_RES5354_TX_FILTBYP 13 /* 0x02000 */ +#define CHIPC_RES5354_RX_FILTBYP 14 /* 0x04000 */ +#define CHIPC_RES5354_XTAL_PU 15 /* 0x08000 */ +#define CHIPC_RES5354_XTAL_EN 16 /* 0x10000 */ +#define CHIPC_RES5354_BB_PLL_FILTBYP 17 /* 0x20000 */ +#define CHIPC_RES5354_RF_PLL_FILTBYP 18 /* 0x40000 */ +#define CHIPC_RES5354_BB_PLL_PU 19 /* 0x80000 */ + +/* 5357 Chip specific ChipControl register bits */ +#define CHIPC_CCTRL5357_EXTPA (1<<14) /* extPA in ChipControl 1, bit 14 */ +#define CHIPC_CCTRL5357_ANT_MUX_2o3 (1<<15) /* 2o3 in ChipControl 1, bit 15 */ + +/* 4328 resources */ +#define CHIPC_RES4328_EXT_SWITCHER_PWM 0 /* 0x00001 */ +#define CHIPC_RES4328_BB_SWITCHER_PWM 1 /* 0x00002 */ +#define CHIPC_RES4328_BB_SWITCHER_BURST 2 /* 0x00004 */ +#define CHIPC_RES4328_BB_EXT_SWITCHER_BURST 3 /* 0x00008 */ +#define CHIPC_RES4328_ILP_REQUEST 4 /* 0x00010 */ +#define CHIPC_RES4328_RADIO_SWITCHER_PWM 5 /* 0x00020 */ +#define CHIPC_RES4328_RADIO_SWITCHER_BURST 6 /* 0x00040 */ +#define CHIPC_RES4328_ROM_SWITCH 7 /* 0x00080 */ +#define CHIPC_RES4328_PA_REF_LDO 8 /* 0x00100 */ +#define CHIPC_RES4328_RADIO_LDO 9 /* 0x00200 */ +#define CHIPC_RES4328_AFE_LDO 10 /* 0x00400 */ +#define CHIPC_RES4328_PLL_LDO 11 /* 0x00800 */ +#define CHIPC_RES4328_BG_FILTBYP 12 /* 0x01000 */ +#define CHIPC_RES4328_TX_FILTBYP 13 /* 0x02000 */ +#define CHIPC_RES4328_RX_FILTBYP 14 /* 0x04000 */ +#define CHIPC_RES4328_XTAL_PU 15 /* 0x08000 */ +#define CHIPC_RES4328_XTAL_EN 16 /* 0x10000 */ +#define CHIPC_RES4328_BB_PLL_FILTBYP 17 /* 0x20000 */ +#define CHIPC_RES4328_RF_PLL_FILTBYP 18 /* 0x40000 */ +#define CHIPC_RES4328_BB_PLL_PU 19 /* 0x80000 */ + +/* 4325 A0/A1 resources */ +#define CHIPC_RES4325_BUCK_BOOST_BURST 0 /* 0x00000001 */ +#define CHIPC_RES4325_CBUCK_BURST 1 /* 0x00000002 */ +#define CHIPC_RES4325_CBUCK_PWM 2 /* 0x00000004 */ +#define CHIPC_RES4325_CLDO_CBUCK_BURST 3 /* 0x00000008 */ +#define CHIPC_RES4325_CLDO_CBUCK_PWM 4 /* 0x00000010 */ +#define CHIPC_RES4325_BUCK_BOOST_PWM 5 /* 0x00000020 */ +#define CHIPC_RES4325_ILP_REQUEST 6 /* 0x00000040 */ +#define CHIPC_RES4325_ABUCK_BURST 7 /* 0x00000080 */ +#define CHIPC_RES4325_ABUCK_PWM 8 /* 0x00000100 */ +#define CHIPC_RES4325_LNLDO1_PU 9 /* 0x00000200 */ +#define CHIPC_RES4325_OTP_PU 10 /* 0x00000400 */ +#define CHIPC_RES4325_LNLDO3_PU 11 /* 0x00000800 */ +#define CHIPC_RES4325_LNLDO4_PU 12 /* 0x00001000 */ +#define CHIPC_RES4325_XTAL_PU 13 /* 0x00002000 */ +#define CHIPC_RES4325_ALP_AVAIL 14 /* 0x00004000 */ +#define CHIPC_RES4325_RX_PWRSW_PU 15 /* 0x00008000 */ +#define CHIPC_RES4325_TX_PWRSW_PU 16 /* 0x00010000 */ +#define CHIPC_RES4325_RFPLL_PWRSW_PU 17 /* 0x00020000 */ +#define CHIPC_RES4325_LOGEN_PWRSW_PU 18 /* 0x00040000 */ +#define CHIPC_RES4325_AFE_PWRSW_PU 19 /* 0x00080000 */ +#define CHIPC_RES4325_BBPLL_PWRSW_PU 20 /* 0x00100000 */ +#define CHIPC_RES4325_HT_AVAIL 21 /* 0x00200000 */ + +/* 4325 B0/C0 resources */ +#define CHIPC_RES4325B0_CBUCK_LPOM 1 /* 0x00000002 */ +#define CHIPC_RES4325B0_CBUCK_BURST 2 /* 0x00000004 */ +#define CHIPC_RES4325B0_CBUCK_PWM 3 /* 0x00000008 */ +#define CHIPC_RES4325B0_CLDO_PU 4 /* 0x00000010 */ + +/* 4325 C1 resources */ +#define CHIPC_RES4325C1_LNLDO2_PU 12 /* 0x00001000 */ + +/* 4325 chip-specific ChipStatus register bits */ +#define CHIPC_CST4325_SPROM_OTP_SEL_MASK CHIPC_CST_SPROM_OTP_SEL_R22_MASK +#define CHIPC_CST4325_SPROM_OTP_SEL_SHIFT CHIPC_CST_SPROM_OTP_SEL_R22_SHIFT +#define CHIPC_CST4325_SDIO_USB_MODE_MASK 0x00000004 +#define CHIPC_CST4325_SDIO_USB_MODE_SHIFT 2 +#define CHIPC_CST4325_RCAL_VALID_MASK 0x00000008 +#define CHIPC_CST4325_RCAL_VALID_SHIFT 3 +#define CHIPC_CST4325_RCAL_VALUE_MASK 0x000001f0 +#define CHIPC_CST4325_RCAL_VALUE_SHIFT 4 +#define CHIPC_CST4325_PMUTOP_2B_MASK 0x00000200 /* 1 for 2b, 0 for to 2a */ +#define CHIPC_CST4325_PMUTOP_2B_SHIFT 9 + +#define CHIPC_RES4329_RESERVED0 0 /* 0x00000001 */ +#define CHIPC_RES4329_CBUCK_LPOM 1 /* 0x00000002 */ +#define CHIPC_RES4329_CBUCK_BURST 2 /* 0x00000004 */ +#define CHIPC_RES4329_CBUCK_PWM 3 /* 0x00000008 */ +#define CHIPC_RES4329_CLDO_PU 4 /* 0x00000010 */ +#define CHIPC_RES4329_PALDO_PU 5 /* 0x00000020 */ +#define CHIPC_RES4329_ILP_REQUEST 6 /* 0x00000040 */ +#define CHIPC_RES4329_RESERVED7 7 /* 0x00000080 */ +#define CHIPC_RES4329_RESERVED8 8 /* 0x00000100 */ +#define CHIPC_RES4329_LNLDO1_PU 9 /* 0x00000200 */ +#define CHIPC_RES4329_OTP_PU 10 /* 0x00000400 */ +#define CHIPC_RES4329_RESERVED11 11 /* 0x00000800 */ +#define CHIPC_RES4329_LNLDO2_PU 12 /* 0x00001000 */ +#define CHIPC_RES4329_XTAL_PU 13 /* 0x00002000 */ +#define CHIPC_RES4329_ALP_AVAIL 14 /* 0x00004000 */ +#define CHIPC_RES4329_RX_PWRSW_PU 15 /* 0x00008000 */ +#define CHIPC_RES4329_TX_PWRSW_PU 16 /* 0x00010000 */ +#define CHIPC_RES4329_RFPLL_PWRSW_PU 17 /* 0x00020000 */ +#define CHIPC_RES4329_LOGEN_PWRSW_PU 18 /* 0x00040000 */ +#define CHIPC_RES4329_AFE_PWRSW_PU 19 /* 0x00080000 */ +#define CHIPC_RES4329_BBPLL_PWRSW_PU 20 /* 0x00100000 */ +#define CHIPC_RES4329_HT_AVAIL 21 /* 0x00200000 */ + +/* 4329 chip-specific ChipStatus register bits */ +#define CHIPC_CST4329_SPROM_OTP_SEL_MASK CHIPC_CST_SPROM_OTP_SEL_R22_MASK +#define CHIPC_CST4329_SPROM_OTP_SEL_SHIFT CHIPC_CST_SPROM_OTP_SEL_R22_SHIFT +#define CHIPC_CST4329_SPI_SDIO_MODE_MASK 0x00000004 +#define CHIPC_CST4329_SPI_SDIO_MODE_SHIFT 2 + +/* 4312 chip-specific ChipStatus register bits */ +#define CHIPC_CST4312_SPROM_OTP_SEL_MASK CHIPC_CST_SPROM_OTP_SEL_R22_MASK +#define CHIPC_CST4312_SPROM_OTP_SEL_SHIFT CHIPC_CST_SPROM_OTP_SEL_R22_SHIFT + +/* 4312 resources (all PMU chips with little memory constraint) */ +#define CHIPC_RES4312_SWITCHER_BURST 0 /* 0x00000001 */ +#define CHIPC_RES4312_SWITCHER_PWM 1 /* 0x00000002 */ +#define CHIPC_RES4312_PA_REF_LDO 2 /* 0x00000004 */ +#define CHIPC_RES4312_CORE_LDO_BURST 3 /* 0x00000008 */ +#define CHIPC_RES4312_CORE_LDO_PWM 4 /* 0x00000010 */ +#define CHIPC_RES4312_RADIO_LDO 5 /* 0x00000020 */ +#define CHIPC_RES4312_ILP_REQUEST 6 /* 0x00000040 */ +#define CHIPC_RES4312_BG_FILTBYP 7 /* 0x00000080 */ +#define CHIPC_RES4312_TX_FILTBYP 8 /* 0x00000100 */ +#define CHIPC_RES4312_RX_FILTBYP 9 /* 0x00000200 */ +#define CHIPC_RES4312_XTAL_PU 10 /* 0x00000400 */ +#define CHIPC_RES4312_ALP_AVAIL 11 /* 0x00000800 */ +#define CHIPC_RES4312_BB_PLL_FILTBYP 12 /* 0x00001000 */ +#define CHIPC_RES4312_RF_PLL_FILTBYP 13 /* 0x00002000 */ +#define CHIPC_RES4312_HT_AVAIL 14 /* 0x00004000 */ + +/* 4322 resources */ +#define CHIPC_RES4322_RF_LDO 0 +#define CHIPC_RES4322_ILP_REQUEST 1 +#define CHIPC_RES4322_XTAL_PU 2 +#define CHIPC_RES4322_ALP_AVAIL 3 +#define CHIPC_RES4322_SI_PLL_ON 4 +#define CHIPC_RES4322_HT_SI_AVAIL 5 +#define CHIPC_RES4322_PHY_PLL_ON 6 +#define CHIPC_RES4322_HT_PHY_AVAIL 7 +#define CHIPC_RES4322_OTP_PU 8 + +/* 4322 chip-specific ChipStatus register bits */ +#define CHIPC_CST4322_XTAL_FREQ_20_40MHZ 0x00000020 +#define CHIPC_CST4322_SPROM_OTP_SEL_MASK CHIPC_CST_SPROM_OTP_SEL_R23_MASK +#define CHIPC_CST4322_SPROM_OTP_SEL_SHIFT CHIPC_CST_SPROM_OTP_SEL_R23_SHIFT +#define CHIPC_CST4322_PCI_OR_USB 0x00000100 +#define CHIPC_CST4322_BOOT_MASK 0x00000600 +#define CHIPC_CST4322_BOOT_SHIFT 9 +#define CHIPC_CST4322_BOOT_FROM_SRAM 0 /* boot from SRAM, ARM in reset */ +#define CHIPC_CST4322_BOOT_FROM_ROM 1 /* boot from ROM */ +#define CHIPC_CST4322_BOOT_FROM_FLASH 2 /* boot from FLASH */ +#define CHIPC_CST4322_BOOT_FROM_INVALID 3 +#define CHIPC_CST4322_ILP_DIV_EN 0x00000800 +#define CHIPC_CST4322_FLASH_TYPE_MASK 0x00001000 +#define CHIPC_CST4322_FLASH_TYPE_SHIFT 12 +#define CHIPC_CST4322_FLASH_TYPE_SHIFT_ST 0 /* ST serial FLASH */ +#define CHIPC_CST4322_FLASH_TYPE_SHIFT_ATMEL 1 /* ATMEL flash */ +#define CHIPC_CST4322_ARM_TAP_SEL 0x00002000 +#define CHIPC_CST4322_RES_INIT_MODE_MASK 0x0000c000 +#define CHIPC_CST4322_RES_INIT_MODE_SHIFT 14 +#define CHIPC_CST4322_RES_INIT_MODE_ILPAVAIL 0 /* resinitmode: ILP available */ +#define CHIPC_CST4322_RES_INIT_MODE_ILPREQ 1 /* resinitmode: ILP request */ +#define CHIPC_CST4322_RES_INIT_MODE_ALPAVAIL 2 /* resinitmode: ALP available */ +#define CHIPC_CST4322_RES_INIT_MODE_HTAVAIL 3 /* resinitmode: HT available */ +#define CHIPC_CST4322_PCIPLLCLK_GATING 0x00010000 +#define CHIPC_CST4322_CLK_SWITCH_PCI_TO_ALP 0x00020000 +#define CHIPC_CST4322_PCI_CARDBUS_MODE 0x00040000 + +/* 43224 chip-specific ChipControl register bits */ +#define CHIPC_CCTRL43224_GPIO_TOGGLE 0x8000 +#define CHIPC_CCTRL_43224A0_12MA_LED_DRIVE 0x00F000F0 /* 12 mA drive strength */ +#define CHIPC_CCTRL_43224B0_12MA_LED_DRIVE 0xF0 /* 12 mA drive strength for later 43224s */ + +/* 43236 resources */ +#define CHIPC_RES43236_REGULATOR 0 +#define CHIPC_RES43236_ILP_REQUEST 1 +#define CHIPC_RES43236_XTAL_PU 2 +#define CHIPC_RES43236_ALP_AVAIL 3 +#define CHIPC_RES43236_SI_PLL_ON 4 +#define CHIPC_RES43236_HT_SI_AVAIL 5 + +/* 43236 chip-specific ChipControl register bits */ +#define CHIPC_CCTRL43236_BT_COEXIST (1<<0) /* 0 disable */ +#define CHIPC_CCTRL43236_SECI (1<<1) /* 0 SECI is disabled (JATG functional) */ +#define CHIPC_CCTRL43236_EXT_LNA (1<<2) /* 0 disable */ +#define CHIPC_CCTRL43236_ANT_MUX_2o3 (1<<3) /* 2o3 mux, chipcontrol bit 3 */ +#define CHIPC_CCTRL43236_GSIO (1<<4) /* 0 disable */ + +/* 43236 Chip specific ChipStatus register bits */ +#define CHIPC_CST43236_SFLASH_MASK 0x00000040 +#define CHIPC_CST43236_OTP_SEL_MASK 0x00000080 +#define CHIPC_CST43236_OTP_SEL_SHIFT 7 +#define CHIPC_CST43236_HSIC_MASK 0x00000100 /* USB/HSIC */ +#define CHIPC_CST43236_BP_CLK 0x00000200 /* 120/96Mbps */ +#define CHIPC_CST43236_BOOT_MASK 0x00001800 +#define CHIPC_CST43236_BOOT_SHIFT 11 +#define CHIPC_CST43236_BOOT_FROM_SRAM 0 /* boot from SRAM, ARM in reset */ +#define CHIPC_CST43236_BOOT_FROM_ROM 1 /* boot from ROM */ +#define CHIPC_CST43236_BOOT_FROM_FLASH 2 /* boot from FLASH */ +#define CHIPC_CST43236_BOOT_FROM_INVALID 3 + +/* 4331 resources */ +#define CHIPC_RES4331_REGULATOR 0 +#define CHIPC_RES4331_ILP_REQUEST 1 +#define CHIPC_RES4331_XTAL_PU 2 +#define CHIPC_RES4331_ALP_AVAIL 3 +#define CHIPC_RES4331_SI_PLL_ON 4 +#define CHIPC_RES4331_HT_SI_AVAIL 5 + +/* 4331 chip-specific ChipControl register bits */ +#define CHIPC_CCTRL4331_BT_COEXIST (1<<0) /* 0 disable */ +#define CHIPC_CCTRL4331_SECI (1<<1) /* 0 SECI is disabled (JATG functional) */ +#define CHIPC_CCTRL4331_EXT_LNA (1<<2) /* 0 disable */ +#define CHIPC_CCTRL4331_SPROM_GPIO13_15 (1<<3) /* sprom/gpio13-15 mux */ +#define CHIPC_CCTRL4331_EXTPA_EN (1<<4) /* 0 ext pa disable, 1 ext pa enabled */ +#define CHIPC_CCTRL4331_GPIOCLK_ON_SPROMCS (1<<5) /* set drive out GPIO_CLK on sprom_cs pin */ +#define CHIPC_CCTRL4331_PCIE_MDIO_ON_SPROMCS (1<<6) /* use sprom_cs pin as PCIE mdio interface */ +#define CHIPC_CCTRL4331_EXTPA_ON_GPIO2_5 (1<<7) /* aband extpa will be at gpio2/5 and sprom_dout */ +#define CHIPC_CCTRL4331_OVR_PIPEAUXCLKEN (1<<8) /* override core control on pipe_AuxClkEnable */ +#define CHIPC_CCTRL4331_OVR_PIPEAUXPWRDOWN (1<<9) /* override core control on pipe_AuxPowerDown */ +#define CHIPC_CCTRL4331_PCIE_AUXCLKEN (1<<10) /* pcie_auxclkenable */ +#define CHIPC_CCTRL4331_PCIE_PIPE_PLLDOWN (1<<11) /* pcie_pipe_pllpowerdown */ +#define CHIPC_CCTRL4331_BT_SHD0_ON_GPIO4 (1<<16) /* enable bt_shd0 at gpio4 */ +#define CHIPC_CCTRL4331_BT_SHD1_ON_GPIO5 (1<<17) /* enable bt_shd1 at gpio5 */ + +/* 4331 Chip specific ChipStatus register bits */ +#define CHIPC_CST4331_XTAL_FREQ 0x00000001 /* crystal frequency 20/40Mhz */ +#define CHIPC_CST4331_SPROM_PRESENT 0x00000002 +#define CHIPC_CST4331_OTP_PRESENT 0x00000004 +#define CHIPC_CST4331_LDO_RF 0x00000008 +#define CHIPC_CST4331_LDO_PAR 0x00000010 + +/* 4315 resources */ +#define CHIPC_RES4315_CBUCK_LPOM 1 /* 0x00000002 */ +#define CHIPC_RES4315_CBUCK_BURST 2 /* 0x00000004 */ +#define CHIPC_RES4315_CBUCK_PWM 3 /* 0x00000008 */ +#define CHIPC_RES4315_CLDO_PU 4 /* 0x00000010 */ +#define CHIPC_RES4315_PALDO_PU 5 /* 0x00000020 */ +#define CHIPC_RES4315_ILP_REQUEST 6 /* 0x00000040 */ +#define CHIPC_RES4315_LNLDO1_PU 9 /* 0x00000200 */ +#define CHIPC_RES4315_OTP_PU 10 /* 0x00000400 */ +#define CHIPC_RES4315_LNLDO2_PU 12 /* 0x00001000 */ +#define CHIPC_RES4315_XTAL_PU 13 /* 0x00002000 */ +#define CHIPC_RES4315_ALP_AVAIL 14 /* 0x00004000 */ +#define CHIPC_RES4315_RX_PWRSW_PU 15 /* 0x00008000 */ +#define CHIPC_RES4315_TX_PWRSW_PU 16 /* 0x00010000 */ +#define CHIPC_RES4315_RFPLL_PWRSW_PU 17 /* 0x00020000 */ +#define CHIPC_RES4315_LOGEN_PWRSW_PU 18 /* 0x00040000 */ +#define CHIPC_RES4315_AFE_PWRSW_PU 19 /* 0x00080000 */ +#define CHIPC_RES4315_BBPLL_PWRSW_PU 20 /* 0x00100000 */ +#define CHIPC_RES4315_HT_AVAIL 21 /* 0x00200000 */ + +/* 4315 chip-specific ChipStatus register bits */ +#define CHIPC_CST4315_SPROM_OTP_SEL_MASK CHIPC_CST_SPROM_OTP_SEL_R22_MASK +#define CHIPC_CST4315_SPROM_OTP_SEL_SHIFT CHIPC_CST_SPROM_OTP_SEL_R22_SHIFT +#define CHIPC_CST4315_SDIO_MODE 0x00000004 /* gpio [8], sdio/usb mode */ +#define CHIPC_CST4315_RCAL_VALID 0x00000008 +#define CHIPC_CST4315_RCAL_VALUE_MASK 0x000001f0 +#define CHIPC_CST4315_RCAL_VALUE_SHIFT 4 +#define CHIPC_CST4315_PALDO_EXTPNP 0x00000200 /* PALDO is configured with external PNP */ +#define CHIPC_CST4315_CBUCK_MODE_MASK 0x00000c00 +#define CHIPC_CST4315_CBUCK_MODE_BURST 0x00000400 +#define CHIPC_CST4315_CBUCK_MODE_LPBURST 0x00000c00 + +/* 4319 resources */ +#define CHIPC_RES4319_CBUCK_LPOM 1 /* 0x00000002 */ +#define CHIPC_RES4319_CBUCK_BURST 2 /* 0x00000004 */ +#define CHIPC_RES4319_CBUCK_PWM 3 /* 0x00000008 */ +#define CHIPC_RES4319_CLDO_PU 4 /* 0x00000010 */ +#define CHIPC_RES4319_PALDO_PU 5 /* 0x00000020 */ +#define CHIPC_RES4319_ILP_REQUEST 6 /* 0x00000040 */ +#define CHIPC_RES4319_LNLDO1_PU 9 /* 0x00000200 */ +#define CHIPC_RES4319_OTP_PU 10 /* 0x00000400 */ +#define CHIPC_RES4319_LNLDO2_PU 12 /* 0x00001000 */ +#define CHIPC_RES4319_XTAL_PU 13 /* 0x00002000 */ +#define CHIPC_RES4319_ALP_AVAIL 14 /* 0x00004000 */ +#define CHIPC_RES4319_RX_PWRSW_PU 15 /* 0x00008000 */ +#define CHIPC_RES4319_TX_PWRSW_PU 16 /* 0x00010000 */ +#define CHIPC_RES4319_RFPLL_PWRSW_PU 17 /* 0x00020000 */ +#define CHIPC_RES4319_LOGEN_PWRSW_PU 18 /* 0x00040000 */ +#define CHIPC_RES4319_AFE_PWRSW_PU 19 /* 0x00080000 */ +#define CHIPC_RES4319_BBPLL_PWRSW_PU 20 /* 0x00100000 */ +#define CHIPC_RES4319_HT_AVAIL 21 /* 0x00200000 */ + +/* 4319 chip-specific ChipStatus register bits */ +#define CHIPC_CST4319_SPI_CPULESSUSB 0x00000001 +#define CHIPC_CST4319_SPI_CLK_POL 0x00000002 +#define CHIPC_CST4319_SPI_CLK_PH 0x00000008 +#define CHIPC_CST4319_SPROM_OTP_SEL_MASK CHIPC_CST_SPROM_OTP_SEL_R23_MASK /* gpio [7:6], SDIO CIS selection */ +#define CHIPC_CST4319_SPROM_OTP_SEL_SHIFT CHIPC_CST_SPROM_OTP_SEL_R23_SHIFT +#define CHIPC_CST4319_SDIO_USB_MODE 0x00000100 /* gpio [8], sdio/usb mode */ +#define CHIPC_CST4319_REMAP_SEL_MASK 0x00000600 +#define CHIPC_CST4319_ILPDIV_EN 0x00000800 +#define CHIPC_CST4319_XTAL_PD_POL 0x00001000 +#define CHIPC_CST4319_LPO_SEL 0x00002000 +#define CHIPC_CST4319_RES_INIT_MODE 0x0000c000 +#define CHIPC_CST4319_PALDO_EXTPNP 0x00010000 /* PALDO is configured with external PNP */ +#define CHIPC_CST4319_CBUCK_MODE_MASK 0x00060000 +#define CHIPC_CST4319_CBUCK_MODE_BURST 0x00020000 +#define CHIPC_CST4319_CBUCK_MODE_LPBURST 0x00060000 +#define CHIPC_CST4319_RCAL_VALID 0x01000000 +#define CHIPC_CST4319_RCAL_VALUE_MASK 0x3e000000 +#define CHIPC_CST4319_RCAL_VALUE_SHIFT 25 + +#define CHIPC_PMU1_PLL0_CHIPCTL0 0 +#define CHIPC_PMU1_PLL0_CHIPCTL1 1 +#define CHIPC_PMU1_PLL0_CHIPCTL2 2 +#define CHIPC_CCTL_4319USB_XTAL_SEL_MASK 0x00180000 +#define CHIPC_CCTL_4319USB_XTAL_SEL_SHIFT 19 +#define CHIPC_CCTL_4319USB_48MHZ_PLL_SEL 1 +#define CHIPC_CCTL_4319USB_24MHZ_PLL_SEL 2 + +/* PMU resources for 4336 */ +#define CHIPC_RES4336_CBUCK_LPOM 0 +#define CHIPC_RES4336_CBUCK_BURST 1 +#define CHIPC_RES4336_CBUCK_LP_PWM 2 +#define CHIPC_RES4336_CBUCK_PWM 3 +#define CHIPC_RES4336_CLDO_PU 4 +#define CHIPC_RES4336_DIS_INT_RESET_PD 5 +#define CHIPC_RES4336_ILP_REQUEST 6 +#define CHIPC_RES4336_LNLDO_PU 7 +#define CHIPC_RES4336_LDO3P3_PU 8 +#define CHIPC_RES4336_OTP_PU 9 +#define CHIPC_RES4336_XTAL_PU 10 +#define CHIPC_RES4336_ALP_AVAIL 11 +#define CHIPC_RES4336_RADIO_PU 12 +#define CHIPC_RES4336_BG_PU 13 +#define CHIPC_RES4336_VREG1p4_PU_PU 14 +#define CHIPC_RES4336_AFE_PWRSW_PU 15 +#define CHIPC_RES4336_RX_PWRSW_PU 16 +#define CHIPC_RES4336_TX_PWRSW_PU 17 +#define CHIPC_RES4336_BB_PWRSW_PU 18 +#define CHIPC_RES4336_SYNTH_PWRSW_PU 19 +#define CHIPC_RES4336_MISC_PWRSW_PU 20 +#define CHIPC_RES4336_LOGEN_PWRSW_PU 21 +#define CHIPC_RES4336_BBPLL_PWRSW_PU 22 +#define CHIPC_RES4336_MACPHY_CLKAVAIL 23 +#define CHIPC_RES4336_HT_AVAIL 24 +#define CHIPC_RES4336_RSVD 25 + +/* 4336 chip-specific ChipStatus register bits */ +#define CHIPC_CST4336_SPI_MODE_MASK 0x00000001 +#define CHIPC_CST4336_SPROM_PRESENT 0x00000002 +#define CHIPC_CST4336_OTP_PRESENT 0x00000004 +#define CHIPC_CST4336_ARMREMAP_0 0x00000008 +#define CHIPC_CST4336_ILPDIV_EN_MASK 0x00000010 +#define CHIPC_CST4336_ILPDIV_EN_SHIFT 4 +#define CHIPC_CST4336_XTAL_PD_POL_MASK 0x00000020 +#define CHIPC_CST4336_XTAL_PD_POL_SHIFT 5 +#define CHIPC_CST4336_LPO_SEL_MASK 0x00000040 +#define CHIPC_CST4336_LPO_SEL_SHIFT 6 +#define CHIPC_CST4336_RES_INIT_MODE_MASK 0x00000180 +#define CHIPC_CST4336_RES_INIT_MODE_SHIFT 7 +#define CHIPC_CST4336_CBUCK_MODE_MASK 0x00000600 +#define CHIPC_CST4336_CBUCK_MODE_SHIFT 9 + +/* 4330 resources */ +#define CHIPC_RES4330_CBUCK_LPOM 0 +#define CHIPC_RES4330_CBUCK_BURST 1 +#define CHIPC_RES4330_CBUCK_LP_PWM 2 +#define CHIPC_RES4330_CBUCK_PWM 3 +#define CHIPC_RES4330_CLDO_PU 4 +#define CHIPC_RES4330_DIS_INT_RESET_PD 5 +#define CHIPC_RES4330_ILP_REQUEST 6 +#define CHIPC_RES4330_LNLDO_PU 7 +#define CHIPC_RES4330_LDO3P3_PU 8 +#define CHIPC_RES4330_OTP_PU 9 +#define CHIPC_RES4330_XTAL_PU 10 +#define CHIPC_RES4330_ALP_AVAIL 11 +#define CHIPC_RES4330_RADIO_PU 12 +#define CHIPC_RES4330_BG_PU 13 +#define CHIPC_RES4330_VREG1p4_PU_PU 14 +#define CHIPC_RES4330_AFE_PWRSW_PU 15 +#define CHIPC_RES4330_RX_PWRSW_PU 16 +#define CHIPC_RES4330_TX_PWRSW_PU 17 +#define CHIPC_RES4330_BB_PWRSW_PU 18 +#define CHIPC_RES4330_SYNTH_PWRSW_PU 19 +#define CHIPC_RES4330_MISC_PWRSW_PU 20 +#define CHIPC_RES4330_LOGEN_PWRSW_PU 21 +#define CHIPC_RES4330_BBPLL_PWRSW_PU 22 +#define CHIPC_RES4330_MACPHY_CLKAVAIL 23 +#define CHIPC_RES4330_HT_AVAIL 24 +#define CHIPC_RES4330_5gRX_PWRSW_PU 25 +#define CHIPC_RES4330_5gTX_PWRSW_PU 26 +#define CHIPC_RES4330_5g_LOGEN_PWRSW_PU 27 + +/* 4330 chip-specific ChipStatus register bits */ +#define CHIPC_CST4330_CHIPMODE_SDIOD(cs) (((cs) & 0x7) < 6) /* SDIO || gSPI */ +#define CHIPC_CST4330_CHIPMODE_USB20D(cs) (((cs) & 0x7) >= 6) /* USB || USBDA */ +#define CHIPC_CST4330_CHIPMODE_SDIO(cs) (((cs) & 0x4) == 0) /* SDIO */ +#define CHIPC_CST4330_CHIPMODE_GSPI(cs) (((cs) & 0x6) == 4) /* gSPI */ +#define CHIPC_CST4330_CHIPMODE_USB(cs) (((cs) & 0x7) == 6) /* USB packet-oriented */ +#define CHIPC_CST4330_CHIPMODE_USBDA(cs) (((cs) & 0x7) == 7) /* USB Direct Access */ +#define CHIPC_CST4330_OTP_PRESENT 0x00000010 +#define CHIPC_CST4330_LPO_AUTODET_EN 0x00000020 +#define CHIPC_CST4330_ARMREMAP_0 0x00000040 +#define CHIPC_CST4330_SPROM_PRESENT 0x00000080 /* takes priority over OTP if both set */ +#define CHIPC_CST4330_ILPDIV_EN 0x00000100 +#define CHIPC_CST4330_LPO_SEL 0x00000200 +#define CHIPC_CST4330_RES_INIT_MODE_SHIFT 10 +#define CHIPC_CST4330_RES_INIT_MODE_MASK 0x00000c00 +#define CHIPC_CST4330_CBUCK_MODE_SHIFT 12 +#define CHIPC_CST4330_CBUCK_MODE_MASK 0x00003000 +#define CHIPC_CST4330_CBUCK_POWER_OK 0x00004000 +#define CHIPC_CST4330_BB_PLL_LOCKED 0x00008000 +#define CHIPC_SOCDEVRAM_4330_BP_ADDR 0x1E000000 +#define CHIPC_SOCDEVRAM_4330_ARM_ADDR 0x00800000 + +/* 4313 resources */ +#define CHIPC_RES4313_BB_PU_RSRC 0 +#define CHIPC_RES4313_ILP_REQ_RSRC 1 +#define CHIPC_RES4313_XTAL_PU_RSRC 2 +#define CHIPC_RES4313_ALP_AVAIL_RSRC 3 +#define CHIPC_RES4313_RADIO_PU_RSRC 4 +#define CHIPC_RES4313_BG_PU_RSRC 5 +#define CHIPC_RES4313_VREG1P4_PU_RSRC 6 +#define CHIPC_RES4313_AFE_PWRSW_RSRC 7 +#define CHIPC_RES4313_RX_PWRSW_RSRC 8 +#define CHIPC_RES4313_TX_PWRSW_RSRC 9 +#define CHIPC_RES4313_BB_PWRSW_RSRC 10 +#define CHIPC_RES4313_SYNTH_PWRSW_RSRC 11 +#define CHIPC_RES4313_MISC_PWRSW_RSRC 12 +#define CHIPC_RES4313_BB_PLL_PWRSW_RSRC 13 +#define CHIPC_RES4313_HT_AVAIL_RSRC 14 +#define CHIPC_RES4313_MACPHY_CLK_AVAIL_RSRC 15 + +/* 4313 chip-specific ChipStatus register bits */ +#define CHIPC_CST4313_SPROM_PRESENT 1 +#define CHIPC_CST4313_OTP_PRESENT 2 +#define CHIPC_CST4313_SPROM_OTP_SEL_MASK 0x00000002 +#define CHIPC_CST4313_SPROM_OTP_SEL_SHIFT 0 + +/* 4313 Chip specific ChipControl register bits */ +#define CHIPC_CCTRL_4313_12MA_LED_DRIVE 0x00000007 /* 12 mA drive strengh for later 4313 */ + +/* 43228 resources */ +#define CHIPC_RES43228_NOT_USED 0 +#define CHIPC_RES43228_ILP_REQUEST 1 +#define CHIPC_RES43228_XTAL_PU 2 +#define CHIPC_RES43228_ALP_AVAIL 3 +#define CHIPC_RES43228_PLL_EN 4 +#define CHIPC_RES43228_HT_PHY_AVAIL 5 + +/* 43228 chipstatus reg bits */ +#define CHIPC_CST43228_ILP_DIV_EN 0x1 +#define CHIPC_CST43228_OTP_PRESENT 0x2 +#define CHIPC_CST43228_SERDES_REFCLK_PADSEL 0x4 +#define CHIPC_CST43228_SDIO_MODE 0x8 + +#define CHIPC_CST43228_SDIO_OTP_PRESENT 0x10 +#define CHIPC_CST43228_SDIO_RESET 0x20 + +/* +* Maximum delay for the PMU state transition in us. +* This is an upper bound intended for spinwaits etc. +*/ +#define CHIPC_PMU_MAX_TRANSITION_DLY 15000 + +/* PMU resource up transition time in ILP cycles */ +#define CHIPC_PMURES_UP_TRANSITION 2 + +/* +* Register eci_inputlo bitfield values. +* - BT packet type information bits [7:0] +*/ +/* [3:0] - Task (link) type */ +#define CHIPC_BT_ACL 0x00 +#define CHIPC_BT_SCO 0x01 +#define CHIPC_BT_eSCO 0x02 +#define CHIPC_BT_A2DP 0x03 +#define CHIPC_BT_SNIFF 0x04 +#define CHIPC_BT_PAGE_SCAN 0x05 +#define CHIPC_BT_INQUIRY_SCAN 0x06 +#define CHIPC_BT_PAGE 0x07 +#define CHIPC_BT_INQUIRY 0x08 +#define CHIPC_BT_MSS 0x09 +#define CHIPC_BT_PARK 0x0a +#define CHIPC_BT_RSSISCAN 0x0b +#define CHIPC_BT_MD_ACL 0x0c +#define CHIPC_BT_MD_eSCO 0x0d +#define CHIPC_BT_SCAN_WITH_SCO_LINK 0x0e +#define CHIPC_BT_SCAN_WITHOUT_SCO_LINK 0x0f +/* [7:4] = packet duration code */ +/* [8] - Master / Slave */ +#define CHIPC_BT_MASTER 0 +#define CHIPC_BT_SLAVE 1 +/* [11:9] - multi-level priority */ +#define CHIPC_BT_LOWEST_PRIO 0x0 +#define CHIPC_BT_HIGHEST_PRIO 0x3 + +#endif /* _BHND_CORES_CHIPC_CHIPCREG_H_ */ diff --git a/sys/dev/bhnd/cores/chipc/chipcvar.h b/sys/dev/bhnd/cores/chipc/chipcvar.h new file mode 100644 index 000000000000..988224b11010 --- /dev/null +++ b/sys/dev/bhnd/cores/chipc/chipcvar.h @@ -0,0 +1,94 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $FreeBSD$ + */ + +#ifndef _BHND_CORES_CHIPC_CHIPCVAR_H_ +#define _BHND_CORES_CHIPC_CHIPCVAR_H_ + +#include "chipc.h" + +DECLARE_CLASS(bhnd_chipc); +extern devclass_t bhnd_chipc_devclass; + +#define CHIPC_MAX_RES 1 +#define CHIPC_MAX_RSPEC (CHIPC_MAX_RES+1) + +/* + * ChipCommon device quirks / features + */ +enum { + /** No quirks */ + CHIPC_QUIRK_NONE = 0, + + /** + * The device always provides an external SROM. + */ + CHIPC_QUIRK_ALWAYS_HAS_SPROM = (1<<1), + + + /** + * SROM availability must be determined through chip-specific + * ChipStatus flags. + */ + CHIPC_QUIRK_SPROM_CHECK_CHIPST = (1<<3), + + /** + * Use the rev22 chipstatus register format when determining SPROM + * availability. + */ + CHIPC_QUIRK_SPROM_CHECK_CST_R22 = (1<<4)|CHIPC_QUIRK_SPROM_CHECK_CHIPST, + + /** + * Use the rev23 chipstatus register format when determining SPROM + * availability. + */ + CHIPC_QUIRK_SPROM_CHECK_CST_R23 = (1<<5)|CHIPC_QUIRK_SPROM_CHECK_CHIPST, + + /** + * External NAND NVRAM is supported, along with the CHIPC_CAP_NFLASH + * capability flag. + */ + CHIPC_QUIRK_SUPPORTS_NFLASH = (1<<6), +}; + +struct chipc_softc { + device_t dev; + + struct resource_spec rspec[CHIPC_MAX_RSPEC]; + struct bhnd_resource *res[CHIPC_MAX_RES]; + + struct bhnd_resource *core; /**< core registers. */ + struct bhnd_chipid ccid; /**< chip identification */ + uint32_t quirks; /**< CHIPC_QUIRK_* quirk flags */ + uint32_t caps; /**< CHIPC_CAP_* capability register flags */ + uint32_t cst; /**< CHIPC_CST* status register flags */ +}; + +#endif /* _BHND_CORES_CHIPC_CHIPCVAR_H_ */ \ No newline at end of file diff --git a/sys/dev/bhnd/cores/pci/bhnd_pci.c b/sys/dev/bhnd/cores/pci/bhnd_pci.c new file mode 100644 index 000000000000..2feccd78c133 --- /dev/null +++ b/sys/dev/bhnd/cores/pci/bhnd_pci.c @@ -0,0 +1,52 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * Broadcom Common PCI Support. + * + * This module provides common implementation shared across the PCI/PCIe + * endpoint and root complex drivers. + */ + +#include +#include +#include + +#include "bhnd_pcivar.h" + +/** + * PCIe MDIO interface device class + */ +devclass_t bhnd_mdio_pci_devclass; + +MODULE_VERSION(bhnd_pci, 1); +MODULE_DEPEND(bhnd_pci, pci, 1, 1, 1); diff --git a/sys/dev/bhnd/cores/pci/bhnd_pci_hostb.c b/sys/dev/bhnd/cores/pci/bhnd_pci_hostb.c new file mode 100644 index 000000000000..c508f8cc1592 --- /dev/null +++ b/sys/dev/bhnd/cores/pci/bhnd_pci_hostb.c @@ -0,0 +1,117 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * Broadcom PCI-BHND Host Bridge. + * + * This driver is used to "eat" PCI(e) cores operating in endpoint mode when + * they're attached to a bhndb_pci driver on the host side. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +struct bhnd_pci_hostb_softc { +}; + +static int +bhnd_pci_hostb_probe(device_t dev) +{ + /* Ignore non-PCI cores */ + switch (bhnd_get_class(dev)){ + case BHND_DEVCLASS_PCI: + case BHND_DEVCLASS_PCIE: + break; + default: + return (ENXIO); + } + + /* Ignore PCI cores not in host bridge mode. */ + if (!bhnd_is_hostb_device(dev)) + return (ENXIO); + + bhnd_set_generic_core_desc(dev); + return (BUS_PROBE_DEFAULT); +} + +static int +bhnd_pci_hostb_attach(device_t dev) +{ + return (0); +} + +static int +bhnd_pci_hostb_detach(device_t dev) +{ + return (0); +} + +static int +bhnd_pci_hostb_suspend(device_t dev) +{ + return (0); +} + +static int +bhnd_pci_hostb_resume(device_t dev) +{ + return (0); +} + +static device_method_t bhnd_pci_hostb_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, bhnd_pci_hostb_probe), + DEVMETHOD(device_attach, bhnd_pci_hostb_attach), + DEVMETHOD(device_detach, bhnd_pci_hostb_detach), + DEVMETHOD(device_suspend, bhnd_pci_hostb_suspend), + DEVMETHOD(device_resume, bhnd_pci_hostb_resume), + + DEVMETHOD_END +}; + +DEFINE_CLASS_0(bhnd_pci_hostb, bhnd_pci_hostb_driver, bhnd_pci_hostb_methods, + sizeof(struct bhnd_pci_hostb_softc)); + +DRIVER_MODULE(bhnd_hostb, bhnd, bhnd_pci_hostb_driver, bhnd_hostb_devclass, 0, 0); + +MODULE_VERSION(bhnd_pci_hostb, 1); +MODULE_DEPEND(bhnd_pci_hostb, pci, 1, 1, 1); +MODULE_DEPEND(bhnd_pci_hostb, bhnd_pci, 1, 1, 1); \ No newline at end of file diff --git a/sys/dev/bhnd/cores/pci/bhnd_pcib.c b/sys/dev/bhnd/cores/pci/bhnd_pcib.c new file mode 100644 index 000000000000..8dbdcd0b653a --- /dev/null +++ b/sys/dev/bhnd/cores/pci/bhnd_pcib.c @@ -0,0 +1,127 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * Broadcom PCI-BHND Host Bridge. + * + * This driver is used to "eat" PCI(e) cores operating in endpoint mode when + * they're attached to a bhndb_pci driver on the host side. + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "bhnd_pcireg.h" + +#include "bhnd_pcibvar.h" + +static const struct bhnd_pcib_device { + uint16_t vendor; + uint16_t device; + const char *desc; +} bhnd_pcib_devs[] = { + { BHND_MFGID_BCM, BHND_COREID_PCI, "BHND Host-PCI bridge" }, + { BHND_MFGID_BCM, BHND_COREID_PCIE, "BHND Host-PCI bridge (PCIe Gen1)" }, + { BHND_MFGID_INVALID, BHND_COREID_INVALID, NULL } +}; + +static int +bhnd_pcib_probe(device_t dev) +{ + const struct bhnd_pcib_device *id; + + /* Ignore PCI cores configured in host bridge mode */ + if (bhnd_is_hostb_device(dev)) + return (ENXIO); + + for (id = bhnd_pcib_devs; id->device != BHND_COREID_INVALID; id++) { + if (bhnd_get_vendor(dev) != id->vendor) + continue; + + if (bhnd_get_device(dev) != id->device) + continue; + + device_set_desc(dev, id->desc); + return (BUS_PROBE_SPECIFIC); + } + + return (ENXIO); +} + +static int +bhnd_pcib_attach(device_t dev) +{ + return (ENXIO); +} + +static int +bhnd_pcib_detach(device_t dev) +{ + return (ENXIO); +} + +static int +bhnd_pcib_suspend(device_t dev) +{ + return (ENXIO); +} + +static int +bhnd_pcib_resume(device_t dev) +{ + return (ENXIO); +} + +static device_method_t bhnd_pcib_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, bhnd_pcib_probe), + DEVMETHOD(device_attach, bhnd_pcib_attach), + DEVMETHOD(device_detach, bhnd_pcib_detach), + DEVMETHOD(device_suspend, bhnd_pcib_suspend), + DEVMETHOD(device_resume, bhnd_pcib_resume), + DEVMETHOD_END +}; + +DEFINE_CLASS_0(bhnd_pcib, bhnd_pcib_driver, bhnd_pcib_methods, sizeof(struct bhnd_pcib_softc)); +DRIVER_MODULE(bhnd_pcib, bhnd, bhnd_pcib_driver, bhnd_hostb_devclass, 0, 0); + +MODULE_VERSION(bhnd_pcib, 1); +MODULE_DEPEND(bhnd_pcib, pci, 1, 1, 1); +MODULE_DEPEND(bhnd_pcib, bhnd_pci_mdio, 1, 1, 1); diff --git a/sys/dev/bhnd/cores/pci/bhnd_pcibvar.h b/sys/dev/bhnd/cores/pci/bhnd_pcibvar.h new file mode 100644 index 000000000000..d30f74d1daf2 --- /dev/null +++ b/sys/dev/bhnd/cores/pci/bhnd_pcibvar.h @@ -0,0 +1,50 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $FreeBSD$ + */ + +#ifndef _BHND_CORES_PCI_BHND_PCIBVAR_H_ +#define _BHND_CORES_PCI_BHND_PCIBVAR_H_ + +#include "bhnd_pcivar.h" + +/* PCI bridge driver-specific state */ +#define BHND_PCIB_MAX_RES 2 +#define BHND_PCIB_MAX_RSPEC (BHND_PCIB_MAX_RES+1) +struct bhnd_pcib_softc { + device_t dev; /**< pci device */ + struct bhnd_resource *core; /**< core registers. */ + bhnd_pci_regfmt_t regfmt; /**< device register format */ + + struct resource_spec rspec[BHND_PCIB_MAX_RSPEC]; + struct bhnd_resource *res[BHND_PCIB_MAX_RES]; + +}; + +#endif /* _BHND_CORES_PCI_BHND_PCIBVAR_H_ */ \ No newline at end of file diff --git a/sys/dev/bhnd/cores/pci/bhnd_pcireg.h b/sys/dev/bhnd/cores/pci/bhnd_pcireg.h new file mode 100644 index 000000000000..e707b9c0348a --- /dev/null +++ b/sys/dev/bhnd/cores/pci/bhnd_pcireg.h @@ -0,0 +1,387 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * Copyright (c) 2010 Broadcom Corporation + * All rights reserved. + * + * This file is derived from the hndsoc.h, pci_core.h, and pcie_core.h headers + * distributed with Broadcom's initial brcm80211 Linux driver release, as + * contributed to the Linux staging repository. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef _BHND_CORES_PCI_BHND_PCIREG_H_ +#define _BHND_CORES_PCI_BHND_PCIREG_H_ + +/* + * PCI/PCIe-Gen1 DMA Constants + */ + +#define BHND_PCI_DMA32_TRANSLATION 0x40000000 /* Client Mode sb2pcitranslation2 (1 GB) */ +#define BHND_PCI_DMA32_SZ 0x40000000 /* Client Mode sb2pcitranslation2 size in bytes */ + +#define BHND_PCIE_DMA32_TRANSLATION BHND_PCI_DMA32_TRANSLATION +#define BHND_PCIE_DMA32_SZ BHND_PCI_DMA32_SZ + +#define BHND_PCIE_DMA64_L32 0x00000000 /**< 64-bit client mode sb2pcitranslation2 (2 ZettaBytes, low 32 bits) */ +#define BHND_PCIE_DMA64_H32 0x80000000 /**< 64-bit client mode sb2pcitranslation2 (2 ZettaBytes, high 32 bits) */ + +/* + * PCI Core Registers + */ + +#define BHND_PCI_CTL 0x000 /**< PCI core control*/ +#define BHND_PCI_ARB_CTL 0x010 /**< PCI arbiter control */ +#define BHND_PCI_CLKRUN_CTL 0x014 /**< PCI clckrun control (>= rev11) */ +#define BHND_PCI_INTR_STATUS 0x020 /**< Interrupt status */ +#define BHND_PCI_INTR_MASK 0x024 /**< Interrupt mask */ +#define BHND_PCI_SBTOPCI_MBOX 0x028 /**< Sonics to PCI mailbox */ +#define BHND_PCI_BCAST_ADDR 0x050 /**< Sonics broadcast address (pci) */ +#define BHND_PCI_BCAST_DATA 0x054 /**< Sonics broadcast data (pci) */ +#define BHND_PCI_GPIO_IN 0x060 /**< GPIO input (>= rev2) */ +#define BHND_PCI_GPIO_OUT 0x064 /**< GPIO output (>= rev2) */ +#define BHND_PCI_GPIO_EN 0x068 /**< GPIO output enable (>= rev2) */ +#define BHND_PCI_GPIO_CTL 0x06C /**< GPIO control (>= rev2) */ +#define BHND_PCI_SBTOPCI0 0x100 /**< Sonics to PCI translation 0 */ +#define BHND_PCI_SBTOPCI1 0x104 /**< Sonics to PCI translation 1 */ +#define BHND_PCI_SBTOPCI2 0x108 /**< Sonics to PCI translation 2 */ +#define BHND_PCI_FUNC0_CFG 0x400 /**< PCI function 0 cfg space (>= rev8) */ +#define BHND_PCI_FUNC1_CFG 0x500 /**< PCI function 1 cfg space (>= rev8) */ +#define BHND_PCI_FUNC2_CFG 0x600 /**< PCI function 2 cfg space (>= rev8) */ +#define BHND_PCI_FUNC3_CFG 0x700 /**< PCI function 3 cfg space (>= rev8) */ +#define BHND_PCI_SPROM_SHADOW 0x800 /**< PCI SPROM shadow */ + +/* BHND_PCI_CTL */ +#define BHND_PCI_CTL_RST_OE 0x01 /* When set, drives PCI_RESET out to pin */ +#define BHND_PCI_CTL_RST 0x02 /* Value driven out to pin */ +#define BHND_PCI_CTL_CLK_OE 0x04 /* When set, drives clock as gated by PCI_CLK out to pin */ +#define BHND_PCI_CTL_CLK 0x08 /* Gate for clock driven out to pin */ + +/* BHND_PCI_ARB_CTL */ +#define BHND_PCI_ARB_INT 0x01 /* When set, use an internal arbiter */ +#define BHND_PCI_ARB_EXT 0x02 /* When set, use an external arbiter */ + +/* BHND_PCI_ARB_CTL - ParkID (>= rev8) */ +#define BHND_PCI_ARB_PARKID_MASK 0x1c /* Selects which agent is parked on an idle bus */ +#define BHND_PCI_ARB_PARKID_SHIFT 2 +#define BHND_PCI_ARB_PARKID_EXT0 0 /* External master 0 */ +#define BHND_PCI_ARB_PARKID_EXT1 1 /* External master 1 */ +#define BHND_PCI_ARB_PARKID_EXT2 2 /* External master 2 */ +#define BHND_PCI_ARB_PARKID_EXT3 3 /* External master 3 (rev >= 11) */ +#define BHND_PCI_ARB_PARKID_INT_r10 3 /* Internal master (rev < 11) */ +#define BHND_PCI_ARB_PARKID_INT_r11 4 /* Internal master (rev >= 11) */ +#define BHND_PCI_ARB_PARKID_LAST_r10 4 /* Last active master (rev < 11) */ +#define BHND_PCI_ARB_PARKID_LAST_r11 5 /* Last active master (rev >= 11) */ + +/* BHND_PCI_CLKRUN_CTL */ +#define BHND_PCI_CLKRUN_DSBL 0x8000 /* Bit 15 forceClkrun */ + +/* BHND_PCI_INTR_STATUS / BHND_PCI_INTR_MASK */ +#define BHND_PCI_INTR_A 0x01 /* PCI INTA# is asserted */ +#define BHND_PCI_INTR_B 0x02 /* PCI INTB# is asserted */ +#define BHND_PCI_INTR_SERR 0x04 /* PCI SERR# has been asserted (write one to clear) */ +#define BHND_PCI_INTR_PERR 0x08 /* PCI PERR# has been asserted (write one to clear) */ + +/* BHND_PCI_SBTOPCI_MBOX + * (General) PCI/SB mailbox interrupts, two bits per pci function */ +#define BHND_PCI_SBTOPCI_MBOX_F0_0 0x100 /* function 0, int 0 */ +#define BHND_PCI_SBTOPCI_MBOX_F0_1 0x200 /* function 0, int 1 */ +#define BHND_PCI_SBTOPCI_MBOX_F1_0 0x400 /* function 1, int 0 */ +#define BHND_PCI_SBTOPCI_MBOX_F1_1 0x800 /* function 1, int 1 */ +#define BHND_PCI_SBTOPCI_MBOX_F2_0 0x1000 /* function 2, int 0 */ +#define BHND_PCI_SBTOPCI_MBOX_F2_1 0x2000 /* function 2, int 1 */ +#define BHND_PCI_SBTOPCI_MBOX_F3_0 0x4000 /* function 3, int 0 */ +#define BHND_PCI_SBTOPCI_MBOX_F3_1 0x8000 /* function 3, int 1 */ + +/* BHND_PCI_BCAST_ADDR */ +#define BHNC_PCI_BCAST_ADDR_MASK 0xFF /* Broadcast register address */ + +/* Sonics to PCI translation types */ +#define BHND_PCI_SBTOPCI0_MASK 0xfc000000 +#define BHND_PCI_SBTOPCI1_MASK 0xfc000000 +#define BHND_PCI_SBTOPCI2_MASK 0xc0000000 + +/* Access type bits (0:1) */ +#define BHND_PCI_SBTOPCI_MEM 0 +#define BHND_PCI_SBTOPCI_IO 1 +#define BHND_PCI_SBTOPCI_CFG0 2 +#define BHND_PCI_SBTOPCI_CFG1 3 + +#define BHND_PCI_SBTOPCI_PREF 0x4 /* prefetch enable */ +#define BHND_PCI_SBTOPCI_BURST 0x8 /* burst enable */ + +#define BHND_PCI_SBTOPCI_RC_MASK 0x30 /* read command (>= rev11) */ +#define BHND_PCI_SBTOPCI_RC_READ 0x00 /* memory read */ +#define BHND_PCI_SBTOPCI_RC_READLINE 0x10 /* memory read line */ +#define BHND_PCI_SBTOPCI_RC_READMULTI 0x20 /* memory read multiple */ + +/* PCI core index in SROM shadow area */ +#define BHND_PCI_SRSH_PI_OFFSET 0 /* first word */ +#define BHND_PCI_SRSH_PI_MASK 0xf000 /* bit 15:12 */ +#define BHND_PCI_SRSH_PI_SHIFT 12 /* bit 15:12 */ + + + +/* + * PCIe-Gen1 Core Registers + */ + +#define BHND_PCIE_CTL BHND_PCI_CTL /**< PCI core control*/ +#define BHND_PCIE_BIST_STATUS 0x00C /**< BIST status */ +#define BHND_PCIE_GPIO_SEL 0x010 /**< GPIO select */ +#define BHND_PCIE_GPIO_OUT_EN 0x014 /**< GPIO output enable */ +#define BHND_PCIE_INTR_STATUS BHND_PCI_INTR_STATUS /**< Interrupt status */ +#define BHND_PCIE_INTR_MASK BHND_PCI_INTR_MASK /**< Interrupt mask */ +#define BHND_PCIE_SBTOPCI_MBOX BHND_PCI_SBTOPCI_MBOX /**< Sonics to PCI mailbox */ +#define BHND_PCIE_SBTOPCI0 BHND_PCI_SBTOPCI0 /**< Sonics to PCI translation 0 */ +#define BHND_PCIE_SBTOPCI1 BHND_PCI_SBTOPCI1 /**< Sonics to PCI translation 1 */ +#define BHND_PCIE_SBTOPCI2 BHND_PCI_SBTOPCI2 /**< Sonics to PCI translation 2 */ + +/* indirect pci config space access */ +#define BHND_PCIE_CFG_ADDR 0x120 /**< pcie config space address */ +#define BHND_PCIE_CFG_DATA 0x124 /**< pcie config space data */ + +/* mdio register access */ +#define BHND_PCIE_MDIO_CTL 0x128 /**< mdio control */ +#define BHND_PCIE_MDIO_DATA 0x12C /**< mdio data */ + +/* indirect protocol phy/dllp/tlp register access */ +#define BHND_PCIE_IND_ADDR 0x130 /**< internal protocol register address */ +#define BHND_PCIE_IND_DATA 0x134 /**< internal protocol register data */ + +#define BHND_PCIE_CLKREQEN_CTL 0x138 /**< clkreq rdma control */ +#define BHND_PCIE_FUNC0_CFG BHND_PCI_FUNC0_CFG /**< PCI function 0 cfg space */ +#define BHND_PCIE_FUNC1_CFG BHND_PCI_FUNC1_CFG /**< PCI function 1 cfg space */ +#define BHND_PCIE_FUNC2_CFG BHND_PCI_FUNC2_CFG /**< PCI function 2 cfg space */ +#define BHND_PCIE_FUNC3_CFG BHND_PCI_FUNC3_CFG /**< PCI function 3 cfg space */ +#define BHND_PCIE_SPROM_SHADOW BHND_PCI_SPROM_SHADOW /**< PCI SPROM shadow */ + +/* BHND_PCIE_CTL */ +#define BHND_PCIE_CTL_RST_OE BHND_PCI_CTL_RST_OE /* When set, drives PCI_RESET out to pin */ +#define BHND_PCIE_CTL_RST BHND_PCI_CTL_RST_OE /* Value driven out to pin */ + +/* BHND_PCI_INTR_STATUS / BHND_PCI_INTR_MASK */ +#define BHND_PCIE_INTR_A BHND_PCI_INTR_A /* PCIE INTA message is received */ +#define BHND_PCIE_INTR_B BHND_PCI_INTR_B /* PCIE INTB message is received */ +#define BHND_PCIE_INTR_FATAL 0x04 /* PCIE INTFATAL message is received */ +#define BHND_PCIE_INTR_NFATAL 0x08 /* PCIE INTNONFATAL message is received */ +#define BHND_PCIE_INTR_CORR 0x10 /* PCIE INTCORR message is received */ +#define BHND_PCIE_INTR_PME 0x20 /* PCIE INTPME message is received */ + +/* SB to PCIE translation masks */ +#define BHND_PCIE_SBTOPCI0_MASK BHND_PCI_SBTOPCI0_MASK +#define BHND_PCIE_SBTOPCI1_MASK BHND_PCI_SBTOPCI1_MASK +#define BHND_PCIE_SBTOPCI2_MASK BHND_PCI_SBTOPCI2_MASK + +/* Access type bits (0:1) */ +#define BHND_PCIE_SBTOPCI_MEM BHND_PCI_SBTOPCI_MEM +#define BHND_PCIE_SBTOPCI_IO BHND_PCI_SBTOPCI_IO +#define BHND_PCIE_SBTOPCI_CFG0 BHND_PCI_SBTOPCI_CFG0 +#define BHND_PCIE_SBTOPCI_CFG1 BHND_PCI_SBTOPCI_CFG1 + +#define BHND_PCIE_SBTOPCI_PREF BHND_PCI_SBTOPCI_PREF /* prefetch enable */ +#define BHND_PCIE_SBTOPCI_BURST BHND_PCI_SBTOPCI_BURST /* burst enable */ + +/* BHND_PCIE_CFG_ADDR / BHND_PCIE_CFG_DATA */ +#define BHND_PCIE_CFG_ADDR_FUNC_MASK 0x7000 +#define BHND_PCIE_CFG_ADDR_FUNC_SHIFT 12 +#define BHND_PCIE_CFG_ADDR_REG_MASK 0x0FFF +#define BHND_PCIE_CFG_ADDR_REG_SHIFT 0 + +#define BHND_PCIE_CFG_OFFSET(f, r) \ + ((((f) & BHND_PCIE_CFG_ADDR_FUNC_MASK) << BHND_PCIE_CFG_ADDR_FUNC_SHIFT) | \ + (((r) & BHND_PCIE_CFG_ADDR_FUNC_SHIFT) << BHND_PCIE_CFG_ADDR_REG_SHIFT)) + +/* PCIE protocol PHY diagnostic registers */ +#define BHND_PCIE_PLP_MODEREG 0x200 /* Mode */ +#define BHND_PCIE_PLP_STATUSREG 0x204 /* Status */ +#define BHND_PCIE_PLP_LTSSMCTRLREG 0x208 /* LTSSM control */ +#define BHND_PCIE_PLP_LTLINKNUMREG 0x20c /* Link Training Link number */ +#define BHND_PCIE_PLP_LTLANENUMREG 0x210 /* Link Training Lane number */ +#define BHND_PCIE_PLP_LTNFTSREG 0x214 /* Link Training N_FTS */ +#define BHND_PCIE_PLP_ATTNREG 0x218 /* Attention */ +#define BHND_PCIE_PLP_ATTNMASKREG 0x21C /* Attention Mask */ +#define BHND_PCIE_PLP_RXERRCTR 0x220 /* Rx Error */ +#define BHND_PCIE_PLP_RXFRMERRCTR 0x224 /* Rx Framing Error */ +#define BHND_PCIE_PLP_RXERRTHRESHREG 0x228 /* Rx Error threshold */ +#define BHND_PCIE_PLP_TESTCTRLREG 0x22C /* Test Control reg */ +#define BHND_PCIE_PLP_SERDESCTRLOVRDREG 0x230 /* SERDES Control Override */ +#define BHND_PCIE_PLP_TIMINGOVRDREG 0x234 /* Timing param override */ +#define BHND_PCIE_PLP_RXTXSMDIAGREG 0x238 /* RXTX State Machine Diag */ +#define BHND_PCIE_PLP_LTSSMDIAGREG 0x23C /* LTSSM State Machine Diag */ + +/* PCIE protocol DLLP diagnostic registers */ +#define BHND_PCIE_DLLP_LCREG 0x100 /* Link Control */ +#define BHND_PCIE_DLLP_LCREG_PCIPM_EN 0x40 /* Enable PCI-PM power management */ +#define BHND_PCIE_DLLP_LSREG 0x104 /* Link Status */ +#define BHND_PCIE_DLLP_LAREG 0x108 /* Link Attention */ +#define BHND_PCIE_DLLP_LAMASKREG 0x10C /* Link Attention Mask */ +#define BHND_PCIE_DLLP_NEXTTXSEQNUMREG 0x110 /* Next Tx Seq Num */ +#define BHND_PCIE_DLLP_ACKEDTXSEQNUMREG 0x114 /* Acked Tx Seq Num */ +#define BHND_PCIE_DLLP_PURGEDTXSEQNUMREG 0x118 /* Purged Tx Seq Num */ +#define BHND_PCIE_DLLP_RXSEQNUMREG 0x11C /* Rx Sequence Number */ +#define BHND_PCIE_DLLP_LRREG 0x120 /* Link Replay */ +#define BHND_PCIE_DLLP_LACKTOREG 0x124 /* Link Ack Timeout */ +#define BHND_PCIE_DLLP_PMTHRESHREG 0x128 /* Power Management Threshold */ +#define BHND_PCIE_L0THRESHOLDTIME_MASK 0xFF00 /* bits 0 - 7 */ +#define BHND_PCIE_L1THRESHOLDTIME_MASK 0xFF00 /* bits 8 - 15 */ +#define BHND_PCIE_L1THRESHOLDTIME_SHIFT 8 /* PCIE_L1THRESHOLDTIME_SHIFT */ +#define BHND_PCIE_L1THRESHOLD_WARVAL 0x72 /* WAR value */ +#define BHND_PCIE_ASPMTIMER_EXTEND 0x1000000 /* > rev7: enable extend ASPM timer */ +#define BHND_PCIE_DLLP_RTRYWPREG 0x12C /* Retry buffer write ptr */ +#define BHND_PCIE_DLLP_RTRYRPREG 0x130 /* Retry buffer Read ptr */ +#define BHND_PCIE_DLLP_RTRYPPREG 0x134 /* Retry buffer Purged ptr */ +#define BHND_PCIE_DLLP_RTRRWREG 0x138 /* Retry buffer Read/Write */ +#define BHND_PCIE_DLLP_ECTHRESHREG 0x13C /* Error Count Threshold */ +#define BHND_PCIE_DLLP_TLPERRCTRREG 0x140 /* TLP Error Counter */ +#define BHND_PCIE_DLLP_ERRCTRREG 0x144 /* Error Counter */ +#define BHND_PCIE_DLLP_NAKRXCTRREG 0x148 /* NAK Received Counter */ +#define BHND_PCIE_DLLP_TESTREG 0x14C /* Test */ +#define BHND_PCIE_DLLP_PKTBIST 0x150 /* Packet BIST */ +#define BHND_PCIE_DLLP_PCIE11 0x154 /* DLLP PCIE 1.1 reg */ + +#define BHND_PCIE_DLLP_LSREG_LINKUP (1 << 16) + +/* PCIE protocol TLP diagnostic registers */ +#define BHND_PCIE_TLP_CONFIGREG 0x000 /* Configuration */ +#define BHND_PCIE_TLP_WORKAROUNDSREG 0x004 /* TLP Workarounds */ +#define BHND_PCIE_TLP_WORKAROUND_URBIT 0x8 /* If enabled, UR status bit is set + * on memory access of an unmatched + * address */ + +#define BHND_PCIE_TLP_WRDMAUPPER 0x010 /* Write DMA Upper Address */ +#define BHND_PCIE_TLP_WRDMALOWER 0x014 /* Write DMA Lower Address */ +#define BHND_PCIE_TLP_WRDMAREQ_LBEREG 0x018 /* Write DMA Len/ByteEn Req */ +#define BHND_PCIE_TLP_RDDMAUPPER 0x01C /* Read DMA Upper Address */ +#define BHND_PCIE_TLP_RDDMALOWER 0x020 /* Read DMA Lower Address */ +#define BHND_PCIE_TLP_RDDMALENREG 0x024 /* Read DMA Len Req */ +#define BHND_PCIE_TLP_MSIDMAUPPER 0x028 /* MSI DMA Upper Address */ +#define BHND_PCIE_TLP_MSIDMALOWER 0x02C /* MSI DMA Lower Address */ +#define BHND_PCIE_TLP_MSIDMALENREG 0x030 /* MSI DMA Len Req */ +#define BHND_PCIE_TLP_SLVREQLENREG 0x034 /* Slave Request Len */ +#define BHND_PCIE_TLP_FCINPUTSREQ 0x038 /* Flow Control Inputs */ +#define BHND_PCIE_TLP_TXSMGRSREQ 0x03C /* Tx StateMachine and Gated Req */ +#define BHND_PCIE_TLP_ADRACKCNTARBLEN 0x040 /* Address Ack XferCnt and ARB Len */ +#define BHND_PCIE_TLP_DMACPLHDR0 0x044 /* DMA Completion Hdr 0 */ +#define BHND_PCIE_TLP_DMACPLHDR1 0x048 /* DMA Completion Hdr 1 */ +#define BHND_PCIE_TLP_DMACPLHDR2 0x04C /* DMA Completion Hdr 2 */ +#define BHND_PCIE_TLP_DMACPLMISC0 0x050 /* DMA Completion Misc0 */ +#define BHND_PCIE_TLP_DMACPLMISC1 0x054 /* DMA Completion Misc1 */ +#define BHND_PCIE_TLP_DMACPLMISC2 0x058 /* DMA Completion Misc2 */ +#define BHND_PCIE_TLP_SPTCTRLLEN 0x05C /* Split Controller Req len */ +#define BHND_PCIE_TLP_SPTCTRLMSIC0 0x060 /* Split Controller Misc 0 */ +#define BHND_PCIE_TLP_SPTCTRLMSIC1 0x064 /* Split Controller Misc 1 */ +#define BHND_PCIE_TLP_BUSDEVFUNC 0x068 /* Bus/Device/Func */ +#define BHND_PCIE_TLP_RESETCTR 0x06C /* Reset Counter */ +#define BHND_PCIE_TLP_RTRYBUF 0x070 /* Retry Buffer value */ +#define BHND_PCIE_TLP_TGTDEBUG1 0x074 /* Target Debug Reg1 */ +#define BHND_PCIE_TLP_TGTDEBUG2 0x078 /* Target Debug Reg2 */ +#define BHND_PCIE_TLP_TGTDEBUG3 0x07C /* Target Debug Reg3 */ +#define BHND_PCIE_TLP_TGTDEBUG4 0x080 /* Target Debug Reg4 */ + + +/* + * PCIe-G1 SerDes MDIO Registers (>= rev10) + */ +#define BHND_PCIE_PHYADDR_SD 0x0 /* serdes PHY address */ +#define BHND_PCIE_DEVAD_SD 0x1 /* serdes pseudo-devad (PMA) recognized by + the bhnd_mdio_pcie driver */ + +#define BHND_PCIE_SD_ADDREXT 0x1F /* serdes address extension register */ +#define BHND_PCIE_SD_ADDREXT_BLK_MASK 0xFFF0 /* register block mask */ +#define BHND_PCIE_SD_ADDREXT_REG_MASK 0x000F /* register address mask */ + +#define BHND_PCIE_SD_REGS_IEEE0 0x0000 /* IEEE0 AN CTRL block */ +#define BHND_PCIE_SD_REGS_IEEE1 0x0010 /* IEEE1 AN ADV block */ +#define BHND_PCIE_SD_REGS_BLK0 0x8000 /* ??? */ +#define BHND_PCIE_SD_REGS_BLK1 0x8010 /* ??? */ +#define BHND_PCIE_SD_REGS_BLK2 0x8020 /* ??? */ +#define BHND_PCIE_SD_REGS_BLK3 0x8030 /* ??? */ +#define BHND_PCIE_SD_REGS_BLK4 0x8040 /* ??? */ +#define BHND_PCIE_SD_REGS_TXPLL 0x8080 /* TXPLL register block */ +#define BHND_PCIE_SD_REGS_TXCTRL0 0x8200 /* ??? */ +#define BHND_PCIE_SD_REGS_SERDESID 0x8310 /* ??? */ +#define BHND_PCIE_SD_REGS_RXCTRL0 0x8400 /* ??? */ + +/* + * PCIe-G1 SerDes-R9 MDIO Registers (<= rev9) + * + * These register definitions appear to match those provided in the + * "PCI Express SerDes Registers" section of the BCM5761 Ethernet Controller + * Programmer's Reference Guide. + */ +#define BHND_PCIE_PHY_SDR9_PLL 0x1C /* SerDes PLL PHY Address*/ +#define BHND_PCIE_SDR9_PLL_CTRL 0x17 /* PLL control reg */ +#define BHND_PCIE_SDR9_PLL_CTRL_FREQDET_EN 0x4000 /* bit 14 is FREQDET on */ +#define BHND_PCIE_PHY_SDR9_TXRX 0x0F /* SerDes RX/TX PHY Address */ + +#define BHND_PCIE_SDR9_RX_CTRL 0x11 /* RX ctrl register */ +#define BHND_PCIE_SDR9_RX_CTRL_FORCE 0x80 /* rxpolarity_force */ +#define BHND_PCIE_SDR9_RX_CTRL_POLARITY_INV 0x40 /* rxpolarity_value (if set, inverse polarity) */ + +#define BHND_PCIE_SDR9_RX_CDR 0x16 /* RX CDR ctrl register */ +#define BHND_PCIE_SDR9_RX_CDR_FREQ_OVR_EN 0x0100 /* freq_override_en flag */ +#define BHND_PCIE_SDR9_RX_CDR_FREQ_OVR_MASK 0x00FF /* freq_override_val */ +#define BHND_PCIE_SDR9_RX_CDR_FREQ_OVR_SHIFT 0 + +#define BHND_PCIE_SDR9_RX_CDRBW 0x17 /* RX CDR bandwidth (PLL tuning) */ +#define BHND_PCIE_SDR9_RX_CDRBW_INTGTRK_MASK 0x7000 /* integral loop bandwidth (phase tracking mode) */ +#define BHND_PCIE_SDR9_RX_CDRBW_INTGTRK_SHIFT 11 +#define BHND_PCIE_SDR9_RX_CDRBW_INTGACQ_MASK 0x0700 /* integral loop bandwidth (phase acquisition mode) */ +#define BHND_PCIE_SDR9_RX_CDRBW_INTGACQ_SHIFT 8 +#define BHND_PCIE_SDR9_RX_CDRBW_PROPTRK_MASK 0x0070 /* proportional loop bandwidth (phase tracking mode) */ +#define BHND_PCIE_SDR9_RX_CDRBW_PROPTRK_SHIFT 4 +#define BHND_PCIE_SDR9_RX_CDRBW_PROPACQ_MASK 0x0007 /* proportional loop bandwidth (phase acquisition mode) */ +#define BHND_PCIE_SDR9_RX_CDRBW_PROPACQ_SHIFT 0 + +#define BHND_PCIE_SDR9_RX_TIMER1 0x12 /* timer1 register */ +#define BHND_PCIE_SDR9_RX_TIMER1_LKTRK_MASK 0xFF00 /* phase tracking delay before asserting RX seq completion (in 16ns units) */ +#define BHND_PCIE_SDR9_RX_TIMER1_LKTRK_SHIFT 8 +#define BHND_PCIE_SDR9_RX_TIMER1_LKACQ_MASK 0x00FF /* phase acquisition mode time (in 1024ns units) */ +#define BHND_PCIE_SDR9_RX_TIMER1_LKACQ_SHIFT 0 + + +/* SPROM offsets */ +#define BHND_PCIE_SRSH_PI_OFFSET BHND_PCI_SRSH_PI_OFFSET /**< PCI core index in SROM shadow area */ +#define BHND_PCIE_SRSH_PI_MASK BHND_PCI_SRSH_PI_MASK +#define BHND_PCIE_SRSH_PI_SHIFT BHND_PCI_SRSH_PI_SHIFT + +#define BHND_PCIE_SRSH_ASPM_OFFSET 8 /* word 4 */ +#define BHND_PCIE_SRSH_ASPM_ENB 0x18 /* bit 3, 4 */ +#define BHND_PCIE_SRSH_ASPM_L1_ENB 0x10 /* bit 4 */ +#define BHND_PCIE_SRSH_ASPM_L0s_ENB 0x8 /* bit 3 */ +#define BHND_PCIE_SRSH_PCIE_MISC_CONFIG 10 /* word 5 */ +#define BHND_PCIE_SRSH_L23READY_EXIT_NOPRST 0x8000 /* bit 15 */ +#define BHND_PCIE_SRSH_CLKREQ_OFFSET_REV5 40 /* word 20 for srom rev <= 5 */ +#define BHND_PCIE_SRSH_CLKREQ_OFFSET_REV8 104 /* word 52 for srom rev 8 */ +#define BHND_PCIE_SRSH_CLKREQ_ENB 0x0800 /* bit 11 */ +#define BHND_PCIE_SRSH_BD_OFFSET 12 /* word 6 */ +#define BHND_PCIE_SRSH_AUTOINIT_OFFSET 36 /* auto initialization enable */ + +/* Linkcontrol reg offset in PCIE Cap */ +#define BHND_PCIE_CAP_LINKCTRL_OFFSET 16 /* linkctrl offset in pcie cap */ +#define BHND_PCIE_CAP_LCREG_ASPML0s 0x01 /* ASPM L0s in linkctrl */ +#define BHND_PCIE_CAP_LCREG_ASPML1 0x02 /* ASPM L1 in linkctrl */ +#define BHND_PCIE_CLKREQ_ENAB 0x100 /* CLKREQ Enab in linkctrl */ + +#define BHND_PCIE_ASPM_ENAB 3 /* ASPM L0s & L1 in linkctrl */ +#define BHND_PCIE_ASPM_L1_ENAB 2 /* ASPM L0s & L1 in linkctrl */ +#define BHND_PCIE_ASPM_L0s_ENAB 1 /* ASPM L0s & L1 in linkctrl */ +#define BHND_PCIE_ASPM_DISAB 0 /* ASPM L0s & L1 in linkctrl */ + +/* Status reg PCIE_PLP_STATUSREG */ +#define BHND_PCIE_PLP_POLARITY_INV 0x10 /* lane polarity is inverted */ + +#endif /* _BHND_CORES_PCI_BHND_PCIREG_H_ */ diff --git a/sys/dev/bhnd/cores/pci/bhnd_pcivar.h b/sys/dev/bhnd/cores/pci/bhnd_pcivar.h new file mode 100644 index 000000000000..070b5cbe6879 --- /dev/null +++ b/sys/dev/bhnd/cores/pci/bhnd_pcivar.h @@ -0,0 +1,125 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $FreeBSD$ + */ + +#ifndef _BHND_CORES_PCI_BHND_PCIVAR_H_ +#define _BHND_CORES_PCI_BHND_PCIVAR_H_ + +#include +#include + +/* + * Shared PCI Bridge/PCI Host Bridge definitions. + */ + +extern devclass_t bhnd_mdio_pci_devclass; + +/* Device register families. */ +typedef enum { + BHND_PCI_REGFMT_PCI = 0, /* PCI register definitions */ + BHND_PCI_REGFMT_PCIE = 1, /* PCIe-Gen1 register definitions */ +} bhnd_pci_regfmt_t; + +/* Common BHND_PCI_*_REG_(EXTRACT|INSERT) implementation */ +#define _BHND_PCI_REG_EXTRACT(_regval, _mask, _shift) \ + ((_regval & _mask) >> _shift) +#define _BHND_PCI_REG_INSERT(_regval, _mask, _shift, _setval) \ + (((_regval) & ~ _mask) | (((_setval) << _shift) & _mask)) + +/** + * Extract a register value by applying _MASK and _SHIFT defines. + * + * @param _regv The register value containing the desired attribute + * @param _attr The register attribute name to which to append `_MASK`/`_SHIFT` + * suffixes. + */ +#define BHND_PCI_REG_EXTRACT(_regv, _attr) \ + _BHND_PCI_REG_EXTRACT(_regv, _attr ## _MASK, _attr ## _SHIFT) + +/** + * Insert a value in @p _regv by applying _MASK and _SHIFT defines. + * + * @param _regv The current register value. + * @param _attr The register attribute name to which to append `_MASK`/`_SHIFT` + * suffixes. + * @param _val The value to be set in @p _regv. + */ +#define BHND_PCI_REG_INSERT(_regv, _attr, _val) \ + _BHND_PCI_REG_INSERT(_regv, _attr ## _MASK, _attr ## _SHIFT, _val) + +/** + * Extract a value by applying _MASK and _SHIFT defines to the common + * PCI/PCIe register definition @p _regv + * + * @param _regf The PCI core register format (BHNDB_PCI_REGFMT_*). + * @param _regv The register value containing the desired attribute + * @param _attr The register attribute name to which to prepend the register + * definition prefix and append `_MASK`/`_SHIFT` suffixes. + */ +#define BHND_PCI_COMMON_REG_EXTRACT(_regf, _regv, _attr) \ + _BHND_PCI_REG_EXTRACT(_regv, \ + BHND_PCI_COMMON_REG((_regf), _attr ## _MASK), \ + BHND_PCI_COMMON_REG((_regf), _attr ## _SHIFT)) + +/** + * Insert a register value by applying _MASK and _SHIFT defines to the common + * PCI/PCIe register definition @p _regv + * + * @param _regf The PCI core register format (BHNDB_PCI_REGFMT_*). + * @param _regv The register value containing the desired attribute + * @param _attr The register attribute name to which to prepend the register + * definition prefix and append `_MASK`/`_SHIFT` suffixes. + * @param _val The value to bet set in @p _regv. + */ +#define BHND_PCI_COMMON_REG_INSERT(_regf, _regv, _attr, _val) \ + _BHND_PCI_REG_INSERT(_regv, \ + BHND_PCI_COMMON_REG((_regf), _attr ## _MASK), \ + BHND_PCI_COMMON_REG((_regf), _attr ## _SHIFT), \ + _val) + + +/** + * Evaluates to the offset of a common PCI/PCIe register definition. + * + * This will trigger a compile-time error if the register is not defined + * for all supported PCI/PCIe cores. + * + * This should be optimized down to a constant value if the register constant + * is the same across the register definitions. + * + * @param _regf The PCI core register format (BHNDB_PCI_REGFMT_*). + * @param _name The base name of the register. + */ +#define BHND_PCI_COMMON_REG(_regf, _name) ( \ + (_regf) == BHND_PCI_REGFMT_PCI ? BHND_PCI_ ## _name : \ + BHND_PCIE_ ## _name \ +) + +#endif /* _BHND_CORES_PCI_BHND_PCIVAR_H_ */ \ No newline at end of file diff --git a/sys/dev/bhnd/cores/pci/mdio_pcie.c b/sys/dev/bhnd/cores/pci/mdio_pcie.c new file mode 100644 index 000000000000..1a29bcccf317 --- /dev/null +++ b/sys/dev/bhnd/cores/pci/mdio_pcie.c @@ -0,0 +1,384 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * MDIO Driver for PCIe-G1 Cores (All Revisions). + * + * The MDIO interface provides access to the PCIe SerDes management registers. + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "bhnd_pcireg.h" + +#include "mdio_pciereg.h" +#include "mdio_pcievar.h" + +#define BHND_MDIO_CTL_DELAY 10 /**< usec delay required between + * MDIO_CTL/MDIO_DATA accesses. */ +#define BHND_MDIO_RETRY_DELAY 2000 /**< usec delay before retrying + * BHND_MDIOCTL_DONE. */ +#define BHND_MDIO_RETRY_COUNT 200 /**< number of times to loop waiting + * for BHND_MDIOCTL_DONE. */ + +#define BHND_MDIO_READ_4(_sc, _reg) \ + bhnd_bus_read_4((_sc)->mem_res, (_sc)->mem_off + (_reg)) + +#define BHND_MDIO_WRITE_4(_sc, _reg, _val) \ + bhnd_bus_write_4((_sc)->mem_res, (_sc)->mem_off + (_reg), (_val)) + +static int +bhnd_mdio_pcie_probe(device_t dev) +{ + device_set_desc(dev, "Broadcom PCIe-G1 MDIO"); + device_quiet(dev); + + return (BUS_PROBE_DEFAULT); +} + +/** + * Helper function that must be called by subclass BHND MDIO drivers + * when implementing DEVICE_ATTACH(). + * + * @param dev The bhnd_mdio device. + * @param mem_res A memory resource containing the device resources; this + * @param mem_rid The @p mem_res resource ID, or -1 if this is a borrowed + * reference that the device should not assume ownership of. + * @param offset The offset within @p mem_res at which the MMIO register + * block is defined. + * @param c22ext If true, the MDIO driver will automatically use the PCIe + * SerDes' non-standard extended address mechanism when handling C45 register + * accesses to the PCIe SerDes device (BHND_PCIE_PHYADDR_SD / + * BHND_PCIE_DEVAD_SD). + */ +int bhnd_mdio_pcie_attach(device_t dev, struct bhnd_resource *mem_res, + int mem_rid, bus_size_t offset, bool c22ext) +{ + struct bhnd_mdio_pcie_softc *sc = device_get_softc(dev); + + sc->dev = dev; + sc->mem_res = mem_res; + sc->mem_rid = mem_rid; + sc->mem_off = offset; + sc->c22ext = c22ext; + + BHND_MDIO_PCIE_LOCK_INIT(sc); + + return (bus_generic_attach(dev)); +} + +static int +bhnd_mdio_pcie_detach(device_t dev) +{ + struct bhnd_mdio_pcie_softc *sc = device_get_softc(dev); + + BHND_MDIO_PCIE_LOCK_DESTROY(sc); + + return (0); +} + +/* Spin until the MDIO device reports itself as idle, or timeout is reached. */ +static int +bhnd_mdio_pcie_wait_idle(struct bhnd_mdio_pcie_softc *sc) +{ + uint32_t ctl; + + /* Spin waiting for the BUSY flag to clear */ + for (int i = 0; i < BHND_MDIO_RETRY_COUNT; i++) { + ctl = BHND_MDIO_READ_4(sc, BHND_MDIO_CTL); + if ((ctl & BHND_MDIOCTL_DONE)) + return (0); + + DELAY(BHND_MDIO_RETRY_DELAY); + } + + return (ETIMEDOUT); +} + + +/** + * Write an MDIO IOCTL and wait for completion. + */ +static int +bhnd_mdio_pcie_ioctl(struct bhnd_mdio_pcie_softc *sc, uint32_t cmd) +{ + BHND_MDIO_PCIE_LOCK_ASSERT(sc, MA_OWNED); + + BHND_MDIO_WRITE_4(sc, BHND_MDIO_CTL, cmd); + DELAY(BHND_MDIO_CTL_DELAY); + return (0); +} + +/** + * Enable MDIO device + */ +static int +bhnd_mdio_pcie_enable(struct bhnd_mdio_pcie_softc *sc) +{ + uint32_t ctl; + + /* Enable MDIO clock and preamble mode */ + ctl = BHND_MDIOCTL_PREAM_EN|BHND_MDIOCTL_DIVISOR_VAL; + return (bhnd_mdio_pcie_ioctl(sc, ctl)); +} + +/** + * Disable MDIO device. + */ +static void +bhnd_mdio_pcie_disable(struct bhnd_mdio_pcie_softc *sc) +{ + if (bhnd_mdio_pcie_ioctl(sc, 0)) + device_printf(sc->dev, "failed to disable MDIO clock\n"); +} + + +/** + * Issue a write command and wait for completion + */ +static int +bhnd_mdio_pcie_cmd_write(struct bhnd_mdio_pcie_softc *sc, uint32_t cmd) +{ + int error; + + BHND_MDIO_PCIE_LOCK_ASSERT(sc, MA_OWNED); + + cmd |= BHND_MDIODATA_START|BHND_MDIODATA_TA|BHND_MDIODATA_CMD_WRITE; + + BHND_MDIO_WRITE_4(sc, BHND_MDIO_DATA, cmd); + DELAY(BHND_MDIO_CTL_DELAY); + + if ((error = bhnd_mdio_pcie_wait_idle(sc))) + return (error); + + return (0); +} + +/** + * Issue an an MDIO read command, wait for completion, and return + * the result in @p data_read. + */ +static int +bhnd_mdio_pcie_cmd_read(struct bhnd_mdio_pcie_softc *sc, uint32_t cmd, + uint16_t *data_read) +{ + int error; + + BHND_MDIO_PCIE_LOCK_ASSERT(sc, MA_OWNED); + + cmd |= BHND_MDIODATA_START|BHND_MDIODATA_TA|BHND_MDIODATA_CMD_READ; + BHND_MDIO_WRITE_4(sc, BHND_MDIO_DATA, cmd); + DELAY(BHND_MDIO_CTL_DELAY); + + if ((error = bhnd_mdio_pcie_wait_idle(sc))) + return (error); + + *data_read = (BHND_MDIO_READ_4(sc, BHND_MDIO_DATA) & + BHND_MDIODATA_DATA_MASK); + return (0); +} + + +static int +bhnd_mdio_pcie_read(device_t dev, int phy, int reg) +{ + struct bhnd_mdio_pcie_softc *sc; + uint32_t cmd; + uint16_t val; + int error; + + sc = device_get_softc(dev); + + /* Enable MDIO access */ + BHND_MDIO_PCIE_LOCK(sc); + bhnd_mdio_pcie_enable(sc); + + /* Issue the read */ + cmd = BHND_MDIODATA_ADDR(phy, reg); + error = bhnd_mdio_pcie_cmd_read(sc, cmd, &val); + + /* Disable MDIO access */ + bhnd_mdio_pcie_disable(sc); + BHND_MDIO_PCIE_UNLOCK(sc); + + if (error) + return (~0U); + + return (val); +} + +static int +bhnd_mdio_pcie_write(device_t dev, int phy, int reg, int val) +{ + struct bhnd_mdio_pcie_softc *sc; + uint32_t cmd; + int error; + + sc = device_get_softc(dev); + + /* Enable MDIO access */ + BHND_MDIO_PCIE_LOCK(sc); + bhnd_mdio_pcie_enable(sc); + + /* Issue the write */ + cmd = BHND_MDIODATA_ADDR(phy, reg) | (val & BHND_MDIODATA_DATA_MASK); + error = bhnd_mdio_pcie_cmd_write(sc, cmd); + + /* Disable MDIO access */ + bhnd_mdio_pcie_disable(sc); + BHND_MDIO_PCIE_UNLOCK(sc); + + return (error); +} + +static int +bhnd_mdio_pcie_read_ext(device_t dev, int phy, int devaddr, int reg) +{ + struct bhnd_mdio_pcie_softc *sc; + uint32_t cmd; + uint16_t blk, val; + uint8_t blk_reg; + int error; + + if (devaddr == MDIO_DEVADDR_NONE) + return (MDIO_READREG(dev, phy, reg)); + + sc = device_get_softc(dev); + + /* Extended register access is only supported for the SerDes device, + * using the non-standard C22 extended address mechanism */ + if (!sc->c22ext) + return (~0U); + if (phy != BHND_PCIE_PHYADDR_SD || devaddr != BHND_PCIE_DEVAD_SD) + return (~0U); + + /* Enable MDIO access */ + BHND_MDIO_PCIE_LOCK(sc); + bhnd_mdio_pcie_enable(sc); + + /* Determine the block and register values */ + blk = (reg & BHND_PCIE_SD_ADDREXT_BLK_MASK); + blk_reg = (reg & BHND_PCIE_SD_ADDREXT_REG_MASK); + + /* Write the block address to the address extension register */ + cmd = BHND_MDIODATA_ADDR(phy, BHND_PCIE_SD_ADDREXT) | + (blk & BHND_MDIODATA_DATA_MASK); + if ((error = bhnd_mdio_pcie_cmd_write(sc, cmd))) + goto cleanup; + + /* Issue the read */ + cmd = BHND_MDIODATA_ADDR(phy, blk_reg); + error = bhnd_mdio_pcie_cmd_read(sc, cmd, &val); + +cleanup: + bhnd_mdio_pcie_disable(sc); + BHND_MDIO_PCIE_UNLOCK(sc); + + if (error) + return (~0U); + + return (val); +} + +static int +bhnd_mdio_pcie_write_ext(device_t dev, int phy, int devaddr, int reg, + int val) +{ + struct bhnd_mdio_pcie_softc *sc; + uint32_t cmd; + uint16_t blk; + uint8_t blk_reg; + int error; + + if (devaddr == MDIO_DEVADDR_NONE) + return (MDIO_READREG(dev, phy, reg)); + + sc = device_get_softc(dev); + + /* Extended register access is only supported for the SerDes device, + * using the non-standard C22 extended address mechanism */ + if (!sc->c22ext) + return (~0U); + if (phy != BHND_PCIE_PHYADDR_SD || devaddr != BHND_PCIE_DEVAD_SD) + return (~0U); + + /* Enable MDIO access */ + BHND_MDIO_PCIE_LOCK(sc); + bhnd_mdio_pcie_enable(sc); + + /* Determine the block and register values */ + blk = (reg & BHND_PCIE_SD_ADDREXT_BLK_MASK); + blk_reg = (reg & BHND_PCIE_SD_ADDREXT_REG_MASK); + + /* Write the block address to the address extension register */ + cmd = BHND_MDIODATA_ADDR(phy, BHND_PCIE_SD_ADDREXT) | + (blk & BHND_MDIODATA_DATA_MASK); + if ((error = bhnd_mdio_pcie_cmd_write(sc, cmd))) + goto cleanup; + + /* Issue the write */ + cmd = BHND_MDIODATA_ADDR(phy, blk_reg) | + (val & BHND_MDIODATA_DATA_MASK); + error = bhnd_mdio_pcie_cmd_write(sc, cmd); + +cleanup: + bhnd_mdio_pcie_disable(sc); + BHND_MDIO_PCIE_UNLOCK(sc); + + return (error); +} + +static device_method_t bhnd_mdio_pcie_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, bhnd_mdio_pcie_probe), + DEVMETHOD(device_detach, bhnd_mdio_pcie_detach), + + /* MDIO interface */ + DEVMETHOD(mdio_readreg, bhnd_mdio_pcie_read), + DEVMETHOD(mdio_writereg, bhnd_mdio_pcie_write), + DEVMETHOD(mdio_readextreg, bhnd_mdio_pcie_read_ext), + DEVMETHOD(mdio_writeextreg, bhnd_mdio_pcie_write_ext), + + DEVMETHOD_END +}; + +DEFINE_CLASS_0(bhnd_mdio_pcie, bhnd_mdio_pcie_driver, bhnd_mdio_pcie_methods, sizeof(struct bhnd_mdio_pcie_softc)); diff --git a/sys/dev/bhnd/cores/pci/mdio_pciereg.h b/sys/dev/bhnd/cores/pci/mdio_pciereg.h new file mode 100644 index 000000000000..293b137071e9 --- /dev/null +++ b/sys/dev/bhnd/cores/pci/mdio_pciereg.h @@ -0,0 +1,57 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * Copyright (c) 2010 Broadcom Corporation + * All rights reserved. + * + * This file is derived from the pcie_core.h header distributed with Broadcom's + * initial brcm80211 Linux driver release, as contributed to the Linux staging + * repository. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef _BHND_CORES_PCI_MDIO_PCIEREG_H_ +#define _BHND_CORES_PCI_MDIO_PCIEREG_H_ + +/* MDIO register offsets */ +#define BHND_MDIO_CTL 0x0 /**< mdio control */ +#define BHND_MDIO_DATA 0x4 /**< mdio data */ + +/* MDIO control */ +#define BHND_MDIOCTL_DIVISOR_MASK 0x7f /* clock divisor mask */ +#define BHND_MDIOCTL_DIVISOR_VAL 0x2 /* default clock divisor */ +#define BHND_MDIOCTL_PREAM_EN 0x80 /* enable preamble mode */ +#define BHND_MDIOCTL_DONE 0x100 /* tranaction completed */ + +/* MDIO Data */ +#define BHND_MDIODATA_PHYADDR_MASK 0x0f800000 /* phy addr */ +#define BHND_MDIODATA_PHYADDR_SHIFT 23 +#define BHND_MDIODATA_REGADDR_MASK 0x007c0000 /* reg/dev addr */ +#define BHND_MDIODATA_REGADDR_SHIFT 18 +#define BHND_MDIODATA_DATA_MASK 0x0000ffff /* data */ + +#define BHND_MDIODATA_TA 0x00020000 /* slave turnaround time */ +#define BHND_MDIODATA_START 0x40000000 /* start of transaction */ +#define BHND_MDIODATA_CMD_WRITE 0x10000000 /* write command */ +#define BHND_MDIODATA_CMD_READ 0x20000000 /* read command */ + +#define BHND_MDIODATA_ADDR(_phyaddr, _regaddr) ( \ + (((_phyaddr) << BHND_MDIODATA_PHYADDR_SHIFT) & \ + BHND_MDIODATA_PHYADDR_MASK) | \ + (((_regaddr) << BHND_MDIODATA_REGADDR_SHIFT) & \ + BHND_MDIODATA_REGADDR_MASK) \ +) + +#endif /* _BHND_CORES_PCI_MDIO_PCIEREG_H_ */ diff --git a/sys/dev/bhnd/cores/pci/mdio_pcievar.h b/sys/dev/bhnd/cores/pci/mdio_pcievar.h new file mode 100644 index 000000000000..40b3ff2bacd6 --- /dev/null +++ b/sys/dev/bhnd/cores/pci/mdio_pcievar.h @@ -0,0 +1,69 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $FreeBSD$ + */ + +#ifndef _BHND_CORES_PCI_MDIO_PCIEVAR_H_ +#define _BHND_CORES_PCI_MDIO_PCIEVAR_H_ + +#include +#include "mdio_if.h" + +DECLARE_CLASS(bhnd_mdio_pcie_driver); + +int bhnd_mdio_pcie_attach(device_t dev, struct bhnd_resource *mem_res, + int mem_rid, bus_size_t offset, bool c22ext); + +struct bhnd_mdio_pcie_softc { + device_t dev; /**< mdio device */ + struct mtx sc_mtx; /**< mdio register lock */ + + struct bhnd_resource *mem_res; /**< parent pcie registers */ + int mem_rid; /**< MDIO register resID, or + -1 if mem_res reference is + borrowed. */ + bus_size_t mem_off; /**< mdio register offset */ + + bool c22ext; /**< automatically rewrite C45 + register requests made + to the PCIe SerDes slave + to use its non-standard + C22 address extension + mechanism. */ +}; + +#define BHND_MDIO_PCIE_LOCK_INIT(sc) \ + mtx_init(&(sc)->sc_mtx, device_get_nameunit((sc)->dev), \ + "bhnd_pci_mdio register lock", MTX_DEF) +#define BHND_MDIO_PCIE_LOCK(sc) mtx_lock(&(sc)->sc_mtx) +#define BHND_MDIO_PCIE_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx) +#define BHND_MDIO_PCIE_LOCK_ASSERT(sc, what) mtx_assert(&(sc)->sc_mtx, what) +#define BHND_MDIO_PCIE_LOCK_DESTROY(sc) mtx_destroy(&(sc)->sc_mtx) + +#endif /* _BHND_CORES_PCI_MDIO_PCIEVAR_H_ */ diff --git a/sys/dev/bhnd/nvram/bhnd_nvram.h b/sys/dev/bhnd/nvram/bhnd_nvram.h new file mode 100644 index 000000000000..e2b6b0b5e3a2 --- /dev/null +++ b/sys/dev/bhnd/nvram/bhnd_nvram.h @@ -0,0 +1,65 @@ +/*- + * Copyright (c) 2015-2016 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $FreeBSD$ + */ + +#ifndef _BHND_NVRAM_BHND_NVRAM_H_ +#define _BHND_NVRAM_BHND_NVRAM_H_ + +/** + * NVRAM data sources supported by bhnd(4) devices. + */ +typedef enum { + BHND_NVRAM_SRC_CIS, /**< Default CIS source; this may + * apply, for example, to PCMCIA cards + * vending Broadcom NVRAM data via + * their standard CIS table. */ + + BHND_NVRAM_SRC_OTP, /**< On-chip one-time-programmable + * memory. */ + + BHND_NVRAM_SRC_NFLASH, /**< External flash device accessible + * via on-chip flash core, such + * as the NAND/QSPI controller cores + * used on Northstar devices to access + * NVRAM. */ + BHND_NVRAM_SRC_SPROM, /**< External serial EEPROM. */ + + BHND_NVRAM_SRC_NONE /**< No NVRAM source is directly + * attached. This is used on devices + * attached via PCI(e) to BHND SoCs, + * where to avoid unnecessary flash + * hardware, NVRAM configuration for + * individual devices is provided by + * hardware attached to the SoC + * itself. + */ +} bhnd_nvram_src_t; + +#endif /* _BHND_NVRAM_BHND_NVRAM_H_ */ \ No newline at end of file diff --git a/sys/dev/bhnd/nvram/bhnd_nvram_if.m b/sys/dev/bhnd/nvram/bhnd_nvram_if.m new file mode 100644 index 000000000000..c4baaecee936 --- /dev/null +++ b/sys/dev/bhnd/nvram/bhnd_nvram_if.m @@ -0,0 +1,64 @@ +#- +# Copyright (c) 2016 Landon Fuller +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE +# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# $FreeBSD$ + +#include +#include + +#include + +INTERFACE bhnd_nvram; + +# +# bhnd(4) NVRAM device interface. +# +# Provides a shared interface to HND NVRAM, OTP, and SPROM devices that provide +# access to a common set of hardware/device configuration variables. +# + +/** + * Read an NVRAM variable. + * + * @param dev The NVRAM device. + * @param name The NVRAM variable name. + * @param[out] buf On success, the requested value will be written + * to this buffer. This argment may be NULL if + * the value is not desired. + * @param[in,out] size The capacity of @p buf. On success, will be set + * to the actual size of the requested value. + * + * @retval 0 success + * @retval ENOENT The requested variable was not found. + * @retval ENOMEM If @p buf is non-NULL and a buffer of @p size is too + * small to hold the requested value. + * @retval non-zero If reading @p name otherwise fails, a regular unix + * error code will be returned. + */ +METHOD int getvar { + device_t dev; + const char *name; + void *buf; + size_t *size; +}; \ No newline at end of file diff --git a/sys/dev/bhnd/siba/siba.c b/sys/dev/bhnd/siba/siba.c new file mode 100644 index 000000000000..5f1410d9c637 --- /dev/null +++ b/sys/dev/bhnd/siba/siba.c @@ -0,0 +1,679 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "sibareg.h" +#include "sibavar.h" + +int +siba_probe(device_t dev) +{ + device_set_desc(dev, "SIBA BHND bus"); + return (BUS_PROBE_DEFAULT); +} + +int +siba_attach(device_t dev) +{ + struct siba_devinfo *dinfo; + device_t *devs; + int ndevs; + int error; + + // TODO: We need to set the initiator timeout for the + // core that will be issuing requests to non-memory locations. + // + // In the case of a bridged device, this is the hostb core. + // On a non-bridged device, this will be the CPU. + + /* Fetch references to the siba SIBA_CFG* blocks for all + * registered devices */ + if ((error = device_get_children(dev, &devs, &ndevs))) + return (error); + + for (int i = 0; i < ndevs; i++) { + struct siba_addrspace *addrspace; + struct siba_port *port; + + dinfo = device_get_ivars(devs[i]); + + KASSERT(!device_is_suspended(devs[i]), + ("siba(4) stateful suspend handling requires that devices " + "not be suspended before siba_attach()")); + + /* Fetch the core register address space */ + port = siba_dinfo_get_port(dinfo, BHND_PORT_DEVICE, 0); + if (port == NULL) { + error = ENXIO; + goto cleanup; + } + + addrspace = siba_find_port_addrspace(port, SIBA_ADDRSPACE_CORE); + if (addrspace == NULL) { + error = ENXIO; + goto cleanup; + } + + /* + * Map the per-core configuration blocks + */ + KASSERT(dinfo->core_id.num_cfg_blocks <= SIBA_CFG_NUM_MAX, + ("config block count %u out of range", + dinfo->core_id.num_cfg_blocks)); + + for (u_int cfgidx = 0; cfgidx < dinfo->core_id.num_cfg_blocks; + cfgidx++) + { + rman_res_t r_start, r_count, r_end; + + /* Determine the config block's address range; configuration + * blocks are allocated starting at SIBA_CFG0_OFFSET, + * growing downwards. */ + r_start = addrspace->sa_base + SIBA_CFG0_OFFSET; + r_start -= cfgidx * SIBA_CFG_SIZE; + + r_count = SIBA_CFG_SIZE; + r_end = r_start + r_count - 1; + + /* Allocate the config resource */ + dinfo->cfg_rid[cfgidx] = 0; + dinfo->cfg[cfgidx] = bhnd_alloc_resource(dev, + SYS_RES_MEMORY, &dinfo->cfg_rid[cfgidx], r_start, + r_end, r_count, RF_ACTIVE); + + if (dinfo->cfg[cfgidx] == NULL) { + device_printf(dev, "failed allocating CFG_%u for " + "core %d\n", cfgidx, i); + error = ENXIO; + goto cleanup; + } + }; + } + +cleanup: + free(devs, M_BHND); + if (error) + return (error); + + /* Delegate remainder to standard bhnd method implementation */ + return (bhnd_generic_attach(dev)); +} + +int +siba_detach(device_t dev) +{ + return (bhnd_generic_detach(dev)); +} + +static int +siba_read_ivar(device_t dev, device_t child, int index, uintptr_t *result) +{ + const struct siba_devinfo *dinfo; + const struct bhnd_core_info *cfg; + + dinfo = device_get_ivars(child); + cfg = &dinfo->core_id.core_info; + + switch (index) { + case BHND_IVAR_VENDOR: + *result = cfg->vendor; + return (0); + case BHND_IVAR_DEVICE: + *result = cfg->device; + return (0); + case BHND_IVAR_HWREV: + *result = cfg->hwrev; + return (0); + case BHND_IVAR_DEVICE_CLASS: + *result = bhnd_core_class(cfg); + return (0); + case BHND_IVAR_VENDOR_NAME: + *result = (uintptr_t) bhnd_vendor_name(cfg->vendor); + return (0); + case BHND_IVAR_DEVICE_NAME: + *result = (uintptr_t) bhnd_core_name(cfg); + return (0); + case BHND_IVAR_CORE_INDEX: + *result = cfg->core_idx; + return (0); + case BHND_IVAR_CORE_UNIT: + *result = cfg->unit; + return (0); + default: + return (ENOENT); + } +} + +static int +siba_write_ivar(device_t dev, device_t child, int index, uintptr_t value) +{ + switch (index) { + case BHND_IVAR_VENDOR: + case BHND_IVAR_DEVICE: + case BHND_IVAR_HWREV: + case BHND_IVAR_DEVICE_CLASS: + case BHND_IVAR_VENDOR_NAME: + case BHND_IVAR_DEVICE_NAME: + case BHND_IVAR_CORE_INDEX: + case BHND_IVAR_CORE_UNIT: + return (EINVAL); + default: + return (ENOENT); + } +} + +static void +siba_child_deleted(device_t dev, device_t child) +{ + struct siba_devinfo *dinfo = device_get_ivars(child); + if (dinfo != NULL) + siba_free_dinfo(dev, dinfo); +} + +static struct resource_list * +siba_get_resource_list(device_t dev, device_t child) +{ + struct siba_devinfo *dinfo = device_get_ivars(child); + return (&dinfo->resources); +} + +static int +siba_reset_core(device_t dev, device_t child, uint16_t flags) +{ + struct siba_devinfo *dinfo; + + if (device_get_parent(child) != dev) + BHND_BUS_RESET_CORE(device_get_parent(dev), child, flags); + + dinfo = device_get_ivars(child); + + /* Can't reset the core without access to the CFG0 registers */ + if (dinfo->cfg[0] == NULL) + return (ENODEV); + + // TODO - perform reset + + return (ENXIO); +} + +static int +siba_suspend_core(device_t dev, device_t child) +{ + struct siba_devinfo *dinfo; + + if (device_get_parent(child) != dev) + BHND_BUS_SUSPEND_CORE(device_get_parent(dev), child); + + dinfo = device_get_ivars(child); + + /* Can't suspend the core without access to the CFG0 registers */ + if (dinfo->cfg[0] == NULL) + return (ENODEV); + + // TODO - perform suspend + + return (ENXIO); +} + + +static u_int +siba_get_port_count(device_t dev, device_t child, bhnd_port_type type) +{ + struct siba_devinfo *dinfo; + + /* delegate non-bus-attached devices to our parent */ + if (device_get_parent(child) != dev) + return (BHND_BUS_GET_PORT_COUNT(device_get_parent(dev), child, + type)); + + dinfo = device_get_ivars(child); + + /* We advertise exactly one port of any type */ + if (siba_dinfo_get_port(dinfo, type, 0) != NULL) + return (1); + + return (0); +} + +static u_int +siba_get_region_count(device_t dev, device_t child, bhnd_port_type type, + u_int port_num) +{ + struct siba_devinfo *dinfo; + struct siba_port *port; + + /* delegate non-bus-attached devices to our parent */ + if (device_get_parent(child) != dev) + return (BHND_BUS_GET_REGION_COUNT(device_get_parent(dev), child, + type, port_num)); + + dinfo = device_get_ivars(child); + port = siba_dinfo_get_port(dinfo, type, port_num); + if (port == NULL) + return (0); + + return (port->sp_num_addrs); +} + +static int +siba_get_port_rid(device_t dev, device_t child, bhnd_port_type port_type, + u_int port_num, u_int region_num) +{ + struct siba_devinfo *dinfo; + struct siba_port *port; + struct siba_addrspace *addrspace; + + /* delegate non-bus-attached devices to our parent */ + if (device_get_parent(child) != dev) + return (BHND_BUS_GET_PORT_RID(device_get_parent(dev), child, + port_type, port_num, region_num)); + + dinfo = device_get_ivars(child); + port = siba_dinfo_get_port(dinfo, port_type, port_num); + if (port == NULL) + return (-1); + + STAILQ_FOREACH(addrspace, &port->sp_addrs, sa_link) { + if (addrspace->sa_region_num == region_num) + return (addrspace->sa_rid); + } + + /* not found */ + return (-1); +} + +static int +siba_decode_port_rid(device_t dev, device_t child, int type, int rid, + bhnd_port_type *port_type, u_int *port_num, u_int *region_num) +{ + struct siba_devinfo *dinfo; + struct siba_port *port; + struct siba_addrspace *addrspace; + + /* delegate non-bus-attached devices to our parent */ + if (device_get_parent(child) != dev) + return (BHND_BUS_DECODE_PORT_RID(device_get_parent(dev), child, + type, rid, port_type, port_num, region_num)); + + dinfo = device_get_ivars(child); + + /* Ports are always memory mapped */ + if (type != SYS_RES_MEMORY) + return (EINVAL); + + /* Starting with the most likely device list, search all three port + * lists */ + bhnd_port_type types[] = { + BHND_PORT_DEVICE, + BHND_PORT_AGENT, + BHND_PORT_BRIDGE + }; + + for (int i = 0; i < nitems(types); i++) { + port = siba_dinfo_get_port(dinfo, types[i], 0); + if (port == NULL) + continue; + + STAILQ_FOREACH(addrspace, &port->sp_addrs, sa_link) { + if (addrspace->sa_rid != rid) + continue; + + *port_type = port->sp_type; + *port_num = port->sp_num; + *region_num = addrspace->sa_region_num; + } + } + + return (ENOENT); +} + +static int +siba_get_region_addr(device_t dev, device_t child, bhnd_port_type port_type, + u_int port_num, u_int region_num, bhnd_addr_t *addr, bhnd_size_t *size) +{ + struct siba_devinfo *dinfo; + struct siba_port *port; + struct siba_addrspace *addrspace; + + /* delegate non-bus-attached devices to our parent */ + if (device_get_parent(child) != dev) { + return (BHND_BUS_GET_REGION_ADDR(device_get_parent(dev), child, + port_type, port_num, region_num, addr, size)); + } + + dinfo = device_get_ivars(child); + port = siba_dinfo_get_port(dinfo, port_type, port_num); + if (port == NULL) + return (ENOENT); + + STAILQ_FOREACH(addrspace, &port->sp_addrs, sa_link) { + if (addrspace->sa_region_num != region_num) + continue; + + *addr = addrspace->sa_base; + *size = addrspace->sa_size; + return (0); + } + + return (ENOENT); +} + + +/** + * Register all address space mappings for @p di. + * + * @param dev The siba bus device. + * @param di The device info instance on which to register all address + * space entries. + * @param r A resource mapping the enumeration table block for @p di. + */ +static int +siba_register_addrspaces(device_t dev, struct siba_devinfo *di, + struct resource *r) +{ + struct siba_core_id *cid; + uint32_t addr; + uint32_t size; + u_int region_num; + int error; + + cid = &di->core_id; + + /* Region numbers must be assigned in order, but our siba address + * space IDs may be sparsely allocated; thus, we track + * the region index seperately. */ + region_num = 0; + + /* Register the device address space entries */ + for (uint8_t sid = 0; sid < di->core_id.num_addrspace; sid++) { + uint32_t adm; + u_int adm_offset; + uint32_t bus_reserved; + + /* Determine the register offset */ + adm_offset = siba_admatch_offset(sid); + if (adm_offset == 0) { + device_printf(dev, "addrspace %hhu is unsupported", sid); + return (ENODEV); + } + + /* Fetch the address match register value */ + adm = bus_read_4(r, adm_offset); + + /* Skip disabled entries */ + if (adm & SIBA_AM_ADEN) + continue; + + /* Parse the value */ + if ((error = siba_parse_admatch(adm, &addr, &size))) { + device_printf(dev, "failed to decode address " + " match register value 0x%x\n", adm); + return (error); + } + + /* If this is the device's core/enumeration addrespace, + * reserve the Sonics configuration register blocks for the + * use of our bus. */ + bus_reserved = 0; + if (sid == SIBA_ADDRSPACE_CORE) + bus_reserved = cid->num_cfg_blocks * SIBA_CFG_SIZE; + + /* Append the region info */ + error = siba_append_dinfo_region(di, BHND_PORT_DEVICE, 0, + region_num, sid, addr, size, bus_reserved); + if (error) + return (error); + + + region_num++; + } + + return (0); +} + +/** + * Scan the core table and add all valid discovered cores to + * the bus. + * + * @param dev The siba bus device. + * @param chipid The chip identifier, if the device does not provide a + * ChipCommon core. Should o NULL otherwise. + */ +int +siba_add_children(device_t dev, const struct bhnd_chipid *chipid) +{ + struct bhnd_chipid ccid; + struct bhnd_core_info *cores; + struct siba_devinfo *dinfo; + struct resource *r; + int rid; + int error; + + dinfo = NULL; + cores = NULL; + r = NULL; + + /* + * Try to determine the number of device cores via the ChipCommon + * identification registers. + * + * A small number of very early devices do not include a ChipCommon + * core, in which case our caller must supply the chip identification + * information via a non-NULL chipid parameter. + */ + if (chipid == NULL) { + uint32_t idhigh, ccreg; + uint16_t vendor, device; + uint8_t ccrev; + + /* Map the first core's register block. If the ChipCommon core + * exists, it will always be the first core. */ + rid = 0; + r = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, + SIBA_CORE_ADDR(0), SIBA_CORE_SIZE, + SIBA_CORE_ADDR(0) + SIBA_CORE_SIZE - 1, + RF_ACTIVE); + + /* Identify the core */ + idhigh = bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDHIGH)); + vendor = SIBA_REG_GET(idhigh, IDH_VENDOR); + device = SIBA_REG_GET(idhigh, IDH_DEVICE); + ccrev = SIBA_IDH_CORE_REV(idhigh); + + if (vendor != OCP_VENDOR_BCM || device != BHND_COREID_CC) { + device_printf(dev, + "cannot identify device: no chipcommon core " + "found\n"); + error = ENXIO; + goto cleanup; + } + + /* Identify the chipset */ + ccreg = bus_read_4(r, CHIPC_ID); + ccid = bhnd_parse_chipid(ccreg, SIBA_ENUM_ADDR); + + if (!CHIPC_NCORES_MIN_HWREV(ccrev)) { + switch (device) { + case BHND_CHIPID_BCM4306: + ccid.ncores = 6; + break; + case BHND_CHIPID_BCM4704: + ccid.ncores = 9; + break; + case BHND_CHIPID_BCM5365: + /* + * BCM5365 does support ID_NUMCORE in at least + * some of its revisions, but for unknown + * reasons, Broadcom's drivers always exclude + * the ChipCommon revision (0x5) used by BCM5365 + * from the set of revisions supporting + * ID_NUMCORE, and instead supply a fixed value. + * + * Presumably, at least some of these devices + * shipped with a broken ID_NUMCORE value. + */ + ccid.ncores = 7; + break; + default: + device_printf(dev, "unable to determine core " + "count for unrecognized chipset 0x%hx\n", + ccid.chip_id); + error = ENXIO; + goto cleanup; + } + } + + chipid = &ccid; + bus_release_resource(dev, SYS_RES_MEMORY, rid, r); + } + + /* Allocate our temporary core table and enumerate all cores */ + cores = malloc(sizeof(*cores) * chipid->ncores, M_BHND, M_NOWAIT); + if (cores == NULL) + return (ENOMEM); + + /* Add all cores. */ + for (u_int i = 0; i < chipid->ncores; i++) { + struct siba_core_id cid; + device_t child; + uint32_t idhigh, idlow; + rman_res_t r_count, r_end, r_start; + + /* Map the core's register block */ + rid = 0; + r_start = SIBA_CORE_ADDR(i); + r_count = SIBA_CORE_SIZE; + r_end = r_start + SIBA_CORE_SIZE - 1; + r = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, r_start, + r_end, r_count, RF_ACTIVE); + if (r == NULL) { + error = ENXIO; + goto cleanup; + } + + /* Read the core info */ + idhigh = bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDHIGH)); + idlow = bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDLOW)); + + cid = siba_parse_core_id(idhigh, idlow, i, 0); + cores[i] = cid.core_info; + + /* Determine unit number */ + for (u_int j = 0; j < i; j++) { + if (cores[j].vendor == cores[i].vendor && + cores[j].device == cores[i].device) + cores[i].unit++; + } + + /* Allocate per-device bus info */ + dinfo = siba_alloc_dinfo(dev, &cid); + if (dinfo == NULL) { + error = ENXIO; + goto cleanup; + } + + /* Register the core's address space(s). */ + if ((error = siba_register_addrspaces(dev, dinfo, r))) + goto cleanup; + + /* Add the child device */ + child = device_add_child(dev, NULL, -1); + if (child == NULL) { + error = ENXIO; + goto cleanup; + } + + /* The child device now owns the dinfo pointer */ + device_set_ivars(child, dinfo); + dinfo = NULL; + + /* If pins are floating or the hardware is otherwise + * unpopulated, the device shouldn't be used. */ + if (bhnd_is_hw_disabled(child)) + device_disable(child); + + /* Release our resource */ + bus_release_resource(dev, SYS_RES_MEMORY, rid, r); + r = NULL; + } + +cleanup: + if (cores != NULL) + free(cores, M_BHND); + + if (dinfo != NULL) + siba_free_dinfo(dev, dinfo); + + if (r != NULL) + bus_release_resource(dev, SYS_RES_MEMORY, rid, r); + + return (error); +} + +static device_method_t siba_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, siba_probe), + DEVMETHOD(device_attach, siba_attach), + DEVMETHOD(device_detach, siba_detach), + + /* Bus interface */ + DEVMETHOD(bus_child_deleted, siba_child_deleted), + DEVMETHOD(bus_read_ivar, siba_read_ivar), + DEVMETHOD(bus_write_ivar, siba_write_ivar), + DEVMETHOD(bus_get_resource_list, siba_get_resource_list), + + /* BHND interface */ + DEVMETHOD(bhnd_bus_reset_core, siba_reset_core), + DEVMETHOD(bhnd_bus_suspend_core, siba_suspend_core), + DEVMETHOD(bhnd_bus_get_port_count, siba_get_port_count), + DEVMETHOD(bhnd_bus_get_region_count, siba_get_region_count), + DEVMETHOD(bhnd_bus_get_port_rid, siba_get_port_rid), + DEVMETHOD(bhnd_bus_decode_port_rid, siba_decode_port_rid), + DEVMETHOD(bhnd_bus_get_region_addr, siba_get_region_addr), + + DEVMETHOD_END +}; + +DEFINE_CLASS_1(bhnd, siba_driver, siba_methods, sizeof(struct siba_softc), bhnd_driver); + +MODULE_VERSION(siba, 1); +MODULE_DEPEND(siba, bhnd, 1, 1, 1); diff --git a/sys/dev/bhnd/siba/siba.h b/sys/dev/bhnd/siba/siba.h new file mode 100644 index 000000000000..9172525241b1 --- /dev/null +++ b/sys/dev/bhnd/siba/siba.h @@ -0,0 +1,49 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $FreeBSD$ + */ + +#ifndef _SIBA_SIBA_H_ +#define _SIBA_SIBA_H_ + +#include +#include +#include +#include +#include + +#include + +/* + * Broadcom Sonics Silicon backplane types and data structures. + */ + +DECLARE_CLASS(siba_driver); + +#endif /* _SIBA_SIBA_H_ */ \ No newline at end of file diff --git a/sys/dev/bhnd/siba/siba_bhndb.c b/sys/dev/bhnd/siba/siba_bhndb.c new file mode 100644 index 000000000000..8d776ad3bcf1 --- /dev/null +++ b/sys/dev/bhnd/siba/siba_bhndb.c @@ -0,0 +1,171 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include +#include +#include + +#include "sibavar.h" + +/* + * Supports attachment of siba(4) bus devices via a bhndb bridge. + */ + +static int +siba_bhndb_probe(device_t dev) +{ + const struct bhnd_chipid *cid; + + /* Check bus type */ + cid = BHNDB_GET_CHIPID(device_get_parent(dev), dev); + if (cid->chip_type != BHND_CHIPTYPE_SIBA) + return (ENXIO); + + /* Delegate to default probe implementation */ + return (siba_probe(dev)); +} + +static int +siba_bhndb_attach(device_t dev) +{ + const struct bhnd_chipid *chipid; + int error; + + /* Enumerate our children. */ + chipid = BHNDB_GET_CHIPID(device_get_parent(dev), dev); + if ((error = siba_add_children(dev, chipid))) + return (error); + + /* Initialize full bridge configuration */ + error = BHNDB_INIT_FULL_CONFIG(device_get_parent(dev), dev, + bhndb_siba_priority_table); + if (error) + return (error); + + /* Call our superclass' implementation */ + return (siba_attach(dev)); +} + +/* Suspend all references to the device's cfg register blocks */ +static void +siba_bhndb_suspend_cfgblocks(device_t dev, struct siba_devinfo *dinfo) { + for (u_int i = 0; i < dinfo->core_id.num_cfg_blocks; i++) { + if (dinfo->cfg[i] == NULL) + continue; + + BHNDB_SUSPEND_RESOURCE(device_get_parent(dev), dev, + SYS_RES_MEMORY, dinfo->cfg[i]->res); + } +} + +static int +siba_bhndb_suspend_child(device_t dev, device_t child) +{ + struct siba_devinfo *dinfo; + int error; + + if (device_get_parent(child) != dev) + BUS_SUSPEND_CHILD(device_get_parent(dev), child); + + dinfo = device_get_ivars(child); + + /* Suspend the child */ + if ((error = bhnd_generic_br_suspend_child(dev, child))) + return (error); + + /* Suspend resource references to the child's config registers */ + siba_bhndb_suspend_cfgblocks(dev, dinfo); + + return (0); +} + +static int +siba_bhndb_resume_child(device_t dev, device_t child) +{ + struct siba_devinfo *dinfo; + int error; + + if (device_get_parent(child) != dev) + BUS_SUSPEND_CHILD(device_get_parent(dev), child); + + if (!device_is_suspended(child)) + return (EBUSY); + + dinfo = device_get_ivars(child); + + /* Resume all resource references to the child's config registers */ + for (u_int i = 0; i < dinfo->core_id.num_cfg_blocks; i++) { + if (dinfo->cfg[i] == NULL) + continue; + + error = BHNDB_RESUME_RESOURCE(device_get_parent(dev), dev, + SYS_RES_MEMORY, dinfo->cfg[i]->res); + if (error) { + siba_bhndb_suspend_cfgblocks(dev, dinfo); + return (error); + } + } + + /* Resume the child */ + if ((error = bhnd_generic_br_resume_child(dev, child))) { + siba_bhndb_suspend_cfgblocks(dev, dinfo); + return (error); + } + + return (0); +} + +static device_method_t siba_bhndb_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, siba_bhndb_probe), + DEVMETHOD(device_attach, siba_bhndb_attach), + + /* Bus interface */ + DEVMETHOD(bus_suspend_child, siba_bhndb_suspend_child), + DEVMETHOD(bus_resume_child, siba_bhndb_resume_child), + + DEVMETHOD_END +}; + +DEFINE_CLASS_1(bhnd, siba_bhndb_driver, siba_bhndb_methods, + sizeof(struct siba_softc), siba_driver); + +DRIVER_MODULE(siba_bhndb, bhndb, siba_bhndb_driver, bhnd_devclass, NULL, NULL); + +MODULE_VERSION(siba_bhndb, 1); +MODULE_DEPEND(siba_bhndb, siba, 1, 1, 1); +MODULE_DEPEND(siba_bhndb, bhndb, 1, 1, 1); \ No newline at end of file diff --git a/sys/dev/bhnd/siba/siba_nexus.c b/sys/dev/bhnd/siba/siba_nexus.c new file mode 100644 index 000000000000..d951b172b0e6 --- /dev/null +++ b/sys/dev/bhnd/siba/siba_nexus.c @@ -0,0 +1,453 @@ +/*- + * Copyright (c) 2007 Bruce M. Simpson. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "sibareg.h" +#include "sibavar.h" + +/* + * Supports siba(4) attachment to a MIPS nexus bus. + * + * This driver is a direct port of Bruce M. Simpson' original siba(4) to the + * bhnd(4) bus infrastructure. + */ + +/* + * TODO: De-mipsify this code. + * TODO: cpu clock calculation. -> move to siba_cc instance + * TODO: Hardwire IRQs for attached cores on siba at probe time. + * TODO: Support detach. + * TODO: Power management. + * TODO: code cleanup. + * TODO: Support deployments of siba other than as a system bus. + */ + +#ifndef MIPS_MEM_RID +#define MIPS_MEM_RID 0x20 +#endif + +extern int rman_debug; + +static struct rman mem_rman; /* XXX move to softc */ + +static int siba_debug = 1; +static const char descfmt[] = "Sonics SiliconBackplane rev %s"; +#define SIBA_DEVDESCLEN sizeof(descfmt) + 8 + +static int siba_nexus_activate_resource(device_t, device_t, int, int, + struct resource *); +static struct resource * + siba_nexus_alloc_resource(device_t, device_t, int, int *, + rman_res_t, rman_res_t, rman_res_t, u_int); +static int siba_nexus_attach(device_t); +#ifdef notyet +static uint8_t siba_nexus_getirq(uint16_t); +#endif +static int siba_nexus_probe(device_t); + +struct siba_nexus_softc { + struct siba_softc parent_sc; + + device_t siba_dev; /* Device ID */ + struct bhnd_chipid siba_cid; + struct resource *siba_mem_res; + bus_space_tag_t siba_mem_bt; + bus_space_handle_t siba_mem_bh; + bus_addr_t siba_maddr; + bus_size_t siba_msize; +}; + +// TODO - depends on bhnd(4) IRQ support +#ifdef notyet +/* + * On the Sentry5, the system bus IRQs are the same as the + * MIPS IRQs. Particular cores are hardwired to certain IRQ lines. + */ +static uint8_t +siba_nexus_getirq(uint16_t devid) +{ + uint8_t irq; + + switch (devid) { + case BHND_COREID_CC: + irq = 0; + break; + case BHND_COREID_ENET: + irq = 1; + break; + case BHND_COREID_IPSEC: + irq = 2; + break; + case BHND_COREID_USB: + irq = 3; + break; + case BHND_COREID_PCI: + irq = 4; + break; +#if 0 + /* + * 5 is reserved for the MIPS on-chip timer interrupt; + * it is hard-wired by the tick driver. + */ + case BHND_COREID_MIPS: + case BHND_COREID_MIPS33: + irq = 5; + break; +#endif + default: + irq = 0xFF; /* this core does not need an irq */ + break; + } + + return (irq); +} +#endif + +static int +siba_nexus_probe(device_t dev) +{ + struct siba_nexus_softc *sc = device_get_softc(dev); + struct bhnd_core_info cc; + uint32_t idhi, idlo; + int error, rid; + + sc->siba_dev = dev; + + //rman_debug = 1; /* XXX */ + + /* + * Read the ChipCommon info using the hints the kernel + * was compiled with. + */ + rid = MIPS_MEM_RID; + sc->siba_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, + RF_ACTIVE); + if (sc->siba_mem_res == NULL) { + device_printf(dev, "unable to allocate probe aperture\n"); + return (ENXIO); + } + sc->siba_mem_bt = rman_get_bustag(sc->siba_mem_res); + sc->siba_mem_bh = rman_get_bushandle(sc->siba_mem_res); + sc->siba_maddr = rman_get_start(sc->siba_mem_res); + sc->siba_msize = rman_get_size(sc->siba_mem_res); + + if (siba_debug) { + device_printf(dev, "start %08x len %08x\n", + sc->siba_maddr, sc->siba_msize); + } + + idlo = bus_read_4(sc->siba_mem_res, SIBA_IDLOW); + idhi = bus_read_4(sc->siba_mem_res, SIBA_IDHIGH); + cc = siba_parse_core_info(idhi, 0, 0); + + if (siba_debug) { + device_printf(dev, "idhi = %08x\n", idhi); + device_printf(dev, " chipcore id = %08x\n", cc.device); + } + + /* + * For now, check that the first core is the ChipCommon core. + */ + if (bhnd_core_class(&cc) != BHND_DEVCLASS_CC) { + if (siba_debug) + device_printf(dev, "first core is not ChipCommon\n"); + return (ENXIO); + } + + /* + * Determine backplane revision and set description string. + */ + uint32_t rev; + char *revp; + char descbuf[SIBA_DEVDESCLEN]; + + rev = SIBA_REG_GET(idlo, IDL_SBREV); + revp = "unknown"; + if (rev == SIBA_IDL_SBREV_2_2) + revp = "2.2"; + else if (rev == SIBA_IDL_SBREV_2_3) + revp = "2.3"; + + (void)snprintf(descbuf, sizeof(descbuf), descfmt, revp); + device_set_desc_copy(dev, descbuf); + + /* + * Determine how many cores are present on this siba bus, so + * that we may map them all. + */ + uint32_t ccidreg; + + ccidreg = bus_read_4(sc->siba_mem_res, CHIPC_ID); + sc->siba_cid = bhnd_parse_chipid(ccidreg, sc->siba_maddr); + if (siba_debug) { + device_printf(dev, "ccid = %08x, cc_id = %04x, cc_rev = %04x\n", + ccidreg, sc->siba_cid.chip_id, sc->siba_cid.chip_rev); + } + + if (sc->siba_cid.ncores == 0) + sc->siba_cid.ncores = siba_get_ncores(&sc->siba_cid); + + if (siba_debug) { + device_printf(dev, "%d cores detected.\n", sc->siba_cid.ncores); + } + + /* + * Now we know how many cores are on this siba, release the + * mapping and allocate a new mapping spanning all cores on the bus. + */ + rid = MIPS_MEM_RID; + error = bus_release_resource(dev, SYS_RES_MEMORY, rid, + sc->siba_mem_res); + if (error != 0) { + device_printf(dev, "error %d releasing resource\n", error); + return (ENXIO); + } + + return (0); +} + +static int +siba_nexus_attach(device_t dev) +{ + struct siba_nexus_softc *sc = device_get_softc(dev); + uint32_t total; + int error, rid; + + if (siba_debug) + printf("%s: entry\n", __func__); + + /* Enumerate the bus. */ + if ((error = siba_add_children(dev, &sc->siba_cid))) + return (error); + + /* Allocate full core aperture */ + total = sc->siba_cid.ncores; + sc->siba_mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, + sc->siba_maddr, sc->siba_maddr + total - 1, total, RF_ACTIVE); + if (sc->siba_mem_res == NULL) { + device_printf(dev, "unable to allocate entire aperture\n"); + return (ENXIO); + } + sc->siba_mem_bt = rman_get_bustag(sc->siba_mem_res); + sc->siba_mem_bh = rman_get_bushandle(sc->siba_mem_res); + sc->siba_maddr = rman_get_start(sc->siba_mem_res); + sc->siba_msize = rman_get_size(sc->siba_mem_res); + + if (siba_debug) { + device_printf(dev, "after remapping: start %08x len %08x\n", + sc->siba_maddr, sc->siba_msize); + } + bus_set_resource(dev, SYS_RES_MEMORY, rid, sc->siba_maddr, + sc->siba_msize); + + /* + * We need a manager for the space we claim on nexus to + * satisfy requests from children. + * We need to keep the source reservation we took because + * otherwise it may be claimed elsewhere. + * XXX move to softc + */ + mem_rman.rm_start = sc->siba_maddr; + mem_rman.rm_end = sc->siba_maddr + sc->siba_msize - 1; + mem_rman.rm_type = RMAN_ARRAY; + mem_rman.rm_descr = "SiBa I/O memory addresses"; + if (rman_init(&mem_rman) != 0 || + rman_manage_region(&mem_rman, mem_rman.rm_start, + mem_rman.rm_end) != 0) { + panic("%s: mem_rman", __func__); + } + + return (siba_attach(dev)); +} + +static const struct bhnd_chipid * +siba_nexus_get_chipid(device_t dev, device_t child) { + struct siba_nexus_softc *sc = device_get_softc(dev); + return (&sc->siba_cid); +} + +static struct resource * +siba_nexus_alloc_resource(device_t bus, device_t child, int type, int *rid, + rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) +{ + struct resource *rv; + struct resource_list *rl; + struct resource_list_entry *rle; + int isdefault, needactivate; + +#if 0 + if (siba_debug) + printf("%s: entry\n", __func__); +#endif + + isdefault = (start == 0UL && end == ~0UL && count == 1); + needactivate = flags & RF_ACTIVE; + rl = BUS_GET_RESOURCE_LIST(bus, child); + rle = NULL; + + if (isdefault) { + rle = resource_list_find(rl, type, *rid); + if (rle == NULL) + return (NULL); + if (rle->res != NULL) + panic("%s: resource entry is busy", __func__); + start = rle->start; + end = rle->end; + count = rle->count; + } + + /* + * If the request is for a resource which we manage, + * attempt to satisfy the allocation ourselves. + */ + if (type == SYS_RES_MEMORY && + start >= mem_rman.rm_start && end <= mem_rman.rm_end) { + + rv = rman_reserve_resource(&mem_rman, start, end, count, + flags, child); + if (rv == 0) { + printf("%s: could not reserve resource\n", __func__); + return (0); + } + + rman_set_rid(rv, *rid); + + if (needactivate) { + if (bus_activate_resource(child, type, *rid, rv)) { + printf("%s: could not activate resource\n", + __func__); + rman_release_resource(rv); + return (0); + } + } + + return (rv); + } + + /* + * Pass the request to the parent, usually MIPS nexus. + */ + if (siba_debug) + printf("%s: proxying request to parent\n", __func__); + return (resource_list_alloc(rl, bus, child, type, rid, + start, end, count, flags)); +} + +/* + * The parent bus is responsible for resource activation; in the + * case of MIPS, this boils down to setting the virtual address and + * bus handle by mapping the physical address into KSEG1. + */ +static int +siba_nexus_activate_resource(device_t bus, device_t child, int type, int rid, + struct resource *r) +{ + return (BUS_ACTIVATE_RESOURCE(device_get_parent(bus), child, type, + rid, r)); +} + +// TODO - depends on bhnd(4) IRQ support +#ifdef notyet +static struct siba_devinfo * +siba_nexus_setup_devinfo(device_t dev, uint8_t idx) +{ + struct siba_nexus_softc *sc = device_get_softc(dev); + struct siba_devinfo *sdi; + uint32_t idlo, idhi, rev; + uint16_t vendorid, devid; + bus_addr_t baseaddr; + + sdi = malloc(sizeof(*sdi), M_DEVBUF, M_WAITOK | M_ZERO); + resource_list_init(&sdi->sdi_rl); + + idlo = siba_mips_read_4(sc, idx, SIBA_IDLOW); + idhi = siba_mips_read_4(sc, idx, SIBA_IDHIGH); + + vendorid = (idhi & SIBA_IDHIGH_VENDORMASK) >> + SIBA_IDHIGH_VENDOR_SHIFT; + devid = ((idhi & 0x8ff0) >> 4); + rev = (idhi & SIBA_IDHIGH_REVLO); + rev |= (idhi & SIBA_IDHIGH_REVHI) >> SIBA_IDHIGH_REVHI_SHIFT; + + sdi->sdi_vid = vendorid; + sdi->sdi_devid = devid; + sdi->sdi_rev = rev; + sdi->sdi_idx = idx; + sdi->sdi_irq = siba_getirq(devid); + + /* + * Determine memory window on bus and irq if one is needed. + */ + baseaddr = sc->siba_maddr + (idx * SIBA_CORE_SIZE); + resource_list_add(&sdi->sdi_rl, SYS_RES_MEMORY, + MIPS_MEM_RID, /* XXX */ + baseaddr, baseaddr + SIBA_CORE_LEN - 1, SIBA_CORE_LEN); + + if (sdi->sdi_irq != 0xff) { + resource_list_add(&sdi->sdi_rl, SYS_RES_IRQ, + 0, sdi->sdi_irq, sdi->sdi_irq, 1); + } + + return (sdi); +} +#endif + +static device_method_t siba_nexus_methods[] = { + /* Device interface */ + DEVMETHOD(device_attach, siba_nexus_attach), + DEVMETHOD(device_probe, siba_nexus_probe), + + /* Bus interface */ + DEVMETHOD(bus_activate_resource,siba_nexus_activate_resource), + DEVMETHOD(bus_alloc_resource, siba_nexus_alloc_resource), + DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), + DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), + + /* bhnd interface */ + DEVMETHOD(bhnd_get_chipid, siba_nexus_get_chipid), + + DEVMETHOD_END +}; + +DEFINE_CLASS_1(bhnd, siba_nexus_driver, siba_nexus_methods, + sizeof(struct siba_nexus_softc), siba_driver); + +DRIVER_MODULE(siba_nexus, nexus, siba_driver, bhnd_devclass, 0, 0); diff --git a/sys/dev/bhnd/siba/siba_subr.c b/sys/dev/bhnd/siba/siba_subr.c new file mode 100644 index 000000000000..5e9b028951c6 --- /dev/null +++ b/sys/dev/bhnd/siba/siba_subr.c @@ -0,0 +1,372 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "sibareg.h" +#include "sibavar.h" + +/** + * Map a siba(4) OCP vendor code to its corresponding JEDEC JEP-106 vendor + * code. + * + * @param ocp_vendor An OCP vendor code. + * @return The BHND_MFGID constant corresponding to @p ocp_vendor, or + * BHND_MFGID_INVALID if the OCP vendor is unknown. + */ +uint16_t +siba_get_bhnd_mfgid(uint16_t ocp_vendor) +{ + switch (ocp_vendor) { + case OCP_VENDOR_BCM: + return (BHND_MFGID_BCM); + default: + return (BHND_MFGID_INVALID); + } +} + +/** + * Parse the SIBA_IDH_* fields from the per-core identification + * registers, returning a siba_core_id representation. + * + * @param idhigh The SIBA_R0_IDHIGH register. + * @param idlow The SIBA_R0_IDLOW register. + * @param core_id The core id (index) to include in the result. + * @param unit The unit number to include in the result. + */ +struct siba_core_id +siba_parse_core_id(uint32_t idhigh, uint32_t idlow, u_int core_idx, int unit) +{ + + uint16_t ocp_vendor; + uint8_t sonics_rev; + uint8_t num_addrspace; + uint8_t num_cfg; + + ocp_vendor = SIBA_REG_GET(idhigh, IDH_VENDOR); + sonics_rev = SIBA_REG_GET(idlow, IDL_SBREV); + num_addrspace = SIBA_REG_GET(idlow, IDL_NRADDR) + 1 /* + enum block */; + + /* Determine the number of sonics config register blocks */ + num_cfg = SIBA_CFG_NUM_2_2; + if (sonics_rev >= SIBA_IDL_SBREV_2_3) + num_cfg = SIBA_CFG_NUM_2_3; + + return (struct siba_core_id) { + .core_info = { + .vendor = siba_get_bhnd_mfgid(ocp_vendor), + .device = SIBA_REG_GET(idhigh, IDH_DEVICE), + .hwrev = SIBA_IDH_CORE_REV(idhigh), + .core_idx = core_idx, + .unit = unit + }, + .sonics_vendor = ocp_vendor, + .sonics_rev = sonics_rev, + .num_addrspace = num_addrspace, + .num_cfg_blocks = num_cfg + }; +} + +/** + * Initialize new port descriptor. + * + * @param port_num Port number. + * @param port_type Port type. + */ +static void +siba_init_port(struct siba_port *port, bhnd_port_type port_type, u_int port_num) +{ + port->sp_num = port_num; + port->sp_type = port_type; + port->sp_num_addrs = 0; + STAILQ_INIT(&port->sp_addrs); +} + +/** + * Deallocate all resources associated with the given port descriptor. + * + * @param port Port descriptor to be deallocated. + */ +static void +siba_release_port(struct siba_port *port) { + struct siba_addrspace *as, *as_next; + + STAILQ_FOREACH_SAFE(as, &port->sp_addrs, sa_link, as_next) { + free(as, M_BHND); + } +} + +/** + * Allocate and initialize new device info structure, copying the + * provided core id. + * + * @param dev The requesting bus device. + * @param core Device core info. + */ +struct siba_devinfo * +siba_alloc_dinfo(device_t bus, const struct siba_core_id *core_id) +{ + struct siba_devinfo *dinfo; + + dinfo = malloc(sizeof(struct siba_devinfo), M_BHND, M_NOWAIT); + if (dinfo == NULL) + return NULL; + + dinfo->core_id = *core_id; + + for (u_int i = 0; i < nitems(dinfo->cfg); i++) { + dinfo->cfg[i] = NULL; + dinfo->cfg_rid[i] = -1; + } + + siba_init_port(&dinfo->device_port, BHND_PORT_DEVICE, 0); + resource_list_init(&dinfo->resources); + + return dinfo; +} + +/** + * Return the @p dinfo port instance for @p type, or NULL. + * + * @param dinfo The siba device info. + * @param type The requested port type. + * + * @retval siba_port If @p port_type and @p port_num are defined on @p dinfo. + * @retval NULL If the requested port is not defined on @p dinfo. + */ +struct siba_port * +siba_dinfo_get_port(struct siba_devinfo *dinfo, bhnd_port_type port_type, + u_int port_num) +{ + /* We only define a single port for any given type. */ + if (port_num != 0) + return (NULL); + + switch (port_type) { + case BHND_PORT_DEVICE: + return (&dinfo->device_port); + case BHND_PORT_BRIDGE: + return (NULL); + case BHND_PORT_AGENT: + return (NULL); + } +} + + +/** + * Find an address space with @p sid on @p port. + * + * @param port The port to search for a matching address space. + * @param sid The siba-assigned address space ID to search for. + */ +struct siba_addrspace * +siba_find_port_addrspace(struct siba_port *port, uint8_t sid) +{ + struct siba_addrspace *addrspace; + + STAILQ_FOREACH(addrspace, &port->sp_addrs, sa_link) { + if (addrspace->sa_sid == sid) + return (addrspace); + } + + /* not found */ + return (NULL); +} + +/** + * Append a new address space entry to @p port_num of type @p port_type + * in @p dinfo. + * + * The range will also be registered in @p dinfo resource list. + * + * @param dinfo The device info entry to update. + * @param port_type The port type. + * @param port_num The port number. + * @param region_num The region index number. + * @param sid The siba-assigned core-unique address space identifier. + * @param base The mapping's base address. + * @param size The mapping size. + * @param bus_reserved Number of bytes to reserve in @p size for bus use + * when registering the resource list entry. This is used to reserve bus + * access to the core's SIBA_CFG* register blocks. + * + * @retval 0 success + * @retval non-zero An error occurred appending the entry. + */ +int +siba_append_dinfo_region(struct siba_devinfo *dinfo, bhnd_port_type port_type, + u_int port_num, u_int region_num, uint8_t sid, uint32_t base, uint32_t size, + uint32_t bus_reserved) +{ + struct siba_addrspace *sa; + struct siba_port *port; + + /* Verify that base + size will not overflow */ + if (UINT32_MAX - size < base) + return (ERANGE); + + /* Must not be 0-length */ + if (size == 0) + return (EINVAL); + + /* Determine target port */ + port = siba_dinfo_get_port(dinfo, port_type, port_num); + if (port == NULL) + return (EINVAL); + + /* Allocate new addrspace entry */ + sa = malloc(sizeof(*sa), M_BHND, M_NOWAIT|M_ZERO); + if (sa == NULL) + return (ENOMEM); + + sa->sa_base = base; + sa->sa_size = size; + sa->sa_sid = sid; + sa->sa_region_num = region_num; + + /* Populate the resource list */ + size -= bus_reserved; + sa->sa_rid = resource_list_add_next(&dinfo->resources, SYS_RES_MEMORY, + base, base + size - 1, size); + + /* Append to target port */ + STAILQ_INSERT_TAIL(&port->sp_addrs, sa, sa_link); + port->sp_num_addrs++; + + return (0); +} + +/** + * Deallocate the given device info structure and any associated resources. + * + * @param dev The requesting bus device. + * @param dinfo Device info to be deallocated. + */ +void +siba_free_dinfo(device_t dev, struct siba_devinfo *dinfo) +{ + siba_release_port(&dinfo->device_port); + + resource_list_free(&dinfo->resources); + + /* Free all mapped configuration blocks */ + for (u_int i = 0; i < nitems(dinfo->cfg); i++) { + if (dinfo->cfg[i] == NULL) + continue; + + bhnd_release_resource(dev, SYS_RES_MEMORY, dinfo->cfg_rid[i], + dinfo->cfg[i]); + + dinfo->cfg[i] = NULL; + dinfo->cfg_rid[i] = -1; + } + + free(dinfo, M_BHND); +} + +/** + * Return the core-enumeration-relative offset for the @p addrspace + * SIBA_R0_ADMATCH* register. + * + * @param addrspace The address space index. + * + * @retval non-zero success + * @retval 0 the given @p addrspace index is not supported. + */ +u_int +siba_admatch_offset(uint8_t addrspace) +{ + switch (addrspace) { + case 0: + return SB0_REG_ABS(SIBA_CFG0_ADMATCH0); + case 1: + return SB0_REG_ABS(SIBA_CFG0_ADMATCH1); + case 2: + return SB0_REG_ABS(SIBA_CFG0_ADMATCH2); + case 3: + return SB0_REG_ABS(SIBA_CFG0_ADMATCH3); + default: + return (0); + } +} + +/** + * Parse a SIBA_R0_ADMATCH* register. + * + * @param addrspace The address space index. + * @param am The address match register value to be parsed. + * @param[out] addr The parsed address. + * @param[out] size The parsed size. + * + * @retval 0 success + * @retval non-zero a parse error occured. + */ +int +siba_parse_admatch(uint32_t am, uint32_t *addr, uint32_t *size) +{ + u_int am_type; + + /* Negative encoding is not supported. This is not used on any + * currently known devices*/ + if (am & SIBA_AM_ADNEG) + return (EINVAL); + + /* Extract the base address and size */ + am_type = SIBA_REG_GET(am, AM_TYPE); + switch (am_type) { + case 0: + *addr = am & SIBA_AM_BASE0_MASK; + *size = 1 << (SIBA_REG_GET(am, AM_ADINT0) + 1); + break; + case 1: + *addr = am & SIBA_AM_BASE1_MASK; + *size = 1 << (SIBA_REG_GET(am, AM_ADINT1) + 1); + break; + case 2: + *addr = am & SIBA_AM_BASE2_MASK; + *size = 1 << (SIBA_REG_GET(am, AM_ADINT2) + 1); + break; + default: + return (EINVAL); + } + + return (0); +} \ No newline at end of file diff --git a/sys/dev/bhnd/siba/sibareg.h b/sys/dev/bhnd/siba/sibareg.h new file mode 100644 index 000000000000..c1a2e267a091 --- /dev/null +++ b/sys/dev/bhnd/siba/sibareg.h @@ -0,0 +1,266 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * Copyright (c) 2010 Broadcom Corporation + * + * This file was derived from the sbconfig.h header distributed with + * Broadcom's initial brcm80211 Linux driver release, as + * contributed to the Linux staging repository. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#ifndef _BHND_SIBA_SIBAREG_ +#define _BHND_SIBA_SIBAREG_ + +#include + +/* + * Broadcom SIBA Configuration Space Registers. + * + * Backplane configuration registers common to siba(4) core register + * blocks. + */ + +/** + * Extract a config attribute by applying _MASK and _SHIFT defines. + * + * @param _reg The register value containing the desired attribute + * @param _attr The BCMA EROM attribute name (e.g. ENTRY_ISVALID), to be + * concatenated with the `SB` prefix and `_MASK`/`_SHIFT` suffixes. + */ +#define SIBA_REG_GET(_entry, _attr) \ + ((_entry & SIBA_ ## _attr ## _MASK) \ + >> SIBA_ ## _attr ## _SHIFT) + + +#define SIBA_ENUM_ADDR BHND_DEFAULT_CHIPC_ADDR /**< enumeration space */ +#define SIBA_ENUM_SIZE 0x00100000 /**< size of the enumeration space */ +#define SIBA_CORE_SIZE BHND_DEFAULT_CORE_SIZE /**< per-core register block size */ +#define SIBA_MAX_CORES \ + (SIBA_ENUM_SIZE/SIBA_CORE_SIZE) /**< Maximum number of cores */ + +#define SIBA_ADDRSPACE_CORE 0 /**< address space identifier of the + core enumeration block. */ + +/**< Evaluates to the bus address of the @p idx core register block */ +#define SIBA_CORE_ADDR(idx) \ + (SIBA_ENUM_ADDR + ((idx) * SIBA_CORE_SIZE)) + +/* + * Sonics configuration registers are mapped to each core's enumeration + * space, at the end of the 4kb device register block, in reverse + * order: + * + * [0x0000-0x0dff] core registers + * [0x0e00-0x0eff] SIBA_R1 registers (sonics >= 2.3) + * [0x0f00-0x0fff] SIBA_R0 registers + */ + +#define SIBA_CFG0_OFFSET 0xf00 /**< first configuration block */ +#define SIBA_CFG1_OFFSET 0xe00 /**< second configuration block (sonics >= 2.3) */ + +#define SIBA_CFG_SIZE 0x100 /**< cfg register block size */ + +/* Return the SIBA_CORE_ADDR-relative offset for a SIBA_CFG* register. */ +#define SB0_REG_ABS(off) ((off) + SIBA_CFG0_OFFSET) +#define SB1_REG_ABS(off) ((off) + SIBA_CFG1_OFFSET) + +/* SIBA_CFG0 registers */ +#define SIBA_CFG0_IPSFLAG 0x08 /**< initiator port ocp slave flag */ +#define SIBA_CFG0_TPSFLAG 0x18 /**< target port ocp slave flag */ +#define SIBA_CFG0_TMERRLOGA 0x48 /**< sonics >= 2.3 */ +#define SIBA_CFG0_TMERRLOG 0x50 /**< sonics >= 2.3 */ +#define SIBA_CFG0_ADMATCH3 0x60 /**< address match3 */ +#define SIBA_CFG0_ADMATCH2 0x68 /**< address match2 */ +#define SIBA_CFG0_ADMATCH1 0x70 /**< address match1 */ +#define SIBA_CFG0_IMSTATE 0x90 /**< initiator agent state */ +#define SIBA_CFG0_INTVEC 0x94 /**< interrupt mask */ +#define SIBA_CFG0_TMSTATELOW 0x98 /**< target state */ +#define SIBA_CFG0_TMSTATEHIGH 0x9c /**< target state */ +#define SIBA_CFG0_BWA0 0xa0 /**< bandwidth allocation table0 */ +#define SIBA_CFG0_IMCONFIGLOW 0xa8 /**< initiator configuration */ +#define SIBA_CFG0_IMCONFIGHIGH 0xac /**< initiator configuration */ +#define SIBA_CFG0_ADMATCH0 0xb0 /**< address match0 */ +#define SIBA_CFG0_TMCONFIGLOW 0xb8 /**< target configuration */ +#define SIBA_CFG0_TMCONFIGHIGH 0xbc /**< target configuration */ +#define SIBA_CFG0_BCONFIG 0xc0 /**< broadcast configuration */ +#define SIBA_CFG0_BSTATE 0xc8 /**< broadcast state */ +#define SIBA_CFG0_ACTCNFG 0xd8 /**< activate configuration */ +#define SIBA_CFG0_FLAGST 0xe8 /**< current sbflags */ +#define SIBA_CFG0_IDLOW 0xf8 /**< identification */ +#define SIBA_CFG0_IDHIGH 0xfc /**< identification */ + +/* SIBA_CFG1 registers (sonics >= 2.3) */ +#define SIBA_CFG1_IMERRLOGA 0xa8 /**< (sonics >= 2.3) */ +#define SIBA_CFG1_IMERRLOG 0xb0 /**< sbtmerrlog (sonics >= 2.3) */ +#define SIBA_CFG1_TMPORTCONNID0 0xd8 /**< sonics >= 2.3 */ +#define SIBA_CFG1_TMPORTLOCK0 0xf8 /**< sonics >= 2.3 */ + +/* sbipsflag */ +#define SIBA_IPS_INT1_MASK 0x3f /* which sbflags get routed to mips interrupt 1 */ +#define SIBA_IPS_INT1_SHIFT 0 +#define SIBA_IPS_INT2_MASK 0x3f00 /* which sbflags get routed to mips interrupt 2 */ +#define SIBA_IPS_INT2_SHIFT 8 +#define SIBA_IPS_INT3_MASK 0x3f0000 /* which sbflags get routed to mips interrupt 3 */ +#define SIBA_IPS_INT3_SHIFT 16 +#define SIBA_IPS_INT4_MASK 0x3f000000 /* which sbflags get routed to mips interrupt 4 */ +#define SIBA_IPS_INT4_SHIFT 24 + +/* sbtpsflag */ +#define SIBA_TPS_NUM0_MASK 0x3f /* interrupt sbFlag # generated by this core */ +#define SIBA_TPS_F0EN0 0x40 /* interrupt is always sent on the backplane */ + +/* sbtmerrlog */ +#define SIBA_TMEL_CM 0x00000007 /* command */ +#define SIBA_TMEL_CI 0x0000ff00 /* connection id */ +#define SIBA_TMEL_EC 0x0f000000 /* error code */ +#define SIBA_TMEL_ME 0x80000000 /* multiple error */ + +/* sbimstate */ +#define SIBA_IM_PC 0xf /* pipecount */ +#define SIBA_IM_AP_MASK 0x30 /* arbitration policy */ +#define SIBA_IM_AP_BOTH 0x00 /* use both timeslaces and token */ +#define SIBA_IM_AP_TS 0x10 /* use timesliaces only */ +#define SIBA_IM_AP_TK 0x20 /* use token only */ +#define SIBA_IM_AP_RSV 0x30 /* reserved */ +#define SIBA_IM_IBE 0x20000 /* inbanderror */ +#define SIBA_IM_TO 0x40000 /* timeout */ +#define SIBA_IM_BY 0x01800000 /* busy (sonics >= 2.3) */ +#define SIBA_IM_RJ 0x02000000 /* reject (sonics >= 2.3) */ + +/* sbtmstatelow */ +#define SIBA_TML_RESET 0x0001 /* reset */ +#define SIBA_TML_REJ_MASK 0x0006 /* reject field */ +#define SIBA_TML_REJ 0x0002 /* reject */ +#define SIBA_TML_TMPREJ 0x0004 /* temporary reject, for error recovery */ + +#define SIBA_TML_SICF_SHIFT 16 /* Shift to locate the SI control flags in sbtml */ + +/* sbtmstatehigh */ +#define SIBA_TMH_SERR 0x0001 /* serror */ +#define SIBA_TMH_INT 0x0002 /* interrupt */ +#define SIBA_TMH_BUSY 0x0004 /* busy */ +#define SIBA_TMH_TO 0x0020 /* timeout (sonics >= 2.3) */ + +#define SIBA_TMH_SISF_SHIFT 16 /* Shift to locate the SI status flags in sbtmh */ + +/* sbbwa0 */ +#define SIBA_BWA_TAB0_MASK 0xffff /* lookup table 0 */ +#define SIBA_BWA_TAB1_MASK 0xffff /* lookup table 1 */ +#define SIBA_BWA_TAB1_SHIFT 16 + +/* sbimconfiglow */ +#define SIBA_IMCL_STO_MASK 0x7 /* service timeout */ +#define SIBA_IMCL_RTO_MASK 0x70 /* request timeout */ +#define SIBA_IMCL_RTO_SHIFT 4 +#define SIBA_IMCL_CID_MASK 0xff0000 /* connection id */ +#define SIBA_IMCL_CID_SHIFT 16 + +/* sbimconfighigh */ +#define SIBA_IMCH_IEM_MASK 0xc /* inband error mode */ +#define SIBA_IMCH_TEM_MASK 0x30 /* timeout error mode */ +#define SIBA_IMCH_TEM_SHIFT 4 +#define SIBA_IMCH_BEM_MASK 0xc0 /* bus error mode */ +#define SIBA_IMCH_BEM_SHIFT 6 + +/* sbadmatch0 */ +#define SIBA_AM_TYPE_MASK 0x3 /* address type */ +#define SIBA_AM_TYPE_SHIFT 0x0 +#define SIBA_AM_AD64 0x4 /* reserved */ +#define SIBA_AM_ADINT0_MASK 0xf8 /* type0 size */ +#define SIBA_AM_ADINT0_SHIFT 3 +#define SIBA_AM_ADINT1_MASK 0x1f8 /* type1 size */ +#define SIBA_AM_ADINT1_SHIFT 3 +#define SIBA_AM_ADINT2_MASK 0x1f8 /* type2 size */ +#define SIBA_AM_ADINT2_SHIFT 3 +#define SIBA_AM_ADEN 0x400 /* enable */ +#define SIBA_AM_ADNEG 0x800 /* negative decode */ +#define SIBA_AM_BASE0_MASK 0xffffff00 /* type0 base address */ +#define SIBA_AM_BASE0_SHIFT 8 +#define SIBA_AM_BASE1_MASK 0xfffff000 /* type1 base address for the core */ +#define SIBA_AM_BASE1_SHIFT 12 +#define SIBA_AM_BASE2_MASK 0xffff0000 /* type2 base address for the core */ +#define SIBA_AM_BASE2_SHIFT 16 + +/* sbtmconfiglow */ +#define SIBA_TMCL_CD_MASK 0xff /* clock divide */ +#define SIBA_TMCL_CO_MASK 0xf800 /* clock offset */ +#define SIBA_TMCL_CO_SHIFT 11 +#define SIBA_TMCL_IF_MASK 0xfc0000 /* interrupt flags */ +#define SIBA_TMCL_IF_SHIFT 18 +#define SIBA_TMCL_IM_MASK 0x3000000 /* interrupt mode */ +#define SIBA_TMCL_IM_SHIFT 24 + +/* sbtmconfighigh */ +#define SIBA_TMCH_BM_MASK 0x3 /* busy mode */ +#define SIBA_TMCH_RM_MASK 0x3 /* retry mode */ +#define SIBA_TMCH_RM_SHIFT 2 +#define SIBA_TMCH_SM_MASK 0x30 /* stop mode */ +#define SIBA_TMCH_SM_SHIFT 4 +#define SIBA_TMCH_EM_MASK 0x300 /* sb error mode */ +#define SIBA_TMCH_EM_SHIFT 8 +#define SIBA_TMCH_IM_MASK 0xc00 /* int mode */ +#define SIBA_TMCH_IM_SHIFT 10 + +/* sbbconfig */ +#define SIBA_BC_LAT_MASK 0x3 /* sb latency */ +#define SIBA_BC_MAX0_MASK 0xf0000 /* maxccntr0 */ +#define SIBA_BC_MAX0_SHIFT 16 +#define SIBA_BC_MAX1_MASK 0xf00000 /* maxccntr1 */ +#define SIBA_BC_MAX1_SHIFT 20 + +/* sbbstate */ +#define SIBA_BS_SRD 0x1 /* st reg disable */ +#define SIBA_BS_HRD 0x2 /* hold reg disable */ + +/* sbidlow */ +#define SIBA_IDL_CS_MASK 0x3 /* config space */ +#define SIBA_IDL_CS_SHIFT 0 +#define SIBA_IDL_NRADDR_MASK 0x38 /* # address ranges supported */ +#define SIBA_IDL_NRADDR_SHIFT 3 +#define SIBA_IDL_SYNCH 0x40 /* sync */ +#define SIBA_IDL_INIT 0x80 /* initiator */ +#define SIBA_IDL_MINLAT_MASK 0xf00 /* minimum backplane latency */ +#define SIBA_IDL_MINLAT_SHIFT 8 +#define SIBA_IDL_MAXLAT_MASK 0xf000 /* maximum backplane latency */ +#define SIBA_IDL_MAXLAT_SHIFT 12 +#define SIBA_IDL_FIRST_MASK 0x10000 /* this initiator is first */ +#define SIBA_IDL_FIRST_SHIFT 16 +#define SIBA_IDL_CW_MASK 0xc0000 /* cycle counter width */ +#define SIBA_IDL_CW_SHIFT 18 +#define SIBA_IDL_TP_MASK 0xf00000 /* target ports */ +#define SIBA_IDL_TP_SHIFT 20 +#define SIBA_IDL_IP_MASK 0xf000000 /* initiator ports */ +#define SIBA_IDL_IP_SHIFT 24 +#define SIBA_IDL_SBREV_MASK 0xf0000000 /* sonics backplane revision code */ +#define SIBA_IDL_SBREV_SHIFT 28 +#define SIBA_IDL_SBREV_2_2 0x0 /* version 2.2 or earlier */ +#define SIBA_IDL_SBREV_2_3 0x1 /* version 2.3 */ + +/* sbidhigh */ +#define SIBA_IDH_RC_MASK 0x000f /* revision code */ +#define SIBA_IDH_RCE_MASK 0x7000 /* revision code extension field */ +#define SIBA_IDH_RCE_SHIFT 8 +#define SIBA_IDH_DEVICE_MASK 0x8ff0 /* core code */ +#define SIBA_IDH_DEVICE_SHIFT 4 +#define SIBA_IDH_VENDOR_MASK 0xffff0000 /* vendor code */ +#define SIBA_IDH_VENDOR_SHIFT 16 + +#define SIBA_IDH_CORE_REV(sbidh) \ + (SIBA_REG_GET((sbidh), IDH_RCE) | ((sbidh) & SIBA_IDH_RC_MASK)) + +#define SIBA_COMMIT 0xfd8 /* update buffered registers value */ + +#endif /* _BHND_SIBA_SIBAREG_ */ diff --git a/sys/dev/bhnd/siba/sibavar.h b/sys/dev/bhnd/siba/sibavar.h new file mode 100644 index 000000000000..764ce238d3bf --- /dev/null +++ b/sys/dev/bhnd/siba/sibavar.h @@ -0,0 +1,150 @@ +/*- + * Copyright (c) 2015 Landon Fuller + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer, + * without modification. + * 2. Redistributions in binary form must reproduce at minimum a disclaimer + * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any + * redistribution must be conditioned upon including a substantially + * similar Disclaimer requirement for further binary redistribution. + * + * NO WARRANTY + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER + * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGES. + * + * $FreeBSD$ + */ + +#ifndef _SIBA_SIBAVAR_H_ +#define _SIBA_SIBAVAR_H_ + +#include +#include +#include + +#include +#include + +#include "siba.h" + +/* + * Internal definitions shared by siba(4) driver implementations. + */ + +struct siba_addrspace; +struct siba_devinfo; +struct siba_port; +struct siba_core_id; + +int siba_probe(device_t dev); +int siba_attach(device_t dev); +int siba_detach(device_t dev); + +uint16_t siba_get_bhnd_mfgid(uint16_t ocp_vendor); + +struct siba_core_id siba_parse_core_id(uint32_t idhigh, uint32_t idlow, + u_int core_idx, int unit); + +int siba_add_children(device_t bus, + const struct bhnd_chipid *chipid); + +struct siba_devinfo *siba_alloc_dinfo(device_t dev, + const struct siba_core_id *core_id); +void siba_free_dinfo(device_t dev, + struct siba_devinfo *dinfo); + +struct siba_port *siba_dinfo_get_port(struct siba_devinfo *dinfo, + bhnd_port_type port_type, u_int port_num); + +struct siba_addrspace *siba_find_port_addrspace(struct siba_port *port, + uint8_t sid); + +int siba_append_dinfo_region(struct siba_devinfo *dinfo, + bhnd_port_type port_type, u_int port_num, + u_int region_num, uint8_t sid, uint32_t base, + uint32_t size, uint32_t bus_reserved); + +u_int siba_admatch_offset(uint8_t addrspace); +int siba_parse_admatch(uint32_t am, uint32_t *addr, + uint32_t *size); + +/* Sonics configuration register blocks */ +#define SIBA_CFG_NUM_2_2 1 /**< sonics <= 2.2 maps SIBA_CFG0. */ +#define SIBA_CFG_NUM_2_3 2 /**< sonics <= 2.3 maps SIBA_CFG0 and SIBA_CFG1 */ +#define SIBA_CFG_NUM_MAX SIBA_CFG_NUM_2_3 /**< maximum number of supported config + register blocks */ + +/** siba(4) address space descriptor */ +struct siba_addrspace { + uint32_t sa_base; /**< base address */ + uint32_t sa_size; /**< size */ + u_int sa_region_num; /**< bhnd region id */ + uint8_t sa_sid; /**< siba-assigned address space ID */ + int sa_rid; /**< bus resource id */ + + STAILQ_ENTRY(siba_addrspace) sa_link; +}; + +/** siba(4) port descriptor */ +struct siba_port { + bhnd_port_type sp_type; /**< port type */ + u_int sp_num; /**< port number */ + u_int sp_num_addrs; /**< number of address space mappings */ + + STAILQ_HEAD(, siba_addrspace) sp_addrs; /**< address spaces mapped to this port */ +}; + +/** + * siba(4) per-core identification info. + */ +struct siba_core_id { + struct bhnd_core_info core_info; /**< standard bhnd(4) core info */ + uint16_t sonics_vendor; /**< OCP vendor identifier used to generate + * the JEDEC-106 bhnd(4) vendor identifier. */ + uint8_t sonics_rev; /**< sonics backplane revision code */ + uint8_t num_addrspace; /**< number of address ranges mapped to + this core. */ + uint8_t num_cfg_blocks; /**< number of Sonics configuration register + blocks mapped to the core's enumeration + space */ +}; + +/** + * siba(4) per-device info + */ +struct siba_devinfo { + struct resource_list resources; /**< per-core memory regions. */ + struct siba_core_id core_id; /**< core identification info */ + + struct siba_port device_port; /**< device port holding ownership + * of all siba address space + * entries for this core. */ + + /** SIBA_CFG* register blocks */ + struct bhnd_resource *cfg[SIBA_CFG_NUM_MAX]; + + /** SIBA_CFG* resource IDs */ + int cfg_rid[SIBA_CFG_NUM_MAX]; +}; + + +/** siba(4) per-instance state */ +struct siba_softc { + struct bhnd_softc bhnd_sc; /**< bhnd state */ +}; + +#endif /* _SIBA_SIBAVAR_H_ */ diff --git a/sys/dev/bhnd/tools/bus_macro.sh b/sys/dev/bhnd/tools/bus_macro.sh new file mode 100755 index 000000000000..de9e7983b9dc --- /dev/null +++ b/sys/dev/bhnd/tools/bus_macro.sh @@ -0,0 +1,84 @@ +#!/bin/sh +# +# Copyright (c) 2015 Landon Fuller +# Copyright (c) 2004-2005 Poul-Henning Kamp. +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# +# Generate the bhnd resource macros at the bottom of dev/bhnd/bhnd.h +# +# Derived from PHK's tools/bus_macros.sh +# + +macro () { + n=${1} + bus_n=$(echo $n | tr "[:lower:]" "[:upper:]") + + shift + echo -n "#define bhnd_bus_${n}(r" + for i + do + echo -n ", ${i}" + done + echo ") \\" + echo " ((r)->direct) ? \\" + echo -n " bus_${n}((r)->res" + for i + do + echo -n ", (${i})" + done + echo ") : \\" + echo -n " BHND_BUS_${bus_n}(" + echo "device_get_parent(rman_get_device((r)->res)), \\" + echo -n " rman_get_device((r)->res), (r)" + for i + do + echo -n ", (${i})" + done + echo ")" + +} + +macro barrier o l f + +# We only support a subset of the bus I/O methods; this may +# be expanded when/if additional functions are required. +for w in 1 2 4 #8 +do + # macro copy_region_$w so dh do c + # macro copy_region_stream_$w ? + # macro peek_$w + for s in "" #stream_ + do + macro read_$s$w o +# macro read_multi_$s$w o d c +# macro read_region_$s$w o d c +# macro set_multi_$s$w o v c +# macro set_region_$s$w o v c + macro write_$s$w o v +# macro write_multi_$s$w o d c +# macro write_region_$s$w o d c + done +done