Index: head/sys/dev/bhnd/bcma/bcma_bhndb.c =================================================================== --- head/sys/dev/bhnd/bcma/bcma_bhndb.c (revision 299995) +++ head/sys/dev/bhnd/bcma/bcma_bhndb.c (revision 299996) @@ -1,189 +1,206 @@ /*- * 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) { struct bcma_softc *sc; const struct bhnd_chipid *cid; struct resource *erom_res; int error; int rid; sc = device_get_softc(dev); /* Map the EROM resource and enumerate our children. */ cid = BHNDB_GET_CHIPID(device_get_parent(dev), dev); 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); /* Ask our parent bridge to find the corresponding bridge core */ sc->hostb_dev = BHNDB_FIND_HOSTB_DEVICE(device_get_parent(dev), dev); /* 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 int +bcma_bhndb_read_board_info(device_t dev, device_t child, + struct bhnd_board_info *info) +{ + int error; + + /* Initialize with NVRAM-derived values */ + if ((error = bhnd_bus_generic_read_board_info(dev, child, info))) + return (error); + + /* Let the bridge fill in any additional data */ + return (BHNDB_POPULATE_BOARD_INFO(device_get_parent(dev), dev, info)); +} + 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), + + /* BHND interface */ + DEVMETHOD(bhnd_bus_read_board_info, bcma_bhndb_read_board_info), 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, bhnd, 1, 1, 1); MODULE_DEPEND(bcma_bhndb, bhndb, 1, 1, 1); Index: head/sys/dev/bhnd/bhnd.c =================================================================== --- head/sys/dev/bhnd/bhnd.c (revision 299995) +++ head/sys/dev/bhnd/bhnd.c (revision 299996) @@ -1,734 +1,667 @@ /*- * 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 "nvram/bhnd_nvram.h" - -#include "bhnd_chipc_if.h" -#include "bhnd_nvram_if.h" - #include "bhnd.h" #include "bhndvar.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); /** * Default bhnd(4) bus driver implementation of DEVICE_ATTACH(). * * This implementation calls device_probe_and_attach() for each of the device's * children, in bhnd probe 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); } /** * Default bhnd(4) bus driver implementation of DEVICE_DETACH(). * * This implementation calls device_detach() for each of the the device's * children, in reverse bhnd probe 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); } /** * Default bhnd(4) bus driver implementation of DEVICE_SHUTDOWN(). * * This implementation calls device_shutdown() for each of the device's * children, in reverse bhnd probe 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); } /** * Default bhnd(4) bus driver implementation of DEVICE_RESUME(). * * This implementation calls BUS_RESUME_CHILD() for each of the device's * children in bhnd probe 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); } /** * Default bhnd(4) bus driver implementation of DEVICE_SUSPEND(). * * This implementation calls BUS_SUSPEND_CHILD() for each of the device's * children in reverse bhnd probe 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)); } /** * Default bhnd(4) bus driver implementation of 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); + /* Must be early enough to provide NVRAM access to the + * host bridge */ + return (BHND_PROBE_ROOT + 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_find_hostb_device(dev) == child) return (BHND_PROBE_ROOT + BHND_PROBE_ORDER_EARLY); return (BHND_PROBE_DEFAULT); default: return (BHND_PROBE_DEFAULT); } } /** * Default bhnd(4) bus driver implementation of 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. */ static 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, "bhnd_nvram", 0); - if (nvram != NULL) - return (nvram); - - /* Remaining checks are only applicable when searching a bhnd(4) - * bus. */ - if (device_get_devclass(dev) != bhnd_devclass) - return (NULL); - - /* Look for a ChipCommon device */ - if ((chipc = bhnd_find_child(dev, BHND_DEVCLASS_CC, -1)) != NULL) { - bhnd_nvram_src_t src; - - /* Query the NVRAM source and determine whether it's - * accessible via the ChipCommon device */ - src = BHND_CHIPC_NVRAM_SRC(chipc); - if (BHND_NVRAM_SRC_CC(src)) - return (chipc); - } - - /* Not found */ - return (NULL); -} - -/** - * Default bhnd(4) bus driver implementation of BHND_BUS_GET_NVRAM_VAR(). - * - * This implementation searches @p dev for a usable NVRAM child device: - * - The first child device implementing the bhnd_nvram devclass is - * returned, otherwise - * - If @p dev is a bhnd(4) bus, a ChipCommon core that advertises an - * attached NVRAM source. - * - * If no usable child device is found on @p dev, the request is delegated to - * the BHND_BUS_GET_NVRAM_VAR() method on the parent of @p dev. - */ -static int -bhnd_generic_get_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_GET_NVRAM_VAR(device_get_parent(dev), child, - name, buf, size)); - - return BHND_NVRAM_GETVAR(nvram, name, buf, size); -} - -/** * Default bhnd(4) bus driver implementation of 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, "%#jx"); } 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); } /** * Default bhnd(4) bus driver implementation of BUS_PROBE_NOMATCH(). * * 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, "%#jx"); 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 BUS_CHILD_LOCATION_STR(). */ 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); } /* * 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. */ #define BHND_IO_READ(_type, _name, _method) \ static _type \ bhnd_read_ ## _name (device_t dev, device_t child, \ struct bhnd_resource *r, bus_size_t offset) \ { \ return (BHND_BUS_READ_ ## _method( \ device_get_parent(dev), child, r, offset)); \ } #define BHND_IO_WRITE(_type, _name, _method) \ static void \ bhnd_write_ ## _name (device_t dev, device_t child, \ struct bhnd_resource *r, bus_size_t offset, _type value) \ { \ return (BHND_BUS_WRITE_ ## _method( \ device_get_parent(dev), child, r, offset, \ value)); \ } #define BHND_IO_MULTI(_type, _rw, _name, _method) \ static void \ bhnd_ ## _rw ## _multi_ ## _name (device_t dev, device_t child, \ struct bhnd_resource *r, bus_size_t offset, _type *datap, \ bus_size_t count) \ { \ BHND_BUS_ ## _method(device_get_parent(dev), child, r, \ offset, datap, count); \ } #define BHND_IO_METHODS(_type, _size) \ BHND_IO_READ(_type, _size, _size) \ BHND_IO_WRITE(_type, _size, _size) \ \ BHND_IO_READ(_type, stream_ ## _size, STREAM_ ## _size) \ BHND_IO_WRITE(_type, stream_ ## _size, STREAM_ ## _size) \ \ BHND_IO_MULTI(_type, read, _size, READ_MULTI_ ## _size) \ BHND_IO_MULTI(_type, write, _size, WRITE_MULTI_ ## _size) \ \ BHND_IO_MULTI(_type, read, stream_ ## _size, \ READ_MULTI_STREAM_ ## _size) \ BHND_IO_MULTI(_type, write, stream_ ## _size, \ WRITE_MULTI_STREAM_ ## _size) \ BHND_IO_METHODS(uint8_t, 1); BHND_IO_METHODS(uint16_t, 2); BHND_IO_METHODS(uint32_t, 4); 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_get_chipid, bhnd_bus_generic_get_chipid), DEVMETHOD(bhnd_bus_get_probe_order, bhnd_generic_get_probe_order), DEVMETHOD(bhnd_bus_is_region_valid, bhnd_generic_is_region_valid), DEVMETHOD(bhnd_bus_is_hw_disabled, bhnd_bus_generic_is_hw_disabled), - DEVMETHOD(bhnd_bus_get_nvram_var, bhnd_generic_get_nvram_var), + DEVMETHOD(bhnd_bus_get_nvram_var, bhnd_bus_generic_get_nvram_var), 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_read_stream_1, bhnd_read_stream_1), DEVMETHOD(bhnd_bus_read_stream_2, bhnd_read_stream_2), DEVMETHOD(bhnd_bus_read_stream_4, bhnd_read_stream_4), DEVMETHOD(bhnd_bus_write_stream_1, bhnd_write_stream_1), DEVMETHOD(bhnd_bus_write_stream_2, bhnd_write_stream_2), DEVMETHOD(bhnd_bus_write_stream_4, bhnd_write_stream_4), DEVMETHOD(bhnd_bus_read_multi_1, bhnd_read_multi_1), DEVMETHOD(bhnd_bus_read_multi_2, bhnd_read_multi_2), DEVMETHOD(bhnd_bus_read_multi_4, bhnd_read_multi_4), DEVMETHOD(bhnd_bus_write_multi_1, bhnd_write_multi_1), DEVMETHOD(bhnd_bus_write_multi_2, bhnd_write_multi_2), DEVMETHOD(bhnd_bus_write_multi_4, bhnd_write_multi_4), DEVMETHOD(bhnd_bus_read_multi_stream_1, bhnd_read_multi_stream_1), DEVMETHOD(bhnd_bus_read_multi_stream_2, bhnd_read_multi_stream_2), DEVMETHOD(bhnd_bus_read_multi_stream_4, bhnd_read_multi_stream_4), DEVMETHOD(bhnd_bus_write_multi_stream_1,bhnd_write_multi_stream_1), DEVMETHOD(bhnd_bus_write_multi_stream_2,bhnd_write_multi_stream_2), DEVMETHOD(bhnd_bus_write_multi_stream_4,bhnd_write_multi_stream_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); Index: head/sys/dev/bhnd/bhnd.h =================================================================== --- head/sys/dev/bhnd/bhnd.h (revision 299995) +++ head/sys/dev/bhnd/bhnd.h (revision 299996) @@ -1,892 +1,1002 @@ /*- * 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_debug.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 /** + * A bhnd(4) board descriptor. + */ +struct bhnd_board_info { + uint16_t board_vendor; /**< PCI-SIG vendor ID (even on non-PCI + * devices). + * + * On PCI devices, this will generally + * be the subsystem vendor ID, but the + * value may be overridden in device + * NVRAM. + */ + uint16_t board_type; /**< Board type (See BHND_BOARD_*) + * + * On PCI devices, this will generally + * be the subsystem device ID, but the + * value may be overridden in device + * NVRAM. + */ + uint16_t board_rev; /**< Board revision. */ + uint8_t board_srom_rev; /**< Board SROM format revision */ + + uint32_t board_flags; /**< Board flags (see BHND_BFL_*) */ + uint32_t board_flags2; /**< Board flags 2 (see BHND_BFL2_*) */ + uint32_t board_flags3; /**< Board flags 3 (see BHND_BFL3_*) */ +}; + + +/** * 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 vendor; /**< JEP-106 vendor (BHND_MFGID_*) */ 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. */ }; +/** +* 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. */ +}; + /** * Wildcard hardware revision match descriptor. */ #define BHND_HWREV_ANY { BHND_HWREV_INVALID, BHND_HWREV_INVALID } #define BHND_HWREV_IS_ANY(_m) \ ((_m)->start == BHND_HWREV_INVALID && (_m)->end == BHND_HWREV_INVALID) /** * Hardware revision match descriptor for an inclusive range. * * @param _start The first applicable hardware revision. * @param _end The last applicable hardware revision, or BHND_HWREV_INVALID * to match on any revision. */ #define BHND_HWREV_RANGE(_start, _end) { _start, _end } /** * Hardware revision match descriptor for a single revision. * * @param _hwrev The hardware revision to match on. */ #define BHND_HWREV_EQ(_hwrev) BHND_HWREV_RANGE(_hwrev, _hwrev) /** * Hardware revision match descriptor for any revision equal to or greater * than @p _start. * * @param _start The first hardware revision to match on. */ #define BHND_HWREV_GTE(_start) BHND_HWREV_RANGE(_start, BHND_HWREV_INVALID) /** * Hardware revision match descriptor for any revision equal to or less * than @p _end. * * @param _end The last hardware revision to match on. */ #define BHND_HWREV_LTE(_end) BHND_HWREV_RANGE(0, _end) /** 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 */ }; /** * Core match descriptor matching against the given @p _vendor, @p _device, * and @p _hwrev match descriptors. */ #define BHND_CORE_MATCH(_vendor, _device, _hwrev) \ { _vendor, _device, _hwrev, BHND_DEVCLASS_INVALID, -1 } /** * Wildcard core match descriptor. */ #define BHND_CORE_MATCH_ANY \ { \ .vendor = BHND_MFGID_INVALID, \ .device = BHND_COREID_INVALID, \ .hwrev = BHND_HWREV_ANY, \ .class = BHND_DEVCLASS_INVALID, \ .unit = -1 \ } -/** A chipset match descriptor. */ +/** + * A chipset match descriptor. + * + * @warning Matching on board/nvram attributes relies on NVRAM access, and will + * fail if a valid NVRAM device cannot be found, or is not yet attached. + */ struct bhnd_chip_match { /** Select fields to be matched */ - uint8_t + uint16_t match_id:1, match_rev:1, match_pkg:1, - match_flags_unused:5; + match_bvendor:1, + match_btype:1, + match_brev:1, + match_srom_rev:1, + match_any:1, + match_flags_unused:8; uint16_t chip_id; /**< required chip id */ struct bhnd_hwrev_match chip_rev; /**< matching chip revisions */ uint8_t chip_pkg; /**< required package */ + + uint16_t board_vendor; /**< required board vendor */ + uint16_t board_type; /**< required board type */ + struct bhnd_hwrev_match board_rev; /**< matching board revisions */ + + struct bhnd_hwrev_match board_srom_rev; /**< matching board srom revisions */ }; #define BHND_CHIP_MATCH_ANY \ - { .match_id = 0, .match_rev = 0, .match_pkg = 0 } + { .match_any = 1 } #define BHND_CHIP_MATCH_IS_ANY(_m) \ - ((_m)->match_id == 0 && (_m)->match_rev == 0 && (_m)->match_pkg == 0) + ((_m)->match_any == 1) +#define BHND_CHIP_MATCH_REQ_BOARD_INFO(_m) \ + ((_m)->match_srom_rev || (_m)->match_bvendor || \ + (_m)->match_btype || (_m)->match_brev) + /** Set the required chip ID within a bhnd_chip_match instance */ #define BHND_CHIP_ID(_cid) \ .match_id = 1, .chip_id = BHND_CHIPID_BCM ## _cid -/** Set the required revision range within a bhnd_chip_match instance */ +/** Set the required chip revision range within a bhnd_chip_match instance */ #define BHND_CHIP_REV(_rev) \ .match_rev = 1, .chip_rev = BHND_ ## _rev /** Set the required package ID within a bhnd_chip_match instance */ #define BHND_CHIP_PKG(_pkg) \ .match_pkg = 1, .chip_pkg = BHND_PKGID_BCM ## _pkg +/** Set the required board vendor within a bhnd_chip_match instance */ +#define BHND_CHIP_BVENDOR(_vend) \ + .match_bvendor = 1, .board_vendor = _vend + +/** Set the required board type within a bhnd_chip_match instance */ +#define BHND_CHIP_BT(_btype) \ + .match_btype = 1, .board_type = BHND_BOARD_BCM ## _btype + +/** Set the required SROM revision range within a bhnd_chip_match instance */ +#define BHND_CHIP_SROMREV(_rev) \ + .match_srom_rev = 1, .board_srom_rev = BHND_ ## _rev + +/** Set the required board revision range within a bhnd_chip_match instance */ +#define BHND_CHIP_BREV(_rev) \ + .match_brev = 1, .board_rev = BHND_ ## _rev + +/** Set the required board vendor and type within a bhnd_chip_match instance */ +#define BHND_CHIP_BVT(_vend, _type) \ + BHND_CHIP_BVEND(_vend), BHND_CHIP_BTYPE(_type) + +/** Set the required board vendor, type, and revision within a bhnd_chip_match + * instance */ +#define BHND_CHIP_BVTR(_vend, _type, _rev) \ + BHND_CHIP_BVT(_vend, _type), BHND_CHIP_BREV(_rev) + /** Set the required chip and package ID within a bhnd_chip_match instance */ #define BHND_CHIP_IP(_cid, _pkg) \ BHND_CHIP_ID(_cid), BHND_CHIP_PKG(_pkg) /** Set the required chip ID, package ID, and revision within a bhnd_chip_match * instance */ #define BHND_CHIP_IPR(_cid, _pkg, _rev) \ BHND_CHIP_ID(_cid), BHND_CHIP_PKG(_pkg), BHND_CHIP_REV(_rev) /** Set the required chip ID and revision within a bhnd_chip_match * instance */ #define BHND_CHIP_IR(_cid, _rev) \ BHND_CHIP_ID(_cid), BHND_CHIP_REV(_rev) /** * Chipset quirk table descriptor. */ struct bhnd_chip_quirk { const struct bhnd_chip_match chip; /**< chip match descriptor */ uint32_t quirks; /**< quirk flags */ }; #define BHND_CHIP_QUIRK_END { BHND_CHIP_MATCH_ANY, 0 } #define BHND_CHIP_QUIRK_IS_END(_q) \ (BHND_CHIP_MATCH_IS_ANY(&(_q)->chip) && (_q)->quirks == 0) /** * Device quirk table descriptor. */ struct bhnd_device_quirk { struct bhnd_hwrev_match hwrev; /**< applicable hardware revisions */ uint32_t quirks; /**< quirk flags */ }; #define BHND_DEVICE_QUIRK_END { BHND_HWREV_ANY, 0 } #define BHND_DEVICE_QUIRK_IS_END(_q) \ (BHND_HWREV_IS_ANY(&(_q)->hwrev) && (_q)->quirks == 0) enum { BHND_DF_ANY = 0, BHND_DF_HOSTB = (1<<0) /**< core is serving as the bus' * host bridge */ }; /** Device probe table descriptor */ struct bhnd_device { const struct bhnd_core_match core; /**< core match descriptor */ const char *desc; /**< device description, or NULL. */ const struct bhnd_device_quirk *quirks_table; /**< quirks table for this device, or NULL */ + const struct bhnd_chip_quirk *chip_quirks_table; /**< chipset-specific quirks for this device, or NULL */ uint32_t device_flags; /**< required BHND_DF_* flags */ }; -#define _BHND_DEVICE(_vendor, _device, _desc, _quirks, _flags, ...) \ - { BHND_CORE_MATCH(BHND_MFGID_ ## _vendor, BHND_COREID_ ## _device, \ - BHND_HWREV_ANY), _desc, _quirks, _flags } +#define _BHND_DEVICE(_vendor, _device, _desc, _quirks, _chip_quirks, \ + _flags, ...) \ + { BHND_CORE_MATCH(BHND_MFGID_ ## _vendor, \ + BHND_COREID_ ## _device, BHND_HWREV_ANY), _desc, _quirks, \ + _chip_quirks, _flags } -#define BHND_MIPS_DEVICE(_device, _desc, _quirks, ...) \ - _BHND_DEVICE(MIPS, _device, _desc, _quirks, ## __VA_ARGS__, 0) +#define BHND_MIPS_DEVICE(_device, _desc, _quirks, _chip_quirks, ...) \ + _BHND_DEVICE(MIPS, _device, _desc, _quirks, _chip_quirks, \ + ## __VA_ARGS__, 0) -#define BHND_ARM_DEVICE(_device, _desc, _quirks, ...) \ - _BHND_DEVICE(ARM, _device, _desc, _quirks, ## __VA_ARGS__, 0) +#define BHND_ARM_DEVICE(_device, _desc, _quirks, _chip_quirks, ...) \ + _BHND_DEVICE(ARM, _device, _desc, _quirks, _chip_quirks, \ + ## __VA_ARGS__, 0) -#define BHND_DEVICE(_device, _desc, _quirks, ...) \ - _BHND_DEVICE(BCM, _device, _desc, _quirks, ## __VA_ARGS__, 0) +#define BHND_DEVICE(_device, _desc, _quirks, _chip_quirks, ...) \ + _BHND_DEVICE(BCM, _device, _desc, _quirks, _chip_quirks, \ + ## __VA_ARGS__, 0) -#define BHND_DEVICE_END { BHND_CORE_MATCH_ANY, NULL, NULL, 0 } +#define BHND_DEVICE_END { BHND_CORE_MATCH_ANY, NULL, NULL, NULL, 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_chip_matches( const struct bhnd_chipid *chipid, + const struct bhnd_board_info *binfo, const struct bhnd_chip_match *desc); bool bhnd_hwrev_matches(uint16_t hwrev, const struct bhnd_hwrev_match *desc); uint32_t bhnd_chip_quirks(device_t dev, const struct bhnd_chip_quirk *table); bool bhnd_device_matches(device_t dev, const struct bhnd_core_match *desc); const struct bhnd_device *bhnd_device_lookup(device_t dev, const struct bhnd_device *table, size_t entry_size); uint32_t bhnd_device_quirks(device_t dev, const struct bhnd_device *table, size_t entry_size); 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_custom_core_desc(device_t dev, const char *name); void bhnd_set_default_core_desc(device_t dev); bool bhnd_bus_generic_is_hw_disabled(device_t dev, device_t child); bool bhnd_bus_generic_is_region_valid(device_t dev, device_t child, bhnd_port_type type, u_int port, u_int region); int bhnd_bus_generic_read_nvram_var(device_t dev, device_t child, const char *name, void *buf, size_t *size); const struct bhnd_chipid *bhnd_bus_generic_get_chipid(device_t dev, device_t child); +int bhnd_bus_generic_read_board_info(device_t dev, + device_t child, + struct bhnd_board_info *info); +int bhnd_bus_generic_get_nvram_var(device_t dev, + device_t child, const char *name, + void *buf, size_t *size); struct bhnd_resource *bhnd_bus_generic_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); int bhnd_bus_generic_release_resource (device_t dev, device_t child, int type, int rid, struct bhnd_resource *r); int bhnd_bus_generic_activate_resource (device_t dev, device_t child, int type, int rid, struct bhnd_resource *r); int bhnd_bus_generic_deactivate_resource (device_t dev, device_t child, int type, int rid, struct bhnd_resource *r); /** * Return the active host bridge core for the bhnd bus, if any, or NULL if * not found. * * @param dev A bhnd bus device. */ static inline device_t bhnd_find_hostb_device(device_t dev) { return (BHND_BUS_FIND_HOSTB_DEVICE(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)); } /** * Return the BHND chip identification info for the bhnd bus. * * @param dev A bhnd bus child device. */ static inline const struct bhnd_chipid * bhnd_get_chipid(device_t dev) { return (BHND_BUS_GET_CHIPID(device_get_parent(dev), dev)); }; /** + * Attempt to read the BHND board identification from the bhnd bus. + * + * This relies on NVRAM access, and will fail if a valid NVRAM device cannot + * be found, or is not yet attached. + * + * @param dev The parent of @p child. + * @param child The bhnd device requesting board info. + * @param[out] info On success, will be populated with the bhnd(4) device's + * board information. + * + * @retval 0 success + * @retval ENODEV No valid NVRAM source could be found. + * @retval non-zero If reading @p name otherwise fails, a regular unix + * error code will be returned. + */ +static inline int +bhnd_read_board_info(device_t dev, struct bhnd_board_info *info) +{ + return (BHND_BUS_READ_BOARD_INFO(device_get_parent(dev), dev, info)); +} + +/** * Determine an NVRAM variable's expected size. * * @param dev A bhnd bus child device. * @param name The variable name. * @param[out] len On success, the variable's size, in bytes. * * @retval 0 success * @retval ENOENT The requested variable was not found. + * @retval ENODEV No valid NVRAM source could be found. * @retval non-zero If reading @p name otherwise fails, a regular unix * error code will be returned. */ static inline int bhnd_nvram_getvarlen(device_t dev, const char *name, size_t *len) { return (BHND_BUS_GET_NVRAM_VAR(device_get_parent(dev), dev, name, NULL, len)); } /** * Read an NVRAM variable. * * @param dev A bhnd bus child device. * @param name The NVRAM variable name. * @param buf A buffer large enough to hold @p len bytes. On success, * the requested value will be written to this buffer. * @param len The required variable length. * * @retval 0 success * @retval ENOENT The requested variable was not found. * @retval EINVAL If @p len does not match the actual variable size. + * @retval ENODEV No valid NVRAM source could be found. * @retval non-zero If reading @p name otherwise fails, a regular unix * error code will be returned. */ static inline int bhnd_nvram_getvar(device_t dev, const char *name, void *buf, size_t len) { size_t var_len; int error; if ((error = bhnd_nvram_getvarlen(dev, name, &var_len))) return (error); if (len != var_len) return (EINVAL); return (BHND_BUS_GET_NVRAM_VAR(device_get_parent(dev), dev, name, buf, &len)); } /** * 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 0 and @c ~0, 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, 0, ~0, 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 occurred 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 occurred 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 occurred 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_read_multi_1(r, o, d, c) \ ((r)->direct) ? \ bus_read_multi_1((r)->res, (o), (d), (c)) : \ BHND_BUS_READ_MULTI_1( \ device_get_parent(rman_get_device((r)->res)), \ rman_get_device((r)->res), (r), (o), (d), (c)) #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_write_multi_1(r, o, d, c) \ ((r)->direct) ? \ bus_write_multi_1((r)->res, (o), (d), (c)) : \ BHND_BUS_WRITE_MULTI_1( \ device_get_parent(rman_get_device((r)->res)), \ rman_get_device((r)->res), (r), (o), (d), (c)) #define bhnd_bus_read_stream_1(r, o) \ ((r)->direct) ? \ bus_read_stream_1((r)->res, (o)) : \ BHND_BUS_READ_STREAM_1( \ device_get_parent(rman_get_device((r)->res)), \ rman_get_device((r)->res), (r), (o)) #define bhnd_bus_read_multi_stream_1(r, o, d, c) \ ((r)->direct) ? \ bus_read_multi_stream_1((r)->res, (o), (d), (c)) : \ BHND_BUS_READ_MULTI_STREAM_1( \ device_get_parent(rman_get_device((r)->res)), \ rman_get_device((r)->res), (r), (o), (d), (c)) #define bhnd_bus_write_stream_1(r, o, v) \ ((r)->direct) ? \ bus_write_stream_1((r)->res, (o), (v)) : \ BHND_BUS_WRITE_STREAM_1( \ device_get_parent(rman_get_device((r)->res)), \ rman_get_device((r)->res), (r), (o), (v)) #define bhnd_bus_write_multi_stream_1(r, o, d, c) \ ((r)->direct) ? \ bus_write_multi_stream_1((r)->res, (o), (d), (c)) : \ BHND_BUS_WRITE_MULTI_STREAM_1( \ device_get_parent(rman_get_device((r)->res)), \ rman_get_device((r)->res), (r), (o), (d), (c)) #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_read_multi_2(r, o, d, c) \ ((r)->direct) ? \ bus_read_multi_2((r)->res, (o), (d), (c)) : \ BHND_BUS_READ_MULTI_2( \ device_get_parent(rman_get_device((r)->res)), \ rman_get_device((r)->res), (r), (o), (d), (c)) #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_write_multi_2(r, o, d, c) \ ((r)->direct) ? \ bus_write_multi_2((r)->res, (o), (d), (c)) : \ BHND_BUS_WRITE_MULTI_2( \ device_get_parent(rman_get_device((r)->res)), \ rman_get_device((r)->res), (r), (o), (d), (c)) #define bhnd_bus_read_stream_2(r, o) \ ((r)->direct) ? \ bus_read_stream_2((r)->res, (o)) : \ BHND_BUS_READ_STREAM_2( \ device_get_parent(rman_get_device((r)->res)), \ rman_get_device((r)->res), (r), (o)) #define bhnd_bus_read_multi_stream_2(r, o, d, c) \ ((r)->direct) ? \ bus_read_multi_stream_2((r)->res, (o), (d), (c)) : \ BHND_BUS_READ_MULTI_STREAM_2( \ device_get_parent(rman_get_device((r)->res)), \ rman_get_device((r)->res), (r), (o), (d), (c)) #define bhnd_bus_write_stream_2(r, o, v) \ ((r)->direct) ? \ bus_write_stream_2((r)->res, (o), (v)) : \ BHND_BUS_WRITE_STREAM_2( \ device_get_parent(rman_get_device((r)->res)), \ rman_get_device((r)->res), (r), (o), (v)) #define bhnd_bus_write_multi_stream_2(r, o, d, c) \ ((r)->direct) ? \ bus_write_multi_stream_2((r)->res, (o), (d), (c)) : \ BHND_BUS_WRITE_MULTI_STREAM_2( \ device_get_parent(rman_get_device((r)->res)), \ rman_get_device((r)->res), (r), (o), (d), (c)) #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_read_multi_4(r, o, d, c) \ ((r)->direct) ? \ bus_read_multi_4((r)->res, (o), (d), (c)) : \ BHND_BUS_READ_MULTI_4( \ device_get_parent(rman_get_device((r)->res)), \ rman_get_device((r)->res), (r), (o), (d), (c)) #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)) #define bhnd_bus_write_multi_4(r, o, d, c) \ ((r)->direct) ? \ bus_write_multi_4((r)->res, (o), (d), (c)) : \ BHND_BUS_WRITE_MULTI_4( \ device_get_parent(rman_get_device((r)->res)), \ rman_get_device((r)->res), (r), (o), (d), (c)) #define bhnd_bus_read_stream_4(r, o) \ ((r)->direct) ? \ bus_read_stream_4((r)->res, (o)) : \ BHND_BUS_READ_STREAM_4( \ device_get_parent(rman_get_device((r)->res)), \ rman_get_device((r)->res), (r), (o)) #define bhnd_bus_read_multi_stream_4(r, o, d, c) \ ((r)->direct) ? \ bus_read_multi_stream_4((r)->res, (o), (d), (c)) : \ BHND_BUS_READ_MULTI_STREAM_4( \ device_get_parent(rman_get_device((r)->res)), \ rman_get_device((r)->res), (r), (o), (d), (c)) #define bhnd_bus_write_stream_4(r, o, v) \ ((r)->direct) ? \ bus_write_stream_4((r)->res, (o), (v)) : \ BHND_BUS_WRITE_STREAM_4( \ device_get_parent(rman_get_device((r)->res)), \ rman_get_device((r)->res), (r), (o), (v)) #define bhnd_bus_write_multi_stream_4(r, o, d, c) \ ((r)->direct) ? \ bus_write_multi_stream_4((r)->res, (o), (d), (c)) : \ BHND_BUS_WRITE_MULTI_STREAM_4( \ device_get_parent(rman_get_device((r)->res)), \ rman_get_device((r)->res), (r), (o), (d), (c)) #endif /* _BHND_BHND_H_ */ Index: head/sys/dev/bhnd/bhnd_bus_if.m =================================================================== --- head/sys/dev/bhnd/bhnd_bus_if.m (revision 299995) +++ head/sys/dev/bhnd/bhnd_bus_if.m (revision 299996) @@ -1,651 +1,681 @@ #- # 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_board_info; 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_bus_get_chipid unimplemented"); } - + + static int + bhnd_bus_null_read_board_info(device_t dev, device_t child, + struct bhnd_board_info *info) + { + panic("bhnd_bus_read_boardinfo unimplemented"); + } + static device_t bhnd_bus_null_find_hostb_device(device_t dev) { panic("bhnd_bus_find_hostb_device unimplemented"); } static bool bhnd_bus_null_is_hw_disabled(device_t dev, device_t child) { panic("bhnd_bus_is_hw_disabled unimplemented"); } static int bhnd_bus_null_get_probe_order(device_t dev, device_t child) { panic("bhnd_bus_get_probe_order 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_get_nvram_var(device_t dev, device_t child, const char *name, void *buf, size_t *size) { - return (ENOENT); + return (ENODEV); } } /** * Return the active host bridge core for the bhnd bus, if any. * * @param dev The bhnd bus device. * * @retval device_t if a hostb device exists * @retval NULL if no hostb device is found. */ METHOD device_t find_hostb_device { device_t dev; } DEFAULT bhnd_bus_null_find_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_bus_null_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_bus_null_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; /** + * Attempt to read the BHND board identification from the parent bus. + * + * This relies on NVRAM access, and will fail if a valid NVRAM device cannot + * be found, or is not yet attached. + * + * @param dev The parent of @p child. + * @param child The bhnd device requesting board info. + * @param[out] info On success, will be populated with the bhnd(4) device's + * board information. + * + * @retval 0 success + * @retval ENODEV No valid NVRAM source could be found. + * @retval non-zero If reading @p name otherwise fails, a regular unix + * error code will be returned. + */ +METHOD int read_board_info { + device_t dev; + device_t child; + struct bhnd_board_info *info; +} DEFAULT bhnd_bus_null_read_board_info; + +/** * 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_bus_generic_alloc_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_bus_generic_release_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_bus_generic_activate_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_bus_generic_deactivate_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 bool is_region_valid { device_t dev; device_t child; bhnd_port_type type; u_int port_num; u_int region_num; }; /** * 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 ENODEV No valid NVRAM source could be found. * @retval non-zero If reading @p name otherwise fails, a regular unix * error code will be returned. */ METHOD int get_nvram_var { device_t dev; device_t child; const char *name; void *buf; size_t *size; } DEFAULT bhnd_bus_null_get_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_read_stream_1() compatible with bhnd_resource */ METHOD uint8_t read_stream_1 { device_t dev; device_t child; struct bhnd_resource *r; bus_size_t offset; } /** An implementation of bus_read_stream_2() compatible with bhnd_resource */ METHOD uint16_t read_stream_2 { device_t dev; device_t child; struct bhnd_resource *r; bus_size_t offset; } /** An implementation of bus_read_stream_4() compatible with bhnd_resource */ METHOD uint32_t read_stream_4 { device_t dev; device_t child; struct bhnd_resource *r; bus_size_t offset; } /** An implementation of bus_write_stream_1() compatible with bhnd_resource */ METHOD void write_stream_1 { device_t dev; device_t child; struct bhnd_resource *r; bus_size_t offset; uint8_t value; } /** An implementation of bus_write_stream_2() compatible with bhnd_resource */ METHOD void write_stream_2 { device_t dev; device_t child; struct bhnd_resource *r; bus_size_t offset; uint16_t value; } /** An implementation of bus_write_stream_4() compatible with bhnd_resource */ METHOD void write_stream_4 { device_t dev; device_t child; struct bhnd_resource *r; bus_size_t offset; uint32_t value; } /** An implementation of bus_read_multi_1() compatible with bhnd_resource */ METHOD void read_multi_1 { device_t dev; device_t child; struct bhnd_resource *r; bus_size_t offset; uint8_t *datap; bus_size_t count; } /** An implementation of bus_read_multi_2() compatible with bhnd_resource */ METHOD void read_multi_2 { device_t dev; device_t child; struct bhnd_resource *r; bus_size_t offset; uint16_t *datap; bus_size_t count; } /** An implementation of bus_read_multi_4() compatible with bhnd_resource */ METHOD void read_multi_4 { device_t dev; device_t child; struct bhnd_resource *r; bus_size_t offset; uint32_t *datap; bus_size_t count; } /** An implementation of bus_write_multi_1() compatible with bhnd_resource */ METHOD void write_multi_1 { device_t dev; device_t child; struct bhnd_resource *r; bus_size_t offset; uint8_t *datap; bus_size_t count; } /** An implementation of bus_write_multi_2() compatible with bhnd_resource */ METHOD void write_multi_2 { device_t dev; device_t child; struct bhnd_resource *r; bus_size_t offset; uint16_t *datap; bus_size_t count; } /** An implementation of bus_write_multi_4() compatible with bhnd_resource */ METHOD void write_multi_4 { device_t dev; device_t child; struct bhnd_resource *r; bus_size_t offset; uint32_t *datap; bus_size_t count; } /** An implementation of bus_read_multi_stream_1() compatible * bhnd_resource */ METHOD void read_multi_stream_1 { device_t dev; device_t child; struct bhnd_resource *r; bus_size_t offset; uint8_t *datap; bus_size_t count; } /** An implementation of bus_read_multi_stream_2() compatible * bhnd_resource */ METHOD void read_multi_stream_2 { device_t dev; device_t child; struct bhnd_resource *r; bus_size_t offset; uint16_t *datap; bus_size_t count; } /** An implementation of bus_read_multi_stream_4() compatible * bhnd_resource */ METHOD void read_multi_stream_4 { device_t dev; device_t child; struct bhnd_resource *r; bus_size_t offset; uint32_t *datap; bus_size_t count; } /** An implementation of bus_write_multi_stream_1() compatible * bhnd_resource */ METHOD void write_multi_stream_1 { device_t dev; device_t child; struct bhnd_resource *r; bus_size_t offset; uint8_t *datap; bus_size_t count; } /** An implementation of bus_write_multi_stream_2() compatible with * bhnd_resource */ METHOD void write_multi_stream_2 { device_t dev; device_t child; struct bhnd_resource *r; bus_size_t offset; uint16_t *datap; bus_size_t count; } /** An implementation of bus_write_multi_stream_4() compatible with * bhnd_resource */ METHOD void write_multi_stream_4 { device_t dev; device_t child; struct bhnd_resource *r; bus_size_t offset; uint32_t *datap; bus_size_t count; } /** 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; } Index: head/sys/dev/bhnd/bhnd_ids.h =================================================================== --- head/sys/dev/bhnd/bhnd_ids.h (revision 299995) +++ head/sys/dev/bhnd/bhnd_ids.h (revision 299996) @@ -1,755 +1,1129 @@ /*- - * Copyright (C) 1999-2013, Broadcom Corporation + * Copyright (c) 2015-2016 Landon Fuller + * Copyright (c) 1999-2015, 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. + * to Android's bcmdhd driver module, later revisions of bcmdevs.h distributed + * with the dd-wrt project, and 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. * - * $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_BCM43462 0xA9C6 /* 43462 chipcommon chipid */ #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_BCM43602 0xaa52 /* 43602 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 Development 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/Embedded/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, Separate paparam for 20/40/80 */ #define BHND_BFL3_TSSI_DIV_WAR_SHIFT 0x7 /* acphy, Separate 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_BOARD_BTC3W_IN 0x850 /* bit 4 is RF_ACTIVE, bit 6 is STATUS, bit 11 is PRI */ +#define BHND_GPIO_BOARD_BTC3W_OUT 0x020 /* bit 5 is TX_CONF */ +#define BHND_GPIO_BOARD_BTCMOD_IN 0x010 /* bit 4 is the alternate BT Coexistence Input */ +#define BHND_GPIO_BOARD_BTCMOD_OUT 0x020 /* bit 5 is the alternate BT Coexistence Out */ +#define BHND_GPIO_BOARD_BTC_IN 0x080 /* bit 7 is BT Coexistence Input */ +#define BHND_GPIO_BOARD_BTC_OUT 0x100 /* bit 8 is BT Coexistence Out */ +#define BHND_GPIO_BOARD_PACTRL 0x200 /* bit 9 controls the PA on new 4306 boards */ +#define BHND_GPIO_BOARD_12 0x1000 /* gpio 12 */ +#define BHND_GPIO_BOARD_13 0x2000 /* gpio 13 */ +#define BHND_GPIO_BOARD_BTC4_IN 0x0800 /* gpio 11, coex4, in */ +#define BHND_GPIO_BOARD_BTC4_BT 0x2000 /* gpio 12, coex4, bt active */ +#define BHND_GPIO_BOARD_BTC4_STAT 0x4000 /* gpio 14, coex4, status */ +#define BHND_GPIO_BOARD_BTC4_WLAN 0x8000 /* gpio 15, coex4, wlan active */ +#define BHND_GPIO_BOARD_1_WLAN_PWR 0x02 /* throttle WLAN power on X21 board */ +#define BHND_GPIO_BOARD_3_WLAN_PWR 0x08 /* throttle WLAN power on X28 board */ +#define BHND_GPIO_BOARD_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 */ +/* Board Types */ +#define BHND_BOARD_BU4710 0x0400 +#define BHND_BOARD_VSIM4710 0x0401 +#define BHND_BOARD_QT4710 0x0402 + +#define BHND_BOARD_BU4309 0x040a +#define BHND_BOARD_BCM94309CB 0x040b +#define BHND_BOARD_BCM94309MP 0x040c +#define BHND_BOARD_BCM4309AP 0x040d + +#define BHND_BOARD_BCM94302MP 0x040e + +#define BHND_BOARD_BU4306 0x0416 +#define BHND_BOARD_BCM94306CB 0x0417 +#define BHND_BOARD_BCM94306MP 0x0418 + +#define BHND_BOARD_BCM94710D 0x041a +#define BHND_BOARD_BCM94710R1 0x041b +#define BHND_BOARD_BCM94710R4 0x041c +#define BHND_BOARD_BCM94710AP 0x041d + +#define BHND_BOARD_BU2050 0x041f + + +#define BHND_BOARD_BCM94309G 0x0421 + +#define BHND_BOARD_BU4704 0x0423 +#define BHND_BOARD_BU4702 0x0424 + +#define BHND_BOARD_BCM94306PC 0x0425 /* pcmcia 3.3v 4306 card */ + + +#define BHND_BOARD_BCM94702MN 0x0428 + +/* BCM4702 1U CompactPCI Board */ +#define BHND_BOARD_BCM94702CPCI 0x0429 + +/* BCM4702 with BCM95380 VLAN Router */ +#define BHND_BOARD_BCM95380RR 0x042a + +/* cb4306 with SiGe PA */ +#define BHND_BOARD_BCM94306CBSG 0x042b + +/* cb4306 with SiGe PA */ +#define BHND_BOARD_PCSG94306 0x042d + +/* bu4704 with sdram */ +#define BHND_BOARD_BU4704SD 0x042e + +/* Dual 11a/11g Router */ +#define BHND_BOARD_BCM94704AGR 0x042f + +/* 11a-only minipci */ +#define BHND_BOARD_BCM94308MP 0x0430 + + + +#define BHND_BOARD_BU4712 0x0444 +#define BHND_BOARD_BU4712SD 0x045d +#define BHND_BOARD_BU4712L 0x045f + +/* BCM4712 boards */ +#define BHND_BOARD_BCM94712AP 0x0445 +#define BHND_BOARD_BCM94712P 0x0446 + +/* BCM4318 boards */ +#define BHND_BOARD_BU4318 0x0447 +#define BHND_BOARD_CB4318 0x0448 +#define BHND_BOARD_MPG4318 0x0449 +#define BHND_BOARD_MP4318 0x044a +#define BHND_BOARD_SD4318 0x044b + +/* BCM4313 boards */ +#define BHND_BOARD_BCM94313BU 0x050f +#define BHND_BOARD_BCM94313HM 0x0510 +#define BHND_BOARD_BCM94313EPA 0x0511 +#define BHND_BOARD_BCM94313HMG 0x051C + +/* BCM63XX boards */ +#define BHND_BOARD_BCM96338 0x6338 +#define BHND_BOARD_BCM96348 0x6348 +#define BHND_BOARD_BCM96358 0x6358 +#define BHND_BOARD_BCM96368 0x6368 + +/* Another mp4306 with SiGe */ +#define BHND_BOARD_BCM94306P 0x044c + +/* mp4303 */ +#define BHND_BOARD_BCM94303MP 0x044e + +/* mpsgh4306 */ +#define BHND_BOARD_BCM94306MPSGH 0x044f + +/* BRCM 4306 w/ Front End Modules */ +#define BHND_BOARD_BCM94306MPM 0x0450 +#define BHND_BOARD_BCM94306MPL 0x0453 + +/* 4712agr */ +#define BHND_BOARD_BCM94712AGR 0x0451 + +/* pcmcia 4303 */ +#define BHND_BOARD_PC4303 0x0454 + +/* 5350K */ +#define BHND_BOARD_BCM95350K 0x0455 + +/* 5350R */ +#define BHND_BOARD_BCM95350R 0x0456 + +/* 4306mplna */ +#define BHND_BOARD_BCM94306MPLNA 0x0457 + +/* 4320 boards */ +#define BHND_BOARD_BU4320 0x0458 +#define BHND_BOARD_BU4320S 0x0459 +#define BHND_BOARD_BCM94320PH 0x045a + +/* 4306mph */ +#define BHND_BOARD_BCM94306MPH 0x045b + +/* 4306pciv */ +#define BHND_BOARD_BCM94306PCIV 0x045c + +#define BHND_BOARD_BU4712SD 0x045d + +#define BHND_BOARD_BCM94320PFLSH 0x045e + +#define BHND_BOARD_BU4712L 0x045f +#define BHND_BOARD_BCM94712LGR 0x0460 +#define BHND_BOARD_BCM94320R 0x0461 + +#define BHND_BOARD_BU5352 0x0462 + +#define BHND_BOARD_BCM94318MPGH 0x0463 + +#define BHND_BOARD_BU4311 0x0464 +#define BHND_BOARD_BCM94311MC 0x0465 +#define BHND_BOARD_BCM94311MCAG 0x0466 + +#define BHND_BOARD_BCM95352GR 0x0467 + +/* bcm95351agr */ +#define BHND_BOARD_BCM95351AGR 0x0470 + +/* bcm94704mpcb */ +#define BHND_BOARD_BCM94704MPCB 0x0472 + +/* 4785 boards */ +#define BHND_BOARD_BU4785 0x0478 + +/* 4321 boards */ +#define BHND_BOARD_BU4321 0x046b +#define BHND_BOARD_BU4321E 0x047c +#define BHND_BOARD_MP4321 0x046c +#define BHND_BOARD_CB2_4321 0x046d +#define BHND_BOARD_CB2_4321_AG 0x0066 +#define BHND_BOARD_MC4321 0x046e + +/* 4328 boards */ +#define BHND_BOARD_BU4328 0x0481 +#define BHND_BOARD_BCM4328SDG 0x0482 +#define BHND_BOARD_BCM4328SDAG 0x0483 +#define BHND_BOARD_BCM4328UG 0x0484 +#define BHND_BOARD_BCM4328UAG 0x0485 +#define BHND_BOARD_BCM4328PC 0x0486 +#define BHND_BOARD_BCM4328CF 0x0487 + +/* 4325 boards */ +#define BHND_BOARD_BCM94325DEVBU 0x0490 +#define BHND_BOARD_BCM94325BGABU 0x0491 + +#define BHND_BOARD_BCM94325SDGWB 0x0492 + +#define BHND_BOARD_BCM94325SDGMDL 0x04aa +#define BHND_BOARD_BCM94325SDGMDL2 0x04c6 +#define BHND_BOARD_BCM94325SDGMDL3 0x04c9 + +#define BHND_BOARD_BCM94325SDABGWBA 0x04e1 + +/* 4322 boards */ +#define BHND_BOARD_BCM94322MC 0x04a4 +#define BHND_BOARD_BCM94322USB 0x04a8 /* dualband */ +#define BHND_BOARD_BCM94322HM 0x04b0 +#define BHND_BOARD_BCM94322USB2D 0x04bf /* single band discrete front end */ + +/* 4312 boards */ +#define BHND_BOARD_BCM4312MCGSG 0x04b5 + +/* 4315 boards */ +#define BHND_BOARD_BCM94315DEVBU 0x04c2 +#define BHND_BOARD_BCM94315USBGP 0x04c7 +#define BHND_BOARD_BCM94315BGABU 0x04ca +#define BHND_BOARD_BCM94315USBGP41 0x04cb + +/* 4319 boards */ +#define BHND_BOARD_BCM94319DEVBU 0X04e5 +#define BHND_BOARD_BCM94319USB 0X04e6 +#define BHND_BOARD_BCM94319SD 0X04e7 + +/* 4716 boards */ +#define BHND_BOARD_BCM94716NR2 0x04cd + +/* 4319 boards */ +#define BHND_BOARD_BCM94319DEVBU 0X04e5 +#define BHND_BOARD_BCM94319USBNP4L 0X04e6 +#define BHND_BOARD_BCM94319WLUSBN4L 0X04e7 +#define BHND_BOARD_BCM94319SDG 0X04ea +#define BHND_BOARD_BCM94319LCUSBSDN4L 0X04eb +#define BHND_BOARD_BCM94319USBB 0x04ee +#define BHND_BOARD_BCM94319LCSDN4L 0X0507 +#define BHND_BOARD_BCM94319LSUSBN4L 0X0508 +#define BHND_BOARD_BCM94319SDNA4L 0X0517 +#define BHND_BOARD_BCM94319SDELNA4L 0X0518 +#define BHND_BOARD_BCM94319SDELNA6L 0X0539 +#define BHND_BOARD_BCM94319ARCADYAN 0X0546 +#define BHND_BOARD_BCM94319WINDSOR 0x0561 +#define BHND_BOARD_BCM94319MLAP 0x0562 +#define BHND_BOARD_BCM94319SDNA 0x058b +#define BHND_BOARD_BCM94319BHEMU3 0x0563 +#define BHND_BOARD_BCM94319SDHMB 0x058c +#define BHND_BOARD_BCM94319SDBREF 0x05a1 +#define BHND_BOARD_BCM94319USBSDB 0x05a2 + +/* 4329 boards */ +#define BHND_BOARD_BCM94329AGB 0X04b9 +#define BHND_BOARD_BCM94329TDKMDL1 0X04ba +#define BHND_BOARD_BCM94329TDKMDL11 0X04fc +#define BHND_BOARD_BCM94329OLYMPICN18 0X04fd +#define BHND_BOARD_BCM94329OLYMPICN90 0X04fe +#define BHND_BOARD_BCM94329OLYMPICN90U 0X050c +#define BHND_BOARD_BCM94329OLYMPICN90M 0X050b +#define BHND_BOARD_BCM94329AGBF 0X04ff +#define BHND_BOARD_BCM94329OLYMPICX17 0X0504 +#define BHND_BOARD_BCM94329OLYMPICX17M 0X050a +#define BHND_BOARD_BCM94329OLYMPICX17U 0X0509 +#define BHND_BOARD_BCM94329OLYMPICUNO 0X0564 +#define BHND_BOARD_BCM94329MOTOROLA 0X0565 +#define BHND_BOARD_BCM94329OLYMPICLOCO 0X0568 + +/* 4336 SDIO board types */ +#define BHND_BOARD_BCM94336SD_WLBGABU 0x0511 +#define BHND_BOARD_BCM94336SD_WLBGAREF 0x0519 +#define BHND_BOARD_BCM94336SDGP 0x0538 +#define BHND_BOARD_BCM94336SDG 0x0519 +#define BHND_BOARD_BCM94336SDGN 0x0538 +#define BHND_BOARD_BCM94336SDGFC 0x056B + +/* 4330 SDIO board types */ +#define BHND_BOARD_BCM94330SDG 0x0528 +#define BHND_BOARD_BCM94330SD_FCBGABU 0x052e +#define BHND_BOARD_BCM94330SD_WLBGABU 0x052f +#define BHND_BOARD_BCM94330SD_FCBGA 0x0530 +#define BHND_BOARD_BCM94330FCSDAGB 0x0532 +#define BHND_BOARD_BCM94330OLYMPICAMG 0x0549 +#define BHND_BOARD_BCM94330OLYMPICAMGEPA 0x054F +#define BHND_BOARD_BCM94330OLYMPICUNO3 0x0551 +#define BHND_BOARD_BCM94330WLSDAGB 0x0547 +#define BHND_BOARD_BCM94330CSPSDAGBB 0x054A + +/* 43224 boards */ +#define BHND_BOARD_BCM943224X21 0x056e +#define BHND_BOARD_BCM943224X21_FCC 0x00d1 +#define BHND_BOARD_BCM943224X21B 0x00e9 +#define BHND_BOARD_BCM943224M93 0x008b +#define BHND_BOARD_BCM943224M93A 0x0090 +#define BHND_BOARD_BCM943224X16 0x0093 +#define BHND_BOARD_BCM94322X9 0x008d +#define BHND_BOARD_BCM94322M35e 0x008e + +/* 43228 Boards */ +#define BHND_BOARD_BCM943228BU8 0x0540 +#define BHND_BOARD_BCM943228BU9 0x0541 +#define BHND_BOARD_BCM943228BU 0x0542 +#define BHND_BOARD_BCM943227HM4L 0x0543 +#define BHND_BOARD_BCM943227HMB 0x0544 +#define BHND_BOARD_BCM943228HM4L 0x0545 +#define BHND_BOARD_BCM943228SD 0x0573 + +/* 43239 Boards */ +#define BHND_BOARD_BCM943239MOD 0x05ac +#define BHND_BOARD_BCM943239REF 0x05aa + +/* 4331 boards */ +#define BHND_BOARD_BCM94331X19 0x00D6 /* X19B */ +#define BHND_BOARD_BCM94331X28 0x00E4 /* X28 */ +#define BHND_BOARD_BCM94331X28B 0x010E /* X28B */ +#define BHND_BOARD_BCM94331PCIEBT3Ax BCM94331X28 +#define BHND_BOARD_BCM94331X12_2G 0x00EC /* X12 2G */ +#define BHND_BOARD_BCM94331X12_5G 0x00ED /* X12 5G */ +#define BHND_BOARD_BCM94331X29B 0x00EF /* X29B */ +#define BHND_BOARD_BCM94331X29D 0x010F /* X29D */ +#define BHND_BOARD_BCM94331CSAX BCM94331X29B +#define BHND_BOARD_BCM94331X19C 0x00F5 /* X19C */ +#define BHND_BOARD_BCM94331X33 0x00F4 /* X33 */ +#define BHND_BOARD_BCM94331BU 0x0523 +#define BHND_BOARD_BCM94331S9BU 0x0524 +#define BHND_BOARD_BCM94331MC 0x0525 +#define BHND_BOARD_BCM94331MCI 0x0526 +#define BHND_BOARD_BCM94331PCIEBT4 0x0527 +#define BHND_BOARD_BCM94331HM 0x0574 +#define BHND_BOARD_BCM94331PCIEDUAL 0x059B +#define BHND_BOARD_BCM94331MCH5 0x05A9 +#define BHND_BOARD_BCM94331CS 0x05C6 +#define BHND_BOARD_BCM94331CD 0x05DA + +/* 4314 Boards */ +#define BHND_BOARD_BCM94314BU 0x05b1 + +/* 53572 Boards */ +#define BHND_BOARD_BCM953572BU 0x058D +#define BHND_BOARD_BCM953572NR2 0x058E +#define BHND_BOARD_BCM947188NR2 0x058F +#define BHND_BOARD_BCM953572SDRNR2 0x0590 + +/* 43236 boards */ +#define BHND_BOARD_BCM943236OLYMPICSULLEY 0x594 +#define BHND_BOARD_BCM943236PREPROTOBLU2O3 0x5b9 +#define BHND_BOARD_BCM943236USBELNA 0x5f8 + +/* 4314 Boards */ +#define BHND_BOARD_BCM94314BUSDIO 0x05c8 +#define BHND_BOARD_BCM94314BGABU 0x05c9 +#define BHND_BOARD_BCM94314HMEPA 0x05ca +#define BHND_BOARD_BCM94314HMEPABK 0x05cb +#define BHND_BOARD_BCM94314SUHMEPA 0x05cc +#define BHND_BOARD_BCM94314SUHM 0x05cd +#define BHND_BOARD_BCM94314HM 0x05d1 + +/* 4334 Boards */ +#define BHND_BOARD_BCM94334FCAGBI 0x05df +#define BHND_BOARD_BCM94334WLAGBI 0x05dd + +/* 4335 Boards */ +#define BHND_BOARD_BCM94335X52 0x0114 + +/* 4345 Boards */ +#define BHND_BOARD_BCM94345 0x0687 + +/* 4360 Boards */ +#define BHND_BOARD_BCM94360X52C 0X0117 +#define BHND_BOARD_BCM94360X52D 0X0137 +#define BHND_BOARD_BCM94360X29C 0X0112 +#define BHND_BOARD_BCM94360X29CP2 0X0134 +#define BHND_BOARD_BCM94360X51 0x0111 +#define BHND_BOARD_BCM94360X51P2 0x0129 +#define BHND_BOARD_BCM94360X51A 0x0135 +#define BHND_BOARD_BCM94360X51B 0x0136 +#define BHND_BOARD_BCM94360CS 0x061B +#define BHND_BOARD_BCM94360J28_D11AC2G 0x0c00 +#define BHND_BOARD_BCM94360J28_D11AC5G 0x0c01 +#define BHND_BOARD_BCM94360USBH5_D11AC5G 0x06aa + +/* 4350 Boards */ +#define BHND_BOARD_BCM94350X52B 0X0116 +#define BHND_BOARD_BCM94350X14 0X0131 + +/* 43217 Boards */ +#define BHND_BOARD_BCM943217BU 0x05d5 +#define BHND_BOARD_BCM943217HM2L 0x05d6 +#define BHND_BOARD_BCM943217HMITR2L 0x05d7 + +/* 43142 Boards */ +#define BHND_BOARD_BCM943142HM 0x05e0 + /* 43341 Boards */ -#define BCM943341WLABGS_SSID 0x062d +#define BHND_BOARD_BCM943341WLABGS 0x062d /* 43342 Boards */ -#define BCM943342FCAGBI_SSID 0x0641 +#define BHND_BOARD_BCM943342FCAGBI 0x0641 + +/* 43602 Boards, unclear yet what boards will be created. */ +#define BHND_BOARD_BCM943602RSVD1 0x06a5 +#define BHND_BOARD_BCM943602RSVD2 0x06a6 +#define BHND_BOARD_BCM943602X87 0X0133 +#define BHND_BOARD_BCM943602X238 0X0132 + +/* 4354 board types */ +#define BHND_BOARD_BCM94354WLSAGBI 0x06db +#define BHND_BOARD_BCM94354Z 0x0707 /* # 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_ */ Index: head/sys/dev/bhnd/bhnd_subr.c =================================================================== --- head/sys/dev/bhnd/bhnd_subr.c (revision 299995) +++ head/sys/dev/bhnd/bhnd_subr.c (revision 299996) @@ -1,930 +1,1122 @@ /*- * 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 "nvram/bhnd_nvram.h" + +#include "bhnd_chipc_if.h" + +#include "bhnd_nvram_if.h" +#include "bhnd_nvram_map.h" + #include "bhndreg.h" #include "bhndvar.h" +static device_t find_nvram_child(device_t dev); + /* 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"); default: return "unknown"; } } 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->class != BHND_DEVCLASS_INVALID && desc->class != bhnd_core_class(core)) return (false); return true; } /** * Return true if the @p chip matches @p desc. * * @param chip A bhnd chip identifier. + * @param board The bhnd board info, or NULL if unavailable. * @param desc A match descriptor to compare against @p chip. * * @retval true if @p chip matches @p match * @retval false if @p chip does not match @p match. */ bool bhnd_chip_matches(const struct bhnd_chipid *chip, + const struct bhnd_board_info *board, const struct bhnd_chip_match *desc) { + /* Explicit wildcard match */ + if (desc->match_any) + return (true); + + /* If board_info is missing, but required, we cannot match. */ + if (BHND_CHIP_MATCH_REQ_BOARD_INFO(desc) && board == NULL) + return (false); + + + /* Chip matching */ if (desc->match_id && chip->chip_id != desc->chip_id) return (false); if (desc->match_pkg && chip->chip_pkg != desc->chip_pkg) return (false); if (desc->match_rev && !bhnd_hwrev_matches(chip->chip_rev, &desc->chip_rev)) return (false); + + /* Board info matching */ + if (desc->match_srom_rev && + !bhnd_hwrev_matches(board->board_srom_rev, &desc->board_srom_rev)) + return (false); + + if (desc->match_bvendor && board->board_vendor != desc->board_vendor) + return (false); + + if (desc->match_btype && board->board_type != desc->board_type) + return (false); + + if (desc->match_brev && + !bhnd_hwrev_matches(board->board_rev, &desc->board_rev)) + 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); } /** * Search @p table for an entry matching @p dev. * * @param dev A bhnd device to match against @p table. * @param table The device table to search. * @param entry_size The @p table entry size, in bytes. * * @retval bhnd_device the first matching device, if any. * @retval NULL if no matching device is found in @p table. */ const struct bhnd_device * bhnd_device_lookup(device_t dev, const struct bhnd_device *table, size_t entry_size) { const struct bhnd_device *entry; device_t hostb, parent; parent = device_get_parent(dev); hostb = bhnd_find_hostb_device(parent); for (entry = table; entry->desc != NULL; entry = (const struct bhnd_device *) ((const char *) entry + entry_size)) { /* match core info */ if (!bhnd_device_matches(dev, &entry->core)) continue; /* match device flags */ if (entry->device_flags & BHND_DF_HOSTB) { if (dev != hostb) continue; } /* device found */ return (entry); } /* not found */ return (NULL); } /** * Scan @p table for all quirk flags applicable to @p dev's chip identifier * (as returned by bhnd_get_chipid). * * @param dev A bhnd device. * @param table The chip quirk table to search. * * @return returns all matching quirk flags. */ uint32_t bhnd_chip_quirks(device_t dev, const struct bhnd_chip_quirk *table) { + struct bhnd_board_info bi, *board; const struct bhnd_chipid *cid; const struct bhnd_chip_quirk *qent; uint32_t quirks; - + int error; + bool need_boardinfo; + cid = bhnd_get_chipid(dev); quirks = 0; + need_boardinfo = 0; + board = NULL; + /* Determine whether quirk matching requires board_info; we want to + * avoid fetching board_info for early devices (e.g. ChipCommon) + * that are brought up prior to NVRAM being readable. */ for (qent = table; !BHND_CHIP_QUIRK_IS_END(qent); qent++) { - if (bhnd_chip_matches(cid, &qent->chip)) + if (!BHND_CHIP_MATCH_REQ_BOARD_INFO(&qent->chip)) + continue; + + need_boardinfo = true; + break; + } + + /* If required, fetch board info */ + if (need_boardinfo) { + error = bhnd_read_board_info(dev, &bi); + if (!error) { + board = &bi; + } else { + device_printf(dev, "failed to read required board info " + "during quirk matching: %d\n", error); + } + } + + /* Apply all matching quirk flags */ + for (qent = table; !BHND_CHIP_QUIRK_IS_END(qent); qent++) { + if (bhnd_chip_matches(cid, board, &qent->chip)) quirks |= qent->quirks; } return (quirks); } /** * Scan @p table for all quirk flags applicable to @p dev. * * @param dev A bhnd device to match against @p table. * @param table The device table to search. * @param entry_size The @p table entry size, in bytes. * * @return returns all matching quirk flags. */ uint32_t bhnd_device_quirks(device_t dev, const struct bhnd_device *table, size_t entry_size) { const struct bhnd_device *dent; const struct bhnd_device_quirk *qtable, *qent; uint32_t quirks; uint16_t hwrev; hwrev = bhnd_get_hwrev(dev); quirks = 0; /* Find the quirk table */ if ((dent = bhnd_device_lookup(dev, table, entry_size)) == NULL) { /* This is almost certainly a (caller) implementation bug */ device_printf(dev, "quirk lookup did not match any device\n"); return (0); } - /* Quirks aren't a mandatory field */ - if ((qtable = dent->quirks_table) == NULL) - return (0); - - /* Collect matching quirk entries */ - for (qent = qtable; !BHND_DEVICE_QUIRK_IS_END(qent); qent++) { - if (bhnd_hwrev_matches(hwrev, &qent->hwrev)) - quirks |= qent->quirks; + /* Collect matching device quirk entries */ + if ((qtable = dent->quirks_table) != NULL) { + for (qent = qtable; !BHND_DEVICE_QUIRK_IS_END(qent); qent++) { + if (bhnd_hwrev_matches(hwrev, &qent->hwrev)) + quirks |= qent->quirks; + } } + /* Collect matching chip quirk entries */ + if (dent->chip_quirks_table != NULL) + quirks |= bhnd_chip_quirks(dev, dent->chip_quirks_table); + return (quirks); } /** * 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 and a custom core name, * populate @p dev's device description. * * @param dev A bhnd-bus attached device. * @param dev_name The core's name (e.g. "SDIO Device Core") */ void bhnd_set_custom_core_desc(device_t dev, const char *dev_name) { const char *vendor_name; char *desc; vendor_name = bhnd_get_vendor_name(dev); asprintf(&desc, M_BHND, "%s %s, rev %hhu", vendor_name, dev_name, bhnd_get_hwrev(dev)); if (desc != NULL) { device_set_desc_copy(dev, desc); free(desc, M_BHND); } else { device_set_desc(dev, dev_name); } } /** * Using the bhnd(4) bus-level core information, populate @p dev's device * description. * * @param dev A bhnd-bus attached device. */ void bhnd_set_default_core_desc(device_t dev) { bhnd_set_custom_core_desc(dev, bhnd_get_device_name(dev)); } /** * 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_bus_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. If no parent exists, the implementation * will panic. */ const struct bhnd_chipid * bhnd_bus_generic_get_chipid(device_t dev, device_t child) { if (device_get_parent(dev) != NULL) return (BHND_BUS_GET_CHIPID(device_get_parent(dev), child)); panic("missing BHND_BUS_GET_CHIPID()"); +} + +/* nvram board_info population macros for bhnd_bus_generic_read_board_info() */ +#define BHND_GV(_dest, _name) \ + bhnd_nvram_getvar(child, BHND_NVAR_ ## _name, &_dest, sizeof(_dest)) + +#define REQ_BHND_GV(_dest, _name) do { \ + if ((error = BHND_GV(_dest, _name))) { \ + device_printf(dev, \ + "error reading " __STRING(_name) ": %d\n", error); \ + return (error); \ + } \ +} while(0) + +#define OPT_BHND_GV(_dest, _name, _default) do { \ + if ((error = BHND_GV(_dest, _name))) { \ + if (error != ENOENT) { \ + device_printf(dev, \ + "error reading " \ + __STRING(_name) ": %d\n", error); \ + return (error); \ + } \ + _dest = _default; \ + } \ +} while(0) + +/** + * Helper function for implementing BHND_BUS_READ_BOARDINFO(). + * + * This implementation populates @p info with information from NVRAM, + * defaulting board_vendor and board_type fields to 0 if the + * requested variables cannot be found. + * + * This behavior is correct for most SoCs, but must be overridden on + * bridged (PCI, PCMCIA, etc) devices to produce a complete bhnd_board_info + * result. + */ +int +bhnd_bus_generic_read_board_info(device_t dev, device_t child, + struct bhnd_board_info *info) +{ + int error; + + OPT_BHND_GV(info->board_vendor, BOARDVENDOR, 0); + OPT_BHND_GV(info->board_type, BOARDTYPE, 0); /* srom >= 2 */ + REQ_BHND_GV(info->board_rev, BOARDREV); + REQ_BHND_GV(info->board_srom_rev,SROMREV); + REQ_BHND_GV(info->board_flags, BOARDFLAGS); + OPT_BHND_GV(info->board_flags2, BOARDFLAGS2, 0); /* srom >= 4 */ + OPT_BHND_GV(info->board_flags3, BOARDFLAGS3, 0); /* srom >= 11 */ + + return (0); +} + +#undef BHND_GV +#undef BHND_GV_REQ +#undef BHND_GV_OPT + + +/** + * 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, "bhnd_nvram", 0); + if (nvram != NULL) + return (nvram); + + /* Remaining checks are only applicable when searching a bhnd(4) + * bus. */ + if (device_get_devclass(dev) != bhnd_devclass) + return (NULL); + + /* Look for a ChipCommon device */ + if ((chipc = bhnd_find_child(dev, BHND_DEVCLASS_CC, -1)) != NULL) { + bhnd_nvram_src_t src; + + /* Query the NVRAM source and determine whether it's + * accessible via the ChipCommon device */ + src = BHND_CHIPC_NVRAM_SRC(chipc); + if (BHND_NVRAM_SRC_CC(src)) + return (chipc); + } + + /* Not found */ + return (NULL); +} + +/** + * Helper function for implementing BHND_BUS_GET_NVRAM_VAR(). + * + * This implementation searches @p dev for a usable NVRAM child device: + * - The first child device implementing the bhnd_nvram devclass is + * returned, otherwise + * - If @p dev is a bhnd(4) bus, a ChipCommon core that advertises an + * attached NVRAM source. + * + * If no usable child device is found on @p dev, the request is delegated to + * the BHND_BUS_GET_NVRAM_VAR() method on the parent of @p dev. + */ +int +bhnd_bus_generic_get_nvram_var(device_t dev, device_t child, const char *name, + void *buf, size_t *size) +{ + device_t nvram; + device_t parent; + + /* Try to find an NVRAM device applicable to @p child */ + if ((nvram = find_nvram_child(dev)) != NULL) + return BHND_NVRAM_GETVAR(nvram, name, buf, size); + + /* Try to delegate to parent */ + if ((parent = device_get_parent(dev)) == NULL) + return (ENODEV); + + return (BHND_BUS_GET_NVRAM_VAR(device_get_parent(dev), child, + name, buf, size)); } /** * Helper function for implementing BHND_BUS_ALLOC_RESOURCE(). * * This implementation of BHND_BUS_ALLOC_RESOURCE() delegates allocation * of the underlying resource to BUS_ALLOC_RESOURCE(), and activation * to @p dev's BHND_BUS_ACTIVATE_RESOURCE(). */ struct bhnd_resource * bhnd_bus_generic_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 bhnd_resource *br; struct resource *res; int error; br = NULL; res = NULL; /* Allocate the real bus resource (without activating it) */ res = BUS_ALLOC_RESOURCE(dev, child, type, rid, start, end, count, (flags & ~RF_ACTIVE)); if (res == NULL) return (NULL); /* Allocate our bhnd resource wrapper. */ br = malloc(sizeof(struct bhnd_resource), M_BHND, M_NOWAIT); if (br == NULL) goto failed; br->direct = false; br->res = res; /* Attempt activation */ if (flags & RF_ACTIVE) { error = BHND_BUS_ACTIVATE_RESOURCE(dev, child, type, *rid, br); if (error) goto failed; } return (br); failed: if (res != NULL) BUS_RELEASE_RESOURCE(dev, child, type, *rid, res); free(br, M_BHND); return (NULL); } /** * Helper function for implementing BHND_BUS_RELEASE_RESOURCE(). * * This implementation of BHND_BUS_RELEASE_RESOURCE() delegates release of * the backing resource to BUS_RELEASE_RESOURCE(). */ int bhnd_bus_generic_release_resource(device_t dev, device_t child, int type, int rid, struct bhnd_resource *r) { int error; if ((error = BUS_RELEASE_RESOURCE(dev, child, type, rid, r->res))) return (error); free(r, M_BHND); return (0); } /** * Helper function for implementing BHND_BUS_ACTIVATE_RESOURCE(). * * This implementation of BHND_BUS_ACTIVATE_RESOURCE() simply calls the * BHND_BUS_ACTIVATE_RESOURCE() method of the parent of @p dev. */ int bhnd_bus_generic_activate_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)); return (EINVAL); }; /** * Helper function for implementing BHND_BUS_DEACTIVATE_RESOURCE(). * * This implementation of BHND_BUS_ACTIVATE_RESOURCE() simply calls the * BHND_BUS_ACTIVATE_RESOURCE() method of the parent of @p dev. */ int bhnd_bus_generic_deactivate_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)); return (EINVAL); }; Index: head/sys/dev/bhnd/bhndb/bhndb.c =================================================================== --- head/sys/dev/bhnd/bhndb/bhndb.c (revision 299995) +++ head/sys/dev/bhnd/bhndb/bhndb.c (revision 299996) @@ -1,2004 +1,1984 @@ /*- * 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 #include "bhnd_chipc_if.h" #include "bhnd_nvram_if.h" #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); bhndb_addrspace bhndb_get_addrspace(struct bhndb_softc *sc, device_t child); static struct rman *bhndb_get_rman(struct bhndb_softc *sc, device_t child, 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, "%#jx"); retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd"); } 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->d.core.port_type, regw->d.core.port, regw->d.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_devinfo *dinfo; 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); /* Populate generic resource allocation state. */ sc->bus_res = bhndb_alloc_resources(dev, sc->parent_dev, cfg); if (sc->bus_res == NULL) { return (ENXIO); } /* Attach our bridged bus device */ sc->bus_dev = BUS_ADD_CHILD(dev, 0, "bhnd", -1); if (sc->bus_dev == NULL) { error = ENXIO; goto failed; } /* Configure address space */ dinfo = device_get_ivars(sc->bus_dev); dinfo->addrspace = BHNDB_ADDRSPACE_BRIDGED; /* Finish attach */ return (bus_generic_attach(dev)); failed: BHNDB_LOCK_DESTROY(sc); 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 bhnd-attached cores */ if ((error = device_get_children(sc->bus_dev, &devs, &ndevs))) return (error); /* Find our host bridge device */ hostb = BHNDB_FIND_HOSTB_DEVICE(dev, child); 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 || BHNDB_DEBUG(PRIO)) 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. */ 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%jx+0x%jx\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%jx+0x%jx\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 address space for the given @p child device. */ bhndb_addrspace bhndb_get_addrspace(struct bhndb_softc *sc, device_t child) { struct bhndb_devinfo *dinfo; device_t imd_dev; /* Find the directly attached parent of the requesting device */ imd_dev = child; while (imd_dev != NULL && device_get_parent(imd_dev) != sc->dev) imd_dev = device_get_parent(imd_dev); if (imd_dev == NULL) panic("bhndb address space request for non-child device %s\n", device_get_nameunit(child)); dinfo = device_get_ivars(imd_dev); return (dinfo->addrspace); } /** * Return the rman instance for a given resource @p type, if any. * * @param sc The bhndb device state. * @param child The requesting child. * @param type The resource type (e.g. SYS_RES_MEMORY, SYS_RES_IRQ, ...) */ static struct rman * bhndb_get_rman(struct bhndb_softc *sc, device_t child, int type) { switch (bhndb_get_addrspace(sc, child)) { case BHNDB_ADDRSPACE_NATIVE: switch (type) { case SYS_RES_MEMORY: return (&sc->bus_res->ht_mem_rman); case SYS_RES_IRQ: return (NULL); default: return (NULL); }; case BHNDB_ADDRSPACE_BRIDGED: switch (type) { case SYS_RES_MEMORY: return (&sc->bus_res->br_mem_rman); case SYS_RES_IRQ: // TODO // return &sc->irq_rman; return (NULL); default: return (NULL); }; } /* Quieten gcc */ 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); } dinfo->addrspace = BHNDB_ADDRSPACE_NATIVE; 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 (BHNDB_FIND_HOSTB_DEVICE(dev, sc->bus_dev) != child); /* Otherwise, assume the core is populated */ return (false); } /* ascending core index comparison used by bhndb_find_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_FIND_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 dev The bhndb device * @param child The requesting bhnd bus. */ static device_t bhndb_find_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); /* 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 }; /* Must be the absolute first matching device on the bus. */ if ((error = device_get_children(child, &devlist, &devcnt))) return (false); /* Sort by core index value, ascending */ qsort(devlist, devcnt, sizeof(*devlist), compare_core_index); /* Find the 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 (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 passthrough, isdefault; sc = device_get_softc(dev); passthrough = (device_get_parent(child) != dev); isdefault = RMAN_IS_DEFAULT_RANGE(start, end); rle = NULL; /* Populate defaults */ if (!passthrough && isdefault) { /* 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 || count > ((end - start) + 1)) return (NULL); /* Fetch the resource manager */ rm = bhndb_get_rman(sc, child, 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: %d\n", *rid, type, device_get_nameunit(child), error); 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, child, 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 offsize and @p size. * * @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: %d\n", (unsigned long long) r_start, (unsigned long long) r_start + r_size - 1, error); 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; r_start = rman_get_start(r); r_size = rman_get_size(r); /* Activate native addrspace resources using the host address space */ if (bhndb_get_addrspace(sc, child) == BHNDB_ADDRSPACE_NATIVE) { struct resource *parent; /* Find the bridge resource referenced by the child */ parent = bhndb_find_resource_range(sc->bus_res, r_start, r_size); if (parent == NULL) { device_printf(sc->dev, "host resource not found " "for 0x%llx-0x%llx\n", (unsigned long long) r_start, (unsigned long long) r_start + r_size - 1); return (ENOENT); } /* Initialize child resource with the real bus values */ error = bhndb_init_child_resource(r, parent, r_start - rman_get_start(parent), r_size); if (error) return (error); /* Try to activate child resource */ return (rman_activate_resource(r)); } /* Default to low priority */ dw_priority = BHNDB_PRIORITY_LOW; /* Look for a bus region matching the resource's address range */ 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, child, type)) == NULL) return (EINVAL); /* Mark inactive */ if ((error = rman_deactivate_resource(r))) return (error); /* Free any dynamic window allocation. */ if (bhndb_get_addrspace(sc, child) == BHNDB_ADDRSPACE_BRIDGED) { 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_ACTIVATE_RESOURCE(). * * For BHNDB_ADDRSPACE_NATIVE children, all resources may be assumed to * be activated by the bridge. * * For BHNDB_ADDRSPACE_BRIDGED children, 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; 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); r_start = rman_get_start(r->res); r_size = rman_get_size(r->res); /* Verify bridged address range's resource priority, and skip direct * allocation if the priority is too low. */ if (bhndb_get_addrspace(sc, child) == BHNDB_ADDRSPACE_BRIDGED) { bhndb_priority_t r_prio; region = bhndb_find_resource_region(sc->bus_res, r_start, r_size); if (region != NULL) r_prio = region->priority; else r_prio = BHNDB_PRIORITY_NONE; /* 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) && bhndb_get_addrspace(sc, child) == BHNDB_ADDRSPACE_BRIDGED) { 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); } -/** - * Default bhndb(4) implementation of BHND_BUS_GET_NVRAM_VAR(). - */ -static int -bhndb_get_nvram_var(device_t dev, device_t child, const char *name, - void *buf, size_t *size) -{ - device_t nvram; - - /* Look for a directly-attached NVRAM child */ - nvram = device_find_child(dev, devclass_get_name(bhnd_nvram_devclass), - 0); - if (nvram != NULL) - return (BHND_NVRAM_GETVAR(nvram, name, buf, size)); - - /* Otherwise, delegate to our parent */ - return (BHND_BUS_GET_NVRAM_VAR(device_get_parent(dev), child, - name, buf, size)); -} - /* * 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, _name) \ static _type \ bhndb_bus_read_ ## _name (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_ ## _name (io_res, io_offset); \ BHNDB_IO_COMMON_TEARDOWN(); \ \ return (v); \ } /* Defines a bhndb_bus_write_* method implementation */ #define BHNDB_IO_WRITE(_type, _name) \ static void \ bhndb_bus_write_ ## _name (device_t dev, device_t child, \ struct bhnd_resource *r, bus_size_t offset, _type value) \ { \ BHNDB_IO_COMMON_SETUP(sizeof(_type)); \ bus_write_ ## _name (io_res, io_offset, value); \ BHNDB_IO_COMMON_TEARDOWN(); \ } /* Defines a bhndb_bus_(read|write)_multi_* method implementation */ #define BHNDB_IO_MULTI(_type, _rw, _name) \ static void \ bhndb_bus_ ## _rw ## _multi_ ## _name (device_t dev, \ device_t child, struct bhnd_resource *r, bus_size_t offset, \ _type *datap, bus_size_t count) \ { \ BHNDB_IO_COMMON_SETUP(sizeof(_type) * count); \ bus_ ## _rw ## _multi_ ## _name (io_res, io_offset, \ datap, count); \ BHNDB_IO_COMMON_TEARDOWN(); \ } /* Defines a complete set of read/write methods */ #define BHNDB_IO_METHODS(_type, _size) \ BHNDB_IO_READ(_type, _size) \ BHNDB_IO_WRITE(_type, _size) \ \ BHNDB_IO_READ(_type, stream_ ## _size) \ BHNDB_IO_WRITE(_type, stream_ ## _size) \ \ BHNDB_IO_MULTI(_type, read, _size) \ BHNDB_IO_MULTI(_type, write, _size) \ \ BHNDB_IO_MULTI(_type, read, stream_ ## _size) \ BHNDB_IO_MULTI(_type, write, stream_ ## _size) BHNDB_IO_METHODS(uint8_t, 1); BHNDB_IO_METHODS(uint16_t, 2); BHNDB_IO_METHODS(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_find_hostb_device, bhndb_find_hostb_device), 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_get_chipid, bhndb_get_chipid), DEVMETHOD(bhnd_bus_activate_resource, bhndb_activate_bhnd_resource), DEVMETHOD(bhnd_bus_deactivate_resource, bhndb_deactivate_bhnd_resource), - DEVMETHOD(bhnd_bus_get_nvram_var, bhndb_get_nvram_var), + DEVMETHOD(bhnd_bus_get_nvram_var, bhnd_bus_generic_get_nvram_var), 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_read_stream_1, bhndb_bus_read_stream_1), DEVMETHOD(bhnd_bus_read_stream_2, bhndb_bus_read_stream_2), DEVMETHOD(bhnd_bus_read_stream_4, bhndb_bus_read_stream_4), DEVMETHOD(bhnd_bus_write_stream_1, bhndb_bus_write_stream_1), DEVMETHOD(bhnd_bus_write_stream_2, bhndb_bus_write_stream_2), DEVMETHOD(bhnd_bus_write_stream_4, bhndb_bus_write_stream_4), DEVMETHOD(bhnd_bus_read_multi_1, bhndb_bus_read_multi_1), DEVMETHOD(bhnd_bus_read_multi_2, bhndb_bus_read_multi_2), DEVMETHOD(bhnd_bus_read_multi_4, bhndb_bus_read_multi_4), DEVMETHOD(bhnd_bus_write_multi_1, bhndb_bus_write_multi_1), DEVMETHOD(bhnd_bus_write_multi_2, bhndb_bus_write_multi_2), DEVMETHOD(bhnd_bus_write_multi_4, bhndb_bus_write_multi_4), DEVMETHOD(bhnd_bus_read_multi_stream_1, bhndb_bus_read_multi_stream_1), DEVMETHOD(bhnd_bus_read_multi_stream_2, bhndb_bus_read_multi_stream_2), DEVMETHOD(bhnd_bus_read_multi_stream_4, bhndb_bus_read_multi_stream_4), DEVMETHOD(bhnd_bus_write_multi_stream_1,bhndb_bus_write_multi_stream_1), DEVMETHOD(bhnd_bus_write_multi_stream_2,bhndb_bus_write_multi_stream_2), DEVMETHOD(bhnd_bus_write_multi_stream_4,bhndb_bus_write_multi_stream_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); Index: head/sys/dev/bhnd/bhndb/bhndb_if.m =================================================================== --- head/sys/dev/bhnd/bhndb/bhndb_if.m (revision 299995) +++ head/sys/dev/bhnd/bhndb/bhndb_if.m (revision 299996) @@ -1,201 +1,223 @@ #- # 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_populate_board_info(device_t dev, device_t child, + struct bhnd_board_info *info) + { + panic("bhndb_populate_board_info 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 device_t bhndb_null_find_hostb_device(device_t dev, device_t child) { panic("bhndb_find_hostb_device 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; + +/** + * Populate @p info with board info known only to the bridge, + * deferring to any existing initialized fields in @p info. + * + * @param dev The parent device of @p child. + * @param child The bhndb-attached device. + * @param[in,out] info A board info structure previously initialized with any + * information available from NVRAM. + */ +METHOD int populate_board_info { + device_t dev; + device_t child; + struct bhnd_board_info *info; +} DEFAULT bhndb_null_populate_board_info; /** * 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; /** * Locate the active host bridge core for the attached bhnd bus. * * @param dev The bridge device. * @param child The bhnd bus device attached to @p dev. */ METHOD device_t find_hostb_device { device_t dev; device_t child; } DEFAULT bhndb_null_find_hostb_device; /** * 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; Index: head/sys/dev/bhnd/bhndb/bhndb_pci.c =================================================================== --- head/sys/dev/bhnd/bhndb/bhndb_pci.c (revision 299995) +++ head/sys/dev/bhnd/bhndb/bhndb_pci.c (revision 299996) @@ -1,586 +1,606 @@ /*- * 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. */ #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 host-level PCI interactions with a PCI/PCIe bridge * core operating in endpoint mode. On the bridged bhnd bus, the PCI core * device will be managed by a bhnd_pci_hostb driver. */ #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 void bhndb_init_sromless_pci_config( struct bhndb_pci_softc *sc); static bus_addr_t bhndb_pci_sprom_addr(struct bhndb_pci_softc *sc); static bus_size_t bhndb_pci_sprom_size(struct bhndb_pci_softc *sc); /** * 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; sc->parent = device_get_parent(dev); /* Enable PCI bus mastering */ pci_enable_busmaster(sc->parent); /* Determine our bridge device class */ sc->pci_devclass = BHND_DEVCLASS_PCI; if (pci_find_cap(sc->parent, PCIY_EXPRESS, ®) == 0) sc->pci_devclass = BHND_DEVCLASS_PCIE; /* Enable clocks (if supported by this hardware) */ if ((error = bhndb_enable_pci_clocks(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); } static int bhndb_pci_init_full_config(device_t dev, device_t child, const struct bhndb_hw_priority *hw_prio_table) { struct bhndb_pci_softc *sc; device_t nv_dev; bus_size_t nv_sz; int error; sc = device_get_softc(dev); /* Let our parent perform standard initialization first */ if ((error = bhndb_generic_init_full_config(dev, child, hw_prio_table))) return (error); /* Fix-up power on defaults for SROM-less devices. */ bhndb_init_sromless_pci_config(sc); /* If SPROM is mapped directly into BAR0, add NVRAM device. */ nv_sz = bhndb_pci_sprom_size(sc); if (nv_sz > 0) { struct bhndb_devinfo *dinfo; const char *dname; if (bootverbose) { device_printf(dev, "found SPROM (%u bytes)\n", (unsigned int) nv_sz); } /* Add sprom device */ dname = "bhnd_nvram"; if ((nv_dev = BUS_ADD_CHILD(dev, 0, dname, -1)) == NULL) { device_printf(dev, "failed to add sprom device\n"); return (ENXIO); } /* Initialize device address space and resource covering the * BAR0 SPROM shadow. */ dinfo = device_get_ivars(nv_dev); dinfo->addrspace = BHNDB_ADDRSPACE_NATIVE; error = bus_set_resource(nv_dev, SYS_RES_MEMORY, 0, bhndb_pci_sprom_addr(sc), nv_sz); if (error) { device_printf(dev, "failed to register sprom resources\n"); return (error); } /* Attach the device */ if ((error = device_probe_and_attach(nv_dev))) { device_printf(dev, "sprom attach failed\n"); return (error); } } return (0); } static const struct bhndb_regwin * bhndb_pci_sprom_regwin(struct bhndb_pci_softc *sc) { struct bhndb_resources *bres; const struct bhndb_hwcfg *cfg; const struct bhndb_regwin *sprom_win; bres = sc->bhndb.bus_res; cfg = bres->cfg; sprom_win = bhndb_regwin_find_type(cfg->register_windows, BHNDB_REGWIN_T_SPROM, BHNDB_PCI_V0_BAR0_SPROM_SIZE); return (sprom_win); } static bus_addr_t bhndb_pci_sprom_addr(struct bhndb_pci_softc *sc) { const struct bhndb_regwin *sprom_win; struct resource *r; /* Fetch the SPROM register window */ sprom_win = bhndb_pci_sprom_regwin(sc); KASSERT(sprom_win != NULL, ("requested sprom address on PCI_V2+")); /* Fetch the associated resource */ r = bhndb_find_regwin_resource(sc->bhndb.bus_res, sprom_win); KASSERT(r != NULL, ("missing resource for sprom window\n")); return (rman_get_start(r) + sprom_win->win_offset); } static bus_size_t bhndb_pci_sprom_size(struct bhndb_pci_softc *sc) { const struct bhndb_regwin *sprom_win; uint32_t sctl; bus_size_t sprom_sz; sprom_win = bhndb_pci_sprom_regwin(sc); /* PCI_V2 and later devices map SPROM/OTP via ChipCommon */ if (sprom_win == NULL) return (0); /* Determine SPROM size */ sctl = pci_read_config(sc->parent, BHNDB_PCI_SPROM_CONTROL, 4); if (sctl & BHNDB_PCI_SPROM_BLANK) return (0); switch (sctl & BHNDB_PCI_SPROM_SZ_MASK) { case BHNDB_PCI_SPROM_SZ_1KB: sprom_sz = (1 * 1024); break; case BHNDB_PCI_SPROM_SZ_4KB: sprom_sz = (4 * 1024); break; case BHNDB_PCI_SPROM_SZ_16KB: sprom_sz = (16 * 1024); break; case BHNDB_PCI_SPROM_SZ_RESERVED: default: device_printf(sc->dev, "invalid PCI sprom size 0x%x\n", sctl); return (0); } if (sprom_sz > sprom_win->win_size) { device_printf(sc->dev, "PCI sprom size (0x%x) overruns defined register window\n", sctl); return (0); } return (sprom_sz); } /* * On devices without a SROM, the PCI(e) cores will be initialized with * their Power-on-Reset defaults; this can leave two of the BAR0 PCI windows * mapped to the wrong core. * * This function updates the SROM shadow to point the BAR0 windows at the * current PCI core. * * Applies to all PCI/PCIe revisions. */ static void bhndb_init_sromless_pci_config(struct bhndb_pci_softc *sc) { struct bhndb_resources *bres; const struct bhndb_hwcfg *cfg; const struct bhndb_regwin *win; struct resource *core_regs; bus_size_t srom_offset; u_int pci_cidx, sprom_cidx; uint16_t val; bres = sc->bhndb.bus_res; cfg = bres->cfg; if (bhnd_get_vendor(sc->bhndb.hostb_dev) != BHND_MFGID_BCM) return; switch (bhnd_get_device(sc->bhndb.hostb_dev)) { case BHND_COREID_PCI: srom_offset = BHND_PCI_SRSH_PI_OFFSET; break; case BHND_COREID_PCIE: srom_offset = BHND_PCIE_SRSH_PI_OFFSET; break; default: device_printf(sc->dev, "unsupported PCI host bridge device\n"); return; } /* Locate the static register window mapping the PCI core */ win = bhndb_regwin_find_core(cfg->register_windows, sc->pci_devclass, 0, BHND_PORT_DEVICE, 0, 0); if (win == NULL) { device_printf(sc->dev, "missing PCI core register window\n"); return; } /* Fetch the resource containing the register window */ core_regs = bhndb_find_regwin_resource(bres, win); if (core_regs == NULL) { device_printf(sc->dev, "missing PCI core register resource\n"); return; } /* Fetch the SPROM's configured core index */ val = bus_read_2(core_regs, win->win_offset + srom_offset); sprom_cidx = (val & BHND_PCI_SRSH_PI_MASK) >> BHND_PCI_SRSH_PI_SHIFT; /* If it doesn't match host bridge's core index, update the index * value */ pci_cidx = bhnd_get_core_index(sc->bhndb.hostb_dev); if (sprom_cidx != pci_cidx) { val &= ~BHND_PCI_SRSH_PI_MASK; val |= (pci_cidx << BHND_PCI_SRSH_PI_SHIFT); bus_write_2(core_regs, win->win_offset + srom_offset, val); } } static int bhndb_pci_resume(device_t dev) { struct bhndb_pci_softc *sc; int error; sc = device_get_softc(dev); /* Enable clocks (if supported by this hardware) */ if ((error = bhndb_enable_pci_clocks(sc))) return (error); /* Perform resume */ return (bhndb_generic_resume(dev)); } static int bhndb_pci_suspend(device_t dev) { struct bhndb_pci_softc *sc; int error; sc = device_get_softc(dev); /* Disable clocks (if supported by this hardware) */ if ((error = bhndb_disable_pci_clocks(sc))) return (error); /* Perform suspend */ return (bhndb_generic_suspend(dev)); } static int bhndb_pci_detach(device_t dev) { struct bhndb_pci_softc *sc; int error; sc = device_get_softc(dev); /* Disable clocks (if supported by this hardware) */ if ((error = bhndb_disable_pci_clocks(sc))) return (error); /* Perform detach */ if ((error = bhndb_generic_detach(dev))) return (error); /* Disable PCI bus mastering */ pci_disable_busmaster(sc->parent); 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) { int error; int reg; if (rw->win_type != BHNDB_REGWIN_T_DYN) return (ENODEV); reg = rw->d.dyn.cfg_offset; 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(sc->parent, reg, 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) { /* 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(sc->parent, rw->d.dyn.cfg_offset, addr, 4); break; default: return (ENODEV); } return (0); } +static int +bhndb_pci_populate_board_info(device_t dev, device_t child, + struct bhnd_board_info *info) +{ + struct bhndb_pci_softc *sc; + + sc = device_get_softc(dev); + + /* If NVRAM did not supply vendor/type info, provide the PCI + * subvendor/subdevice values. */ + if (info->board_vendor == 0) + info->board_vendor = pci_get_subvendor(sc->parent); + + if (info->board_type == 0) + info->board_type = pci_get_subdevice(sc->parent); + + return (0); +} + /** * Enable externally managed clocks, if required. * * Some PCI chipsets (BCM4306, possibly others) chips 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. * * @param sc Bridge driver state. */ static int bhndb_enable_pci_clocks(struct bhndb_pci_softc *sc) { uint32_t gpio_in, gpio_out, gpio_en; uint32_t gpio_flags; uint16_t pci_status; /* Only supported and required on PCI devices */ if (sc->pci_devclass != BHND_DEVCLASS_PCI) return (0); /* Read state of XTAL pin */ gpio_in = pci_read_config(sc->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(sc->parent, BHNDB_PCI_GPIO_OUT, 4); gpio_en = pci_read_config(sc->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(sc->parent, BHNDB_PCI_GPIO_OUT, gpio_out, 4); pci_write_config(sc->parent, BHNDB_PCI_GPIO_OUTEN, gpio_en, 4); DELAY(1000); /* Reset PLL_OFF */ gpio_out &= ~BHNDB_PCI_GPIO_PLL_OFF; pci_write_config(sc->parent, BHNDB_PCI_GPIO_OUT, gpio_out, 4); DELAY(5000); /* Clear any PCI 'sent target-abort' flag. */ pci_status = pci_read_config(sc->parent, PCIR_STATUS, 2); pci_status &= ~PCIM_STATUS_STABORT; pci_write_config(sc->parent, PCIR_STATUS, pci_status, 2); return (0); } /** * Disable externally managed clocks, if required. * * @param sc Bridge driver state. */ static int bhndb_disable_pci_clocks(struct bhndb_pci_softc *sc) { uint32_t gpio_out, gpio_en; /* Only supported and required on PCI devices */ if (sc->pci_devclass != BHND_DEVCLASS_PCI) return (0); // 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(sc->parent, BHNDB_PCI_GPIO_OUT, 4); gpio_en = pci_read_config(sc->parent, 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(sc->parent, 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(sc->parent, BHNDB_PCI_GPIO_OUTEN, gpio_en, 4); return (0); } static device_method_t bhndb_pci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, bhndb_pci_probe), DEVMETHOD(device_attach, bhndb_pci_attach), DEVMETHOD(device_resume, bhndb_pci_resume), DEVMETHOD(device_suspend, bhndb_pci_suspend), DEVMETHOD(device_detach, bhndb_pci_detach), /* BHNDB interface */ DEVMETHOD(bhndb_init_full_config, bhndb_pci_init_full_config), DEVMETHOD(bhndb_set_window_addr, bhndb_pci_set_window_addr), + DEVMETHOD(bhndb_populate_board_info, bhndb_pci_populate_board_info), DEVMETHOD_END }; DEFINE_CLASS_1(bhndb, bhndb_pci_driver, bhndb_pci_methods, sizeof(struct bhndb_pci_softc), bhndb_driver); MODULE_VERSION(bhndb_pci, 1); MODULE_DEPEND(bhndb_pci, bhnd_pci_hostb, 1, 1, 1); MODULE_DEPEND(bhndb_pci, pci, 1, 1, 1); MODULE_DEPEND(bhndb_pci, bhndb, 1, 1, 1); MODULE_DEPEND(bhndb_pci, bhnd, 1, 1, 1); Index: head/sys/dev/bhnd/cores/chipc/chipc.c =================================================================== --- head/sys/dev/bhnd/cores/chipc/chipc.c (revision 299995) +++ head/sys/dev/bhnd/cores/chipc/chipc.c (revision 299996) @@ -1,513 +1,513 @@ /*- * 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 "bhnd_nvram_if.h" #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 } }; static struct bhnd_device_quirk chipc_quirks[]; +static struct bhnd_chip_quirk chipc_chip_quirks[]; /* Supported device identifiers */ static const struct bhnd_device chipc_devices[] = { - BHND_DEVICE(CC, "CC", chipc_quirks), + BHND_DEVICE(CC, "CC", chipc_quirks, chipc_chip_quirks), BHND_DEVICE_END }; /* Device quirks table */ static struct bhnd_device_quirk chipc_quirks[] = { { BHND_HWREV_GTE (32), CHIPC_QUIRK_SUPPORTS_SPROM }, { BHND_HWREV_GTE (35), CHIPC_QUIRK_SUPPORTS_NFLASH }, BHND_DEVICE_QUIRK_END }; /* Chip-specific quirks table */ static struct bhnd_chip_quirk chipc_chip_quirks[] = { /* 4331 12x9 packages */ {{ BHND_CHIP_IP(4331, 4331TN) }, CHIPC_QUIRK_4331_GPIO2_5_MUX_SPROM }, {{ BHND_CHIP_IP(4331, 4331TNA0) }, CHIPC_QUIRK_4331_GPIO2_5_MUX_SPROM }, /* 4331 12x12 packages */ {{ BHND_CHIP_IPR(4331, 4331TT, HWREV_GTE(1)) }, CHIPC_QUIRK_4331_EXTPA2_MUX_SPROM }, /* 4331 (all packages/revisions) */ {{ BHND_CHIP_ID(4331) }, CHIPC_QUIRK_4331_EXTPA_MUX_SPROM }, /* 4360 family (all revs <= 2) */ {{ BHND_CHIP_IR(4352, HWREV_LTE(2)) }, CHIPC_QUIRK_4360_FEM_MUX_SPROM }, {{ BHND_CHIP_IR(43460, HWREV_LTE(2)) }, CHIPC_QUIRK_4360_FEM_MUX_SPROM }, {{ BHND_CHIP_IR(43462, HWREV_LTE(2)) }, CHIPC_QUIRK_4360_FEM_MUX_SPROM }, {{ BHND_CHIP_IR(43602, HWREV_LTE(2)) }, CHIPC_QUIRK_4360_FEM_MUX_SPROM }, BHND_CHIP_QUIRK_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 bhnd_nvram_src_t chipc_nvram_identify(struct chipc_softc *sc); static int chipc_sprom_init(struct chipc_softc *); static int chipc_enable_sprom_pins(struct chipc_softc *); static int chipc_disable_sprom_pins(struct chipc_softc *); static int chipc_probe(device_t dev) { const struct bhnd_device *id; id = bhnd_device_lookup(dev, chipc_devices, sizeof(chipc_devices[0])); if (id == NULL) return (ENXIO); bhnd_set_default_core_desc(dev); return (BUS_PROBE_DEFAULT); } static int chipc_attach(device_t dev) { 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; sc->quirks = bhnd_device_quirks(dev, chipc_devices, sizeof(chipc_devices[0])); - sc->quirks |= bhnd_chip_quirks(dev, chipc_chip_quirks); CHIPC_LOCK_INIT(sc); /* 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); /* Identify NVRAM source */ sc->nvram_src = chipc_nvram_identify(sc); /* Read NVRAM data */ switch (sc->nvram_src) { case BHND_NVRAM_SRC_OTP: // TODO (requires access to OTP hardware) device_printf(sc->dev, "NVRAM-OTP unsupported\n"); break; case BHND_NVRAM_SRC_NFLASH: // TODO (requires access to NFLASH hardware) device_printf(sc->dev, "NVRAM-NFLASH unsupported\n"); break; case BHND_NVRAM_SRC_SPROM: if ((error = chipc_sprom_init(sc))) goto cleanup; break; case BHND_NVRAM_SRC_UNKNOWN: /* Handled externally */ break; } return (0); cleanup: bhnd_release_resources(dev, sc->rspec, sc->res); CHIPC_LOCK_DESTROY(sc); 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); bhnd_sprom_fini(&sc->sprom); CHIPC_LOCK_DESTROY(sc); return (0); } static int chipc_suspend(device_t dev) { return (0); } static int chipc_resume(device_t dev) { return (0); } /** * Initialize local SPROM shadow, if required. * * @param sc chipc driver state. */ static int chipc_sprom_init(struct chipc_softc *sc) { int error; KASSERT(sc->nvram_src == BHND_NVRAM_SRC_SPROM, ("non-SPROM source (%u)\n", sc->nvram_src)); /* Enable access to the SPROM */ CHIPC_LOCK(sc); if ((error = chipc_enable_sprom_pins(sc))) goto failed; /* Initialize SPROM parser */ error = bhnd_sprom_init(&sc->sprom, sc->core, CHIPC_SPROM_OTP); if (error) { device_printf(sc->dev, "SPROM identification failed: %d\n", error); chipc_disable_sprom_pins(sc); goto failed; } /* Drop access to the SPROM lines */ if ((error = chipc_disable_sprom_pins(sc))) { bhnd_sprom_fini(&sc->sprom); goto failed; } CHIPC_UNLOCK(sc); return (0); failed: CHIPC_UNLOCK(sc); return (error); } /** * Determine the NVRAM data source for this device. * * @param sc chipc driver state. */ static bhnd_nvram_src_t chipc_nvram_identify(struct chipc_softc *sc) { uint32_t srom_ctrl; /* Very early devices vend SPROM/OTP/CIS (if at all) via the * host bridge interface instead of ChipCommon. */ if (!CHIPC_QUIRK(sc, SUPPORTS_SPROM)) return (BHND_NVRAM_SRC_UNKNOWN); /* * Later chipset revisions standardized the SPROM 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_UNKNOWN); } /** * If required by this device, enable access to the SPROM. * * @param sc chipc driver state. */ static int chipc_enable_sprom_pins(struct chipc_softc *sc) { uint32_t cctrl; CHIPC_LOCK_ASSERT(sc, MA_OWNED); /* Nothing to do? */ if (!CHIPC_QUIRK(sc, MUX_SPROM)) return (0); cctrl = bhnd_bus_read_4(sc->core, CHIPC_CHIPCTRL); /* 4331 devices */ if (CHIPC_QUIRK(sc, 4331_EXTPA_MUX_SPROM)) { cctrl &= ~CHIPC_CCTRL4331_EXTPA_EN; if (CHIPC_QUIRK(sc, 4331_GPIO2_5_MUX_SPROM)) cctrl &= ~CHIPC_CCTRL4331_EXTPA_ON_GPIO2_5; if (CHIPC_QUIRK(sc, 4331_EXTPA2_MUX_SPROM)) cctrl &= ~CHIPC_CCTRL4331_EXTPA_EN2; bhnd_bus_write_4(sc->core, CHIPC_CHIPCTRL, cctrl); return (0); } /* 4360 devices */ if (CHIPC_QUIRK(sc, 4360_FEM_MUX_SPROM)) { /* Unimplemented */ } /* Refuse to proceed on unsupported devices with muxed SPROM pins */ device_printf(sc->dev, "muxed sprom lines on unrecognized device\n"); return (ENXIO); } /** * If required by this device, revert any GPIO/pin configuration applied * to allow SPROM access. * * @param sc chipc driver state. */ static int chipc_disable_sprom_pins(struct chipc_softc *sc) { uint32_t cctrl; CHIPC_LOCK_ASSERT(sc, MA_OWNED); /* Nothing to do? */ if (!CHIPC_QUIRK(sc, MUX_SPROM)) return (0); cctrl = bhnd_bus_read_4(sc->core, CHIPC_CHIPCTRL); /* 4331 devices */ if (CHIPC_QUIRK(sc, 4331_EXTPA_MUX_SPROM)) { cctrl |= CHIPC_CCTRL4331_EXTPA_EN; if (CHIPC_QUIRK(sc, 4331_GPIO2_5_MUX_SPROM)) cctrl |= CHIPC_CCTRL4331_EXTPA_ON_GPIO2_5; if (CHIPC_QUIRK(sc, 4331_EXTPA2_MUX_SPROM)) cctrl |= CHIPC_CCTRL4331_EXTPA_EN2; bhnd_bus_write_4(sc->core, CHIPC_CHIPCTRL, cctrl); return (0); } /* 4360 devices */ if (CHIPC_QUIRK(sc, 4360_FEM_MUX_SPROM)) { /* Unimplemented */ } /* Refuse to proceed on unsupported devices with muxed SPROM pins */ device_printf(sc->dev, "muxed sprom lines on unrecognized device\n"); return (ENXIO); } static bhnd_nvram_src_t chipc_nvram_src(device_t dev) { struct chipc_softc *sc = device_get_softc(dev); return (sc->nvram_src); } static int chipc_nvram_getvar(device_t dev, const char *name, void *buf, size_t *len) { struct chipc_softc *sc; int error; sc = device_get_softc(dev); switch (sc->nvram_src) { case BHND_NVRAM_SRC_SPROM: CHIPC_LOCK(sc); error = bhnd_sprom_getvar(&sc->sprom, name, buf, len); CHIPC_UNLOCK(sc); return (error); case BHND_NVRAM_SRC_OTP: case BHND_NVRAM_SRC_NFLASH: /* Currently unsupported */ return (ENXIO); case BHND_NVRAM_SRC_UNKNOWN: return (ENODEV); } /* Unknown NVRAM source */ return (ENODEV); } static int chipc_nvram_setvar(device_t dev, const char *name, const void *buf, size_t len) { struct chipc_softc *sc; int error; sc = device_get_softc(dev); switch (sc->nvram_src) { case BHND_NVRAM_SRC_SPROM: CHIPC_LOCK(sc); error = bhnd_sprom_setvar(&sc->sprom, name, buf, len); CHIPC_UNLOCK(sc); return (error); case BHND_NVRAM_SRC_OTP: case BHND_NVRAM_SRC_NFLASH: /* Currently unsupported */ return (ENXIO); case BHND_NVRAM_SRC_UNKNOWN: default: return (ENODEV); } /* Unknown NVRAM source */ return (ENODEV); } 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), /* NVRAM interface */ DEVMETHOD(bhnd_nvram_getvar, chipc_nvram_getvar), DEVMETHOD(bhnd_nvram_setvar, chipc_nvram_setvar), 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_DEPEND(bhnd_chipc, bhnd, 1, 1, 1); MODULE_VERSION(bhnd_chipc, 1); Index: head/sys/dev/bhnd/cores/pci/bhnd_pci.c =================================================================== --- head/sys/dev/bhnd/cores/pci/bhnd_pci.c (revision 299995) +++ head/sys/dev/bhnd/cores/pci/bhnd_pci.c (revision 299996) @@ -1,548 +1,548 @@ /*- * 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/PCIe Support. * * This base driver implementation is shared by the bhnd_pcib (root complex) * and bhnd_pci_hostb (host bridge) drivers. */ #include #include #include #include #include #include #include #include #include #include #include #include "bhnd_pcireg.h" #include "bhnd_pcivar.h" static int bhnd_pcie_mdio_wait_idle(struct bhnd_pci_softc *sc); static int bhnd_pcie_mdio_ioctl(struct bhnd_pci_softc *sc, uint32_t cmd); static int bhnd_pcie_mdio_enable(struct bhnd_pci_softc *sc); static void bhnd_pcie_mdio_disable(struct bhnd_pci_softc *sc); static int bhnd_pcie_mdio_cmd_write(struct bhnd_pci_softc *sc, uint32_t cmd); static int bhnd_pcie_mdio_cmd_read(struct bhnd_pci_softc *sc, uint32_t cmd, uint16_t *data_read); static struct bhnd_device_quirk bhnd_pci_quirks[]; static struct bhnd_device_quirk bhnd_pcie_quirks[]; #define BHND_PCI_QUIRKS bhnd_pci_quirks #define BHND_PCIE_QUIRKS bhnd_pcie_quirks -#define BHND_PCI_DEV(_core, _desc, ...) \ - { BHND_DEVICE(_core, _desc, BHND_ ## _core ## _QUIRKS, \ +#define BHND_PCI_DEV(_core, _desc, ...) \ + { BHND_DEVICE(_core, _desc, BHND_ ## _core ## _QUIRKS, NULL, \ ## __VA_ARGS__), BHND_PCI_REGFMT_ ## _core } static const struct bhnd_pci_device { struct bhnd_device device; bhnd_pci_regfmt_t regfmt; /**< register format */ } bhnd_pci_devs[] = { BHND_PCI_DEV(PCI, "Host-PCI bridge", BHND_DF_HOSTB), BHND_PCI_DEV(PCI, "PCI-BHND bridge"), BHND_PCI_DEV(PCIE, "PCIe-G1 Host-PCI bridge", BHND_DF_HOSTB), BHND_PCI_DEV(PCIE, "PCIe-G1 PCI-BHND bridge"), { BHND_DEVICE_END, 0 } }; /* Device quirks tables */ static struct bhnd_device_quirk bhnd_pci_quirks[] = { BHND_DEVICE_QUIRK_END }; static struct bhnd_device_quirk bhnd_pcie_quirks[] = { { BHND_HWREV_GTE (10), BHND_PCI_QUIRK_SD_C22_EXTADDR }, BHND_DEVICE_QUIRK_END }; #define BHND_PCIE_MDIO_CTL_DELAY 10 /**< usec delay required between * MDIO_CTL/MDIO_DATA accesses. */ #define BHND_PCIE_MDIO_RETRY_DELAY 2000 /**< usec delay before retrying * BHND_PCIE_MDIOCTL_DONE. */ #define BHND_PCIE_MDIO_RETRY_COUNT 200 /**< number of times to loop waiting * for BHND_PCIE_MDIOCTL_DONE. */ #define BHND_PCI_READ_4(_sc, _reg) \ bhnd_bus_read_4((_sc)->mem_res, (_reg)) #define BHND_PCI_WRITE_4(_sc, _reg, _val) \ bhnd_bus_write_4((_sc)->mem_res, (_reg), (_val)) #define BHND_PCIE_ASSERT(sc) \ KASSERT(bhnd_get_class(sc->dev) == BHND_DEVCLASS_PCIE, \ ("not a pcie device!")); int bhnd_pci_generic_probe(device_t dev) { const struct bhnd_device *id; id = bhnd_device_lookup(dev, &bhnd_pci_devs[0].device, sizeof(bhnd_pci_devs[0])); if (id == NULL) return (ENXIO); bhnd_set_custom_core_desc(dev, id->desc); return (BUS_PROBE_DEFAULT); } int bhnd_pci_generic_attach(device_t dev) { struct bhnd_pci_softc *sc; int error; sc = device_get_softc(dev); sc->dev = dev; sc->quirks = bhnd_device_quirks(dev, &bhnd_pci_devs[0].device, sizeof(bhnd_pci_devs[0])); /* Allocate bus resources */ sc->mem_res = bhnd_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid, RF_ACTIVE); if (sc->mem_res == NULL) return (ENXIO); BHND_PCI_LOCK_INIT(sc); /* Probe and attach children */ if ((error = bus_generic_attach(dev))) goto cleanup; return (0); cleanup: bhnd_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem_res); BHND_PCI_LOCK_DESTROY(sc); return (error); } int bhnd_pci_generic_detach(device_t dev) { struct bhnd_pci_softc *sc; int error; sc = device_get_softc(dev); if ((error = bus_generic_detach(dev))) return (error); bhnd_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, sc->mem_res); BHND_PCI_LOCK_DESTROY(sc); return (0); } static struct resource_list * bhnd_pci_get_resource_list(device_t dev, device_t child) { struct bhnd_pci_devinfo *dinfo; if (device_get_parent(child) != dev) return (NULL); dinfo = device_get_ivars(child); return (&dinfo->resources); } static device_t bhnd_pci_add_child(device_t dev, u_int order, const char *name, int unit) { struct bhnd_pci_devinfo *dinfo; device_t child; child = device_add_child_ordered(dev, order, name, unit); if (child == NULL) return (NULL); dinfo = malloc(sizeof(struct bhnd_pci_devinfo), M_DEVBUF, M_NOWAIT); if (dinfo == NULL) { device_delete_child(dev, child); return (NULL); } resource_list_init(&dinfo->resources); device_set_ivars(child, dinfo); return (child); } static void bhnd_pci_child_deleted(device_t dev, device_t child) { struct bhnd_pci_devinfo *dinfo; if (device_get_parent(child) != dev) return; dinfo = device_get_ivars(child); if (dinfo != NULL) { resource_list_free(&dinfo->resources); free(dinfo, M_DEVBUF); } device_set_ivars(child, NULL); } int bhnd_pci_generic_suspend(device_t dev) { return (bus_generic_suspend(dev)); } int bhnd_pci_generic_resume(device_t dev) { return (bus_generic_resume(dev)); } /** * Read a 32-bit PCIe TLP/DLLP/PLP protocol register. * * @param sc The bhndb_pci driver state. * @param addr The protocol register offset. */ uint32_t bhnd_pcie_read_proto_reg(struct bhnd_pci_softc *sc, uint32_t addr) { uint32_t val; BHND_PCIE_ASSERT(sc); BHND_PCI_LOCK(sc); BHND_PCI_WRITE_4(sc, BHND_PCIE_IND_ADDR, addr); val = BHND_PCI_READ_4(sc, BHND_PCIE_IND_DATA); BHND_PCI_UNLOCK(sc); 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. */ void bhnd_pcie_write_proto_reg(struct bhnd_pci_softc *sc, uint32_t addr, uint32_t val) { BHND_PCIE_ASSERT(sc); BHND_PCI_LOCK(sc); BHND_PCI_WRITE_4(sc, BHND_PCIE_IND_ADDR, addr); BHND_PCI_WRITE_4(sc, BHND_PCIE_IND_DATA, val); BHND_PCI_UNLOCK(sc); } /* Spin until the MDIO device reports itself as idle, or timeout is reached. */ static int bhnd_pcie_mdio_wait_idle(struct bhnd_pci_softc *sc) { uint32_t ctl; /* Spin waiting for the BUSY flag to clear */ for (int i = 0; i < BHND_PCIE_MDIO_RETRY_COUNT; i++) { ctl = BHND_PCI_READ_4(sc, BHND_PCIE_MDIO_CTL); if ((ctl & BHND_PCIE_MDIOCTL_DONE)) return (0); DELAY(BHND_PCIE_MDIO_RETRY_DELAY); } return (ETIMEDOUT); } /** * Write an MDIO IOCTL and wait for completion. */ static int bhnd_pcie_mdio_ioctl(struct bhnd_pci_softc *sc, uint32_t cmd) { BHND_PCI_LOCK_ASSERT(sc, MA_OWNED); BHND_PCI_WRITE_4(sc, BHND_PCIE_MDIO_CTL, cmd); DELAY(BHND_PCIE_MDIO_CTL_DELAY); return (0); } /** * Enable MDIO device */ static int bhnd_pcie_mdio_enable(struct bhnd_pci_softc *sc) { uint32_t ctl; BHND_PCIE_ASSERT(sc); /* Enable MDIO clock and preamble mode */ ctl = BHND_PCIE_MDIOCTL_PREAM_EN|BHND_PCIE_MDIOCTL_DIVISOR_VAL; return (bhnd_pcie_mdio_ioctl(sc, ctl)); } /** * Disable MDIO device. */ static void bhnd_pcie_mdio_disable(struct bhnd_pci_softc *sc) { if (bhnd_pcie_mdio_ioctl(sc, 0)) device_printf(sc->dev, "failed to disable MDIO clock\n"); } /** * Issue a write command and wait for completion */ static int bhnd_pcie_mdio_cmd_write(struct bhnd_pci_softc *sc, uint32_t cmd) { int error; BHND_PCI_LOCK_ASSERT(sc, MA_OWNED); cmd |= BHND_PCIE_MDIODATA_START|BHND_PCIE_MDIODATA_TA|BHND_PCIE_MDIODATA_CMD_WRITE; BHND_PCI_WRITE_4(sc, BHND_PCIE_MDIO_DATA, cmd); DELAY(BHND_PCIE_MDIO_CTL_DELAY); if ((error = bhnd_pcie_mdio_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_pcie_mdio_cmd_read(struct bhnd_pci_softc *sc, uint32_t cmd, uint16_t *data_read) { int error; BHND_PCI_LOCK_ASSERT(sc, MA_OWNED); cmd |= BHND_PCIE_MDIODATA_START|BHND_PCIE_MDIODATA_TA|BHND_PCIE_MDIODATA_CMD_READ; BHND_PCI_WRITE_4(sc, BHND_PCIE_MDIO_DATA, cmd); DELAY(BHND_PCIE_MDIO_CTL_DELAY); if ((error = bhnd_pcie_mdio_wait_idle(sc))) return (error); *data_read = (BHND_PCI_READ_4(sc, BHND_PCIE_MDIO_DATA) & BHND_PCIE_MDIODATA_DATA_MASK); return (0); } int bhnd_pcie_mdio_read(struct bhnd_pci_softc *sc, int phy, int reg) { uint32_t cmd; uint16_t val; int error; /* Enable MDIO access */ BHND_PCI_LOCK(sc); bhnd_pcie_mdio_enable(sc); /* Issue the read */ cmd = BHND_PCIE_MDIODATA_ADDR(phy, reg); error = bhnd_pcie_mdio_cmd_read(sc, cmd, &val); /* Disable MDIO access */ bhnd_pcie_mdio_disable(sc); BHND_PCI_UNLOCK(sc); if (error) return (~0U); return (val); } int bhnd_pcie_mdio_write(struct bhnd_pci_softc *sc, int phy, int reg, int val) { uint32_t cmd; int error; /* Enable MDIO access */ BHND_PCI_LOCK(sc); bhnd_pcie_mdio_enable(sc); /* Issue the write */ cmd = BHND_PCIE_MDIODATA_ADDR(phy, reg) | (val & BHND_PCIE_MDIODATA_DATA_MASK); error = bhnd_pcie_mdio_cmd_write(sc, cmd); /* Disable MDIO access */ bhnd_pcie_mdio_disable(sc); BHND_PCI_UNLOCK(sc); return (error); } int bhnd_pcie_mdio_read_ext(struct bhnd_pci_softc *sc, int phy, int devaddr, int reg) { uint32_t cmd; uint16_t blk, val; uint8_t blk_reg; int error; if (devaddr == MDIO_DEVADDR_NONE) return (bhnd_pcie_mdio_read(sc, phy, reg)); /* Extended register access is only supported for the SerDes device, * using the non-standard C22 extended address mechanism */ if (!(sc->quirks & BHND_PCI_QUIRK_SD_C22_EXTADDR)) return (~0U); if (phy != BHND_PCIE_PHYADDR_SD || devaddr != BHND_PCIE_DEVAD_SD) return (~0U); /* Enable MDIO access */ BHND_PCI_LOCK(sc); bhnd_pcie_mdio_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_PCIE_MDIODATA_ADDR(phy, BHND_PCIE_SD_ADDREXT) | (blk & BHND_PCIE_MDIODATA_DATA_MASK); if ((error = bhnd_pcie_mdio_cmd_write(sc, cmd))) goto cleanup; /* Issue the read */ cmd = BHND_PCIE_MDIODATA_ADDR(phy, blk_reg); error = bhnd_pcie_mdio_cmd_read(sc, cmd, &val); cleanup: bhnd_pcie_mdio_disable(sc); BHND_PCI_UNLOCK(sc); if (error) return (~0U); return (val); } int bhnd_pcie_mdio_write_ext(struct bhnd_pci_softc *sc, int phy, int devaddr, int reg, int val) { uint32_t cmd; uint16_t blk; uint8_t blk_reg; int error; if (devaddr == MDIO_DEVADDR_NONE) return (bhnd_pcie_mdio_write(sc, phy, reg, val)); /* Extended register access is only supported for the SerDes device, * using the non-standard C22 extended address mechanism */ if (!(sc->quirks & BHND_PCI_QUIRK_SD_C22_EXTADDR)) return (~0U); if (phy != BHND_PCIE_PHYADDR_SD || devaddr != BHND_PCIE_DEVAD_SD) return (~0U); /* Enable MDIO access */ BHND_PCI_LOCK(sc); bhnd_pcie_mdio_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_PCIE_MDIODATA_ADDR(phy, BHND_PCIE_SD_ADDREXT) | (blk & BHND_PCIE_MDIODATA_DATA_MASK); if ((error = bhnd_pcie_mdio_cmd_write(sc, cmd))) goto cleanup; /* Issue the write */ cmd = BHND_PCIE_MDIODATA_ADDR(phy, blk_reg) | (val & BHND_PCIE_MDIODATA_DATA_MASK); error = bhnd_pcie_mdio_cmd_write(sc, cmd); cleanup: bhnd_pcie_mdio_disable(sc); BHND_PCI_UNLOCK(sc); return (error); } static device_method_t bhnd_pci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, bhnd_pci_generic_probe), DEVMETHOD(device_attach, bhnd_pci_generic_attach), DEVMETHOD(device_detach, bhnd_pci_generic_detach), DEVMETHOD(device_suspend, bhnd_pci_generic_suspend), DEVMETHOD(device_resume, bhnd_pci_generic_resume), /* Bus interface */ DEVMETHOD(bus_add_child, bhnd_pci_add_child), DEVMETHOD(bus_child_deleted, bhnd_pci_child_deleted), DEVMETHOD(bus_print_child, bus_generic_print_child), DEVMETHOD(bus_get_resource_list, bhnd_pci_get_resource_list), DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), DEVMETHOD(bus_delete_resource, bus_generic_rl_delete_resource), DEVMETHOD(bus_alloc_resource, bus_generic_rl_alloc_resource), DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource), DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource), DEVMETHOD_END }; DEFINE_CLASS_0(bhnd_pci, bhnd_pci_driver, bhnd_pci_methods, sizeof(struct bhnd_pci_softc)); MODULE_DEPEND(bhnd_pci, bhnd, 1, 1, 1); MODULE_DEPEND(bhnd_pci, pci, 1, 1, 1); MODULE_VERSION(bhnd_pci, 1); Index: head/sys/dev/bhnd/cores/pci/bhnd_pci_hostb.c =================================================================== --- head/sys/dev/bhnd/cores/pci/bhnd_pci_hostb.c (revision 299995) +++ head/sys/dev/bhnd/cores/pci/bhnd_pci_hostb.c (revision 299996) @@ -1,453 +1,466 @@ /*- * 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 BHND PCI/PCIe-Gen1 PCI-Host Bridge. * * This driver handles all interactions with PCI bridge cores operating in * endpoint mode. * * Host-level PCI operations are handled at the bhndb bridge level by the * bhndb_pci driver. */ #include #include #include #include #include #include #include #include #include #include #include "bhnd_pcireg.h" #include "bhnd_pci_hostbvar.h" #define BHND_PCI_ASSERT_QUIRK(_sc, _name) \ KASSERT((_sc)->quirks & (_name), ("quirk " __STRING(_name) " not set")) -#define BHND_PCI_DEV(_core, _quirks) \ - BHND_DEVICE(_core, "", _quirks, BHND_DF_HOSTB) +#define BHND_PCI_DEV(_core, _quirks, _chip_quirks) \ + BHND_DEVICE(_core, "", _quirks, _chip_quirks, BHND_DF_HOSTB) static const struct bhnd_device_quirk bhnd_pci_quirks[]; static const struct bhnd_device_quirk bhnd_pcie_quirks[]; +static const struct bhnd_chip_quirk bhnd_pcie_chip_quirks[]; static int bhnd_pci_wars_early_once(struct bhnd_pcihb_softc *sc); static int bhnd_pci_wars_hwup(struct bhnd_pcihb_softc *sc); static int bhnd_pci_wars_hwdown(struct bhnd_pcihb_softc *sc); /* * device/quirk tables */ static const struct bhnd_device bhnd_pci_devs[] = { - BHND_PCI_DEV(PCI, bhnd_pci_quirks), - BHND_PCI_DEV(PCIE, bhnd_pcie_quirks), + BHND_PCI_DEV(PCI, bhnd_pci_quirks, NULL), + BHND_PCI_DEV(PCIE, bhnd_pcie_quirks, bhnd_pcie_chip_quirks), BHND_DEVICE_END }; static const struct bhnd_device_quirk bhnd_pci_quirks[] = { { BHND_HWREV_ANY, BHND_PCI_QUIRK_SBTOPCI2_PREF_BURST }, { BHND_HWREV_GTE(11), BHND_PCI_QUIRK_SBTOPCI2_READMULTI | BHND_PCI_QUIRK_CLKRUN_DSBL }, BHND_DEVICE_QUIRK_END }; static const struct bhnd_device_quirk bhnd_pcie_quirks[] = { { BHND_HWREV_EQ (0), BHND_PCIE_QUIRK_SDR9_L0s_HANG }, { BHND_HWREV_RANGE (0, 1), BHND_PCIE_QUIRK_UR_STATUS_FIX }, { BHND_HWREV_EQ (1), BHND_PCIE_QUIRK_PCIPM_REQEN }, { BHND_HWREV_RANGE (3, 5), BHND_PCIE_QUIRK_ASPM_OVR | BHND_PCIE_QUIRK_SDR9_POLARITY | BHND_PCIE_QUIRK_SDR9_NO_FREQRETRY }, { BHND_HWREV_LTE (6), BHND_PCIE_QUIRK_L1_IDLE_THRESH }, { BHND_HWREV_GTE (6), BHND_PCIE_QUIRK_SPROM_L23_PCI_RESET }, { BHND_HWREV_EQ (7), BHND_PCIE_QUIRK_SERDES_NOPLLDOWN }, { BHND_HWREV_GTE (8), BHND_PCIE_QUIRK_L1_TIMER_PERF }, { BHND_HWREV_GTE (10), BHND_PCIE_QUIRK_SD_C22_EXTADDR }, BHND_DEVICE_QUIRK_END }; +static const struct bhnd_chip_quirk bhnd_pcie_chip_quirks[] = { + /* Apple boards on which BHND_BFL2_PCIEWAR_OVR should be assumed + * to be set. */ + {{ BHND_CHIP_BVENDOR (PCI_VENDOR_APPLE), + BHND_CHIP_SROMREV (HWREV_EQ(4)), + BHND_CHIP_BREV (HWREV_LTE(0x71)) }, + BHND_PCIE_QUIRK_BFL2_PCIEWAR_EN }, + + BHND_CHIP_QUIRK_END +}; + // Quirk handling TODO // WARs for the following are not yet implemented: // - BHND_PCIE_QUIRK_ASPM_OVR +// - BHND_PCIE_QUIRK_BFL2_PCIEWAR_EN // - 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) #define BHND_PCI_SOFTC(_sc) (&((_sc)->common)) #define BHND_PCI_READ_2(_sc, _reg) \ bhnd_bus_read_2(BHND_PCI_SOFTC(_sc)->mem_res, (_reg)) #define BHND_PCI_READ_4(_sc, _reg) \ bhnd_bus_read_4(BHND_PCI_SOFTC(_sc)->mem_res, (_reg)) #define BHND_PCI_WRITE_2(_sc, _reg, _val) \ bhnd_bus_write_2(BHND_PCI_SOFTC(_sc)->mem_res, (_reg), (_val)) #define BHND_PCI_WRITE_4(_sc, _reg, _val) \ bhnd_bus_write_4(BHND_PCI_SOFTC(_sc)->mem_res, (_reg), (_val)) #define BHND_PCI_PROTO_READ_4(_sc, _reg) \ bhnd_pcie_read_proto_reg(BHND_PCI_SOFTC(_sc), (_reg)) #define BHND_PCI_PROTO_WRITE_4(_sc, _reg, _val) \ bhnd_pcie_write_proto_reg(BHND_PCI_SOFTC(_sc), (_reg), (_val)) #define BHND_PCI_MDIO_READ(_sc, _phy, _reg) \ bhnd_pcie_mdio_read(BHND_PCI_SOFTC(_sc), (_phy), (_reg)) #define BHND_PCI_MDIO_WRITE(_sc, _phy, _reg, _val) \ bhnd_pcie_mdio_write(BHND_PCI_SOFTC(_sc), (_phy), (_reg), (_val)) #define BPCI_REG_SET(_regv, _attr, _val) \ BHND_PCI_REG_SET((_regv), BHND_ ## _attr, (_val)) #define BPCI_REG_GET(_regv, _attr) \ BHND_PCI_REG_GET((_regv), BHND_ ## _attr) #define BPCI_CMN_REG_SET(_regv, _attr, _val) \ BHND_PCI_CMN_REG_SET(BHND_PCI_SOFTC(_sc)->regfmt, (_regv), \ BHND_ ## _attr, (_val)) #define BPCI_CMN_REG_GET(_regv, _attr) \ BHND_PCI_CMN_REG_GET(BHND_PCI_SOFTC(_sc)->regfmt, (_regv), \ BHND_ ## _attr) static int bhnd_pci_hostb_attach(device_t dev) { struct bhnd_pcihb_softc *sc; int error; sc = device_get_softc(dev); sc->quirks = bhnd_device_quirks(dev, bhnd_pci_devs, sizeof(bhnd_pci_devs[0])); if ((error = bhnd_pci_generic_attach(dev))) return (error); /* Apply early single-shot work-arounds */ if ((error = bhnd_pci_wars_early_once(sc))) { bhnd_pci_generic_detach(dev); return (error); } /* Apply attach/resume work-arounds */ if ((error = bhnd_pci_wars_hwup(sc))) { bhnd_pci_generic_detach(dev); return (error); } return (0); } static int bhnd_pci_hostb_detach(device_t dev) { struct bhnd_pcihb_softc *sc; int error; sc = device_get_softc(dev); /* Apply suspend/detach work-arounds */ if ((error = bhnd_pci_wars_hwdown(sc))) return (error); return (bhnd_pci_generic_detach(dev)); } static int bhnd_pci_hostb_suspend(device_t dev) { struct bhnd_pcihb_softc *sc; int error; sc = device_get_softc(dev); /* Apply suspend/detach work-arounds */ if ((error = bhnd_pci_wars_hwdown(sc))) return (error); return (bhnd_pci_generic_suspend(dev)); } static int bhnd_pci_hostb_resume(device_t dev) { struct bhnd_pcihb_softc *sc; int error; sc = device_get_softc(dev); if ((error = bhnd_pci_generic_resume(dev))) return (error); /* Apply attach/resume work-arounds */ if ((error = bhnd_pci_wars_hwup(sc))) { bhnd_pci_generic_detach(dev); 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 bhnd_pci_wars_early_once(struct bhnd_pcihb_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 (sc->quirks & BHND_PCIE_QUIRK_SDR9_POLARITY) { uint32_t st; bool inv; st = BHND_PCI_PROTO_READ_4(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 bhnd_pci_wars_hwup(struct bhnd_pcihb_softc *sc) { /* Note that the order here matters; these work-arounds * should not be re-ordered without careful review of their * interdependencies */ /* Enable PCI prefetch/burst/readmulti flags */ if (sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_PREF_BURST || sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_READMULTI) { uint32_t sbp2; sbp2 = BHND_PCI_READ_4(sc, BHND_PCI_SBTOPCI2); if (sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_PREF_BURST) sbp2 |= (BHND_PCI_SBTOPCI_PREF|BHND_PCI_SBTOPCI_BURST); if (sc->quirks & BHND_PCI_QUIRK_SBTOPCI2_READMULTI) sbp2 |= BHND_PCI_SBTOPCI_RC_READMULTI; BHND_PCI_WRITE_4(sc, BHND_PCI_SBTOPCI2, sbp2); } /* Disable PCI CLKRUN# */ if (sc->quirks & BHND_PCI_QUIRK_CLKRUN_DSBL) { uint32_t ctl; ctl = BHND_PCI_READ_4(sc, BHND_PCI_CLKRUN_CTL); ctl |= BHND_PCI_CLKRUN_DSBL; BHND_PCI_WRITE_4(sc, BHND_PCI_CLKRUN_CTL, ctl); } /* Enable TLP unmatched address handling work-around */ if (sc->quirks & BHND_PCIE_QUIRK_UR_STATUS_FIX) { uint32_t wrs; wrs = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_TLP_WORKAROUNDSREG); wrs |= BHND_PCIE_TLP_WORKAROUND_URBIT; BHND_PCI_PROTO_WRITE_4(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 (sc->quirks & BHND_PCIE_QUIRK_SDR9_L0s_HANG) { uint16_t sdv; /* Set RX track/acquire timers to 2.064us/40.96us */ sdv = BPCI_REG_SET(0, PCIE_SDR9_RX_TIMER1_LKTRK, (2064/16)); sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_TIMER1_LKACQ, (40960/1024)); BHND_PCI_MDIO_WRITE(sc, 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_SET(sdv, PCIE_SDR9_RX_CDR_FREQ_OVR, 0x0); BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX, BHND_PCIE_SDR9_RX_CDR, sdv); /* Apply CDR BW tunings */ sdv = 0; sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_INTGTRK, 0x2); sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_INTGACQ, 0x4); sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_PROPTRK, 0x6); sdv = BPCI_REG_SET(sdv, PCIE_SDR9_RX_CDRBW_PROPACQ, 0x6); BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX, BHND_PCIE_SDR9_RX_CDRBW, sdv); } /* Force correct SerDes polarity */ if (sc->quirks & BHND_PCIE_QUIRK_SDR9_POLARITY) { uint16_t rxctl; rxctl = BHND_PCI_MDIO_READ(sc, 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; BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_TXRX, BHND_PCIE_SDR9_RX_CTRL, rxctl); } /* Disable startup retry on PLL frequency detection failure */ if (sc->quirks & BHND_PCIE_QUIRK_SDR9_NO_FREQRETRY) { uint16_t pctl; pctl = BHND_PCI_MDIO_READ(sc, BHND_PCIE_PHY_SDR9_PLL, BHND_PCIE_SDR9_PLL_CTRL); pctl &= ~BHND_PCIE_SDR9_PLL_CTRL_FREQDET_EN; BHND_PCI_MDIO_WRITE(sc, BHND_PCIE_PHY_SDR9_PLL, BHND_PCIE_SDR9_PLL_CTRL, pctl); } /* Explicitly enable PCI-PM */ if (sc->quirks & BHND_PCIE_QUIRK_PCIPM_REQEN) { uint32_t lcreg; lcreg = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_DLLP_LCREG); lcreg |= BHND_PCIE_DLLP_LCREG_PCIPM_EN; BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_LCREG, lcreg); } /* Adjust L1 timer to fix slow L1->L0 transitions */ if (sc->quirks & BHND_PCIE_QUIRK_L1_IDLE_THRESH) { uint32_t pmt; pmt = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_DLLP_PMTHRESHREG); pmt = BPCI_REG_SET(pmt, PCIE_L1THRESHOLDTIME, BHND_PCIE_L1THRESHOLD_WARVAL); BHND_PCI_PROTO_WRITE_4(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 (sc->quirks & BHND_PCIE_QUIRK_L1_TIMER_PERF) { uint32_t pmt; pmt = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_DLLP_PMTHRESHREG); pmt |= BHND_PCIE_ASPMTIMER_EXTEND; BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_PMTHRESHREG, pmt); } /* Enable L23READY_EXIT_NOPRST if not already set in SPROM. */ if (sc->quirks & BHND_PCIE_QUIRK_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 = BHND_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; BHND_PCI_WRITE_2(sc, reg, cfg); } } return (0); } /** * Apply any hardware workarounds that are required upon detach or suspend * of the bridge device. */ static int bhnd_pci_wars_hwdown(struct bhnd_pcihb_softc *sc) { /* 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 (sc->quirks & BHND_PCIE_QUIRK_L1_TIMER_PERF) { uint32_t pmt; pmt = BHND_PCI_PROTO_READ_4(sc, BHND_PCIE_DLLP_PMTHRESHREG); pmt &= ~BHND_PCIE_ASPMTIMER_EXTEND; BHND_PCI_PROTO_WRITE_4(sc, BHND_PCIE_DLLP_PMTHRESHREG, pmt); } return (0); } static device_method_t bhnd_pci_hostb_methods[] = { /* Device interface */ 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_1(bhnd_pci_hostb, bhnd_pci_hostb_driver, bhnd_pci_hostb_methods, sizeof(struct bhnd_pcihb_softc), bhnd_pci_driver); 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, bhnd, 1, 1, 1); MODULE_DEPEND(bhnd_pci_hostb, bhnd_pci, 1, 1, 1); Index: head/sys/dev/bhnd/cores/pci/bhnd_pci_hostbvar.h =================================================================== --- head/sys/dev/bhnd/cores/pci/bhnd_pci_hostbvar.h (revision 299995) +++ head/sys/dev/bhnd/cores/pci/bhnd_pci_hostbvar.h (revision 299996) @@ -1,194 +1,201 @@ /*- * 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_PCI_BHND_PCI_HOSTBVAR_H_ #define _BHND_CORES_PCI_BHND_PCI_HOSTBVAR_H_ /* * PCI/PCIe-Gen1 Host Bridge definitions. */ #include #include #include "bhnd_pcivar.h" DECLARE_CLASS(bhnd_pci_hostb_driver); /* * PCI/PCIe-Gen1 endpoint-mode device quirks */ enum { /** No quirks */ BHND_PCI_QUIRK_NONE = 0, /** * SBTOPCI_PREF and SBTOPCI_BURST must be set on the * SSB_PCICORE_SBTOPCI2 register. */ BHND_PCI_QUIRK_SBTOPCI2_PREF_BURST = (1<<1), /** * SBTOPCI_RC_READMULTI must be set on the SSB_PCICORE_SBTOPCI2 * register. */ BHND_PCI_QUIRK_SBTOPCI2_READMULTI = (1<<2), /** * 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. */ BHND_PCI_QUIRK_CLKRUN_DSBL = (1<<3), /** * 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. */ BHND_PCIE_QUIRK_UR_STATUS_FIX = (1<<4), /** * PCI-PM power management must be explicitly enabled via * the data link control register. */ BHND_PCIE_QUIRK_PCIPM_REQEN = (1<<5), /** * 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. */ BHND_PCIE_QUIRK_SDR9_L0s_HANG = (1<<6), /** * The idle time for entering L1 low-power state must be * explicitly set (to 114ns) to fix slow L1->L0 transition issues. */ BHND_PCIE_QUIRK_L1_IDLE_THRESH = (1<<7), /** * The ASPM L1 entry timer should be extended for better performance, * and restored for better power savings. */ BHND_PCIE_QUIRK_L1_TIMER_PERF = (1<<8), /** * 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. */ BHND_PCIE_QUIRK_ASPM_OVR = (1<<9), - + /** + * A subset of Apple devices did not set the BHND_BFL2_PCIEWAR_OVR + * flag in SPROM; on these devices, the BHND_BFL2_PCIEWAR_OVR flag + * should always be treated as if set. + */ + BHND_PCIE_QUIRK_BFL2_PCIEWAR_EN = (1<<10), + + /** * Fix SerDes polarity on SerDes <= rev9 devices. * * The SerDes polarity must be saved at device attachment, and * restored on suspend/resume. */ - BHND_PCIE_QUIRK_SDR9_POLARITY = (1<<10), + BHND_PCIE_QUIRK_SDR9_POLARITY = (1<<11), /** * SerDes PLL down flag must be manually disabled (by ChipCommon) on * resume. */ - BHND_PCIE_QUIRK_SERDES_NOPLLDOWN = (1<<11), + BHND_PCIE_QUIRK_SERDES_NOPLLDOWN = (1<<12), /** * 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 */ - BHND_PCIE_QUIRK_SPROM_L23_PCI_RESET = (1<<12), + BHND_PCIE_QUIRK_SPROM_L23_PCI_RESET = (1<<13), /** * 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. */ - BHND_PCIE_QUIRK_SD_C22_EXTADDR = (1<<13), + BHND_PCIE_QUIRK_SD_C22_EXTADDR = (1<<14), /** * 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. */ - BHND_PCIE_QUIRK_SDR9_NO_FREQRETRY = (1<<14), + BHND_PCIE_QUIRK_SDR9_NO_FREQRETRY = (1<<15), }; /** * bhnd_pci_hostb driver instance state. */ struct bhnd_pcihb_softc { struct bhnd_pci_softc common; /**< common bhnd_pci state */ uint32_t quirks; /**< hostb device quirks */ /** BHND_PCIE_QUIRK_SDR9_POLARITY state. */ 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; }; #endif /* _BHND_CORES_PCI_BHND_PCI_HOSTBVAR_H_ */ \ No newline at end of file Index: head/sys/dev/bhnd/nvram/nvram_map =================================================================== --- head/sys/dev/bhnd/nvram/nvram_map (revision 299995) +++ head/sys/dev/bhnd/nvram/nvram_map (revision 299996) @@ -1,1445 +1,1450 @@ #- # Copyright (c) 2015-2016 Landon Fuller # Copyright (C) 2008-2015, Broadcom Corporation. # All Rights Reserved. # # The contents of this file (variable names, descriptions, and offsets) were # extracted or derived from Broadcom's ISC-licensed sources. # # 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$ # # NVRAM variable definitions and revision-specific SPROM offsets. # # Processed by nvram_map_gen.awk to produce bhnd_nvram_map.h # # NOTE: file was originally generated automatically by using libclang # to analyze and extract format information and descriptions from Broadcom's # available ISC-licensed CIS and SROM code and associated headers. # +# Board Info +# + +u16 boardvendor {} # PCI vendor ID (SoC NVRAM-only) +u16 subvid { srom >= 2 0x6 } # PCI subvendor ID +u16 devid { srom >= 8 0x60 } # PCI device ID + +u32 boardflags { + srom 1 u16 0x72 + srom 2 u16 0x72 | u16 0x38 (<<16) + srom 3 u16 0x72 | u16 0x7A (<<16) + srom 4 0x44 + srom 5-7 0x4A + srom >= 8 0x84 +} +u32 boardflags2 { + srom 4 0x48 + srom 5-7 0x4E + srom >= 8 0x88 +} +u32 boardflags3 { + srom >= 11 0x8C +} + +# Board serial number, independent of mac addr +u16 boardnum { + srom 1-2 0x4C + srom 3 0x4E + srom 4 0x50 + srom 5-7 0x56 + srom 8-10 0x90 + srom >= 11 0x94 +} + +# Board revision +u16 boardrev { + srom 1-3 u8 0x5D + srom 4-7 0x42 + srom >= 8 0x82 +} + +# Board type +u16 boardtype { + srom >= 2 0x4 +} + +# SROM revision +u8 sromrev { + srom 1-3 0x74 + srom 4-9 0x1B6 + srom 10 0x1CA + srom 11 0x1D2 +} + # Antennas available u8 aa2g { srom 1-3 0x5C (&0x30, >>4) srom 4-7 0x5D srom 8-10 0x9D srom >= 11 0xA1 } u8 aa5g { srom 1-3 0x5C (&0xC0, >>6) srom 4-7 0x5C srom 8-10 0x9C srom >= 11 0xA0 } # ACPHY PA trimming parameters: 40 u16[12] pa5gbw40a0 { srom >= 11 0x110 } # ACPHY PA trimming parameters: 80 u16[12] pa5gbw80a0 { srom >= 11 0x138 } # ACPHY PA trimming parameters: 40/80 u16[12] pa5gbw4080a0 { srom >= 11 0x138 } u16[12] pa5gbw4080a1 { srom >= 11 u16 0xB6, u16 0xBC, u16 0xCE, u16 0xD4, u16[8] 0x128 } # ACPHY PA trimming parameters: CCK u16[3] pa2gccka0 { srom >= 11 0x102 } # ACPHY Power-per-rate 2gpo u16 dot11agofdmhrbw202gpo { srom >= 11 0x15C } u16 ofdmlrbw202gpo { srom >= 11 0x15E } # ACPHY Power-per-rate 5gpo u32 mcsbw805glpo { srom >= 11 0x168 } u32 mcsbw805gmpo { srom >= 11 0x178 } u32 mcsbw805ghpo { srom >= 11 0x188 } u16 mcslr5glpo { srom >= 11 0x190 (&0xFFF) } u16 mcslr5gmpo { srom >= 11 0x192 } u16 mcslr5ghpo { srom >= 11 0x194 } # ACPHY Power-per-rate sbpo u16 sb20in40hrpo { srom >= 11 0x196 } u16 sb20in80and160hr5glpo { srom >= 11 0x198 } u16 sb40and80hr5glpo { srom >= 11 0x19A } u16 sb20in80and160hr5gmpo { srom >= 11 0x19C } u16 sb40and80hr5gmpo { srom >= 11 0x19E } u16 sb20in80and160hr5ghpo { srom >= 11 0x1A0 } u16 sb40and80hr5ghpo { srom >= 11 0x1A2 } u16 sb20in40lrpo { srom >= 11 0x1A4 } u16 sb20in80and160lr5glpo { srom >= 11 0x1A6 } u16 sb40and80lr5glpo { srom >= 11 0x1A8 } u16 sb20in80and160lr5gmpo { srom >= 11 0x1AA } u16 sb40and80lr5gmpo { srom >= 11 0x1AC } u16 sb20in80and160lr5ghpo { srom >= 11 0x1AE } u16 sb40and80lr5ghpo { srom >= 11 0x1B0 } u16 dot11agduphrpo { srom >= 11 0x1B2 } u16 dot11agduplrpo { srom >= 11 0x1B4 } # Antenna gain u8 ag0 { srom 1-3 0x75 srom 4-7 0x5F srom 8-10 0x9F } u8 ag1 { srom 1-3 0x74 srom 4-7 0x5E srom 8-10 0x9E } u8 ag2 { srom 4-7 0x61 srom 8-10 0xA1 } u8 ag3 { srom 4-7 0x60 srom 8-10 0xA0 } u8 agbg0 { srom >= 11 0xA2 } u8 agbg1 { srom >= 11 0xA3 } u8 agbg2 { srom >= 11 0xA4 } u8 aga0 { srom >= 11 0xA5 } u8 aga1 { srom >= 11 0xA6 } u8 aga2 { srom >= 11 0xA7 } -# board flags -u32 boardflags { - srom 1 u16 0x72 - srom 2 u16 0x72 | u16 0x38 (<<16) - srom 3 u16 0x72 | u16 0x7A (<<16) - srom 4 0x44 - srom 5-7 0x4A - srom >= 8 0x84 -} -u32 boardflags2 { - srom 4 0x48 - srom 5-7 0x4E - srom >= 8 0x88 -} -u32 boardflags3 { - srom >= 11 0x8C -} - -# board serial number, independent of mac addr -u16 boardnum { - srom 1-2 0x4C - srom 3 0x4E - srom 4 0x50 - srom 5-7 0x56 - srom 8-10 0x90 - srom >= 11 0x94 -} - -# One byte board revision -u16 boardrev { - srom 1-3 u8 0x5D - srom 4-7 0x42 - srom >= 8 0x82 -} - -# 2 bytes; boardtype -u16 boardtype { - srom >= 2 0x4 -} - # Default country code (sromrev == 1) u8 cc { srom 1 0x5C (&0xF) } # 2 bytes each # CCK Power offsets for 20 MHz rates (11, 5.5, 2, 1Mbps) # cckbw202gpo cckbw20ul2gpo # u16 cckbw202gpo { srom 9-10 0x140 srom >= 11 0x150 } u16 cckbw20ul2gpo { srom 9-10 0x142 srom >= 11 0x152 } # Country code (2 bytes ascii + 1 byte cctl) # in rev 2 # char[2] ccode { sfmt ccode srom 0-3 0x76 srom 4 0x52 srom 5-7 0x44 srom 8-10 0x92 srom >= 11 0x96 } # 2 byte; txchain, rxchain u8 txchain { all1 ignore srom 4-7 0x7B (&0xF) srom 8-10 0xA3 (&0xF) srom >= 11 0xA9 (&0xF) } u8 rxchain { all1 ignore srom 4-7 0x7B (&0xF0, >>4) srom 8-10 0xA3 (&0xF0, >>4) srom >= 11 0xA9 (&0xF0, >>4) } u16 antswitch { all1 ignore srom 4-7 u8 0x7A srom 8-10 u8 0xA2 srom >= 11 u8 0xA8 } -# PCI device id -private u16 devid { - srom >= 8 u16 0x60 -} - u8 elna2g { srom 8-10 0xBB } u8 elna5g { srom 8-10 0xBA } # 11n front-end specification u8 antswctl2g { srom 8-10 0xAE (&0xF8, >>3) } u8 triso2g { srom 8-10 0xAE (&0x7) } u8 pdetrange2g { srom 8-10 0xAF (&0xF8, >>3) } u8 extpagain2g { srom 8-10 0xAF (&0x6, >>1) } u8 tssipos2g { srom 8-10 0xAF (&0x1) } u8 antswctl5g { srom 8-10 0xB0 (&0xF8, >>3) } u8 triso5g { srom 8-10 0xB0 (&0x7) } u8 pdetrange5g { srom 8-10 0xB1 (&0xF8, >>3) } u8 extpagain5g { srom 8-10 0xB1 (&0x6, >>1) } u8 tssipos5g { srom 8-10 0xB1 (&0x1) } # FEM config u8 femctrl { sfmt decimal srom >= 11 0xAA (&0xF8, >>3) } u8 papdcap2g { sfmt decimal srom >= 11 0xAA (&0x4, >>2) } u8 tworangetssi2g { sfmt decimal srom >= 11 0xAA (&0x2, >>1) } u8 pdgain2g { sfmt decimal srom >= 11 u16 0xAA (&0x1F0, >>4) } u8 epagain2g { sfmt decimal srom >= 11 0xAB (&0xE, >>1) } u8 tssiposslope2g { sfmt decimal srom >= 11 0xAB (&0x1) } u8 gainctrlsph { sfmt decimal srom >= 11 0xAC (&0xF8, >>3) } u8 papdcap5g { sfmt decimal srom >= 11 0xAC (&0x4, >>2) } u8 tworangetssi5g { sfmt decimal srom >= 11 0xAC (&0x2, >>1) } u8 pdgain5g { sfmt decimal srom >= 11 u16 0xAC (&0x1F0, >>4) } u8 epagain5g { sfmt decimal srom >= 11 0xAD (&0xE, >>1) } u8 tssiposslope5g { sfmt decimal srom >= 11 0xAD (&0x1) } # LED duty cycle u8[2] leddc { sfmt led_dc all1 ignore srom 3 0x7C srom 4 0x5A srom 5-7 0x5A srom 8-10 0x9A srom >= 11 0x9E } # LED set u8 ledbh0 { all1 ignore srom 1-3 0x65 srom 4 0x57 srom 5-7 0x77 srom 8-10 0x97 srom >= 11 0x9B } u8 ledbh1 { all1 ignore srom 1-3 0x64 srom 4 0x56 srom 5-7 0x76 srom 8-10 0x96 srom >= 11 0x9A } u8 ledbh2 { all1 ignore srom 1-3 0x67 srom 4 0x59 srom 5-7 0x79 srom 8-10 0x99 srom >= 11 0x9D } u8 ledbh3 { all1 ignore srom 1-3 0x66 srom 4 0x58 srom 5-7 0x78 srom 8-10 0x98 srom >= 11 0x9C } # 2 bytes total # Additional power offset for Legacy Dup40 transmissions. # Applied in addition to legofdmbw20ulXpo, X=2g, 5gl, 5gm, or 5gh. # LSB nibble: 2G band, MSB nibble: 5G band high subband. # leg40dup5ghpo, leg40dup5gmpo, leg40dup5glpo, leg40dup2gpo # u16 legofdm40duppo { srom 9-10 0x196 } # 4 bytes each # OFDM power offsets for 20 MHz Legacy rates # (54, 48, 36, 24, 18, 12, 9, 6 Mbps) # legofdmbw202gpo legofdmbw20ul2gpo # u32 legofdmbw202gpo { srom 9-10 0x144 } u32 legofdmbw20ul2gpo { srom 9-10 0x148 } # 4 bytes each # 5G band: OFDM power offsets for 20 MHz Legacy rates # (54, 48, 36, 24, 18, 12, 9, 6 Mbps) # low subband : legofdmbw205glpo legofdmbw20ul2glpo # mid subband :legofdmbw205gmpo legofdmbw20ul2gmpo # high subband :legofdmbw205ghpo legofdmbw20ul2ghpo # u32 legofdmbw205glpo { srom 9-10 0x14C } u32 legofdmbw20ul5glpo { srom 9-10 0x150 } u32 legofdmbw205gmpo { srom 9-10 0x154 } u32 legofdmbw20ul5gmpo { srom 9-10 0x158 } u32 legofdmbw205ghpo { srom 9-10 0x15C } u32 legofdmbw20ul5ghpo { srom 9-10 0x160 } # mac addr override for the standard CIS LAN_NID u8[6] macaddr { sfmt macaddr srom 3 u8 0x4B, u8 0x4A, u8 0x4D, u8 0x4C, u8 0x4F, u8 0x4E srom 4 u8 0x4D, u8 0x4C, u8 0x4F, u8 0x4E, u8 0x51, u8 0x50 srom 5-7 u8 0x53, u8 0x52, u8 0x55, u8 0x54, u8 0x57, u8 0x56 srom 8-10 u8 0x8D, u8 0x8C, u8 0x8F, u8 0x8E, u8 0x91, u8 0x90 srom >= 11 u8 0x91, u8 0x90, u8 0x93, u8 0x92, u8 0x95, u8 0x94 } # 4 bytes each # mcs 0-7 power-offset. LSB nibble: m0, MSB nibble: m7 # mcsbw202gpo mcsbw20ul2gpo mcsbw402gpo # u32 mcsbw202gpo { srom 9-10 0x164 srom >= 11 0x154 } u32 mcsbw20ul2gpo { srom 9-10 0x168 } u32 mcsbw402gpo { srom 9-10 0x16C srom >= 11 0x158 } # 4 bytes each # 5G high subband mcs 0-7 power-offset. # LSB nibble: m0, MSB nibble: m7 # mcsbw205ghpo mcsbw20ul5ghpo mcsbw405ghpo # u32 mcsbw205ghpo { srom 9-10 0x188 srom >= 11 0x180 } u32 mcsbw20ul5ghpo { srom 9-10 0x18C } u32 mcsbw405ghpo { srom 9-10 0x190 srom >= 11 0x184 } # 4 bytes each # 5G low subband mcs 0-7 power-offset. # LSB nibble: m0, MSB nibble: m7 # mcsbw205glpo mcsbw20ul5glpo mcsbw405glpo # u32 mcsbw205glpo { srom 9-10 0x170 srom >= 11 0x160 } u32 mcsbw20ul5glpo { srom 9-10 0x174 } u32 mcsbw405glpo { srom 9-10 0x178 srom >= 11 0x164 } # 4 bytes each # 5G mid subband mcs 0-7 power-offset. # LSB nibble: m0, MSB nibble: m7 # mcsbw205gmpo mcsbw20ul5gmpo mcsbw405gmpo # u32 mcsbw205gmpo { srom 9-10 0x17C srom >= 11 0x170 } u32 mcsbw20ul5gmpo { srom 9-10 0x180 } u32 mcsbw405gmpo { srom 9-10 0x184 srom >= 11 0x174 } # 2 bytes total # mcs-32 power offset for each band/subband. # LSB nibble: 2G band, MSB nibble: # mcs322ghpo, mcs325gmpo, mcs325glpo, mcs322gpo # u16 mcs32po { srom 9-10 0x194 } u8 measpower { srom 8-10 0xB4 (&0xFE, >>1) srom >= 11 0xB0 (&0xFE, >>1) } u8 measpower1 { srom 8-10 0xBF (&0x7F) srom >= 11 0xBB (&0x7F) } u8 measpower2 { srom 8-10 u16 0xBE (&0x3F80, >>7) srom >= 11 u16 0xBA (&0x3F80, >>7) } u16 rawtempsense { srom 8-10 0xB4 (&0x1FF) srom >= 11 0xB0 (&0x1FF) } u8 noiselvl2ga0 { sfmt decimal srom 8-10 0x1AB (&0x1F) srom >= 11 0x1BD (&0x1F) } u8 noiselvl2ga1 { sfmt decimal srom 8-10 u16 0x1AA (&0x3E0, >>5) srom >= 11 u16 0x1BC (&0x3E0, >>5) } u8 noiselvl2ga2 { sfmt decimal srom 8-10 0x1AA (&0x7C, >>2) srom >= 11 0x1BC (&0x7C, >>2) } u8[4] noiselvl5ga0 { sfmt decimal srom >= 11 u8 0x1BF (&0x1F), u8 0x1C1 (&0x1F), u8 0x1C3 (&0x1F), u8 0x1C5 (&0x1F) } u8[4] noiselvl5ga1 { sfmt decimal srom >= 11 u16[4] 0x1BE (&0x3E0, >>5) } u8[4] noiselvl5ga2 { sfmt decimal srom >= 11 u8 0x1BE (&0x7C, >>2), u8 0x1C0 (&0x7C, >>2), u8 0x1C2 (&0x7C, >>2), u8 0x1C4 (&0x7C, >>2) } # paparambwver u8 paparambwver { sfmt decimal srom >= 11 0x190 (&0xF0, >>4) } # PA parameters: 8 (sromrev == 1) # or 9 (sromrev > 1) bytes # u16 pa0b0 { sfmt decimal srom 1-3 0x5E srom 8-10 0xC2 } u16 pa0b1 { sfmt decimal srom 1-3 0x60 srom 8-10 0xC4 } u16 pa0b2 { sfmt decimal srom 1-3 0x62 srom 8-10 0xC6 } u8 pa0itssit { sfmt decimal srom 1-3 0x71 srom 8-10 0xC0 } u8 pa0maxpwr { sfmt decimal srom 1-3 0x69 srom 8-10 0xC1 } u8 opo { srom 2-3 0x79 srom 8-10 0x143 } # 5G PA params u16 pa1b0 { sfmt decimal srom 1-3 0x6A srom 8-10 0xCC } u16 pa1b1 { sfmt decimal srom 1-3 0x6C srom 8-10 0xCE } u16 pa1b2 { sfmt decimal srom 1-3 0x6E srom 8-10 0xD0 } u16 pa1lob0 { sfmt decimal srom 2-3 0x3C srom 8-10 0xD2 } u16 pa1lob1 { sfmt decimal srom 2-3 0x3E srom 8-10 0xD4 } u16 pa1lob2 { sfmt decimal srom 2-3 0x40 srom 8-10 0xD6 } u16 pa1hib0 { sfmt decimal srom 2-3 0x42 srom 8-10 0xD8 } u16 pa1hib1 { sfmt decimal srom 2-3 0x44 srom 8-10 0xDA } u16 pa1hib2 { sfmt decimal srom 2-3 0x46 srom 8-10 0xDC } u8 pa1itssit { sfmt decimal srom 1-3 0x70 srom 8-10 0xC8 } u8 pa1maxpwr { sfmt decimal srom 1-3 0x68 srom 8-10 0xC9 } u8 pa1lomaxpwr { sfmt decimal srom 2-3 0x3A srom 8-10 0xCA } u8 pa1himaxpwr { sfmt decimal srom 2-3 0x3B srom 8-10 0xCB } u16 pdoffset40ma0 { srom >= 11 0xCA } u16 pdoffset40ma1 { srom >= 11 0xCC } u16 pdoffset40ma2 { srom >= 11 0xCE } u16 pdoffset80ma0 { srom >= 11 0xD0 } u16 pdoffset80ma1 { srom >= 11 0xD2 } u16 pdoffset80ma2 { srom >= 11 0xD4 } u8 pdoffset2g40ma0 { srom >= 11 0xC9 (&0xF) } u8 pdoffset2g40ma1 { srom >= 11 0xC9 (&0xF0, >>4) } u8 pdoffset2g40ma2 { srom >= 11 0xC8 (&0xF) } u8 pdoffset2g40mvalid { srom >= 11 0xC8 (&0x80, >>7) } # 40Mhz channel 2g/5g power offset u16 bw40po { srom 4-7 0x18E srom 8 0x196 } # 40Mhz channel dup 2g/5g power offset u16 bwduppo { srom 4-7 0x190 srom 8 0x198 } # cck2g/ofdm2g/ofdm5g power offset u16 cck2gpo { srom 4-7 0x138 srom 8 0x140 } u32 ofdm2gpo { srom 4-7 0x13A srom 8 0x142 } u32 ofdm5gpo { srom 4-7 0x13E srom 8 0x146 } u32 ofdm5glpo { srom 4-7 0x142 srom 8 0x14A } u32 ofdm5ghpo { srom 4-7 0x146 srom 8 0x14E } # cdd2g/5g power offset u16 cddpo { srom 4-7 0x18A srom 8 0x192 } # mcs2g power offset u16 mcs2gpo0 { srom 4-7 0x14A srom 8 0x152 } u16 mcs2gpo1 { srom 4-7 0x14C srom 8 0x154 } u16 mcs2gpo2 { srom 4-7 0x14E srom 8 0x156 } u16 mcs2gpo3 { srom 4-7 0x150 srom 8 0x158 } u16 mcs2gpo4 { srom 4-7 0x152 srom 8 0x15A } u16 mcs2gpo5 { srom 4-7 0x154 srom 8 0x15C } u16 mcs2gpo6 { srom 4-7 0x156 srom 8 0x15E } u16 mcs2gpo7 { srom 4-7 0x158 srom 8 0x160 } # mcs5g low-high band power offset u16 mcs5glpo0 { srom 4-7 0x16A srom 8 0x172 } u16 mcs5glpo1 { srom 4-7 0x16C srom 8 0x174 } u16 mcs5glpo2 { srom 4-7 0x16E srom 8 0x176 } u16 mcs5glpo3 { srom 4-7 0x170 srom 8 0x178 } u16 mcs5glpo4 { srom 4-7 0x172 srom 8 0x17A } u16 mcs5glpo5 { srom 4-7 0x174 srom 8 0x17C } u16 mcs5glpo6 { srom 4-7 0x176 srom 8 0x17E } u16 mcs5glpo7 { srom 4-7 0x178 srom 8 0x180 } u16 mcs5ghpo0 { srom 4-7 0x17A srom 8 0x182 } u16 mcs5ghpo1 { srom 4-7 0x17C srom 8 0x184 } u16 mcs5ghpo2 { srom 4-7 0x17E srom 8 0x186 } u16 mcs5ghpo3 { srom 4-7 0x180 srom 8 0x188 } u16 mcs5ghpo4 { srom 4-7 0x182 srom 8 0x18A } u16 mcs5ghpo5 { srom 4-7 0x184 srom 8 0x18C } u16 mcs5ghpo6 { srom 4-7 0x186 srom 8 0x18E } u16 mcs5ghpo7 { srom 4-7 0x188 srom 8 0x190 } # mcs5g mid band power offset u16 mcs5gpo0 { srom 4-7 0x15A srom 8 0x162 } u16 mcs5gpo1 { srom 4-7 0x15C srom 8 0x164 } u16 mcs5gpo2 { srom 4-7 0x15E srom 8 0x166 } u16 mcs5gpo3 { srom 4-7 0x160 srom 8 0x168 } u16 mcs5gpo4 { srom 4-7 0x162 srom 8 0x16A } u16 mcs5gpo5 { srom 4-7 0x164 srom 8 0x16C } u16 mcs5gpo6 { srom 4-7 0x166 srom 8 0x16E } u16 mcs5gpo7 { srom 4-7 0x168 srom 8 0x170 } # stbc2g/5g power offset u16 stbcpo { srom 4-7 0x18C srom 8 0x194 } u8 regrev { srom 3 0x78 srom 4 0x55 srom 5-7 0x47 srom 8-10 0x95 srom >= 11 0x99 } # 4328 2G RSSI mid pt sel & board switch arch, # 2 bytes, rev 3. # u8 rssismf2g { srom 3 0x51 (&0xF) srom 8-10 0xA5 (&0xF) } u8 rssismc2g { srom 3 0x51 (&0xF0, >>4) srom 8-10 0xA5 (&0xF0, >>4) } u8 rssisav2g { srom 3 0x50 (&0x7) srom 8-10 0xA4 (&0x7) } u8 bxa2g { srom 3 0x50 (&0x18, >>3) srom 8-10 0xA4 (&0x18, >>3) } # 4328 5G RSSI mid pt sel & board switch arch, # 2 bytes, rev 3. # u8 rssismf5g { srom 3 0x53 (&0xF) srom 8-10 0xA7 (&0xF) } u8 rssismc5g { srom 3 0x53 (&0xF0, >>4) srom 8-10 0xA7 (&0xF0, >>4) } u8 rssisav5g { srom 3 0x52 (&0x7) srom 8-10 0xA6 (&0x7) } u8 bxa5g { srom 3 0x52 (&0x18, >>3) srom 8-10 0xA6 (&0x18, >>3) } u8 rxgainerr2ga0 { srom 8-10 0x19B (&0x3F) srom >= 11 0x1C7 (&0x3F) } u8 rxgainerr2ga1 { srom 8-10 u16 0x19A (&0x7C0, >>6) srom >= 11 u16 0x1C6 (&0x7C0, >>6) } u8 rxgainerr2ga2 { srom 8-10 0x19A (&0xF8, >>3) srom >= 11 0x1C6 (&0xF8, >>3) } u8[4] rxgainerr5ga0 { srom >= 11 u8 0x1C9 (&0x3F), u8 0x1CB (&0x3F), u8 0x1CD (&0x3F), u8 0x1CF (&0x3F) } u8[4] rxgainerr5ga1 { srom >= 11 u16[4] 0x1C8 (&0x7C0, >>6) } u8[4] rxgainerr5ga2 { srom >= 11 u8 0x1C8 (&0xF8, >>3), u8 0x1CA (&0xF8, >>3), u8 0x1CC (&0xF8, >>3), u8 0x1CE (&0xF8, >>3) } u8 rxgainerr5gha0 { srom 8-10 0x1A1 (&0x3F) } u8 rxgainerr5gha1 { srom 8-10 u16 0x1A0 (&0x7C0, >>6) } u8 rxgainerr5gha2 { srom 8-10 0x1A0 (&0xF8, >>3) } u8 rxgainerr5gla0 { srom 8-10 0x19D (&0x3F) } u8 rxgainerr5gla1 { srom 8-10 u16 0x19C (&0x7C0, >>6) } u8 rxgainerr5gla2 { srom 8-10 0x19C (&0xF8, >>3) } u8 rxgainerr5gma0 { srom 8-10 0x19F (&0x3F) } u8 rxgainerr5gma1 { srom 8-10 u16 0x19E (&0x7C0, >>6) } u8 rxgainerr5gma2 { srom 8-10 0x19E (&0xF8, >>3) } u8 rxgainerr5gua0 { srom 8-10 0x1A3 (&0x3F) } u8 rxgainerr5gua1 { srom 8-10 u16 0x1A2 (&0x7C0, >>6) } u8 rxgainerr5gua2 { srom 8-10 0x1A2 (&0xF8, >>3) } # 4328 2G RX power offset i8 rxpo2g { sfmt decimal srom 3 0x5B srom 8-10 0xAD } # 4328 5G RX power offset i8 rxpo5g { sfmt decimal srom 3 0x5A srom 8-10 0xAC } u16 subband5gver { srom 8-10 u8 0x1A5 (&0x7) srom >= 11 0xD6 } # 2 bytes # byte1 tempthresh # byte2 period(msb 4 bits) | hysterisis(lsb 4 bits) # u8 tempthresh { srom 8-10 0xB2 srom >= 11 0xAE } u8 temps_period { sfmt decimal srom 8-10 0xBC (&0xF) srom >= 11 0xB8 (&0xF) } u8 temps_hysteresis { sfmt decimal srom 8-10 0xBC (&0xF0, >>4) srom >= 11 0xB8 (&0xF0, >>4) } u8 tempoffset { sfmt decimal srom 8-10 0xB3 srom >= 11 0xAF } u8 tempsense_slope { srom 8-10 0xB7 srom >= 11 0xB3 } u8 tempcorrx { srom 8-10 0xB6 (&0xFC, >>2) srom >= 11 0xB2 (&0xFC, >>2) } u8 tempsense_option { srom 8-10 0xB6 (&0x3) srom >= 11 0xB2 (&0x3) } u8 phycal_tempdelta { sfmt decimal srom 8-10 0xBD srom >= 11 0xB9 } # 4328 2G TR isolation, 1 byte u8 tri2g { srom 3 0x55 srom 8-10 0xA9 } # 4328 5G TR isolation, 3 bytes u8 tri5gl { srom 3 0x57 srom 8-10 0xAB } u8 tri5g { srom 3 0x54 srom 8-10 0xA8 } u8 tri5gh { srom 3 0x56 srom 8-10 0xAA } # phy txbf rpcalvars u16 rpcal2g { srom >= 11 0x16C } u16 rpcal5gb0 { srom >= 11 0x16E } u16 rpcal5gb1 { srom >= 11 0x17C } u16 rpcal5gb2 { srom >= 11 0x17E } u16 rpcal5gb3 { srom >= 11 0x18C } # Crystal frequency in kilohertz u32 xtalfreq { sfmt decimal srom >= 11 u16 0xB4 } # N-PHY tx power workaround u8 txpid2ga0 { srom 4-7 0x63 } u8 txpid2ga1 { srom 4-7 0x62 } u8 txpid2ga2 { srom 4-7 0x65 } u8 txpid2ga3 { srom 4-7 0x64 } u8 txpid5ga0 { srom 4-7 0x67 } u8 txpid5ga1 { srom 4-7 0x66 } u8 txpid5ga2 { srom 4-7 0x69 } u8 txpid5ga3 { srom 4-7 0x68 } u8 txpid5gha0 { srom 4-7 0x6F } u8 txpid5gha1 { srom 4-7 0x6E } u8 txpid5gha2 { srom 4-7 0x71 } u8 txpid5gha3 { srom 4-7 0x70 } u8 txpid5gla0 { srom 4-7 0x6B } u8 txpid5gla1 { srom 4-7 0x6A } u8 txpid5gla2 { srom 4-7 0x6D } u8 txpid5gla3 { srom 4-7 0x6C } u16 cckPwrOffset { srom 10 0x1B4 } u8[6] et1macaddr { sfmt macaddr srom 0-2 u8 0x55, u8 0x54, u8 0x57, u8 0x56, u8 0x59, u8 0x58 } u8 eu_edthresh2g { srom 8 0x1A9 srom 9 0x199 srom 10 0x199 srom 11 0x1D1 } u8 eu_edthresh5g { srom 8 0x1A8 srom 9 0x198 srom 10 0x198 srom 11 0x1D0 } u8 freqoffset_corr { srom 8-10 0xB9 (&0xF) } u8 hw_iqcal_en { srom 8-10 0xB9 (&0x20, >>5) } u8[6] il0macaddr { sfmt macaddr srom 0-2 u8 0x49, u8 0x48, u8 0x51, u8 0x50, u8 0x53, u8 0x52 } u8 iqcal_swp_dis { srom 8-10 0xB9 (&0x10, >>4) } u8 noisecaloffset { srom 8-9 0x1B5 } u8 noisecaloffset5g { srom 8-9 0x1B4 } u8 noiselvl5gha0 { srom 8-10 0x1B1 (&0x1F) } u8 noiselvl5gha1 { srom 8-10 u16 0x1B0 (&0x3E0, >>5) } u8 noiselvl5gha2 { srom 8-10 0x1B0 (&0x7C, >>2) } u8 noiselvl5gla0 { srom 8-10 0x1AD (&0x1F) } u8 noiselvl5gla1 { srom 8-10 u16 0x1AC (&0x3E0, >>5) } u8 noiselvl5gla2 { srom 8-10 0x1AC (&0x7C, >>2) } u8 noiselvl5gma0 { srom 8-10 0x1AF (&0x1F) } u8 noiselvl5gma1 { srom 8-10 u16 0x1AE (&0x3E0, >>5) } u8 noiselvl5gma2 { srom 8-10 0x1AE (&0x7C, >>2) } u8 noiselvl5gua0 { srom 8-10 0x1B3 (&0x1F) } u8 noiselvl5gua1 { srom 8-10 u16 0x1B2 (&0x3E0, >>5) } u8 noiselvl5gua2 { srom 8-10 0x1B2 (&0x7C, >>2) } u8 pcieingress_war { srom 8-10 0x1A7 (&0xF) } u8 pdoffsetcckma0 { srom >= 11 0x18F (&0xF) } u8 pdoffsetcckma1 { srom >= 11 0x18F (&0xF0, >>4) } u8 pdoffsetcckma2 { srom >= 11 0x18E (&0xF) } u8 sar2g { srom 9-10 0x1A9 srom >= 11 0x1BB } u8 sar5g { srom 9-10 0x1A8 srom >= 11 0x1BA -} - -u16 subvid { - srom >= 2 0x6 } u32[5] swctrlmap_2g { srom 10 u32[4] 0x1B8, u16 0x1C8 } u16 tssifloor2g { srom >= 11 0xBE (&0x3FF) } u16[4] tssifloor5g { srom >= 11 0xC0 (&0x3FF) } u8 txidxcap2g { srom >= 11 u16 0x1A8 (&0xFF0, >>4) } u8 txidxcap5g { srom >= 11 u16 0x1AC (&0xFF0, >>4) } # # Any variables defined within a `struct` block will be interpreted relative to # the provided array of SPROM base addresses; this is used to define # a common layout defined at the given base addresses. # # To produce SPROM variable names matching those used in the Broadcom HND # ASCII 'key=value\0' NVRAM, the index number of the variable's # struct instance will be appended (e.g., given a variable of noiselvl5ga, the # generated variable instances will be named noiselvl5ga0, noiselvl5ga1, # noiselvl5ga2, noiselvl5ga3 ...) # # PHY chain[0-4] parameters struct phy_chains[] { srom 4-7 [0x080, 0x0AE, 0x0DC, 0x10A] srom 8-10 [0x0C0, 0x0E0, 0x100, 0x120] srom >= 11 [0x0D8, 0x100, 0x128] # AC-PHY PA parameters u8[4] maxp5ga { srom 4-7 u8 0xB srom 8-10 u8 0x9 srom >= 11 u8 0xD, u8 0xC, u8 0xF, u8 0xE } u16[3] pa2ga { srom >= 11 0x2 } u8 maxp2ga { srom 4-7 0x1 srom 8-10 0x1 srom >= 11 0x1 } u16[12] pa5ga { srom >= 11 0x10 } # AC-PHY rxgains u8 rxgains5ghtrelnabypa { srom >= 11 0x8 (&0x80, >>7) } u8 rxgains5ghelnagaina { srom >= 11 0x8 (&0x7) } u8 rxgains5gelnagaina { srom >= 11 0xA (&0x7) } u8 rxgains5gmtrelnabypa { srom >= 11 0x9 (&0x80, >>7) } u8 rxgains2gtrelnabypa { srom >= 11 0xB (&0x80, >>7) } u8 rxgains5gmtrisoa { srom >= 11 0x9 (&0x78, >>3) } u8 rxgains5gmelnagaina { srom >= 11 0x9 (&0x7) } u8 rxgains2gelnagaina { srom >= 11 0xB (&0x7) } u8 rxgains5gtrisoa { srom >= 11 0xA (&0x78, >>3) } u8 rxgains5gtrelnabypa { srom >= 11 0xA (&0x80, >>7) } u8 rxgains2gtrisoa { srom >= 11 0xB (&0x78, >>3) } u8 rxgains5ghtrisoa { srom >= 11 0x8 (&0x78, >>3) } # 11n PA parameters u16 pa5gw2a { srom 4-7 0x12 srom 8-10 0x10 } u16 pa5ghw1a { srom 4-7 0x20 srom 8-10 0x1A } u16 pa5glw3a { srom 4-7 0x1C } u16 pa5glw1a { srom 4-7 0x18 srom 8-10 0x14 } u16 pa5gw1a { srom 4-7 0x10 srom 8-10 0xE } u16 pa5glw0a { srom 4-7 0x16 srom 8-10 0x12 } u16 pa5gw3a { srom 4-7 0x14 } u16 pa5glw2a { srom 4-7 0x1A srom 8-10 0x16 } u16 pa5ghw3a { srom 4-7 0x24 } u16 pa5gw0a { srom 4-7 0xE srom 8-10 0xC } u8 maxp5gha { srom 4-7 0xD srom 8-10 0xB } u16 pa5ghw2a { srom 4-7 0x22 srom 8-10 0x1C } u16 pa5ghw0a { srom 4-7 0x1E srom 8-10 0x18 } u16 pa2gw3a { srom 4-7 0x8 } u16 pa2gw2a { srom 4-7 0x6 srom 8-10 0x6 } u16 pa2gw1a { srom 4-7 0x4 srom 8-10 0x4 } u16 pa2gw0a { srom 4-7 0x2 srom 8-10 0x2 } u8 maxp5gla { srom 4-7 0xC srom 8-10 0xA } u8 itt5ga { srom 4-7 0xA srom 8-10 0x8 } u8 itt2ga { srom 4-7 0x0 srom 8-10 0x0 } } Index: head/sys/dev/bhnd/siba/siba_bhndb.c =================================================================== --- head/sys/dev/bhnd/siba/siba_bhndb.c (revision 299995) +++ head/sys/dev/bhnd/siba/siba_bhndb.c (revision 299996) @@ -1,189 +1,206 @@ /*- * 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. */ // // TODO: PCI rev < 6 interrupt handling // // On early PCI cores (rev < 6) interrupt masking is handled via interconnect // configuration registers (SBINTVEC), rather than the PCI_INT_MASK // config register. // // On those devices, we should handle interrupts locally using SBINTVEC, rather // than delegating to our parent bhndb device. // 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) { struct siba_softc *sc; const struct bhnd_chipid *chipid; int error; sc = device_get_softc(dev); /* 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); /* Ask our parent bridge to find the corresponding bridge core */ sc->hostb_dev = BHNDB_FIND_HOSTB_DEVICE(device_get_parent(dev), dev); /* 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 int +siba_bhndb_read_board_info(device_t dev, device_t child, + struct bhnd_board_info *info) +{ + int error; + + /* Initialize with NVRAM-derived values */ + if ((error = bhnd_bus_generic_read_board_info(dev, child, info))) + return (error); + + /* Let the bridge fill in any additional data */ + return (BHNDB_POPULATE_BOARD_INFO(device_get_parent(dev), dev, info)); +} + 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), + + /* BHND interface */ + DEVMETHOD(bhnd_bus_read_board_info, siba_bhndb_read_board_info), 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, bhnd, 1, 1, 1); MODULE_DEPEND(siba_bhndb, bhndb, 1, 1, 1);