Bring over the initial rewrite of the broadcom bus support found in their

SoCs and various chips (including, famously, their wifi chips.)

This is "just" (all 20,000 lines of it) code to enumerate the various
versions of busses inside these devices, including the PCI bridge and
the direct SIBA bridge found in MIPS chips.

It also includes shared code for some bus operations (suspend, resume, etc);
EEPROM/SROM/etc parsing and other things that are shared between chips.

Eventually this'll replace the code that bwi/bwn uses for the internal
bus, as well as some apparently upcoming mips74k broadcom SoC support
which uses bwn!

Thanks to Landon Fuller <landonf@landonf.org> for all this work!

Obtained from:	https://github.com/landonf/freebsd/compare/user/landonf/bcm4331-CURRENT
This commit is contained in:
Adrian Chadd 2016-02-26 03:34:08 +00:00
parent 9021e53b29
commit 4ad7e9b01a
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=296077
58 changed files with 18833 additions and 0 deletions

482
sys/dev/bhnd/bcma/bcma.c Normal file
View file

@ -0,0 +1,482 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/systm.h>
#include <machine/bus.h>
#include "bcmavar.h"
#include "bcma_eromreg.h"
#include "bcma_eromvar.h"
int
bcma_probe(device_t dev)
{
device_set_desc(dev, "BCMA BHND bus");
return (BUS_PROBE_DEFAULT);
}
int
bcma_attach(device_t dev)
{
struct bcma_devinfo *dinfo;
device_t *devs, child;
int ndevs;
int error;
if ((error = device_get_children(dev, &devs, &ndevs)))
return (error);
/*
* Map our children's agent register block.
*/
for (int i = 0; i < ndevs; i++) {
bhnd_addr_t addr;
bhnd_size_t size;
rman_res_t r_start, r_count, r_end;
child = devs[i];
dinfo = device_get_ivars(child);
KASSERT(!device_is_suspended(child),
("bcma(4) stateful suspend handling requires that devices "
"not be suspended before bcma_attach()"));
/* Verify that the agent register block exists and is
* mappable */
if (bhnd_get_port_rid(child, BHND_PORT_AGENT, 0, 0) == -1)
continue;
/* Fetch the address of the agent register block */
error = bhnd_get_region_addr(child, BHND_PORT_AGENT, 0, 0,
&addr, &size);
if (error) {
device_printf(dev, "failed fetching agent register "
"block address for core %d\n", i);
goto cleanup;
}
/* Allocate the resource */
r_start = addr;
r_count = size;
r_end = r_start + r_count - 1;
dinfo->rid_agent = 0;
dinfo->res_agent = bhnd_alloc_resource(dev, SYS_RES_MEMORY,
&dinfo->rid_agent, r_start, r_end, r_count, RF_ACTIVE);
if (dinfo->res_agent == NULL) {
device_printf(dev, "failed allocating agent register "
"block for core %d\n", i);
error = ENXIO;
goto cleanup;
}
}
cleanup:
free(devs, M_BHND);
if (error)
return (error);
return (bhnd_generic_attach(dev));
}
int
bcma_detach(device_t dev)
{
return (bhnd_generic_detach(dev));
}
static int
bcma_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
{
const struct bcma_devinfo *dinfo;
const struct bhnd_core_info *ci;
dinfo = device_get_ivars(child);
ci = &dinfo->corecfg->core_info;
switch (index) {
case BHND_IVAR_VENDOR:
*result = ci->vendor;
return (0);
case BHND_IVAR_DEVICE:
*result = ci->device;
return (0);
case BHND_IVAR_HWREV:
*result = ci->hwrev;
return (0);
case BHND_IVAR_DEVICE_CLASS:
*result = bhnd_core_class(ci);
return (0);
case BHND_IVAR_VENDOR_NAME:
*result = (uintptr_t) bhnd_vendor_name(ci->vendor);
return (0);
case BHND_IVAR_DEVICE_NAME:
*result = (uintptr_t) bhnd_core_name(ci);
return (0);
case BHND_IVAR_CORE_INDEX:
*result = ci->core_idx;
return (0);
case BHND_IVAR_CORE_UNIT:
*result = ci->unit;
return (0);
default:
return (ENOENT);
}
}
static int
bcma_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
{
switch (index) {
case BHND_IVAR_VENDOR:
case BHND_IVAR_DEVICE:
case BHND_IVAR_HWREV:
case BHND_IVAR_DEVICE_CLASS:
case BHND_IVAR_VENDOR_NAME:
case BHND_IVAR_DEVICE_NAME:
case BHND_IVAR_CORE_INDEX:
case BHND_IVAR_CORE_UNIT:
return (EINVAL);
default:
return (ENOENT);
}
}
static void
bcma_child_deleted(device_t dev, device_t child)
{
struct bcma_devinfo *dinfo = device_get_ivars(child);
if (dinfo != NULL)
bcma_free_dinfo(dev, dinfo);
}
static struct resource_list *
bcma_get_resource_list(device_t dev, device_t child)
{
struct bcma_devinfo *dinfo = device_get_ivars(child);
return (&dinfo->resources);
}
static int
bcma_reset_core(device_t dev, device_t child, uint16_t flags)
{
struct bcma_devinfo *dinfo;
if (device_get_parent(child) != dev)
BHND_BUS_RESET_CORE(device_get_parent(dev), child, flags);
dinfo = device_get_ivars(child);
/* Can't reset the core without access to the agent registers */
if (dinfo->res_agent == NULL)
return (ENODEV);
// TODO - perform reset
return (ENXIO);
}
static int
bcma_suspend_core(device_t dev, device_t child)
{
struct bcma_devinfo *dinfo;
if (device_get_parent(child) != dev)
BHND_BUS_SUSPEND_CORE(device_get_parent(dev), child);
dinfo = device_get_ivars(child);
/* Can't suspend the core without access to the agent registers */
if (dinfo->res_agent == NULL)
return (ENODEV);
// TODO - perform suspend
return (ENXIO);
}
static u_int
bcma_get_port_count(device_t dev, device_t child, bhnd_port_type type)
{
struct bcma_devinfo *dinfo;
/* delegate non-bus-attached devices to our parent */
if (device_get_parent(child) != dev)
return (BHND_BUS_GET_PORT_COUNT(device_get_parent(dev), child,
type));
dinfo = device_get_ivars(child);
switch (type) {
case BHND_PORT_DEVICE:
return (dinfo->corecfg->num_dev_ports);
case BHND_PORT_BRIDGE:
return (dinfo->corecfg->num_bridge_ports);
case BHND_PORT_AGENT:
return (dinfo->corecfg->num_wrapper_ports);
}
}
static u_int
bcma_get_region_count(device_t dev, device_t child, bhnd_port_type type,
u_int port_num)
{
struct bcma_devinfo *dinfo;
struct bcma_sport_list *ports;
struct bcma_sport *port;
/* delegate non-bus-attached devices to our parent */
if (device_get_parent(child) != dev)
return (BHND_BUS_GET_REGION_COUNT(device_get_parent(dev), child,
type, port_num));
dinfo = device_get_ivars(child);
ports = bcma_corecfg_get_port_list(dinfo->corecfg, type);
STAILQ_FOREACH(port, ports, sp_link) {
if (port->sp_num == port_num)
return (port->sp_num_maps);
}
/* not found */
return (0);
}
static int
bcma_get_port_rid(device_t dev, device_t child, bhnd_port_type port_type,
u_int port_num, u_int region_num)
{
struct bcma_devinfo *dinfo;
struct bcma_map *map;
struct bcma_sport_list *ports;
struct bcma_sport *port;
dinfo = device_get_ivars(child);
ports = bcma_corecfg_get_port_list(dinfo->corecfg, port_type);
STAILQ_FOREACH(port, ports, sp_link) {
if (port->sp_num != port_num)
continue;
STAILQ_FOREACH(map, &port->sp_maps, m_link)
if (map->m_region_num == region_num)
return map->m_rid;
}
return -1;
}
static int
bcma_decode_port_rid(device_t dev, device_t child, int type, int rid,
bhnd_port_type *port_type, u_int *port_num, u_int *region_num)
{
struct bcma_devinfo *dinfo;
struct bcma_map *map;
struct bcma_sport_list *ports;
struct bcma_sport *port;
dinfo = device_get_ivars(child);
/* Ports are always memory mapped */
if (type != SYS_RES_MEMORY)
return (EINVAL);
/* Starting with the most likely device list, search all three port
* lists */
bhnd_port_type types[] = {
BHND_PORT_DEVICE,
BHND_PORT_AGENT,
BHND_PORT_BRIDGE
};
for (int i = 0; i < nitems(types); i++) {
ports = bcma_corecfg_get_port_list(dinfo->corecfg, types[i]);
STAILQ_FOREACH(port, ports, sp_link) {
STAILQ_FOREACH(map, &port->sp_maps, m_link) {
if (map->m_rid != rid)
continue;
*port_type = port->sp_type;
*port_num = port->sp_num;
*region_num = map->m_region_num;
return (0);
}
}
}
return (ENOENT);
}
static int
bcma_get_region_addr(device_t dev, device_t child, bhnd_port_type port_type,
u_int port_num, u_int region_num, bhnd_addr_t *addr, bhnd_size_t *size)
{
struct bcma_devinfo *dinfo;
struct bcma_map *map;
struct bcma_sport_list *ports;
struct bcma_sport *port;
dinfo = device_get_ivars(child);
ports = bcma_corecfg_get_port_list(dinfo->corecfg, port_type);
/* Search the port list */
STAILQ_FOREACH(port, ports, sp_link) {
if (port->sp_num != port_num)
continue;
STAILQ_FOREACH(map, &port->sp_maps, m_link) {
if (map->m_region_num != region_num)
continue;
/* Found! */
*addr = map->m_base;
*size = map->m_size;
return (0);
}
}
return (ENOENT);
}
/**
* Scan a device enumeration ROM table, adding all valid discovered cores to
* the bus.
*
* @param bus The bcma bus.
* @param erom_res An active resource mapping the EROM core.
* @param erom_offset Base offset of the EROM core's register mapping.
*/
int
bcma_add_children(device_t bus, struct resource *erom_res, bus_size_t erom_offset)
{
struct bcma_erom erom;
struct bcma_corecfg *corecfg;
struct bcma_devinfo *dinfo;
device_t child;
int error;
dinfo = NULL;
corecfg = NULL;
/* Initialize our reader */
error = bcma_erom_open(&erom, erom_res, erom_offset);
if (error)
return (error);
/* Add all cores. */
while (!error) {
/* Parse next core */
error = bcma_erom_parse_corecfg(&erom, &corecfg);
if (error && error == ENOENT) {
return (0);
} else if (error) {
goto failed;
}
/* Allocate per-device bus info */
dinfo = bcma_alloc_dinfo(bus, corecfg);
if (dinfo == NULL) {
error = ENXIO;
goto failed;
}
/* The dinfo instance now owns the corecfg value */
corecfg = NULL;
/* Add the child device */
child = device_add_child(bus, NULL, -1);
if (child == NULL) {
error = ENXIO;
goto failed;
}
/* The child device now owns the dinfo pointer */
device_set_ivars(child, dinfo);
dinfo = NULL;
/* If pins are floating or the hardware is otherwise
* unpopulated, the device shouldn't be used. */
if (bhnd_is_hw_disabled(child))
device_disable(child);
}
/* Hit EOF parsing cores? */
if (error == ENOENT)
return (0);
failed:
if (dinfo != NULL)
bcma_free_dinfo(bus, dinfo);
if (corecfg != NULL)
bcma_free_corecfg(corecfg);
return (error);
}
static device_method_t bcma_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, bcma_probe),
DEVMETHOD(device_attach, bcma_attach),
DEVMETHOD(device_detach, bcma_detach),
/* Bus interface */
DEVMETHOD(bus_child_deleted, bcma_child_deleted),
DEVMETHOD(bus_read_ivar, bcma_read_ivar),
DEVMETHOD(bus_write_ivar, bcma_write_ivar),
DEVMETHOD(bus_get_resource_list, bcma_get_resource_list),
/* BHND interface */
DEVMETHOD(bhnd_bus_reset_core, bcma_reset_core),
DEVMETHOD(bhnd_bus_suspend_core, bcma_suspend_core),
DEVMETHOD(bhnd_bus_get_port_count, bcma_get_port_count),
DEVMETHOD(bhnd_bus_get_region_count, bcma_get_region_count),
DEVMETHOD(bhnd_bus_get_port_rid, bcma_get_port_rid),
DEVMETHOD(bhnd_bus_decode_port_rid, bcma_decode_port_rid),
DEVMETHOD(bhnd_bus_get_region_addr, bcma_get_region_addr),
DEVMETHOD_END
};
DEFINE_CLASS_1(bhnd, bcma_driver, bcma_methods, sizeof(struct bcma_softc), bhnd_driver);
MODULE_VERSION(bcma, 1);
MODULE_DEPEND(bcma, bhnd, 1, 1, 1);

49
sys/dev/bhnd/bcma/bcma.h Normal file
View file

@ -0,0 +1,49 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
* $FreeBSD$
*/
#ifndef _BCMA_BCMA_H_
#define _BCMA_BCMA_H_
#include <sys/types.h>
#include <sys/bus.h>
#include <sys/malloc.h>
#include <sys/queue.h>
#include <sys/rman.h>
#include <dev/bhnd/bhndvar.h>
/*
* Broadcom AMBA backplane types and data structures.
*/
DECLARE_CLASS(bcma_driver);
#endif /* _BCMA_BCMA_H_ */

View file

@ -0,0 +1,183 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/module.h>
#include <dev/bhnd/bhnd_ids.h>
#include <dev/bhnd/bhndb/bhndbvar.h>
#include <dev/bhnd/bhndb/bhndb_hwdata.h>
#include "bcmavar.h"
#include "bcma_eromreg.h"
#include "bcma_eromvar.h"
/*
* Supports attachment of bcma(4) bus devices via a bhndb bridge.
*/
static int
bcma_bhndb_probe(device_t dev)
{
const struct bhnd_chipid *cid;
/* Check bus type */
cid = BHNDB_GET_CHIPID(device_get_parent(dev), dev);
if (cid->chip_type != BHND_CHIPTYPE_BCMA)
return (ENXIO);
/* Delegate to default probe implementation */
return (bcma_probe(dev));
}
static int
bcma_bhndb_attach(device_t dev)
{
const struct bhnd_chipid *cid;
struct resource *erom_res;
int error;
int rid;
cid = BHNDB_GET_CHIPID(device_get_parent(dev), dev);
/* Map the EROM resource and enumerate our children. */
rid = 0;
erom_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, cid->enum_addr,
cid->enum_addr + BCMA_EROM_TABLE_SIZE, BCMA_EROM_TABLE_SIZE,
RF_ACTIVE);
if (erom_res == NULL) {
device_printf(dev, "failed to allocate EROM resource\n");
return (ENXIO);
}
error = bcma_add_children(dev, erom_res, BCMA_EROM_TABLE_START);
/* Clean up */
bus_release_resource(dev, SYS_RES_MEMORY, rid, erom_res);
if (error)
return (error);
/* Initialize full bridge configuration */
error = BHNDB_INIT_FULL_CONFIG(device_get_parent(dev), dev,
bhndb_bcma_priority_table);
if (error)
return (error);
/* Call our superclass' implementation */
return (bcma_attach(dev));
}
static int
bcma_bhndb_suspend_child(device_t dev, device_t child)
{
struct bcma_devinfo *dinfo;
int error;
if (device_get_parent(child) != dev)
BUS_SUSPEND_CHILD(device_get_parent(dev), child);
if (device_is_suspended(child))
return (EBUSY);
dinfo = device_get_ivars(child);
/* Suspend the child */
if ((error = bhnd_generic_br_suspend_child(dev, child)))
return (error);
/* Suspend child's agent resource */
if (dinfo->res_agent != NULL)
BHNDB_SUSPEND_RESOURCE(device_get_parent(dev), dev,
SYS_RES_MEMORY, dinfo->res_agent->res);
return (0);
}
static int
bcma_bhndb_resume_child(device_t dev, device_t child)
{
struct bcma_devinfo *dinfo;
int error;
if (device_get_parent(child) != dev)
BUS_SUSPEND_CHILD(device_get_parent(dev), child);
if (!device_is_suspended(child))
return (EBUSY);
dinfo = device_get_ivars(child);
/* Resume child's agent resource */
if (dinfo->res_agent != NULL) {
error = BHNDB_RESUME_RESOURCE(device_get_parent(dev), dev,
SYS_RES_MEMORY, dinfo->res_agent->res);
if (error)
return (error);
}
/* Resume the child */
if ((error = bhnd_generic_br_resume_child(dev, child))) {
/* On failure, re-suspend the agent resource */
if (dinfo->res_agent != NULL) {
BHNDB_SUSPEND_RESOURCE(device_get_parent(dev), dev,
SYS_RES_MEMORY, dinfo->res_agent->res);
}
return (error);
}
return (0);
}
static device_method_t bcma_bhndb_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, bcma_bhndb_probe),
DEVMETHOD(device_attach, bcma_bhndb_attach),
/* Bus interface */
DEVMETHOD(bus_suspend_child, bcma_bhndb_suspend_child),
DEVMETHOD(bus_resume_child, bcma_bhndb_resume_child),
DEVMETHOD_END
};
DEFINE_CLASS_1(bhnd, bcma_bhndb_driver, bcma_bhndb_methods,
sizeof(struct bcma_softc), bcma_driver);
DRIVER_MODULE(bcma_bhndb, bhndb, bcma_bhndb_driver, bhnd_devclass, NULL, NULL);
MODULE_VERSION(bcma_bhndb, 1);
MODULE_DEPEND(bcma_bhndb, bcma, 1, 1, 1);
MODULE_DEPEND(bcma_bhndb, bhndb, 1, 1, 1);

View file

@ -0,0 +1,193 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* Copyright (c) 2010 Broadcom Corporation
*
* Portions of this file were derived from the aidmp.h header
* distributed with Broadcom's initial brcm80211 Linux driver release, as
* contributed to the Linux staging repository.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $FreeBSD$
*/
#ifndef _BCMA_BCMA_DMP_H_
#define _BCMA_BCMA_DMP_H_
/*
* PL-368 Device Management Plugin (DMP) Registers & Constants
*
* The "DMP" core used in Broadcom HND devices has been described
* by Broadcom engineers (and in published header files) as being
* ARM's PL-368 "Device Management Plugin" system IP, included with
* the CoreLink AMBA Designer tooling.
*
* Documentation for the PL-368 is not publicly available, however,
* and the only public reference by ARM to its existence appears to be
* in the proprietary "NIC-301 Interconnect Device Management (PL368)"
* errata publication, available to licensees as part of ARM's
* CoreLink Controllers and Peripherals Engineering Errata.
*/
/* Out-of-band Router registers */
#define BCMA_OOB_BUSCONFIG 0x020
#define BCMA_OOB_STATUSA 0x100
#define BCMA_OOB_STATUSB 0x104
#define BCMA_OOB_STATUSC 0x108
#define BCMA_OOB_STATUSD 0x10c
#define BCMA_OOB_ENABLEA0 0x200
#define BCMA_OOB_ENABLEA1 0x204
#define BCMA_OOB_ENABLEA2 0x208
#define BCMA_OOB_ENABLEA3 0x20c
#define BCMA_OOB_ENABLEB0 0x280
#define BCMA_OOB_ENABLEB1 0x284
#define BCMA_OOB_ENABLEB2 0x288
#define BCMA_OOB_ENABLEB3 0x28c
#define BCMA_OOB_ENABLEC0 0x300
#define BCMA_OOB_ENABLEC1 0x304
#define BCMA_OOB_ENABLEC2 0x308
#define BCMA_OOB_ENABLEC3 0x30c
#define BCMA_OOB_ENABLED0 0x380
#define BCMA_OOB_ENABLED1 0x384
#define BCMA_OOB_ENABLED2 0x388
#define BCMA_OOB_ENABLED3 0x38c
#define BCMA_OOB_ITCR 0xf00
#define BCMA_OOB_ITIPOOBA 0xf10
#define BCMA_OOB_ITIPOOBB 0xf14
#define BCMA_OOB_ITIPOOBC 0xf18
#define BCMA_OOB_ITIPOOBD 0xf1c
#define BCMA_OOB_ITOPOOBA 0xf30
#define BCMA_OOB_ITOPOOBB 0xf34
#define BCMA_OOB_ITOPOOBC 0xf38
#define BCMA_OOB_ITOPOOBD 0xf3c
/* DMP wrapper registers */
#define BCMA_DMP_OOBSELINA30 0x000
#define BCMA_DMP_OOBSELINA74 0x004
#define BCMA_DMP_OOBSELINB30 0x020
#define BCMA_DMP_OOBSELINB74 0x024
#define BCMA_DMP_OOBSELINC30 0x040
#define BCMA_DMP_OOBSELINC74 0x044
#define BCMA_DMP_OOBSELIND30 0x060
#define BCMA_DMP_OOBSELIND74 0x064
#define BCMA_DMP_OOBSELOUTA30 0x100
#define BCMA_DMP_OOBSELOUTA74 0x104
#define BCMA_DMP_OOBSELOUTB30 0x120
#define BCMA_DMP_OOBSELOUTB74 0x124
#define BCMA_DMP_OOBSELOUTC30 0x140
#define BCMA_DMP_OOBSELOUTC74 0x144
#define BCMA_DMP_OOBSELOUTD30 0x160
#define BCMA_DMP_OOBSELOUTD74 0x164
#define BCMA_DMP_OOBSYNCA 0x200
#define BCMA_DMP_OOBSELOUTAEN 0x204
#define BCMA_DMP_OOBSYNCB 0x220
#define BCMA_DMP_OOBSELOUTBEN 0x224
#define BCMA_DMP_OOBSYNCC 0x240
#define BCMA_DMP_OOBSELOUTCEN 0x244
#define BCMA_DMP_OOBSYNCD 0x260
#define BCMA_DMP_OOBSELOUTDEN 0x264
#define BCMA_DMP_OOBAEXTWIDTH 0x300
#define BCMA_DMP_OOBAINWIDTH 0x304
#define BCMA_DMP_OOBAOUTWIDTH 0x308
#define BCMA_DMP_OOBBEXTWIDTH 0x320
#define BCMA_DMP_OOBBINWIDTH 0x324
#define BCMA_DMP_OOBBOUTWIDTH 0x328
#define BCMA_DMP_OOBCEXTWIDTH 0x340
#define BCMA_DMP_OOBCINWIDTH 0x344
#define BCMA_DMP_OOBCOUTWIDTH 0x348
#define BCMA_DMP_OOBDEXTWIDTH 0x360
#define BCMA_DMP_OOBDINWIDTH 0x364
#define BCMA_DMP_OOBDOUTWIDTH 0x368
// This was inherited from Broadcom's aidmp.h header
// Is it required for any of our use-cases?
#if 0 /* defined(IL_BIGENDIAN) && defined(BCMHND74K) */
/* Selective swapped defines for those registers we need in
* big-endian code.
*/
#define BCMA_DMP_IOCTRLSET 0x404
#define BCMA_DMP_IOCTRLCLEAR 0x400
#define BCMA_DMP_IOCTRL 0x40c
#define BCMA_DMP_IOSTATUS 0x504
#define BCMA_DMP_RESETCTRL 0x804
#define BCMA_DMP_RESETSTATUS 0x800
#else /* !IL_BIGENDIAN || !BCMHND74K */
#define BCMA_DMP_IOCTRLSET 0x400
#define BCMA_DMP_IOCTRLCLEAR 0x404
#define BCMA_DMP_IOCTRL 0x408
#define BCMA_DMP_IOSTATUS 0x500
#define BCMA_DMP_RESETCTRL 0x800
#define BCMA_DMP_RESETSTATUS 0x804
#endif /* IL_BIGENDIAN && BCMHND74K */
#define BCMA_DMP_IOCTRLWIDTH 0x700
#define BCMA_DMP_IOSTATUSWIDTH 0x704
#define BCMA_DMP_RESETREADID 0x808
#define BCMA_DMP_RESETWRITEID 0x80c
#define BCMA_DMP_ERRLOGCTRL 0xa00
#define BCMA_DMP_ERRLOGDONE 0xa04
#define BCMA_DMP_ERRLOGSTATUS 0xa08
#define BCMA_DMP_ERRLOGADDRLO 0xa0c
#define BCMA_DMP_ERRLOGADDRHI 0xa10
#define BCMA_DMP_ERRLOGID 0xa14
#define BCMA_DMP_ERRLOGUSER 0xa18
#define BCMA_DMP_ERRLOGFLAGS 0xa1c
#define BCMA_DMP_INTSTATUS 0xa00
#define BCMA_DMP_CONFIG 0xe00
#define BCMA_DMP_ITCR 0xf00
#define BCMA_DMP_ITIPOOBA 0xf10
#define BCMA_DMP_ITIPOOBB 0xf14
#define BCMA_DMP_ITIPOOBC 0xf18
#define BCMA_DMP_ITIPOOBD 0xf1c
#define BCMA_DMP_ITIPOOBAOUT 0xf30
#define BCMA_DMP_ITIPOOBBOUT 0xf34
#define BCMA_DMP_ITIPOOBCOUT 0xf38
#define BCMA_DMP_ITIPOOBDOUT 0xf3c
#define BCMA_DMP_ITOPOOBA 0xf50
#define BCMA_DMP_ITOPOOBB 0xf54
#define BCMA_DMP_ITOPOOBC 0xf58
#define BCMA_DMP_ITOPOOBD 0xf5c
#define BCMA_DMP_ITOPOOBAIN 0xf70
#define BCMA_DMP_ITOPOOBBIN 0xf74
#define BCMA_DMP_ITOPOOBCIN 0xf78
#define BCMA_DMP_ITOPOOBDIN 0xf7c
#define BCMA_DMP_ITOPRESET 0xf90
#define BCMA_DMP_PERIPHERIALID4 0xfd0
#define BCMA_DMP_PERIPHERIALID5 0xfd4
#define BCMA_DMP_PERIPHERIALID6 0xfd8
#define BCMA_DMP_PERIPHERIALID7 0xfdc
#define BCMA_DMP_PERIPHERIALID0 0xfe0
#define BCMA_DMP_PERIPHERIALID1 0xfe4
#define BCMA_DMP_PERIPHERIALID2 0xfe8
#define BCMA_DMP_PERIPHERIALID3 0xfec
#define BCMA_DMP_COMPONENTID0 0xff0
#define BCMA_DMP_COMPONENTID1 0xff4
#define BCMA_DMP_COMPONENTID2 0xff8
#define BCMA_DMP_COMPONENTID3 0xffc
/* resetctrl */
#define BMCA_DMP_RC_RESET 1
/* config */
#define BCMA_DMP_CFG_OOB 0x00000020
#define BCMA_DMP_CFG_IOS 0x00000010
#define BCMA_DMP_CFGIOC 0x00000008
#define BCMA_DMP_CFGTO 0x00000004
#define BCMA_DMP_CFGERRL 0x00000002
#define BCMA_DMP_CFGRST 0x00000001
#endif /* _BCMA_BCMA_DMP_H_ */

View file

@ -0,0 +1,897 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/limits.h>
#include <sys/systm.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include "bcma_eromreg.h"
#include "bcma_eromvar.h"
/*
* BCMA Enumeration ROM (EROM) Table
*
* Provides auto-discovery of BCMA cores on Broadcom's HND SoC.
*
* The EROM core address can be found at BCMA_CC_EROM_ADDR within the
* ChipCommon registers. The table itself is comprised of 32-bit
* type-tagged entries, organized into an array of variable-length
* core descriptor records.
*
* The final core descriptor is followed by a 32-bit BCMA_EROM_TABLE_EOF (0xF)
* marker.
*/
static const char *erom_entry_type_name (uint8_t entry);
static int erom_read32(struct bcma_erom *erom, uint32_t *entry);
static int erom_skip32(struct bcma_erom *erom);
static int erom_skip_core(struct bcma_erom *erom);
static int erom_skip_mport(struct bcma_erom *erom);
static int erom_skip_sport_region(struct bcma_erom *erom);
static int erom_seek_next(struct bcma_erom *erom, uint8_t etype);
#define EROM_LOG(erom, fmt, ...) \
device_printf(erom->dev, "erom[0x%llx]: " fmt, \
(unsigned long long) (erom->offset), ##__VA_ARGS__);
/**
* Open an EROM table for reading.
*
* @param[out] erom On success, will be populated with a valid EROM
* read state.
* @param r An active resource mapping the EROM core.
* @param offset Offset of the EROM core within @p resource.
*
* @retval 0 success
* @retval non-zero if the erom table could not be opened.
*/
int
bcma_erom_open(struct bcma_erom *erom, struct resource *r, bus_size_t offset)
{
/* Initialize the EROM reader */
erom->dev = rman_get_device(r);
erom->r = r;
erom->start = offset + BCMA_EROM_TABLE_START;
erom->offset = 0;
return (0);
}
/** Return the type name for an EROM entry */
static const char *
erom_entry_type_name (uint8_t entry)
{
switch (BCMA_EROM_GET_ATTR(entry, ENTRY_TYPE)) {
case BCMA_EROM_ENTRY_TYPE_CORE:
return "core";
case BCMA_EROM_ENTRY_TYPE_MPORT:
return "mport";
case BCMA_EROM_ENTRY_TYPE_REGION:
return "region";
default:
return "unknown";
}
}
/**
* Return the current read position.
*/
bus_size_t
bcma_erom_tell(struct bcma_erom *erom)
{
return (erom->offset);
}
/**
* Seek to an absolute read position.
*/
void
bcma_erom_seek(struct bcma_erom *erom, bus_size_t offset)
{
erom->offset = offset;
}
/**
* Read a 32-bit entry value from the EROM table without advancing the
* read position.
*
* @param erom EROM read state.
* @param entry Will contain the read result on success.
* @retval 0 success
* @retval ENOENT The end of the EROM table was reached.
* @retval non-zero The read could not be completed.
*/
int
bcma_erom_peek32(struct bcma_erom *erom, uint32_t *entry)
{
if (erom->offset >= BCMA_EROM_TABLE_SIZE) {
EROM_LOG(erom, "BCMA EROM table missing terminating EOF\n");
return (EINVAL);
}
*entry = bus_read_4(erom->r, erom->start + erom->offset);
return (0);
}
/**
* Read a 32-bit entry value from the EROM table.
*
* @param erom EROM read state.
* @param entry Will contain the read result on success.
* @retval 0 success
* @retval ENOENT The end of the EROM table was reached.
* @retval non-zero The read could not be completed.
*/
static int
erom_read32(struct bcma_erom *erom, uint32_t *entry)
{
int error;
if ((error = bcma_erom_peek32(erom, entry)) == 0)
erom->offset += 4;
return (error);
}
/**
* Read and discard 32-bit entry value from the EROM table.
*
* @param erom EROM read state.
* @retval 0 success
* @retval ENOENT The end of the EROM table was reached.
* @retval non-zero The read could not be completed.
*/
static int
erom_skip32(struct bcma_erom *erom)
{
uint32_t entry;
return erom_read32(erom, &entry);
}
/**
* Read and discard a core descriptor from the EROM table.
*
* @param erom EROM read state.
* @retval 0 success
* @retval ENOENT The end of the EROM table was reached.
* @retval non-zero The read could not be completed.
*/
static int
erom_skip_core(struct bcma_erom *erom)
{
struct bcma_erom_core core;
return (bcma_erom_parse_core(erom, &core));
}
/**
* Read and discard a master port descriptor from the EROM table.
*
* @param erom EROM read state.
* @retval 0 success
* @retval ENOENT The end of the EROM table was reached.
* @retval non-zero The read could not be completed.
*/
static int
erom_skip_mport(struct bcma_erom *erom)
{
struct bcma_erom_mport mp;
return (bcma_erom_parse_mport(erom, &mp));
}
/**
* Read and discard a port region descriptor from the EROM table.
*
* @param erom EROM read state.
* @retval 0 success
* @retval ENOENT The end of the EROM table was reached.
* @retval non-zero The read could not be completed.
*/
static int
erom_skip_sport_region(struct bcma_erom *erom)
{
struct bcma_erom_sport_region r;
return (bcma_erom_parse_sport_region(erom, &r));
}
/**
* Seek to the next entry matching the given EROM entry type.
*
* @param erom EROM read state.
* @param etype One of BCMA_EROM_ENTRY_TYPE_CORE,
* BCMA_EROM_ENTRY_TYPE_MPORT, or BCMA_EROM_ENTRY_TYPE_REGION.
* @retval 0 success
* @retval ENOENT The end of the EROM table was reached.
* @retval non-zero Reading or parsing the descriptor failed.
*/
static int
erom_seek_next(struct bcma_erom *erom, uint8_t etype)
{
uint32_t entry;
int error;
/* Iterate until we hit an entry matching the requested type. */
while (!(error = bcma_erom_peek32(erom, &entry))) {
/* Handle EOF */
if (entry == BCMA_EROM_TABLE_EOF)
return (ENOENT);
/* Invalid entry */
if (!BCMA_EROM_GET_ATTR(entry, ENTRY_ISVALID))
return (EINVAL);
/* Entry type matches? */
if (BCMA_EROM_GET_ATTR(entry, ENTRY_TYPE) == etype)
return (0);
/* Skip non-matching entry types. */
switch (BCMA_EROM_GET_ATTR(entry, ENTRY_TYPE)) {
case BCMA_EROM_ENTRY_TYPE_CORE:
if ((error = erom_skip_core(erom)))
return (error);
break;
case BCMA_EROM_ENTRY_TYPE_MPORT:
if ((error = erom_skip_mport(erom)))
return (error);
break;
case BCMA_EROM_ENTRY_TYPE_REGION:
if ((error = erom_skip_sport_region(erom)))
return (error);
break;
default:
/* Unknown entry type! */
return (EINVAL);
}
}
return (error);
}
/**
* Return the read position to the start of the EROM table.
*
* @param erom EROM read state.
*/
void
bcma_erom_reset(struct bcma_erom *erom)
{
erom->offset = 0;
}
/**
* Seek to the requested core entry.
*
* @param erom EROM read state.
* @param core_index Index of the core to seek to.
* @retval 0 success
* @retval ENOENT The end of the EROM table was reached before @p index was
* found.
* @retval non-zero Reading or parsing failed.
*/
int
bcma_erom_seek_core_index(struct bcma_erom *erom, u_int core_index)
{
int error;
/* Start search at top of EROM */
bcma_erom_reset(erom);
/* Skip core descriptors till we hit the requested entry */
for (u_int i = 0; i < core_index; i++) {
struct bcma_erom_core core;
/* Read past the core descriptor */
if ((error = bcma_erom_parse_core(erom, &core)))
return (error);
/* Seek to the next readable core entry */
error = erom_seek_next(erom, BCMA_EROM_ENTRY_TYPE_CORE);
if (error)
return (error);
}
return (0);
}
/**
* Read the next core descriptor from the EROM table.
*
* @param erom EROM read state.
* @param[out] core On success, will be populated with the parsed core
* descriptor data.
* @retval 0 success
* @retval ENOENT The end of the EROM table was reached.
* @retval non-zero Reading or parsing the core descriptor failed.
*/
int
bcma_erom_parse_core(struct bcma_erom *erom, struct bcma_erom_core *core)
{
uint32_t entry;
int error;
/* Parse CoreDescA */
if ((error = erom_read32(erom, &entry)))
return (error);
/* Handle EOF */
if (entry == BCMA_EROM_TABLE_EOF)
return (ENOENT);
if (!BCMA_EROM_ENTRY_IS(entry, CORE)) {
EROM_LOG(erom, "Unexpected EROM entry 0x%x (type=%s)\n",
entry, erom_entry_type_name(entry));
return (EINVAL);
}
core->vendor = BCMA_EROM_GET_ATTR(entry, COREA_DESIGNER);
core->device = BCMA_EROM_GET_ATTR(entry, COREA_ID);
/* Parse CoreDescB */
if ((error = erom_read32(erom, &entry)))
return (error);
if (!BCMA_EROM_ENTRY_IS(entry, CORE)) {
return (EINVAL);
}
core->rev = BCMA_EROM_GET_ATTR(entry, COREB_REV);
core->num_mport = BCMA_EROM_GET_ATTR(entry, COREB_NUM_MP);
core->num_dport = BCMA_EROM_GET_ATTR(entry, COREB_NUM_DP);
core->num_mwrap = BCMA_EROM_GET_ATTR(entry, COREB_NUM_WMP);
core->num_swrap = BCMA_EROM_GET_ATTR(entry, COREB_NUM_WSP);
return (0);
}
/**
* Read the next master port descriptor from the EROM table.
*
* @param erom EROM read state.
* @param[out] mport On success, will be populated with the parsed
* descriptor data.
* @retval 0 success
* @retval non-zero Reading or parsing the descriptor failed.
*/
int
bcma_erom_parse_mport(struct bcma_erom *erom,
struct bcma_erom_mport *mport)
{
uint32_t entry;
int error;
/* Parse the master port descriptor */
if ((error = erom_read32(erom, &entry)))
return (error);
if (!BCMA_EROM_ENTRY_IS(entry, MPORT))
return (EINVAL);
mport->port_vid = BCMA_EROM_GET_ATTR(entry, MPORT_ID);
mport->port_num = BCMA_EROM_GET_ATTR(entry, MPORT_NUM);
return (0);
}
/**
* Read the next slave port region descriptor from the EROM table.
*
* @param erom EROM read state.
* @param[out] mport On success, will be populated with the parsed
* descriptor data.
* @retval 0 success
* @retval ENOENT The end of the region descriptor table was reached.
* @retval non-zero Reading or parsing the descriptor failed.
*/
int
bcma_erom_parse_sport_region(struct bcma_erom *erom,
struct bcma_erom_sport_region *region)
{
uint32_t entry;
uint8_t size_type;
int error;
/* Peek at the region descriptor */
if (bcma_erom_peek32(erom, &entry))
return (EINVAL);
/* A non-region entry signals the end of the region table */
if (!BCMA_EROM_ENTRY_IS(entry, REGION)) {
return (ENOENT);
} else {
erom_skip32(erom);
}
region->base_addr = BCMA_EROM_GET_ATTR(entry, REGION_BASE);
region->region_type = BCMA_EROM_GET_ATTR(entry, REGION_TYPE);
region->region_port = BCMA_EROM_GET_ATTR(entry, REGION_PORT);
size_type = BCMA_EROM_GET_ATTR(entry, REGION_SIZE);
/* If region address is 64-bit, fetch the high bits. */
if (BCMA_EROM_GET_ATTR(entry, REGION_64BIT)) {
if ((error = erom_read32(erom, &entry)))
return (error);
region->base_addr |= ((bhnd_addr_t) entry << 32);
}
/* Parse the region size; it's either encoded as the binary logarithm
* of the number of 4K pages (i.e. log2 n), or its encoded as a
* 32-bit/64-bit literal value directly following the current entry. */
if (size_type == BCMA_EROM_REGION_SIZE_OTHER) {
if ((error = erom_read32(erom, &entry)))
return (error);
region->size = BCMA_EROM_GET_ATTR(entry, RSIZE_VAL);
if (BCMA_EROM_GET_ATTR(entry, RSIZE_64BIT)) {
if ((error = erom_read32(erom, &entry)))
return (error);
region->size |= ((bhnd_size_t) entry << 32);
}
} else {
region->size = BCMA_EROM_REGION_SIZE_BASE << size_type;
}
/* Verify that addr+size does not overflow. */
if (region->size != 0 &&
BHND_ADDR_MAX - (region->size - 1) < region->base_addr)
{
EROM_LOG(erom, "%s%u: invalid address map %llx:%llx\n",
erom_entry_type_name(region->region_type),
region->region_port,
(unsigned long long) region->base_addr,
(unsigned long long) region->size);
return (EINVAL);
}
return (0);
}
/**
* Parse all cores descriptors from @p erom and return the array
* in @p cores and the count in @p num_cores. The current EROM read position
* is left unmodified.
*
* The memory allocated for the table should be freed using
* `free(*cores, M_BHND)`. @p cores and @p num_cores are not changed
* when an error is returned.
*
* @param erom EROM read state.
* @param[out] cores the table of parsed core descriptors.
* @param[out] num_cores the number of core records in @p cores.
*/
int
bcma_erom_get_core_info(struct bcma_erom *erom,
struct bhnd_core_info **cores,
u_int *num_cores)
{
struct bhnd_core_info *buffer;
bus_size_t initial_offset;
u_int count;
int error;
buffer = NULL;
initial_offset = bcma_erom_tell(erom);
/* Determine the core count */
bcma_erom_reset(erom);
for (count = 0, error = 0; !error; count++) {
struct bcma_erom_core core;
/* Seek to the first readable core entry */
error = erom_seek_next(erom, BCMA_EROM_ENTRY_TYPE_CORE);
if (error == ENOENT)
break;
else if (error)
goto cleanup;
/* Read past the core descriptor */
if ((error = bcma_erom_parse_core(erom, &core)))
goto cleanup;
}
/* Allocate our output buffer */
buffer = malloc(sizeof(struct bhnd_core_info) * count, M_BHND,
M_NOWAIT);
if (buffer == NULL) {
error = ENOMEM;
goto cleanup;
}
/* Parse all core descriptors */
bcma_erom_reset(erom);
for (u_int i = 0; i < count; i++) {
struct bcma_erom_core core;
/* Parse the core */
error = erom_seek_next(erom, BCMA_EROM_ENTRY_TYPE_CORE);
if (error)
goto cleanup;
error = bcma_erom_parse_core(erom, &core);
if (error)
goto cleanup;
/* Convert to a bhnd info record */
buffer[i].vendor = core.vendor;
buffer[i].device = core.device;
buffer[i].hwrev = core.rev;
buffer[i].core_idx = i;
buffer[i].unit = 0;
/* Determine the unit number */
for (u_int j = 0; j < i; j++) {
if (buffer[i].vendor == buffer[j].vendor &&
buffer[i].device == buffer[j].device)
buffer[i].unit++;;
}
}
cleanup:
if (!error) {
*cores = buffer;
*num_cores = count;
} else {
if (buffer != NULL)
free(buffer, M_BHND);
}
/* Restore the initial position */
bcma_erom_seek(erom, initial_offset);
return (error);
}
/**
* Register all MMIO region descriptors for the given slave port.
*
* @param erom EROM read state.
* @param corecfg Core info to be populated with the scanned port regions.
* @param port_num Port index for which regions will be parsed.
* @param region_type The region type to be parsed.
* @param[out] offset The offset at which to perform parsing. On success, this
* will be updated to point to the next EROM table entry.
*/
static int
erom_corecfg_fill_port_regions(struct bcma_erom *erom,
struct bcma_corecfg *corecfg, bcma_pid_t port_num,
uint8_t region_type)
{
struct bcma_sport *sport;
struct bcma_sport_list *sports;
bus_size_t entry_offset;
int error;
bhnd_port_type port_type;
error = 0;
/* Determine the port type for this region type. */
switch (region_type) {
case BCMA_EROM_REGION_TYPE_DEVICE:
port_type = BHND_PORT_DEVICE;
break;
case BCMA_EROM_REGION_TYPE_BRIDGE:
port_type = BHND_PORT_BRIDGE;
break;
case BCMA_EROM_REGION_TYPE_MWRAP:
case BCMA_EROM_REGION_TYPE_SWRAP:
port_type = BHND_PORT_AGENT;
break;
default:
EROM_LOG(erom, "unsupported region type %hhx\n",
region_type);
return (EINVAL);
};
/* Fetch the list to be populated */
sports = bcma_corecfg_get_port_list(corecfg, port_type);
/* Allocate a new port descriptor */
sport = bcma_alloc_sport(port_num, port_type);
if (sport == NULL)
return (ENOMEM);
/* Read all address regions defined for this port */
for (bcma_rmid_t region_num = 0;; region_num++) {
struct bcma_map *map;
struct bcma_erom_sport_region spr;
/* No valid port definition should come anywhere near
* BCMA_RMID_MAX. */
if (region_num == BCMA_RMID_MAX) {
EROM_LOG(erom, "core%u %s%u: region count reached "
"upper limit of %u\n",
corecfg->core_info.core_idx,
bhnd_port_type_name(port_type),
port_num, BCMA_RMID_MAX);
error = EINVAL;
goto cleanup;
}
/* Parse the next region entry. */
entry_offset = bcma_erom_tell(erom);
error = bcma_erom_parse_sport_region(erom, &spr);
if (error && error != ENOENT) {
EROM_LOG(erom, "core%u %s%u.%u: invalid slave port "
"address region\n",
corecfg->core_info.core_idx,
bhnd_port_type_name(port_type),
port_num, region_num);
goto cleanup;
}
/* ENOENT signals no further region entries */
if (error == ENOENT) {
/* No further entries */
error = 0;
break;
}
/* A region or type mismatch also signals no further region
* entries */
if (spr.region_port != port_num ||
spr.region_type != region_type)
{
/* We don't want to consume this entry */
bcma_erom_seek(erom, entry_offset);
error = 0;
goto cleanup;
}
/*
* Create the map entry.
*/
map = malloc(sizeof(struct bcma_map), M_BHND, M_NOWAIT);
if (map == NULL) {
error = ENOMEM;
goto cleanup;
}
map->m_region_num = region_num;
map->m_base = spr.base_addr;
map->m_size = spr.size;
map->m_rid = -1;
/* Add the region map to the port */
STAILQ_INSERT_TAIL(&sport->sp_maps, map, m_link);
sport->sp_num_maps++;
}
cleanup:
/* Append the new port descriptor on success, or deallocate the
* partially parsed descriptor on failure. */
if (error == 0) {
STAILQ_INSERT_TAIL(sports, sport, sp_link);
} else if (sport != NULL) {
bcma_free_sport(sport);
}
return error;
}
/**
* Parse the next core entry from the EROM table and produce a bcma_corecfg
* to be owned by the caller.
*
* @param erom EROM read state.
* @param[out] result On success, the core's device info. The caller inherits
* ownership of this allocation.
*
* @return If successful, returns 0. If the end of the EROM table is hit,
* ENOENT will be returned. On error, returns a non-zero error value.
*/
int
bcma_erom_parse_corecfg(struct bcma_erom *erom, struct bcma_corecfg **result)
{
struct bcma_corecfg *cfg;
struct bcma_erom_core core;
uint8_t first_region_type;
bus_size_t initial_offset;
u_int core_index;
int core_unit;
int error;
cfg = NULL;
initial_offset = bcma_erom_tell(erom);
/* Parse the next core entry */
if ((error = bcma_erom_parse_core(erom, &core)))
return (error);
/* Determine the core's index and unit numbers */
bcma_erom_reset(erom);
core_unit = 0;
core_index = 0;
for (; bcma_erom_tell(erom) != initial_offset; core_index++) {
struct bcma_erom_core prev_core;
/* Parse next core */
if ((error = erom_seek_next(erom, BCMA_EROM_ENTRY_TYPE_CORE)))
return (error);
if ((error = bcma_erom_parse_core(erom, &prev_core)))
return (error);
/* Is earlier unit? */
if (core.vendor == prev_core.vendor &&
core.device == prev_core.device)
{
core_unit++;
}
/* Seek to next core */
if ((error = erom_seek_next(erom, BCMA_EROM_ENTRY_TYPE_CORE)))
return (error);
}
/* We already parsed the core descriptor */
if ((error = erom_skip_core(erom)))
return (error);
/* Allocate our corecfg */
cfg = bcma_alloc_corecfg(core_index, core_unit, core.vendor,
core.device, core.rev);
if (cfg == NULL)
return (ENOMEM);
/* These are 5-bit values in the EROM table, and should never be able
* to overflow BCMA_PID_MAX. */
KASSERT(core.num_mport <= BCMA_PID_MAX, ("unsupported mport count"));
KASSERT(core.num_dport <= BCMA_PID_MAX, ("unsupported dport count"));
KASSERT(core.num_mwrap + core.num_swrap <= BCMA_PID_MAX,
("unsupported wport count"));
if (bootverbose) {
EROM_LOG(erom,
"core%u: %s %s (cid=%hx, rev=%hu, unit=%d)\n",
core_index,
bhnd_vendor_name(core.vendor),
bhnd_find_core_name(core.vendor, core.device),
core.device, core.rev, core_unit);
}
cfg->num_master_ports = core.num_mport;
cfg->num_dev_ports = 0; /* determined below */
cfg->num_bridge_ports = 0; /* determined blow */
cfg->num_wrapper_ports = core.num_mwrap + core.num_swrap;
/* Parse Master Port Descriptors */
for (uint8_t i = 0; i < core.num_mport; i++) {
struct bcma_mport *mport;
struct bcma_erom_mport mpd;
/* Parse the master port descriptor */
error = bcma_erom_parse_mport(erom, &mpd);
if (error)
goto failed;
/* Initialize a new bus mport structure */
mport = malloc(sizeof(struct bcma_mport), M_BHND, M_NOWAIT);
if (mport == NULL) {
error = ENOMEM;
goto failed;
}
mport->mp_vid = mpd.port_vid;
mport->mp_num = mpd.port_num;
/* Update dinfo */
STAILQ_INSERT_TAIL(&cfg->master_ports, mport, mp_link);
}
/*
* Determine whether this is a bridge device; if so, we can
* expect the first sequence of address region descriptors to
* be of EROM_REGION_TYPE_BRIDGE instead of
* BCMA_EROM_REGION_TYPE_DEVICE.
*
* It's unclear whether this is the correct mechanism by which we
* should detect/handle bridge devices, but this approach matches
* that of (some of) Broadcom's published drivers.
*/
if (core.num_dport > 0) {
uint32_t entry;
if ((error = bcma_erom_peek32(erom, &entry)))
goto failed;
if (BCMA_EROM_ENTRY_IS(entry, REGION) &&
BCMA_EROM_GET_ATTR(entry, REGION_TYPE) == BCMA_EROM_REGION_TYPE_BRIDGE)
{
first_region_type = BCMA_EROM_REGION_TYPE_BRIDGE;
cfg->num_dev_ports = 0;
cfg->num_bridge_ports = core.num_dport;
} else {
first_region_type = BCMA_EROM_REGION_TYPE_DEVICE;
cfg->num_dev_ports = core.num_dport;
cfg->num_bridge_ports = 0;
}
}
/* Device/bridge port descriptors */
for (uint8_t sp_num = 0; sp_num < core.num_dport; sp_num++) {
error = erom_corecfg_fill_port_regions(erom, cfg, sp_num,
first_region_type);
if (error)
goto failed;
}
/* Wrapper (aka device management) descriptors (for master ports). */
for (uint8_t sp_num = 0; sp_num < core.num_mwrap; sp_num++) {
error = erom_corecfg_fill_port_regions(erom, cfg, sp_num,
BCMA_EROM_REGION_TYPE_MWRAP);
if (error)
goto failed;
}
/* Wrapper (aka device management) descriptors (for slave ports). */
for (uint8_t i = 0; i < core.num_swrap; i++) {
/* Slave wrapper ports are not numbered distinctly from master
* wrapper ports. */
uint8_t sp_num = core.num_mwrap + i;
error = erom_corecfg_fill_port_regions(erom, cfg, sp_num,
BCMA_EROM_REGION_TYPE_SWRAP);
if (error)
goto failed;
}
*result = cfg;
return (0);
failed:
if (cfg != NULL)
bcma_free_corecfg(cfg);
return error;
}

View file

@ -0,0 +1,135 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* Copyright (c) 2010 Broadcom Corporation
*
* Portions of this file were derived from the aidmp.h header
* distributed with Broadcom's initial brcm80211 Linux driver release, as
* contributed to the Linux staging repository.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $FreeBSD$
*/
#ifndef _BCMA_BCMA_EROM_REG_H_
#define _BCMA_BCMA_EROM_REG_H_
/* Enumeration ROM device registers */
#define BCMA_EROM_TABLE_START 0x000 /**< device enumeration table offset */
#define BCMA_EROM_REMAPCONTROL 0xe00
#define BCMA_EROM_REMAPSELECT 0xe04
#define BCMA_EROM_MASTERSELECT 0xe10
#define BCMA_EROM_ITCR 0xf00
#define BCMA_EROM_ITIP 0xf04
#define BCMA_EROM_TABLE_SIZE BCMA_EROM_REMAPCONTROL - BCMA_EROM_TABLE_START
/**
* Extract an entry attribute by applying _MASK and _SHIFT defines.
*
* @param _entry The entry containing the desired attribute
* @param _attr The BCMA EROM attribute name (e.g. ENTRY_ISVALID), to be
* concatenated with the `BCMA_EROM_` prefix and `_MASK`/`_SHIFT` suffixes.
*/
#define BCMA_EROM_GET_ATTR(_entry, _attr) \
((_entry & BCMA_EROM_ ## _attr ## _MASK) \
>> BCMA_EROM_ ## _attr ## _SHIFT)
/**
* Test an EROM entry's validity and type.
*
* @param _entry The entry to test.
* @param _type The required type
* @retval true if the entry type matches and the BCMA_EROM_ENTRY_ISVALID flag
* is set.
* @retval false if the entry is not valid, or if the type does not match.
*/
#define BCMA_EROM_ENTRY_IS(_entry, _type) \
(BCMA_EROM_GET_ATTR(_entry, ENTRY_ISVALID) && \
BCMA_EROM_GET_ATTR(_entry, ENTRY_TYPE) == BCMA_EROM_ENTRY_TYPE_ ## _type)
/*
* Enumeration ROM Constants
*/
#define BCMA_EROM_TABLE_EOF 0xF /* end of EROM table */
#define BCMA_EROM_ENTRY_ISVALID_MASK 0x1 /* is entry valid? */
#define BCMA_EROM_ENTRY_ISVALID_SHIFT 0
/* EROM Entry Types */
#define BCMA_EROM_ENTRY_TYPE_MASK 0x6 /* entry type mask */
#define BCMA_EROM_ENTRY_TYPE_SHIFT 0
# define BCMA_EROM_ENTRY_TYPE_CORE 0x0 /* core descriptor */
# define BCMA_EROM_ENTRY_TYPE_MPORT 0x2 /* master port descriptor */
# define BCMA_EROM_ENTRY_TYPE_REGION 0x4 /* address region descriptor */
/* EROM Core DescriptorA (31:0) */
#define BCMA_EROM_COREA_DESIGNER_MASK 0xFFF00000 /* core designer (JEP-106 mfg id) */
#define BCMA_EROM_COREA_DESIGNER_SHIFT 20
#define BCMA_EROM_COREA_ID_MASK 0x000FFF00 /* broadcom-assigned core id */
#define BCMA_EROM_COREA_ID_SHIFT 8
#define BCMA_EROM_COREA_CLASS_MASK 0x000000F0 /* core class */
#define BCMA_EROM_COREA_CLASS_SHIFT 4
/* EROM Core DescriptorB (63:32) */
#define BCMA_EROM_COREB_NUM_MP_MASK 0x000001F0 /* master port count */
#define BCMA_EROM_COREB_NUM_MP_SHIFT 4
#define BCMA_EROM_COREB_NUM_DP_MASK 0x00003E00 /* device/bridge port count */
#define BCMA_EROM_COREB_NUM_DP_SHIFT 9
#define BCMA_EROM_COREB_NUM_WMP_MASK 0x0007C000 /* master wrapper port count */
#define BCMA_EROM_COREB_NUM_WMP_SHIFT 14
#define BCMA_EROM_COREB_NUM_WSP_MASK 0x00F80000 /* slave wrapper port count */
#define BCMA_EROM_COREB_NUM_WSP_SHIFT 19
#define BCMA_EROM_COREB_REV_MASK 0xFF000000 /* broadcom-assigned core revision */
#define BCMA_EROM_COREB_REV_SHIFT 24
/* EROM Master Port Descriptor
*
* The attribute descriptions are derived from background information
* on the AXI bus and PL301 interconnect, but are undocumented
* by Broadcom and may be incorrect.
*/
#define BCMA_EROM_MPORT_NUM_MASK 0x0000FF00 /* AXI master number (unique per interconnect) */
#define BCMA_EROM_MPORT_NUM_SHIFT 8
#define BCMA_EROM_MPORT_ID_MASK 0x000000F0 /* AXI master ID (unique per master). */
#define BCMA_EROM_MPORT_ID_SHIFT 4
/* EROM Slave Port MMIO Region Descriptor */
#define BCMA_EROM_REGION_BASE_MASK 0xFFFFF000 /* region base address */
#define BCMA_EROM_REGION_BASE_SHIFT 0
#define BCMA_EROM_REGION_64BIT_MASK 0x00000008 /* base address spans two 32-bit entries */
#define BCMA_EROM_REGION_64BIT_SHIFT 0
#define BCMA_EROM_REGION_PORT_MASK 0x00000F00 /* region's associated port */
#define BCMA_EROM_REGION_PORT_SHIFT 8
#define BCMA_EROM_REGION_TYPE_MASK 0x000000C0 /* region type */
#define BCMA_EROM_REGION_TYPE_SHIFT 6
#define BCMA_EROM_REGION_TYPE_DEVICE 0 /* region maps to a device */
#define BCMA_EROM_REGION_TYPE_BRIDGE 1 /* region maps to a bridge (e.g. AXI2APB) */
#define BCMA_EROM_REGION_TYPE_SWRAP 2 /* region maps to a slave port's DMP agent/wrapper */
#define BCMA_EROM_REGION_TYPE_MWRAP 3 /* region maps to a master port's DMP agent/wrapper */
#define BCMA_EROM_REGION_SIZE_MASK 0x00000030 /* region size encoding */
#define BCMA_EROM_REGION_SIZE_SHIFT 4
#define BCMA_EROM_REGION_SIZE_4K 0 /* 4K region */
#define BCMA_EROM_REGION_SIZE_8K 1 /* 8K region */
#define BCMA_EROM_REGION_SIZE_16K 2 /* 16K region */
#define BCMA_EROM_REGION_SIZE_OTHER 3 /* defined by an additional size descriptor entry. */
#define BCMA_EROM_REGION_SIZE_BASE 0x1000
/* Region Size Descriptor */
#define BCMA_EROM_RSIZE_VAL_MASK 0xFFFFF000 /* region size */
#define BCMA_EROM_RSIZE_VAL_SHIFT 0
#define BCMA_EROM_RSIZE_64BIT_MASK 0x00000008 /* size spans two 32-bit entries */
#define BCMA_EROM_RSIZE_64BIT_SHIFT 0
#endif /* _BCMA_BCMA_EROM_REG_H_ */

View file

@ -0,0 +1,104 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
* $FreeBSD$
*/
#ifndef _BCMA_BCMA_EROMVAR_H_
#define _BCMA_BCMA_EROMVAR_H_
#include <dev/bhnd/bhnd.h>
#include "bcmavar.h"
/**
* EROM read context.
*/
struct bcma_erom {
device_t dev; /**< EROM parent device */
struct resource *r; /**< EROM table resource. */
bus_size_t start; /**< EROM table offset */
bus_size_t offset; /**< current read offset */
};
/** EROM core descriptor. */
struct bcma_erom_core {
uint16_t vendor; /**< core's designer */
uint16_t device; /**< core's device identifier */
uint16_t rev; /**< core's hardware revision */
u_long num_mport; /**< number of master port descriptors */
u_long num_dport; /**< number of slave port descriptors */
u_long num_mwrap; /**< number of master wrapper slave port descriptors */
u_long num_swrap; /**< number of slave wrapper slave port descriptors */
};
/** EROM master port descriptor. */
struct bcma_erom_mport {
uint8_t port_num; /**< the port number (bus-unique) */
uint8_t port_vid; /**< the port VID. A single physical
master port may have multiple VIDs;
the canonical port address is
composed of the port number + the
port VID */
};
/** EROM slave port region descriptor. */
struct bcma_erom_sport_region {
uint8_t region_port; /**< the slave port mapping this region */
uint8_t region_type; /**< the mapping port's type */
bhnd_addr_t base_addr; /**< region base address */
bhnd_addr_t size; /**< region size */
};
int bcma_erom_open(struct bcma_erom *erom, struct resource *r,
bus_size_t offset);
int bcma_erom_peek32(struct bcma_erom *erom, uint32_t *entry);
bus_size_t bcma_erom_tell(struct bcma_erom *erom);
void bcma_erom_seek(struct bcma_erom *erom, bus_size_t offset);
void bcma_erom_reset(struct bcma_erom *erom);
int bcma_erom_seek_core_index(struct bcma_erom *erom,
u_int core_index);
int bcma_erom_parse_core(struct bcma_erom *erom,
struct bcma_erom_core *core);
int bcma_erom_parse_mport(struct bcma_erom *erom,
struct bcma_erom_mport *mport);
int bcma_erom_parse_sport_region(struct bcma_erom *erom,
struct bcma_erom_sport_region *region);
int bcma_erom_get_core_info(struct bcma_erom *erom,
struct bhnd_core_info **cores,
u_int *num_cores);
int bcma_erom_parse_corecfg(struct bcma_erom *erom,
struct bcma_corecfg **result);
#endif /* _BCMA_BCMA_EROMVAR_H_ */

View file

@ -0,0 +1,279 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/limits.h>
#include <sys/systm.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <dev/bhnd/bhndvar.h>
#include "bcmavar.h"
/**
* Allocate and initialize new core config structure.
*
* @param core_index Core index on the bus.
* @param core_unit Core unit number.
* @param vendor Core designer.
* @param device Core identifier (e.g. part number).
* @param hwrev Core revision.
*/
struct bcma_corecfg *
bcma_alloc_corecfg(u_int core_index, int core_unit, uint16_t vendor,
uint16_t device, uint8_t hwrev)
{
struct bcma_corecfg *cfg;
cfg = malloc(sizeof(*cfg), M_BHND, M_NOWAIT);
if (cfg == NULL)
return NULL;
cfg->core_info = (struct bhnd_core_info) {
.vendor = vendor,
.device = device,
.hwrev = hwrev,
.core_idx = core_index,
.unit = core_unit
};
STAILQ_INIT(&cfg->master_ports);
cfg->num_master_ports = 0;
STAILQ_INIT(&cfg->dev_ports);
cfg->num_dev_ports = 0;
STAILQ_INIT(&cfg->bridge_ports);
cfg->num_bridge_ports = 0;
STAILQ_INIT(&cfg->wrapper_ports);
cfg->num_wrapper_ports = 0;
return (cfg);
}
/**
* Deallocate the given core config and any associated resources.
*
* @param corecfg Core info to be deallocated.
*/
void
bcma_free_corecfg(struct bcma_corecfg *corecfg)
{
struct bcma_mport *mport, *mnext;
struct bcma_sport *sport, *snext;
STAILQ_FOREACH_SAFE(mport, &corecfg->master_ports, mp_link, mnext) {
free(mport, M_BHND);
}
STAILQ_FOREACH_SAFE(sport, &corecfg->dev_ports, sp_link, snext) {
bcma_free_sport(sport);
}
STAILQ_FOREACH_SAFE(sport, &corecfg->bridge_ports, sp_link, snext) {
bcma_free_sport(sport);
}
STAILQ_FOREACH_SAFE(sport, &corecfg->wrapper_ports, sp_link, snext) {
bcma_free_sport(sport);
}
free(corecfg, M_BHND);
}
/**
* Return the @p cfg port list for @p type.
*
* @param cfg The core configuration.
* @param type The requested port type.
*/
struct bcma_sport_list *
bcma_corecfg_get_port_list(struct bcma_corecfg *cfg, bhnd_port_type type)
{
switch (type) {
case BHND_PORT_DEVICE:
return (&cfg->dev_ports);
break;
case BHND_PORT_BRIDGE:
return (&cfg->bridge_ports);
break;
case BHND_PORT_AGENT:
return (&cfg->wrapper_ports);
break;
}
}
/**
* Populate the resource list and bcma_map RIDs using the maps defined on
* @p ports.
*
* @param bus The requesting bus device.
* @param dinfo The device info instance to be initialized.
* @param ports The set of ports to be enumerated
*/
static void
bcma_dinfo_init_resource_info(device_t bus, struct bcma_devinfo *dinfo,
struct bcma_sport_list *ports)
{
struct bcma_map *map;
struct bcma_sport *port;
bhnd_addr_t end;
STAILQ_FOREACH(port, ports, sp_link) {
STAILQ_FOREACH(map, &port->sp_maps, m_link) {
/*
* Create the corresponding device resource list entry.
*
* We necessarily skip registration if the region's
* device memory range is not representable via
* rman_res_t.
*
* When rman_res_t is migrated to uintmax_t, any
* range should be representable.
*/
end = map->m_base + map->m_size;
if (map->m_base <= RM_MAX_END && end <= RM_MAX_END) {
map->m_rid = resource_list_add_next(
&dinfo->resources, SYS_RES_MEMORY,
map->m_base, end, map->m_size);
} else if (bootverbose) {
device_printf(bus,
"core%u %s%u.%u: region %llx-%llx extends "
"beyond supported addressable range\n",
dinfo->corecfg->core_info.core_idx,
bhnd_port_type_name(port->sp_type),
port->sp_num, map->m_region_num,
(unsigned long long) map->m_base,
(unsigned long long) end);
}
}
}
}
/**
* Allocate and initialize new device info structure, assuming ownership
* of the provided core configuration.
*
* @param bus The requesting bus device.
* @param corecfg Device core configuration.
*/
struct bcma_devinfo *
bcma_alloc_dinfo(device_t bus, struct bcma_corecfg *corecfg)
{
struct bcma_devinfo *dinfo;
dinfo = malloc(sizeof(struct bcma_devinfo), M_BHND, M_NOWAIT);
if (dinfo == NULL)
return NULL;
dinfo->corecfg = corecfg;
dinfo->res_agent = NULL;
dinfo->rid_agent = -1;
resource_list_init(&dinfo->resources);
/* The device ports must always be initialized first to ensure that
* rid 0 maps to the first device port */
bcma_dinfo_init_resource_info(bus, dinfo, &corecfg->dev_ports);
bcma_dinfo_init_resource_info(bus, dinfo, &corecfg->bridge_ports);
bcma_dinfo_init_resource_info(bus, dinfo, &corecfg->wrapper_ports);
return dinfo;
}
/**
* Deallocate the given device info structure and any associated resources.
*
* @param bus The requesting bus device.
* @param dinfo Device info to be deallocated.
*/
void
bcma_free_dinfo(device_t bus, struct bcma_devinfo *dinfo)
{
bcma_free_corecfg(dinfo->corecfg);
resource_list_free(&dinfo->resources);
/* Release agent resource, if any */
if (dinfo->res_agent != NULL) {
bhnd_release_resource(bus, SYS_RES_MEMORY, dinfo->rid_agent,
dinfo->res_agent);
}
free(dinfo, M_BHND);
}
/**
* Allocate and initialize new slave port descriptor.
*
* @param port_num Per-core port number.
* @param port_type Port type.
*/
struct bcma_sport *
bcma_alloc_sport(bcma_pid_t port_num, bhnd_port_type port_type)
{
struct bcma_sport *sport;
sport = malloc(sizeof(struct bcma_sport), M_BHND, M_NOWAIT);
if (sport == NULL)
return NULL;
sport->sp_num = port_num;
sport->sp_type = port_type;
sport->sp_num_maps = 0;
STAILQ_INIT(&sport->sp_maps);
return sport;
}
/**
* Deallocate all resources associated with the given port descriptor.
*
* @param sport Port descriptor to be deallocated.
*/
void
bcma_free_sport(struct bcma_sport *sport) {
struct bcma_map *map, *mapnext;
STAILQ_FOREACH_SAFE(map, &sport->sp_maps, m_link, mapnext) {
free(map, M_BHND);
}
free(sport, M_BHND);
}

149
sys/dev/bhnd/bcma/bcmavar.h Normal file
View file

@ -0,0 +1,149 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
* $FreeBSD$
*/
#ifndef _BCMA_BCMAVAR_H_
#define _BCMA_BCMAVAR_H_
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/limits.h>
#include <machine/bus.h>
#include <sys/rman.h>
#include "bcma.h"
/*
* Internal definitions shared by bcma(4) driver implementations.
*/
/** BCMA port identifier. */
typedef u_int bcma_pid_t;
#define BCMA_PID_MAX UINT_MAX /**< Maximum bcma_pid_t value */
/** BCMA per-port region map identifier. */
typedef u_int bcma_rmid_t;
#define BCMA_RMID_MAX UINT_MAX /**< Maximum bcma_rmid_t value */
struct bcma_devinfo;
struct bcma_corecfg;
struct bcma_map;
struct bcma_mport;
struct bcma_sport;
int bcma_probe(device_t dev);
int bcma_attach(device_t dev);
int bcma_detach(device_t dev);
int bcma_add_children(device_t bus,
struct resource *erom_res, bus_size_t erom_offset);
struct bcma_sport_list *bcma_corecfg_get_port_list(struct bcma_corecfg *cfg,
bhnd_port_type type);
struct bcma_devinfo *bcma_alloc_dinfo(device_t bus,
struct bcma_corecfg *corecfg);
void bcma_free_dinfo(device_t bus,
struct bcma_devinfo *dinfo);
struct bcma_corecfg *bcma_alloc_corecfg(u_int core_index, int core_unit,
uint16_t vendor, uint16_t device, uint8_t hwrev);
void bcma_free_corecfg(struct bcma_corecfg *corecfg);
struct bcma_sport *bcma_alloc_sport(bcma_pid_t port_num, bhnd_port_type port_type);
void bcma_free_sport(struct bcma_sport *sport);
/** BCMA master port descriptor */
struct bcma_mport {
bcma_pid_t mp_num; /**< AXI port identifier (bus-unique) */
bcma_pid_t mp_vid; /**< AXI master virtual ID (core-unique) */
STAILQ_ENTRY(bcma_mport) mp_link;
};
/** BCMA memory region descriptor */
struct bcma_map {
bcma_rmid_t m_region_num; /**< region identifier (port-unique). */
bhnd_addr_t m_base; /**< base address */
bhnd_size_t m_size; /**< size */
int m_rid; /**< bus resource id, or -1. */
STAILQ_ENTRY(bcma_map) m_link;
};
/** BCMA slave port descriptor */
struct bcma_sport {
bcma_pid_t sp_num; /**< slave port number (core-unique) */
bhnd_port_type sp_type; /**< port type */
u_long sp_num_maps; /**< number of regions mapped to this port */
STAILQ_HEAD(, bcma_map) sp_maps;
STAILQ_ENTRY(bcma_sport) sp_link;
};
STAILQ_HEAD(bcma_mport_list, bcma_mport);
STAILQ_HEAD(bcma_sport_list, bcma_sport);
/** BCMA IP core/block configuration */
struct bcma_corecfg {
struct bhnd_core_info core_info; /**< standard core info */
u_long num_master_ports; /**< number of master port descriptors. */
struct bcma_mport_list master_ports; /**< master port descriptors */
u_long num_dev_ports; /**< number of device slave port descriptors. */
struct bcma_sport_list dev_ports; /**< device port descriptors */
u_long num_bridge_ports; /**< number of bridge slave port descriptors. */
struct bcma_sport_list bridge_ports; /**< bridge port descriptors */
u_long num_wrapper_ports; /**< number of wrapper slave port descriptors. */
struct bcma_sport_list wrapper_ports; /**< wrapper port descriptors */
};
/**
* BCMA per-device info
*/
struct bcma_devinfo {
struct resource_list resources; /**< Slave port memory regions. */
struct bcma_corecfg *corecfg; /**< IP core/block config */
struct bhnd_resource *res_agent; /**< Agent (wrapper) resource, or NULL. Not
* all bcma(4) cores have or require an agent. */
int rid_agent; /**< Agent resource ID, or -1 */
};
/** BMCA per-instance state */
struct bcma_softc {
struct bhnd_softc bhnd_sc; /**< bhnd state */
};
#endif /* _BCMA_BCMAVAR_H_ */

373
sys/dev/bhnd/bcmsrom_fmt.h Normal file
View file

@ -0,0 +1,373 @@
/*-
* Copyright (c) 2010 Broadcom Corporation
*
* This file is derived from the bcmsrom.h header distributed with Broadcom's
* brcm80211 Linux driver release, as contributed to the Linux staging
* repository.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $FreeBSD$
*/
#ifndef _BHND_BCMSROM_FMT_H_
#define _BHND_BCMSROM_FMT_H_
/* Maximum srom: 6 Kilobits == 768 bytes */
#define SROM_MAX 768
#define SROM_MAXW 384
#define VARS_MAX 4096
/* PCI fields */
#define PCI_F0DEVID 48
#define SROM_WORDS 64
#define SROM3_SWRGN_OFF 28 /* s/w region offset in words */
#define SROM_SSID 2
#define SROM_WL1LHMAXP 29
#define SROM_WL1LPAB0 30
#define SROM_WL1LPAB1 31
#define SROM_WL1LPAB2 32
#define SROM_WL1HPAB0 33
#define SROM_WL1HPAB1 34
#define SROM_WL1HPAB2 35
#define SROM_MACHI_IL0 36
#define SROM_MACMID_IL0 37
#define SROM_MACLO_IL0 38
#define SROM_MACHI_ET0 39
#define SROM_MACMID_ET0 40
#define SROM_MACLO_ET0 41
#define SROM_MACHI_ET1 42
#define SROM_MACMID_ET1 43
#define SROM_MACLO_ET1 44
#define SROM3_MACHI 37
#define SROM3_MACMID 38
#define SROM3_MACLO 39
#define SROM_BXARSSI2G 40
#define SROM_BXARSSI5G 41
#define SROM_TRI52G 42
#define SROM_TRI5GHL 43
#define SROM_RXPO52G 45
#define SROM2_ENETPHY 45
#define SROM_AABREV 46
/* Fields in AABREV */
#define SROM_BR_MASK 0x00ff
#define SROM_CC_MASK 0x0f00
#define SROM_CC_SHIFT 8
#define SROM_AA0_MASK 0x3000
#define SROM_AA0_SHIFT 12
#define SROM_AA1_MASK 0xc000
#define SROM_AA1_SHIFT 14
#define SROM_WL0PAB0 47
#define SROM_WL0PAB1 48
#define SROM_WL0PAB2 49
#define SROM_LEDBH10 50
#define SROM_LEDBH32 51
#define SROM_WL10MAXP 52
#define SROM_WL1PAB0 53
#define SROM_WL1PAB1 54
#define SROM_WL1PAB2 55
#define SROM_ITT 56
#define SROM_BFL 57
#define SROM_BFL2 28
#define SROM3_BFL2 61
#define SROM_AG10 58
#define SROM_CCODE 59
#define SROM_OPO 60
#define SROM3_LEDDC 62
#define SROM_CRCREV 63
/* SROM Rev 4: Reallocate the software part of the srom to accommodate
* MIMO features. It assumes up to two PCIE functions and 440 bytes
* of useable srom i.e. the useable storage in chips with OTP that
* implements hardware redundancy.
*/
#define SROM4_WORDS 220
#define SROM4_SIGN 32
#define SROM4_SIGNATURE 0x5372
#define SROM4_BREV 33
#define SROM4_BFL0 34
#define SROM4_BFL1 35
#define SROM4_BFL2 36
#define SROM4_BFL3 37
#define SROM5_BFL0 37
#define SROM5_BFL1 38
#define SROM5_BFL2 39
#define SROM5_BFL3 40
#define SROM4_MACHI 38
#define SROM4_MACMID 39
#define SROM4_MACLO 40
#define SROM5_MACHI 41
#define SROM5_MACMID 42
#define SROM5_MACLO 43
#define SROM4_CCODE 41
#define SROM4_REGREV 42
#define SROM5_CCODE 34
#define SROM5_REGREV 35
#define SROM4_LEDBH10 43
#define SROM4_LEDBH32 44
#define SROM5_LEDBH10 59
#define SROM5_LEDBH32 60
#define SROM4_LEDDC 45
#define SROM5_LEDDC 45
#define SROM4_AA 46
#define SROM4_AA2G_MASK 0x00ff
#define SROM4_AA2G_SHIFT 0
#define SROM4_AA5G_MASK 0xff00
#define SROM4_AA5G_SHIFT 8
#define SROM4_AG10 47
#define SROM4_AG32 48
#define SROM4_TXPID2G 49
#define SROM4_TXPID5G 51
#define SROM4_TXPID5GL 53
#define SROM4_TXPID5GH 55
#define SROM4_TXRXC 61
#define SROM4_TXCHAIN_MASK 0x000f
#define SROM4_TXCHAIN_SHIFT 0
#define SROM4_RXCHAIN_MASK 0x00f0
#define SROM4_RXCHAIN_SHIFT 4
#define SROM4_SWITCH_MASK 0xff00
#define SROM4_SWITCH_SHIFT 8
/* Per-path fields */
#define MAX_PATH_SROM 4
#define SROM4_PATH0 64
#define SROM4_PATH1 87
#define SROM4_PATH2 110
#define SROM4_PATH3 133
#define SROM4_2G_ITT_MAXP 0
#define SROM4_2G_PA 1
#define SROM4_5G_ITT_MAXP 5
#define SROM4_5GLH_MAXP 6
#define SROM4_5G_PA 7
#define SROM4_5GL_PA 11
#define SROM4_5GH_PA 15
/* Fields in the ITT_MAXP and 5GLH_MAXP words */
#define B2G_MAXP_MASK 0xff
#define B2G_ITT_SHIFT 8
#define B5G_MAXP_MASK 0xff
#define B5G_ITT_SHIFT 8
#define B5GH_MAXP_MASK 0xff
#define B5GL_MAXP_SHIFT 8
/* All the miriad power offsets */
#define SROM4_2G_CCKPO 156
#define SROM4_2G_OFDMPO 157
#define SROM4_5G_OFDMPO 159
#define SROM4_5GL_OFDMPO 161
#define SROM4_5GH_OFDMPO 163
#define SROM4_2G_MCSPO 165
#define SROM4_5G_MCSPO 173
#define SROM4_5GL_MCSPO 181
#define SROM4_5GH_MCSPO 189
#define SROM4_CDDPO 197
#define SROM4_STBCPO 198
#define SROM4_BW40PO 199
#define SROM4_BWDUPPO 200
#define SROM4_CRCREV 219
/* SROM Rev 8: Make space for a 48word hardware header for PCIe rev >= 6.
* This is acombined srom for both MIMO and SISO boards, usable in
* the .130 4Kilobit OTP with hardware redundancy.
*/
#define SROM8_SIGN 64
#define SROM8_BREV 65
#define SROM8_BFL0 66
#define SROM8_BFL1 67
#define SROM8_BFL2 68
#define SROM8_BFL3 69
#define SROM8_MACHI 70
#define SROM8_MACMID 71
#define SROM8_MACLO 72
#define SROM8_CCODE 73
#define SROM8_REGREV 74
#define SROM8_LEDBH10 75
#define SROM8_LEDBH32 76
#define SROM8_LEDDC 77
#define SROM8_AA 78
#define SROM8_AG10 79
#define SROM8_AG32 80
#define SROM8_TXRXC 81
#define SROM8_BXARSSI2G 82
#define SROM8_BXARSSI5G 83
#define SROM8_TRI52G 84
#define SROM8_TRI5GHL 85
#define SROM8_RXPO52G 86
#define SROM8_FEM2G 87
#define SROM8_FEM5G 88
#define SROM8_FEM_ANTSWLUT_MASK 0xf800
#define SROM8_FEM_ANTSWLUT_SHIFT 11
#define SROM8_FEM_TR_ISO_MASK 0x0700
#define SROM8_FEM_TR_ISO_SHIFT 8
#define SROM8_FEM_PDET_RANGE_MASK 0x00f8
#define SROM8_FEM_PDET_RANGE_SHIFT 3
#define SROM8_FEM_EXTPA_GAIN_MASK 0x0006
#define SROM8_FEM_EXTPA_GAIN_SHIFT 1
#define SROM8_FEM_TSSIPOS_MASK 0x0001
#define SROM8_FEM_TSSIPOS_SHIFT 0
#define SROM8_THERMAL 89
/* Temp sense related entries */
#define SROM8_MPWR_RAWTS 90
#define SROM8_TS_SLP_OPT_CORRX 91
/* FOC: freiquency offset correction, HWIQ: H/W IOCAL enable, IQSWP: IQ CAL swap disable */
#define SROM8_FOC_HWIQ_IQSWP 92
/* Temperature delta for PHY calibration */
#define SROM8_PHYCAL_TEMPDELTA 93
/* Per-path offsets & fields */
#define SROM8_PATH0 96
#define SROM8_PATH1 112
#define SROM8_PATH2 128
#define SROM8_PATH3 144
#define SROM8_2G_ITT_MAXP 0
#define SROM8_2G_PA 1
#define SROM8_5G_ITT_MAXP 4
#define SROM8_5GLH_MAXP 5
#define SROM8_5G_PA 6
#define SROM8_5GL_PA 9
#define SROM8_5GH_PA 12
/* All the miriad power offsets */
#define SROM8_2G_CCKPO 160
#define SROM8_2G_OFDMPO 161
#define SROM8_5G_OFDMPO 163
#define SROM8_5GL_OFDMPO 165
#define SROM8_5GH_OFDMPO 167
#define SROM8_2G_MCSPO 169
#define SROM8_5G_MCSPO 177
#define SROM8_5GL_MCSPO 185
#define SROM8_5GH_MCSPO 193
#define SROM8_CDDPO 201
#define SROM8_STBCPO 202
#define SROM8_BW40PO 203
#define SROM8_BWDUPPO 204
/* SISO PA parameters are in the path0 spaces */
#define SROM8_SISO 96
/* Legacy names for SISO PA paramters */
#define SROM8_W0_ITTMAXP (SROM8_SISO + SROM8_2G_ITT_MAXP)
#define SROM8_W0_PAB0 (SROM8_SISO + SROM8_2G_PA)
#define SROM8_W0_PAB1 (SROM8_SISO + SROM8_2G_PA + 1)
#define SROM8_W0_PAB2 (SROM8_SISO + SROM8_2G_PA + 2)
#define SROM8_W1_ITTMAXP (SROM8_SISO + SROM8_5G_ITT_MAXP)
#define SROM8_W1_MAXP_LCHC (SROM8_SISO + SROM8_5GLH_MAXP)
#define SROM8_W1_PAB0 (SROM8_SISO + SROM8_5G_PA)
#define SROM8_W1_PAB1 (SROM8_SISO + SROM8_5G_PA + 1)
#define SROM8_W1_PAB2 (SROM8_SISO + SROM8_5G_PA + 2)
#define SROM8_W1_PAB0_LC (SROM8_SISO + SROM8_5GL_PA)
#define SROM8_W1_PAB1_LC (SROM8_SISO + SROM8_5GL_PA + 1)
#define SROM8_W1_PAB2_LC (SROM8_SISO + SROM8_5GL_PA + 2)
#define SROM8_W1_PAB0_HC (SROM8_SISO + SROM8_5GH_PA)
#define SROM8_W1_PAB1_HC (SROM8_SISO + SROM8_5GH_PA + 1)
#define SROM8_W1_PAB2_HC (SROM8_SISO + SROM8_5GH_PA + 2)
#define SROM8_CRCREV 219
/* SROM REV 9 */
#define SROM9_2GPO_CCKBW20 160
#define SROM9_2GPO_CCKBW20UL 161
#define SROM9_2GPO_LOFDMBW20 162
#define SROM9_2GPO_LOFDMBW20UL 164
#define SROM9_5GLPO_LOFDMBW20 166
#define SROM9_5GLPO_LOFDMBW20UL 168
#define SROM9_5GMPO_LOFDMBW20 170
#define SROM9_5GMPO_LOFDMBW20UL 172
#define SROM9_5GHPO_LOFDMBW20 174
#define SROM9_5GHPO_LOFDMBW20UL 176
#define SROM9_2GPO_MCSBW20 178
#define SROM9_2GPO_MCSBW20UL 180
#define SROM9_2GPO_MCSBW40 182
#define SROM9_5GLPO_MCSBW20 184
#define SROM9_5GLPO_MCSBW20UL 186
#define SROM9_5GLPO_MCSBW40 188
#define SROM9_5GMPO_MCSBW20 190
#define SROM9_5GMPO_MCSBW20UL 192
#define SROM9_5GMPO_MCSBW40 194
#define SROM9_5GHPO_MCSBW20 196
#define SROM9_5GHPO_MCSBW20UL 198
#define SROM9_5GHPO_MCSBW40 200
#define SROM9_PO_MCS32 202
#define SROM9_PO_LOFDM40DUP 203
#define SROM9_REV_CRC 219
typedef struct {
u8 tssipos; /* TSSI positive slope, 1: positive, 0: negative */
u8 extpagain; /* Ext PA gain-type: full-gain: 0, pa-lite: 1, no_pa: 2 */
u8 pdetrange; /* support 32 combinations of different Pdet dynamic ranges */
u8 triso; /* TR switch isolation */
u8 antswctrllut; /* antswctrl lookup table configuration: 32 possible choices */
} srom_fem_t;
#endif /* _BHND_BCMSROM_TBL_H_ */

577
sys/dev/bhnd/bcmsrom_tbl.h Normal file
View file

@ -0,0 +1,577 @@
/*-
* Copyright (c) 2010 Broadcom Corporation
*
* This file is derived from the bcmsrom.h header distributed with Broadcom's
* brcm80211 Linux driver release, as contributed to the Linux staging
* repository.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $FreeBSD$
*/
#ifndef _BHND_BCMSROM_TBL_H_
#define _BHND_BCMSROM_TBL_H_
#include "bcmsrom_fmt.h"
typedef struct {
const char *name;
u32 revmask;
u32 flags;
u16 off;
u16 mask;
} sromvar_t;
#define SRFL_MORE 1 /* value continues as described by the next entry */
#define SRFL_NOFFS 2 /* value bits can't be all one's */
#define SRFL_PRHEX 4 /* value is in hexdecimal format */
#define SRFL_PRSIGN 8 /* value is in signed decimal format */
#define SRFL_CCODE 0x10 /* value is in country code format */
#define SRFL_ETHADDR 0x20 /* value is an Ethernet address */
#define SRFL_LEDDC 0x40 /* value is an LED duty cycle */
#define SRFL_NOVAR 0x80 /* do not generate a nvram param, entry is for mfgc */
/* Assumptions:
* - Ethernet address spans across 3 consective words
*
* Table rules:
* - Add multiple entries next to each other if a value spans across multiple words
* (even multiple fields in the same word) with each entry except the last having
* it's SRFL_MORE bit set.
* - Ethernet address entry does not follow above rule and must not have SRFL_MORE
* bit set. Its SRFL_ETHADDR bit implies it takes multiple words.
* - The last entry's name field must be NULL to indicate the end of the table. Other
* entries must have non-NULL name.
*/
static const sromvar_t pci_sromvars[] = {
{"devid", 0xffffff00, SRFL_PRHEX | SRFL_NOVAR, PCI_F0DEVID, 0xffff},
{"boardrev", 0x0000000e, SRFL_PRHEX, SROM_AABREV, SROM_BR_MASK},
{"boardrev", 0x000000f0, SRFL_PRHEX, SROM4_BREV, 0xffff},
{"boardrev", 0xffffff00, SRFL_PRHEX, SROM8_BREV, 0xffff},
{"boardflags", 0x00000002, SRFL_PRHEX, SROM_BFL, 0xffff},
{"boardflags", 0x00000004, SRFL_PRHEX | SRFL_MORE, SROM_BFL, 0xffff},
{"", 0, 0, SROM_BFL2, 0xffff},
{"boardflags", 0x00000008, SRFL_PRHEX | SRFL_MORE, SROM_BFL, 0xffff},
{"", 0, 0, SROM3_BFL2, 0xffff},
{"boardflags", 0x00000010, SRFL_PRHEX | SRFL_MORE, SROM4_BFL0, 0xffff},
{"", 0, 0, SROM4_BFL1, 0xffff},
{"boardflags", 0x000000e0, SRFL_PRHEX | SRFL_MORE, SROM5_BFL0, 0xffff},
{"", 0, 0, SROM5_BFL1, 0xffff},
{"boardflags", 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL0, 0xffff},
{"", 0, 0, SROM8_BFL1, 0xffff},
{"boardflags2", 0x00000010, SRFL_PRHEX | SRFL_MORE, SROM4_BFL2, 0xffff},
{"", 0, 0, SROM4_BFL3, 0xffff},
{"boardflags2", 0x000000e0, SRFL_PRHEX | SRFL_MORE, SROM5_BFL2, 0xffff},
{"", 0, 0, SROM5_BFL3, 0xffff},
{"boardflags2", 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL2, 0xffff},
{"", 0, 0, SROM8_BFL3, 0xffff},
{"boardtype", 0xfffffffc, SRFL_PRHEX, SROM_SSID, 0xffff},
{"boardnum", 0x00000006, 0, SROM_MACLO_IL0, 0xffff},
{"boardnum", 0x00000008, 0, SROM3_MACLO, 0xffff},
{"boardnum", 0x00000010, 0, SROM4_MACLO, 0xffff},
{"boardnum", 0x000000e0, 0, SROM5_MACLO, 0xffff},
{"boardnum", 0xffffff00, 0, SROM8_MACLO, 0xffff},
{"cc", 0x00000002, 0, SROM_AABREV, SROM_CC_MASK},
{"regrev", 0x00000008, 0, SROM_OPO, 0xff00},
{"regrev", 0x00000010, 0, SROM4_REGREV, 0x00ff},
{"regrev", 0x000000e0, 0, SROM5_REGREV, 0x00ff},
{"regrev", 0xffffff00, 0, SROM8_REGREV, 0x00ff},
{"ledbh0", 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0x00ff},
{"ledbh1", 0x0000000e, SRFL_NOFFS, SROM_LEDBH10, 0xff00},
{"ledbh2", 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0x00ff},
{"ledbh3", 0x0000000e, SRFL_NOFFS, SROM_LEDBH32, 0xff00},
{"ledbh0", 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0x00ff},
{"ledbh1", 0x00000010, SRFL_NOFFS, SROM4_LEDBH10, 0xff00},
{"ledbh2", 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0x00ff},
{"ledbh3", 0x00000010, SRFL_NOFFS, SROM4_LEDBH32, 0xff00},
{"ledbh0", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0x00ff},
{"ledbh1", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH10, 0xff00},
{"ledbh2", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0x00ff},
{"ledbh3", 0x000000e0, SRFL_NOFFS, SROM5_LEDBH32, 0xff00},
{"ledbh0", 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0x00ff},
{"ledbh1", 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0xff00},
{"ledbh2", 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0x00ff},
{"ledbh3", 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0xff00},
{"pa0b0", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB0, 0xffff},
{"pa0b1", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB1, 0xffff},
{"pa0b2", 0x0000000e, SRFL_PRHEX, SROM_WL0PAB2, 0xffff},
{"pa0itssit", 0x0000000e, 0, SROM_ITT, 0x00ff},
{"pa0maxpwr", 0x0000000e, 0, SROM_WL10MAXP, 0x00ff},
{"pa0b0", 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB0, 0xffff},
{"pa0b1", 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB1, 0xffff},
{"pa0b2", 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB2, 0xffff},
{"pa0itssit", 0xffffff00, 0, SROM8_W0_ITTMAXP, 0xff00},
{"pa0maxpwr", 0xffffff00, 0, SROM8_W0_ITTMAXP, 0x00ff},
{"opo", 0x0000000c, 0, SROM_OPO, 0x00ff},
{"opo", 0xffffff00, 0, SROM8_2G_OFDMPO, 0x00ff},
{"aa2g", 0x0000000e, 0, SROM_AABREV, SROM_AA0_MASK},
{"aa2g", 0x000000f0, 0, SROM4_AA, 0x00ff},
{"aa2g", 0xffffff00, 0, SROM8_AA, 0x00ff},
{"aa5g", 0x0000000e, 0, SROM_AABREV, SROM_AA1_MASK},
{"aa5g", 0x000000f0, 0, SROM4_AA, 0xff00},
{"aa5g", 0xffffff00, 0, SROM8_AA, 0xff00},
{"ag0", 0x0000000e, 0, SROM_AG10, 0x00ff},
{"ag1", 0x0000000e, 0, SROM_AG10, 0xff00},
{"ag0", 0x000000f0, 0, SROM4_AG10, 0x00ff},
{"ag1", 0x000000f0, 0, SROM4_AG10, 0xff00},
{"ag2", 0x000000f0, 0, SROM4_AG32, 0x00ff},
{"ag3", 0x000000f0, 0, SROM4_AG32, 0xff00},
{"ag0", 0xffffff00, 0, SROM8_AG10, 0x00ff},
{"ag1", 0xffffff00, 0, SROM8_AG10, 0xff00},
{"ag2", 0xffffff00, 0, SROM8_AG32, 0x00ff},
{"ag3", 0xffffff00, 0, SROM8_AG32, 0xff00},
{"pa1b0", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB0, 0xffff},
{"pa1b1", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB1, 0xffff},
{"pa1b2", 0x0000000e, SRFL_PRHEX, SROM_WL1PAB2, 0xffff},
{"pa1lob0", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB0, 0xffff},
{"pa1lob1", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB1, 0xffff},
{"pa1lob2", 0x0000000c, SRFL_PRHEX, SROM_WL1LPAB2, 0xffff},
{"pa1hib0", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB0, 0xffff},
{"pa1hib1", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB1, 0xffff},
{"pa1hib2", 0x0000000c, SRFL_PRHEX, SROM_WL1HPAB2, 0xffff},
{"pa1itssit", 0x0000000e, 0, SROM_ITT, 0xff00},
{"pa1maxpwr", 0x0000000e, 0, SROM_WL10MAXP, 0xff00},
{"pa1lomaxpwr", 0x0000000c, 0, SROM_WL1LHMAXP, 0xff00},
{"pa1himaxpwr", 0x0000000c, 0, SROM_WL1LHMAXP, 0x00ff},
{"pa1b0", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0, 0xffff},
{"pa1b1", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1, 0xffff},
{"pa1b2", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2, 0xffff},
{"pa1lob0", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0_LC, 0xffff},
{"pa1lob1", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1_LC, 0xffff},
{"pa1lob2", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2_LC, 0xffff},
{"pa1hib0", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0_HC, 0xffff},
{"pa1hib1", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1_HC, 0xffff},
{"pa1hib2", 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2_HC, 0xffff},
{"pa1itssit", 0xffffff00, 0, SROM8_W1_ITTMAXP, 0xff00},
{"pa1maxpwr", 0xffffff00, 0, SROM8_W1_ITTMAXP, 0x00ff},
{"pa1lomaxpwr", 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0xff00},
{"pa1himaxpwr", 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0x00ff},
{"bxa2g", 0x00000008, 0, SROM_BXARSSI2G, 0x1800},
{"rssisav2g", 0x00000008, 0, SROM_BXARSSI2G, 0x0700},
{"rssismc2g", 0x00000008, 0, SROM_BXARSSI2G, 0x00f0},
{"rssismf2g", 0x00000008, 0, SROM_BXARSSI2G, 0x000f},
{"bxa2g", 0xffffff00, 0, SROM8_BXARSSI2G, 0x1800},
{"rssisav2g", 0xffffff00, 0, SROM8_BXARSSI2G, 0x0700},
{"rssismc2g", 0xffffff00, 0, SROM8_BXARSSI2G, 0x00f0},
{"rssismf2g", 0xffffff00, 0, SROM8_BXARSSI2G, 0x000f},
{"bxa5g", 0x00000008, 0, SROM_BXARSSI5G, 0x1800},
{"rssisav5g", 0x00000008, 0, SROM_BXARSSI5G, 0x0700},
{"rssismc5g", 0x00000008, 0, SROM_BXARSSI5G, 0x00f0},
{"rssismf5g", 0x00000008, 0, SROM_BXARSSI5G, 0x000f},
{"bxa5g", 0xffffff00, 0, SROM8_BXARSSI5G, 0x1800},
{"rssisav5g", 0xffffff00, 0, SROM8_BXARSSI5G, 0x0700},
{"rssismc5g", 0xffffff00, 0, SROM8_BXARSSI5G, 0x00f0},
{"rssismf5g", 0xffffff00, 0, SROM8_BXARSSI5G, 0x000f},
{"tri2g", 0x00000008, 0, SROM_TRI52G, 0x00ff},
{"tri5g", 0x00000008, 0, SROM_TRI52G, 0xff00},
{"tri5gl", 0x00000008, 0, SROM_TRI5GHL, 0x00ff},
{"tri5gh", 0x00000008, 0, SROM_TRI5GHL, 0xff00},
{"tri2g", 0xffffff00, 0, SROM8_TRI52G, 0x00ff},
{"tri5g", 0xffffff00, 0, SROM8_TRI52G, 0xff00},
{"tri5gl", 0xffffff00, 0, SROM8_TRI5GHL, 0x00ff},
{"tri5gh", 0xffffff00, 0, SROM8_TRI5GHL, 0xff00},
{"rxpo2g", 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0x00ff},
{"rxpo5g", 0x00000008, SRFL_PRSIGN, SROM_RXPO52G, 0xff00},
{"rxpo2g", 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0x00ff},
{"rxpo5g", 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0xff00},
{"txchain", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_TXCHAIN_MASK},
{"rxchain", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_RXCHAIN_MASK},
{"antswitch", 0x000000f0, SRFL_NOFFS, SROM4_TXRXC, SROM4_SWITCH_MASK},
{"txchain", 0xffffff00, SRFL_NOFFS, SROM8_TXRXC, SROM4_TXCHAIN_MASK},
{"rxchain", 0xffffff00, SRFL_NOFFS, SROM8_TXRXC, SROM4_RXCHAIN_MASK},
{"antswitch", 0xffffff00, SRFL_NOFFS, SROM8_TXRXC, SROM4_SWITCH_MASK},
{"tssipos2g", 0xffffff00, 0, SROM8_FEM2G, SROM8_FEM_TSSIPOS_MASK},
{"extpagain2g", 0xffffff00, 0, SROM8_FEM2G, SROM8_FEM_EXTPA_GAIN_MASK},
{"pdetrange2g", 0xffffff00, 0, SROM8_FEM2G, SROM8_FEM_PDET_RANGE_MASK},
{"triso2g", 0xffffff00, 0, SROM8_FEM2G, SROM8_FEM_TR_ISO_MASK},
{"antswctl2g", 0xffffff00, 0, SROM8_FEM2G, SROM8_FEM_ANTSWLUT_MASK},
{"tssipos5g", 0xffffff00, 0, SROM8_FEM5G, SROM8_FEM_TSSIPOS_MASK},
{"extpagain5g", 0xffffff00, 0, SROM8_FEM5G, SROM8_FEM_EXTPA_GAIN_MASK},
{"pdetrange5g", 0xffffff00, 0, SROM8_FEM5G, SROM8_FEM_PDET_RANGE_MASK},
{"triso5g", 0xffffff00, 0, SROM8_FEM5G, SROM8_FEM_TR_ISO_MASK},
{"antswctl5g", 0xffffff00, 0, SROM8_FEM5G, SROM8_FEM_ANTSWLUT_MASK},
{"tempthresh", 0xffffff00, 0, SROM8_THERMAL, 0xff00},
{"tempoffset", 0xffffff00, 0, SROM8_THERMAL, 0x00ff},
{"txpid2ga0", 0x000000f0, 0, SROM4_TXPID2G, 0x00ff},
{"txpid2ga1", 0x000000f0, 0, SROM4_TXPID2G, 0xff00},
{"txpid2ga2", 0x000000f0, 0, SROM4_TXPID2G+1, 0x00ff},
{"txpid2ga3", 0x000000f0, 0, SROM4_TXPID2G+1, 0xff00},
{"txpid5ga0", 0x000000f0, 0, SROM4_TXPID5G, 0x00ff},
{"txpid5ga1", 0x000000f0, 0, SROM4_TXPID5G, 0xff00},
{"txpid5ga2", 0x000000f0, 0, SROM4_TXPID5G+1, 0x00ff},
{"txpid5ga3", 0x000000f0, 0, SROM4_TXPID5G+1, 0xff00},
{"txpid5gla0", 0x000000f0, 0, SROM4_TXPID5GL, 0x00ff},
{"txpid5gla1", 0x000000f0, 0, SROM4_TXPID5GL, 0xff00},
{"txpid5gla2", 0x000000f0, 0, SROM4_TXPID5GL+1, 0x00ff},
{"txpid5gla3", 0x000000f0, 0, SROM4_TXPID5GL+1, 0xff00},
{"txpid5gha0", 0x000000f0, 0, SROM4_TXPID5GH, 0x00ff},
{"txpid5gha1", 0x000000f0, 0, SROM4_TXPID5GH, 0xff00},
{"txpid5gha2", 0x000000f0, 0, SROM4_TXPID5GH+1, 0x00ff},
{"txpid5gha3", 0x000000f0, 0, SROM4_TXPID5GH+1, 0xff00},
{"ccode", 0x0000000f, SRFL_CCODE, SROM_CCODE, 0xffff},
{"ccode", 0x00000010, SRFL_CCODE, SROM4_CCODE, 0xffff},
{"ccode", 0x000000e0, SRFL_CCODE, SROM5_CCODE, 0xffff},
{"ccode", 0xffffff00, SRFL_CCODE, SROM8_CCODE, 0xffff},
{"macaddr", 0xffffff00, SRFL_ETHADDR, SROM8_MACHI, 0xffff},
{"macaddr", 0x000000e0, SRFL_ETHADDR, SROM5_MACHI, 0xffff},
{"macaddr", 0x00000010, SRFL_ETHADDR, SROM4_MACHI, 0xffff},
{"macaddr", 0x00000008, SRFL_ETHADDR, SROM3_MACHI, 0xffff},
{"il0macaddr", 0x00000007, SRFL_ETHADDR, SROM_MACHI_IL0, 0xffff},
{"et1macaddr", 0x00000007, SRFL_ETHADDR, SROM_MACHI_ET1, 0xffff},
{"leddc", 0xffffff00, SRFL_NOFFS | SRFL_LEDDC, SROM8_LEDDC, 0xffff},
{"leddc", 0x000000e0, SRFL_NOFFS | SRFL_LEDDC, SROM5_LEDDC, 0xffff},
{"leddc", 0x00000010, SRFL_NOFFS | SRFL_LEDDC, SROM4_LEDDC, 0xffff},
{"leddc", 0x00000008, SRFL_NOFFS | SRFL_LEDDC, SROM3_LEDDC, 0xffff},
{"rawtempsense",0xffffff00, SRFL_PRHEX, SROM8_MPWR_RAWTS, 0x01ff},
{"measpower", 0xffffff00, SRFL_PRHEX, SROM8_MPWR_RAWTS, 0xfe00},
{"tempsense_slope",0xffffff00, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX, 0x00ff},
{"tempcorrx", 0xffffff00, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX, 0xfc00},
{"tempsense_option",0xffffff00, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX, 0x0300},
{"freqoffset_corr",0xffffff00, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, 0x000f},
{"iqcal_swp_dis",0xffffff00, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, 0x0010},
{"hw_iqcal_en", 0xffffff00, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP, 0x0020},
{"phycal_tempdelta",0xffffff00, 0, SROM8_PHYCAL_TEMPDELTA, 0x00ff},
{"cck2gpo", 0x000000f0, 0, SROM4_2G_CCKPO, 0xffff},
{"cck2gpo", 0x00000100, 0, SROM8_2G_CCKPO, 0xffff},
{"ofdm2gpo", 0x000000f0, SRFL_MORE, SROM4_2G_OFDMPO, 0xffff},
{"", 0, 0, SROM4_2G_OFDMPO+1, 0xffff},
{"ofdm5gpo", 0x000000f0, SRFL_MORE, SROM4_5G_OFDMPO, 0xffff},
{"", 0, 0, SROM4_5G_OFDMPO+1, 0xffff},
{"ofdm5glpo", 0x000000f0, SRFL_MORE, SROM4_5GL_OFDMPO, 0xffff},
{"", 0, 0, SROM4_5GL_OFDMPO+1, 0xffff},
{"ofdm5ghpo", 0x000000f0, SRFL_MORE, SROM4_5GH_OFDMPO, 0xffff},
{"", 0, 0, SROM4_5GH_OFDMPO+1, 0xffff},
{"ofdm2gpo", 0x00000100, SRFL_MORE, SROM8_2G_OFDMPO, 0xffff},
{"", 0, 0, SROM8_2G_OFDMPO+1, 0xffff},
{"ofdm5gpo", 0x00000100, SRFL_MORE, SROM8_5G_OFDMPO, 0xffff},
{"", 0, 0, SROM8_5G_OFDMPO+1, 0xffff},
{"ofdm5glpo", 0x00000100, SRFL_MORE, SROM8_5GL_OFDMPO, 0xffff},
{"", 0, 0, SROM8_5GL_OFDMPO+1, 0xffff},
{"ofdm5ghpo", 0x00000100, SRFL_MORE, SROM8_5GH_OFDMPO, 0xffff},
{"", 0, 0, SROM8_5GH_OFDMPO+1, 0xffff},
{"mcs2gpo0", 0x000000f0, 0, SROM4_2G_MCSPO, 0xffff},
{"mcs2gpo1", 0x000000f0, 0, SROM4_2G_MCSPO+1, 0xffff},
{"mcs2gpo2", 0x000000f0, 0, SROM4_2G_MCSPO+2, 0xffff},
{"mcs2gpo3", 0x000000f0, 0, SROM4_2G_MCSPO+3, 0xffff},
{"mcs2gpo4", 0x000000f0, 0, SROM4_2G_MCSPO+4, 0xffff},
{"mcs2gpo5", 0x000000f0, 0, SROM4_2G_MCSPO+5, 0xffff},
{"mcs2gpo6", 0x000000f0, 0, SROM4_2G_MCSPO+6, 0xffff},
{"mcs2gpo7", 0x000000f0, 0, SROM4_2G_MCSPO+7, 0xffff},
{"mcs5gpo0", 0x000000f0, 0, SROM4_5G_MCSPO, 0xffff},
{"mcs5gpo1", 0x000000f0, 0, SROM4_5G_MCSPO+1, 0xffff},
{"mcs5gpo2", 0x000000f0, 0, SROM4_5G_MCSPO+2, 0xffff},
{"mcs5gpo3", 0x000000f0, 0, SROM4_5G_MCSPO+3, 0xffff},
{"mcs5gpo4", 0x000000f0, 0, SROM4_5G_MCSPO+4, 0xffff},
{"mcs5gpo5", 0x000000f0, 0, SROM4_5G_MCSPO+5, 0xffff},
{"mcs5gpo6", 0x000000f0, 0, SROM4_5G_MCSPO+6, 0xffff},
{"mcs5gpo7", 0x000000f0, 0, SROM4_5G_MCSPO+7, 0xffff},
{"mcs5glpo0", 0x000000f0, 0, SROM4_5GL_MCSPO, 0xffff},
{"mcs5glpo1", 0x000000f0, 0, SROM4_5GL_MCSPO+1, 0xffff},
{"mcs5glpo2", 0x000000f0, 0, SROM4_5GL_MCSPO+2, 0xffff},
{"mcs5glpo3", 0x000000f0, 0, SROM4_5GL_MCSPO+3, 0xffff},
{"mcs5glpo4", 0x000000f0, 0, SROM4_5GL_MCSPO+4, 0xffff},
{"mcs5glpo5", 0x000000f0, 0, SROM4_5GL_MCSPO+5, 0xffff},
{"mcs5glpo6", 0x000000f0, 0, SROM4_5GL_MCSPO+6, 0xffff},
{"mcs5glpo7", 0x000000f0, 0, SROM4_5GL_MCSPO+7, 0xffff},
{"mcs5ghpo0", 0x000000f0, 0, SROM4_5GH_MCSPO, 0xffff},
{"mcs5ghpo1", 0x000000f0, 0, SROM4_5GH_MCSPO+1, 0xffff},
{"mcs5ghpo2", 0x000000f0, 0, SROM4_5GH_MCSPO+2, 0xffff},
{"mcs5ghpo3", 0x000000f0, 0, SROM4_5GH_MCSPO+3, 0xffff},
{"mcs5ghpo4", 0x000000f0, 0, SROM4_5GH_MCSPO+4, 0xffff},
{"mcs5ghpo5", 0x000000f0, 0, SROM4_5GH_MCSPO+5, 0xffff},
{"mcs5ghpo6", 0x000000f0, 0, SROM4_5GH_MCSPO+6, 0xffff},
{"mcs5ghpo7", 0x000000f0, 0, SROM4_5GH_MCSPO+7, 0xffff},
{"mcs2gpo0", 0x00000100, 0, SROM8_2G_MCSPO, 0xffff},
{"mcs2gpo1", 0x00000100, 0, SROM8_2G_MCSPO+1, 0xffff},
{"mcs2gpo2", 0x00000100, 0, SROM8_2G_MCSPO+2, 0xffff},
{"mcs2gpo3", 0x00000100, 0, SROM8_2G_MCSPO+3, 0xffff},
{"mcs2gpo4", 0x00000100, 0, SROM8_2G_MCSPO+4, 0xffff},
{"mcs2gpo5", 0x00000100, 0, SROM8_2G_MCSPO+5, 0xffff},
{"mcs2gpo6", 0x00000100, 0, SROM8_2G_MCSPO+6, 0xffff},
{"mcs2gpo7", 0x00000100, 0, SROM8_2G_MCSPO+7, 0xffff},
{"mcs5gpo0", 0x00000100, 0, SROM8_5G_MCSPO, 0xffff},
{"mcs5gpo1", 0x00000100, 0, SROM8_5G_MCSPO+1, 0xffff},
{"mcs5gpo2", 0x00000100, 0, SROM8_5G_MCSPO+2, 0xffff},
{"mcs5gpo3", 0x00000100, 0, SROM8_5G_MCSPO+3, 0xffff},
{"mcs5gpo4", 0x00000100, 0, SROM8_5G_MCSPO+4, 0xffff},
{"mcs5gpo5", 0x00000100, 0, SROM8_5G_MCSPO+5, 0xffff},
{"mcs5gpo6", 0x00000100, 0, SROM8_5G_MCSPO+6, 0xffff},
{"mcs5gpo7", 0x00000100, 0, SROM8_5G_MCSPO+7, 0xffff},
{"mcs5glpo0", 0x00000100, 0, SROM8_5GL_MCSPO, 0xffff},
{"mcs5glpo1", 0x00000100, 0, SROM8_5GL_MCSPO+1, 0xffff},
{"mcs5glpo2", 0x00000100, 0, SROM8_5GL_MCSPO+2, 0xffff},
{"mcs5glpo3", 0x00000100, 0, SROM8_5GL_MCSPO+3, 0xffff},
{"mcs5glpo4", 0x00000100, 0, SROM8_5GL_MCSPO+4, 0xffff},
{"mcs5glpo5", 0x00000100, 0, SROM8_5GL_MCSPO+5, 0xffff},
{"mcs5glpo6", 0x00000100, 0, SROM8_5GL_MCSPO+6, 0xffff},
{"mcs5glpo7", 0x00000100, 0, SROM8_5GL_MCSPO+7, 0xffff},
{"mcs5ghpo0", 0x00000100, 0, SROM8_5GH_MCSPO, 0xffff},
{"mcs5ghpo1", 0x00000100, 0, SROM8_5GH_MCSPO+1, 0xffff},
{"mcs5ghpo2", 0x00000100, 0, SROM8_5GH_MCSPO+2, 0xffff},
{"mcs5ghpo3", 0x00000100, 0, SROM8_5GH_MCSPO+3, 0xffff},
{"mcs5ghpo4", 0x00000100, 0, SROM8_5GH_MCSPO+4, 0xffff},
{"mcs5ghpo5", 0x00000100, 0, SROM8_5GH_MCSPO+5, 0xffff},
{"mcs5ghpo6", 0x00000100, 0, SROM8_5GH_MCSPO+6, 0xffff},
{"mcs5ghpo7", 0x00000100, 0, SROM8_5GH_MCSPO+7, 0xffff},
{"cddpo", 0x000000f0, 0, SROM4_CDDPO, 0xffff},
{"stbcpo", 0x000000f0, 0, SROM4_STBCPO, 0xffff},
{"bw40po", 0x000000f0, 0, SROM4_BW40PO, 0xffff},
{"bwduppo", 0x000000f0, 0, SROM4_BWDUPPO, 0xffff},
{"cddpo", 0x00000100, 0, SROM8_CDDPO, 0xffff},
{"stbcpo", 0x00000100, 0, SROM8_STBCPO, 0xffff},
{"bw40po", 0x00000100, 0, SROM8_BW40PO, 0xffff},
{"bwduppo", 0x00000100, 0, SROM8_BWDUPPO, 0xffff},
/* power per rate from sromrev 9 */
{"cckbw202gpo", 0xfffffe00, 0, SROM9_2GPO_CCKBW20, 0xffff},
{"cckbw20ul2gpo",0xfffffe00, 0, SROM9_2GPO_CCKBW20UL, 0xffff},
{"legofdmbw202gpo",0xfffffe00, SRFL_MORE, SROM9_2GPO_LOFDMBW20, 0xffff},
{"", 0, 0, SROM9_2GPO_LOFDMBW20+1, 0xffff},
{"legofdmbw20ul2gpo",0xfffffe00,SRFL_MORE, SROM9_2GPO_LOFDMBW20UL, 0xffff},
{"", 0, 0, SROM9_2GPO_LOFDMBW20UL+1,0xffff},
{"legofdmbw205glpo",0xfffffe00, SRFL_MORE, SROM9_5GLPO_LOFDMBW20, 0xffff},
{"", 0, 0, SROM9_5GLPO_LOFDMBW20+1,0xffff},
{"legofdmbw20ul5glpo",0xfffffe00,SRFL_MORE, SROM9_5GLPO_LOFDMBW20UL,0xffff},
{"", 0, 0, SROM9_5GLPO_LOFDMBW20UL+1,0xffff},
{"legofdmbw205gmpo",0xfffffe00, SRFL_MORE, SROM9_5GMPO_LOFDMBW20, 0xffff},
{"", 0, 0, SROM9_5GMPO_LOFDMBW20+1,0xffff},
{"legofdmbw20ul5gmpo",0xfffffe00,SRFL_MORE, SROM9_5GMPO_LOFDMBW20UL,0xffff},
{"", 0, 0, SROM9_5GMPO_LOFDMBW20UL+1,0xffff},
{"legofdmbw205ghpo",0xfffffe00, SRFL_MORE, SROM9_5GHPO_LOFDMBW20, 0xffff},
{"", 0, 0, SROM9_5GHPO_LOFDMBW20+1,0xffff},
{"legofdmbw20ul5ghpo",0xfffffe00,SRFL_MORE, SROM9_5GHPO_LOFDMBW20UL,0xffff},
{"", 0, 0, SROM9_5GHPO_LOFDMBW20UL+1,0xffff},
{"mcsbw202gpo", 0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW20, 0xffff},
{"", 0, 0, SROM9_2GPO_MCSBW20+1, 0xffff},
{"mcsbw20ul2gpo",0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW20UL, 0xffff},
{"", 0, 0, SROM9_2GPO_MCSBW20UL+1, 0xffff},
{"mcsbw402gpo", 0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW40, 0xffff},
{"", 0, 0, SROM9_2GPO_MCSBW40+1, 0xffff},
{"mcsbw205glpo",0xfffffe00, SRFL_MORE, SROM9_5GLPO_MCSBW20, 0xffff},
{"", 0, 0, SROM9_5GLPO_MCSBW20+1, 0xffff},
{"mcsbw20ul5glpo",0xfffffe00, SRFL_MORE, SROM9_5GLPO_MCSBW20UL, 0xffff},
{"", 0, 0, SROM9_5GLPO_MCSBW20UL+1,0xffff},
{"mcsbw405glpo",0xfffffe00, SRFL_MORE, SROM9_5GLPO_MCSBW40, 0xffff},
{"", 0, 0, SROM9_5GLPO_MCSBW40+1, 0xffff},
{"mcsbw205gmpo",0xfffffe00, SRFL_MORE, SROM9_5GMPO_MCSBW20, 0xffff},
{"", 0, 0, SROM9_5GMPO_MCSBW20+1, 0xffff},
{"mcsbw20ul5gmpo",0xfffffe00, SRFL_MORE, SROM9_5GMPO_MCSBW20UL, 0xffff},
{"", 0, 0, SROM9_5GMPO_MCSBW20UL+1,0xffff},
{"mcsbw405gmpo",0xfffffe00, SRFL_MORE, SROM9_5GMPO_MCSBW40, 0xffff},
{"", 0, 0, SROM9_5GMPO_MCSBW40+1, 0xffff},
{"mcsbw205ghpo",0xfffffe00, SRFL_MORE, SROM9_5GHPO_MCSBW20, 0xffff},
{"", 0, 0, SROM9_5GHPO_MCSBW20+1, 0xffff},
{"mcsbw20ul5ghpo",0xfffffe00, SRFL_MORE, SROM9_5GHPO_MCSBW20UL, 0xffff},
{"", 0, 0, SROM9_5GHPO_MCSBW20UL+1,0xffff},
{"mcsbw405ghpo",0xfffffe00, SRFL_MORE, SROM9_5GHPO_MCSBW40, 0xffff},
{"", 0, 0, SROM9_5GHPO_MCSBW40+1, 0xffff},
{"mcs32po", 0xfffffe00, 0, SROM9_PO_MCS32, 0xffff},
{"legofdm40duppo",0xfffffe00, 0, SROM9_PO_LOFDM40DUP, 0xffff},
{NULL, 0, 0, 0, 0}
};
static const sromvar_t perpath_pci_sromvars[] = {
{"maxp2ga", 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0x00ff},
{"itt2ga", 0x000000f0, 0, SROM4_2G_ITT_MAXP, 0xff00},
{"itt5ga", 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0xff00},
{"pa2gw0a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA, 0xffff},
{"pa2gw1a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA+1, 0xffff},
{"pa2gw2a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA+2, 0xffff},
{"pa2gw3a", 0x000000f0, SRFL_PRHEX, SROM4_2G_PA+3, 0xffff},
{"maxp5ga", 0x000000f0, 0, SROM4_5G_ITT_MAXP, 0x00ff},
{"maxp5gha", 0x000000f0, 0, SROM4_5GLH_MAXP, 0x00ff},
{"maxp5gla", 0x000000f0, 0, SROM4_5GLH_MAXP, 0xff00},
{"pa5gw0a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA, 0xffff},
{"pa5gw1a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA+1, 0xffff},
{"pa5gw2a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA+2, 0xffff},
{"pa5gw3a", 0x000000f0, SRFL_PRHEX, SROM4_5G_PA+3, 0xffff},
{"pa5glw0a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA, 0xffff},
{"pa5glw1a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA+1, 0xffff},
{"pa5glw2a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA+2, 0xffff},
{"pa5glw3a", 0x000000f0, SRFL_PRHEX, SROM4_5GL_PA+3, 0xffff},
{"pa5ghw0a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA, 0xffff},
{"pa5ghw1a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA+1, 0xffff},
{"pa5ghw2a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA+2, 0xffff},
{"pa5ghw3a", 0x000000f0, SRFL_PRHEX, SROM4_5GH_PA+3, 0xffff},
{"maxp2ga", 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0x00ff},
{"itt2ga", 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0xff00},
{"itt5ga", 0xffffff00, 0, SROM8_5G_ITT_MAXP, 0xff00},
{"pa2gw0a", 0xffffff00, SRFL_PRHEX, SROM8_2G_PA, 0xffff},
{"pa2gw1a", 0xffffff00, SRFL_PRHEX, SROM8_2G_PA+1, 0xffff},
{"pa2gw2a", 0xffffff00, SRFL_PRHEX, SROM8_2G_PA+2, 0xffff},
{"maxp5ga", 0xffffff00, 0, SROM8_5G_ITT_MAXP, 0x00ff},
{"maxp5gha", 0xffffff00, 0, SROM8_5GLH_MAXP, 0x00ff},
{"maxp5gla", 0xffffff00, 0, SROM8_5GLH_MAXP, 0xff00},
{"pa5gw0a", 0xffffff00, SRFL_PRHEX, SROM8_5G_PA, 0xffff},
{"pa5gw1a", 0xffffff00, SRFL_PRHEX, SROM8_5G_PA+1, 0xffff},
{"pa5gw2a", 0xffffff00, SRFL_PRHEX, SROM8_5G_PA+2, 0xffff},
{"pa5glw0a", 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA, 0xffff},
{"pa5glw1a", 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA+1, 0xffff},
{"pa5glw2a", 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA+2, 0xffff},
{"pa5ghw0a", 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA, 0xffff},
{"pa5ghw1a", 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA+1, 0xffff},
{"pa5ghw2a", 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA+2, 0xffff},
{NULL, 0, 0, 0, 0}
};
#if !(defined(PHY_TYPE_N) && defined(PHY_TYPE_LP))
#define PHY_TYPE_N 4 /* N-Phy value */
#define PHY_TYPE_LP 5 /* LP-Phy value */
#endif /* !(defined(PHY_TYPE_N) && defined(PHY_TYPE_LP)) */
#if !defined(PHY_TYPE_NULL)
#define PHY_TYPE_NULL 0xf /* Invalid Phy value */
#endif /* !defined(PHY_TYPE_NULL) */
typedef struct {
u16 phy_type;
u16 bandrange;
u16 chain;
const char *vars;
} pavars_t;
static const pavars_t pavars[] = {
/* NPHY */
{PHY_TYPE_N, WL_CHAN_FREQ_RANGE_2G, 0, "pa2gw0a0 pa2gw1a0 pa2gw2a0"},
{PHY_TYPE_N, WL_CHAN_FREQ_RANGE_2G, 1, "pa2gw0a1 pa2gw1a1 pa2gw2a1"},
{PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GL, 0, "pa5glw0a0 pa5glw1a0 pa5glw2a0"},
{PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GL, 1, "pa5glw0a1 pa5glw1a1 pa5glw2a1"},
{PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GM, 0, "pa5gw0a0 pa5gw1a0 pa5gw2a0"},
{PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GM, 1, "pa5gw0a1 pa5gw1a1 pa5gw2a1"},
{PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GH, 0, "pa5ghw0a0 pa5ghw1a0 pa5ghw2a0"},
{PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GH, 1, "pa5ghw0a1 pa5ghw1a1 pa5ghw2a1"},
/* LPPHY */
{PHY_TYPE_LP, WL_CHAN_FREQ_RANGE_2G, 0, "pa0b0 pa0b1 pa0b2"},
{PHY_TYPE_LP, WL_CHAN_FREQ_RANGE_5GL, 0, "pa1lob0 pa1lob1 pa1lob2"},
{PHY_TYPE_LP, WL_CHAN_FREQ_RANGE_5GM, 0, "pa1b0 pa1b1 pa1b2"},
{PHY_TYPE_LP, WL_CHAN_FREQ_RANGE_5GH, 0, "pa1hib0 pa1hib1 pa1hib2"},
{PHY_TYPE_NULL, 0, 0, ""}
};
typedef struct {
u16 phy_type;
u16 bandrange;
const char *vars;
} povars_t;
static const povars_t povars[] = {
/* NPHY */
{PHY_TYPE_N, WL_CHAN_FREQ_RANGE_2G,
"mcs2gpo0 mcs2gpo1 mcs2gpo2 mcs2gpo3 "
"mcs2gpo4 mcs2gpo5 mcs2gpo6 mcs2gpo7"},
{PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GL,
"mcs5glpo0 mcs5glpo1 mcs5glpo2 mcs5glpo3 "
"mcs5glpo4 mcs5glpo5 mcs5glpo6 mcs5glpo7"},
{PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GM,
"mcs5gpo0 mcs5gpo1 mcs5gpo2 mcs5gpo3 "
"mcs5gpo4 mcs5gpo5 mcs5gpo6 mcs5gpo7"},
{PHY_TYPE_N, WL_CHAN_FREQ_RANGE_5GH,
"mcs5ghpo0 mcs5ghpo1 mcs5ghpo2 mcs5ghpo3 "
"mcs5ghpo4 mcs5ghpo5 mcs5ghpo6 mcs5ghpo7"},
{PHY_TYPE_NULL, 0, ""}
};
typedef struct {
u8 tag; /* Broadcom subtag name */
u8 len; /* Length field of the tuple, note that it includes the
* subtag name (1 byte): 1 + tuple content length
*/
const char *params;
} cis_tuple_t;
#define OTP_RAW (0xff - 1) /* Reserved tuple number for wrvar Raw input */
#define OTP_VERS_1 (0xff - 2) /* CISTPL_VERS_1 */
#define OTP_MANFID (0xff - 3) /* CISTPL_MANFID */
#define OTP_RAW1 (0xff - 4) /* Like RAW, but comes first */
static const cis_tuple_t cis_hnbuvars[] = {
{OTP_RAW1, 0, ""}, /* special case */
{OTP_VERS_1, 0, "smanf sproductname"}, /* special case (non BRCM tuple) */
{OTP_MANFID, 4, "2manfid 2prodid"}, /* special case (non BRCM tuple) */
{HNBU_SROMREV, 2, "1sromrev"},
/* NOTE: subdevid is also written to boardtype.
* Need to write HNBU_BOARDTYPE to change it if it is different.
*/
{HNBU_CHIPID, 11, "2vendid 2devid 2chiprev 2subvendid 2subdevid"},
{HNBU_BOARDREV, 3, "2boardrev"},
{HNBU_PAPARMS, 10, "2pa0b0 2pa0b1 2pa0b2 1pa0itssit 1pa0maxpwr 1opo"},
{HNBU_AA, 3, "1aa2g 1aa5g"},
{HNBU_AA, 3, "1aa0 1aa1"}, /* backward compatibility */
{HNBU_AG, 5, "1ag0 1ag1 1ag2 1ag3"},
{HNBU_BOARDFLAGS, 9, "4boardflags 4boardflags2"},
{HNBU_LEDS, 5, "1ledbh0 1ledbh1 1ledbh2 1ledbh3"},
{HNBU_CCODE, 4, "2ccode 1cctl"},
{HNBU_CCKPO, 3, "2cckpo"},
{HNBU_OFDMPO, 5, "4ofdmpo"},
{HNBU_RDLID, 3, "2rdlid"},
{HNBU_RSSISMBXA2G, 3, "0rssismf2g 0rssismc2g 0rssisav2g 0bxa2g"}, /* special case */
{HNBU_RSSISMBXA5G, 3, "0rssismf5g 0rssismc5g 0rssisav5g 0bxa5g"}, /* special case */
{HNBU_XTALFREQ, 5, "4xtalfreq"},
{HNBU_TRI2G, 2, "1tri2g"},
{HNBU_TRI5G, 4, "1tri5gl 1tri5g 1tri5gh"},
{HNBU_RXPO2G, 2, "1rxpo2g"},
{HNBU_RXPO5G, 2, "1rxpo5g"},
{HNBU_BOARDNUM, 3, "2boardnum"},
{HNBU_MACADDR, 7, "6macaddr"}, /* special case */
{HNBU_RDLSN, 3, "2rdlsn"},
{HNBU_BOARDTYPE, 3, "2boardtype"},
{HNBU_LEDDC, 3, "2leddc"},
{HNBU_RDLRNDIS, 2, "1rdlndis"},
{HNBU_CHAINSWITCH, 5, "1txchain 1rxchain 2antswitch"},
{HNBU_REGREV, 2, "1regrev"},
{HNBU_FEM, 5, "0antswctl2g, 0triso2g, 0pdetrange2g, 0extpagain2g, 0tssipos2g" "0antswctl5g, 0triso5g, 0pdetrange5g, 0extpagain5g, 0tssipos5g"}, /* special case */
{HNBU_PAPARMS_C0, 31, "1maxp2ga0 1itt2ga0 2pa2gw0a0 2pa2gw1a0 "
"2pa2gw2a0 1maxp5ga0 1itt5ga0 1maxp5gha0 1maxp5gla0 2pa5gw0a0 "
"2pa5gw1a0 2pa5gw2a0 2pa5glw0a0 2pa5glw1a0 2pa5glw2a0 2pa5ghw0a0 "
"2pa5ghw1a0 2pa5ghw2a0"},
{HNBU_PAPARMS_C1, 31, "1maxp2ga1 1itt2ga1 2pa2gw0a1 2pa2gw1a1 "
"2pa2gw2a1 1maxp5ga1 1itt5ga1 1maxp5gha1 1maxp5gla1 2pa5gw0a1 "
"2pa5gw1a1 2pa5gw2a1 2pa5glw0a1 2pa5glw1a1 2pa5glw2a1 2pa5ghw0a1 "
"2pa5ghw1a1 2pa5ghw2a1"},
{HNBU_PO_CCKOFDM, 19, "2cck2gpo 4ofdm2gpo 4ofdm5gpo 4ofdm5glpo "
"4ofdm5ghpo"},
{HNBU_PO_MCS2G, 17, "2mcs2gpo0 2mcs2gpo1 2mcs2gpo2 2mcs2gpo3 "
"2mcs2gpo4 2mcs2gpo5 2mcs2gpo6 2mcs2gpo7"},
{HNBU_PO_MCS5GM, 17, "2mcs5gpo0 2mcs5gpo1 2mcs5gpo2 2mcs5gpo3 "
"2mcs5gpo4 2mcs5gpo5 2mcs5gpo6 2mcs5gpo7"},
{HNBU_PO_MCS5GLH, 33, "2mcs5glpo0 2mcs5glpo1 2mcs5glpo2 2mcs5glpo3 "
"2mcs5glpo4 2mcs5glpo5 2mcs5glpo6 2mcs5glpo7 "
"2mcs5ghpo0 2mcs5ghpo1 2mcs5ghpo2 2mcs5ghpo3 "
"2mcs5ghpo4 2mcs5ghpo5 2mcs5ghpo6 2mcs5ghpo7"},
{HNBU_CCKFILTTYPE, 2, "1cckdigfilttype"},
{HNBU_PO_CDD, 3, "2cddpo"},
{HNBU_PO_STBC, 3, "2stbcpo"},
{HNBU_PO_40M, 3, "2bw40po"},
{HNBU_PO_40MDUP, 3, "2bwduppo"},
{HNBU_RDLRWU, 2, "1rdlrwu"},
{HNBU_WPS, 3, "1wpsgpio 1wpsled"},
{HNBU_USBFS, 2, "1usbfs"},
{HNBU_CUSTOM1, 5, "4customvar1"},
{OTP_RAW, 0, ""}, /* special case */
{HNBU_OFDMPO5G, 13, "4ofdm5gpo 4ofdm5glpo 4ofdm5ghpo"},
{HNBU_USBEPNUM, 3, "2usbepnum"},
{0xFF, 0, ""}
};
#endif /* _BHND_BCMSROM_TBL_H_ */

910
sys/dev/bhnd/bhnd.c Normal file
View file

@ -0,0 +1,910 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* 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 <sys/cdefs.h>
__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 <sys/param.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/module.h>
#include <sys/systm.h>
#include <machine/bus.h>
#include <sys/rman.h>
#include <machine/resource.h>
#include "bhnd.h"
#include "bhndvar.h"
#include "bhnd_nvram_if.h"
MALLOC_DEFINE(M_BHND, "bhnd", "bhnd bus data structures");
/**
* bhnd_generic_probe_nomatch() reporting configuration.
*/
static const struct bhnd_nomatch {
uint16_t vendor; /**< core designer */
uint16_t device; /**< core id */
bool if_verbose; /**< print when bootverbose is set. */
} bhnd_nomatch_table[] = {
{ BHND_MFGID_ARM, BHND_COREID_OOB_ROUTER, true },
{ BHND_MFGID_ARM, BHND_COREID_EROM, true },
{ BHND_MFGID_ARM, BHND_COREID_PL301, true },
{ BHND_MFGID_ARM, BHND_COREID_APB_BRIDGE, true },
{ BHND_MFGID_ARM, BHND_COREID_AXI_UNMAPPED, false },
{ BHND_MFGID_INVALID, BHND_COREID_INVALID, false }
};
static device_t find_nvram_child(device_t dev);
static int compare_ascending_probe_order(const void *lhs,
const void *rhs);
static int compare_descending_probe_order(const void *lhs,
const void *rhs);
/**
* Helper function for implementing DEVICE_ATTACH().
*
* This function can be used to implement DEVICE_ATTACH() for bhnd(4)
* bus implementations. It calls device_probe_and_attach() for each
* of the device's children, in order.
*/
int
bhnd_generic_attach(device_t dev)
{
device_t *devs;
int ndevs;
int error;
if (device_is_attached(dev))
return (EBUSY);
if ((error = device_get_children(dev, &devs, &ndevs)))
return (error);
qsort(devs, ndevs, sizeof(*devs), compare_ascending_probe_order);
for (int i = 0; i < ndevs; i++) {
device_t child = devs[i];
device_probe_and_attach(child);
}
free(devs, M_TEMP);
return (0);
}
/**
* Helper function for implementing DEVICE_DETACH().
*
* This function can be used to implement DEVICE_DETACH() for bhnd(4)
* bus implementations. It calls device_detach() for each
* of the device's children, in reverse order, terminating if
* any call to device_detach() fails.
*/
int
bhnd_generic_detach(device_t dev)
{
device_t *devs;
int ndevs;
int error;
if (!device_is_attached(dev))
return (EBUSY);
if ((error = device_get_children(dev, &devs, &ndevs)))
return (error);
/* Detach in the reverse of attach order */
qsort(devs, ndevs, sizeof(*devs), compare_descending_probe_order);
for (int i = 0; i < ndevs; i++) {
device_t child = devs[i];
/* Terminate on first error */
if ((error = device_detach(child)))
goto cleanup;
}
cleanup:
free(devs, M_TEMP);
return (error);
}
/**
* Helper function for implementing DEVICE_SHUTDOWN().
*
* This function can be used to implement DEVICE_SHUTDOWN() for bhnd(4)
* bus implementations. It calls device_shutdown() for each
* of the device's children, in reverse order, terminating if
* any call to device_shutdown() fails.
*/
int
bhnd_generic_shutdown(device_t dev)
{
device_t *devs;
int ndevs;
int error;
if (!device_is_attached(dev))
return (EBUSY);
if ((error = device_get_children(dev, &devs, &ndevs)))
return (error);
/* Shutdown in the reverse of attach order */
qsort(devs, ndevs, sizeof(*devs), compare_descending_probe_order);
for (int i = 0; i < ndevs; i++) {
device_t child = devs[i];
/* Terminate on first error */
if ((error = device_shutdown(child)))
goto cleanup;
}
cleanup:
free(devs, M_TEMP);
return (error);
}
/**
* Helper function for implementing DEVICE_RESUME().
*
* This function can be used to implement DEVICE_RESUME() for bhnd(4)
* bus implementations. It calls BUS_RESUME_CHILD() for each
* of the device's children, in order, terminating if
* any call to BUS_RESUME_CHILD() fails.
*/
int
bhnd_generic_resume(device_t dev)
{
device_t *devs;
int ndevs;
int error;
if (!device_is_attached(dev))
return (EBUSY);
if ((error = device_get_children(dev, &devs, &ndevs)))
return (error);
qsort(devs, ndevs, sizeof(*devs), compare_ascending_probe_order);
for (int i = 0; i < ndevs; i++) {
device_t child = devs[i];
/* Terminate on first error */
if ((error = BUS_RESUME_CHILD(device_get_parent(child), child)))
goto cleanup;
}
cleanup:
free(devs, M_TEMP);
return (error);
}
/**
* Helper function for implementing DEVICE_SUSPEND().
*
* This function can be used to implement DEVICE_SUSPEND() for bhnd(4)
* bus implementations. It calls BUS_SUSPEND_CHILD() for each
* of the device's children, in reverse order. If any call to
* BUS_SUSPEND_CHILD() fails, the suspend operation is terminated and
* any devices that were suspended are resumed immediately by calling
* their BUS_RESUME_CHILD() methods.
*/
int
bhnd_generic_suspend(device_t dev)
{
device_t *devs;
int ndevs;
int error;
if (!device_is_attached(dev))
return (EBUSY);
if ((error = device_get_children(dev, &devs, &ndevs)))
return (error);
/* Suspend in the reverse of attach order */
qsort(devs, ndevs, sizeof(*devs), compare_descending_probe_order);
for (int i = 0; i < ndevs; i++) {
device_t child = devs[i];
error = BUS_SUSPEND_CHILD(device_get_parent(child), child);
/* On error, resume suspended devices and then terminate */
if (error) {
for (int j = 0; j < i; j++) {
BUS_RESUME_CHILD(device_get_parent(devs[j]),
devs[j]);
}
goto cleanup;
}
}
cleanup:
free(devs, M_TEMP);
return (error);
}
/*
* Ascending comparison of bhnd device's probe order.
*/
static int
compare_ascending_probe_order(const void *lhs, const void *rhs)
{
device_t ldev, rdev;
int lorder, rorder;
ldev = (*(const device_t *) lhs);
rdev = (*(const device_t *) rhs);
lorder = BHND_BUS_GET_PROBE_ORDER(device_get_parent(ldev), ldev);
rorder = BHND_BUS_GET_PROBE_ORDER(device_get_parent(rdev), rdev);
if (lorder < rorder) {
return (-1);
} else if (lorder > rorder) {
return (1);
} else {
return (0);
}
}
/*
* Descending comparison of bhnd device's probe order.
*/
static int
compare_descending_probe_order(const void *lhs, const void *rhs)
{
return (compare_ascending_probe_order(rhs, lhs));
}
/**
* Helper function for implementing BHND_BUS_GET_PROBE_ORDER().
*
* This implementation determines probe ordering based on the device's class
* and other properties, including whether the device is serving as a host
* bridge.
*/
int
bhnd_generic_get_probe_order(device_t dev, device_t child)
{
switch (bhnd_get_class(child)) {
case BHND_DEVCLASS_CC:
return (BHND_PROBE_BUS + BHND_PROBE_ORDER_FIRST);
case BHND_DEVCLASS_CC_B:
/* fall through */
case BHND_DEVCLASS_PMU:
return (BHND_PROBE_BUS + BHND_PROBE_ORDER_EARLY);
case BHND_DEVCLASS_SOC_ROUTER:
return (BHND_PROBE_BUS + BHND_PROBE_ORDER_LATE);
case BHND_DEVCLASS_SOC_BRIDGE:
return (BHND_PROBE_BUS + BHND_PROBE_ORDER_LAST);
case BHND_DEVCLASS_CPU:
return (BHND_PROBE_CPU + BHND_PROBE_ORDER_FIRST);
case BHND_DEVCLASS_RAM:
/* fall through */
case BHND_DEVCLASS_MEMC:
return (BHND_PROBE_CPU + BHND_PROBE_ORDER_EARLY);
case BHND_DEVCLASS_NVRAM:
return (BHND_PROBE_RESOURCE + BHND_PROBE_ORDER_EARLY);
case BHND_DEVCLASS_PCI:
case BHND_DEVCLASS_PCIE:
case BHND_DEVCLASS_PCCARD:
case BHND_DEVCLASS_ENET:
case BHND_DEVCLASS_ENET_MAC:
case BHND_DEVCLASS_ENET_PHY:
case BHND_DEVCLASS_WLAN:
case BHND_DEVCLASS_WLAN_MAC:
case BHND_DEVCLASS_WLAN_PHY:
case BHND_DEVCLASS_EROM:
case BHND_DEVCLASS_OTHER:
case BHND_DEVCLASS_INVALID:
if (bhnd_is_hostb_device(child))
return (BHND_PROBE_ROOT + BHND_PROBE_ORDER_EARLY);
return (BHND_PROBE_DEFAULT);
}
}
/**
* Helper function for implementing BHND_BUS_IS_REGION_VALID().
*
* This implementation assumes that port and region numbers are 0-indexed and
* are allocated non-sparsely, using BHND_BUS_GET_PORT_COUNT() and
* BHND_BUS_GET_REGION_COUNT() to determine if @p port and @p region fall
* within the defined range.
*/
bool
bhnd_generic_is_region_valid(device_t dev, device_t child,
bhnd_port_type type, u_int port, u_int region)
{
if (port >= bhnd_get_port_count(child, type))
return (false);
if (region >= bhnd_get_region_count(child, type, port))
return (false);
return (true);
}
/**
* Find an NVRAM child device on @p dev, if any.
*
* @retval device_t An NVRAM device.
* @retval NULL If no NVRAM device is found.
*/
static device_t
find_nvram_child(device_t dev)
{
device_t chipc, nvram;
/* Look for a directly-attached NVRAM child */
nvram = device_find_child(dev, devclass_get_name(bhnd_nvram_devclass),
-1);
if (nvram == NULL)
return (NULL);
/* Further checks require a bhnd(4) bus */
if (device_get_devclass(dev) != bhnd_devclass)
return (NULL);
/* Look for a ChipCommon-attached OTP device */
if ((chipc = bhnd_find_child(dev, BHND_DEVCLASS_CC, -1)) != NULL) {
/* Recursively search the ChipCommon device */
if ((nvram = find_nvram_child(chipc)) != NULL)
return (nvram);
}
/* Not found */
return (NULL);
}
/**
* Helper function for implementing BHND_BUS_READ_NVRAM_VAR().
*
* This implementation searches @p dev for a valid NVRAM device. If no NVRAM
* child device is found on @p dev, the request is delegated to the
* BHND_BUS_READ_NVRAM_VAR() method on the parent
* of @p dev.
*/
int
bhnd_generic_read_nvram_var(device_t dev, device_t child, const char *name,
void *buf, size_t *size)
{
device_t nvram;
/* Try to find an NVRAM device applicable to @p child */
if ((nvram = find_nvram_child(dev)) == NULL)
return (BHND_BUS_READ_NVRAM_VAR(device_get_parent(dev), child,
name, buf, size));
return BHND_NVRAM_GETVAR(nvram, name, buf, size);
}
/**
* Helper function for implementing BUS_PRINT_CHILD().
*
* This implementation requests the device's struct resource_list via
* BUS_GET_RESOURCE_LIST.
*/
int
bhnd_generic_print_child(device_t dev, device_t child)
{
struct resource_list *rl;
int retval = 0;
retval += bus_print_child_header(dev, child);
rl = BUS_GET_RESOURCE_LIST(dev, child);
if (rl != NULL) {
retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY,
"%#lx");
}
retval += printf(" at core %u", bhnd_get_core_index(child));
retval += bus_print_child_domain(dev, child);
retval += bus_print_child_footer(dev, child);
return (retval);
}
/**
* Helper function for implementing BUS_PRINT_CHILD().
*
* This implementation requests the device's struct resource_list via
* BUS_GET_RESOURCE_LIST.
*/
void
bhnd_generic_probe_nomatch(device_t dev, device_t child)
{
struct resource_list *rl;
const struct bhnd_nomatch *nm;
bool report;
/* Fetch reporting configuration for this device */
report = true;
for (nm = bhnd_nomatch_table; nm->device != BHND_COREID_INVALID; nm++) {
if (nm->vendor != bhnd_get_vendor(child))
continue;
if (nm->device != bhnd_get_device(child))
continue;
report = false;
if (bootverbose && nm->if_verbose)
report = true;
break;
}
if (!report)
return;
/* Print the non-matched device info */
device_printf(dev, "<%s %s>", bhnd_get_vendor_name(child),
bhnd_get_device_name(child));
rl = BUS_GET_RESOURCE_LIST(dev, child);
if (rl != NULL)
resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
printf(" at core %u (no driver attached)\n",
bhnd_get_core_index(child));
}
/**
* Default implementation of BUS_CHILD_PNPINFO_STR().
*/
static int
bhnd_child_pnpinfo_str(device_t dev, device_t child, char *buf,
size_t buflen)
{
if (device_get_parent(child) != dev) {
return (BUS_CHILD_PNPINFO_STR(device_get_parent(dev), child,
buf, buflen));
}
snprintf(buf, buflen, "vendor=0x%hx device=0x%hx rev=0x%hhx",
bhnd_get_vendor(child), bhnd_get_device(child),
bhnd_get_hwrev(child));
return (0);
}
/**
* Default implementation of implementing BUS_PRINT_CHILD().
*/
static int
bhnd_child_location_str(device_t dev, device_t child, char *buf,
size_t buflen)
{
bhnd_addr_t addr;
bhnd_size_t size;
if (device_get_parent(child) != dev) {
return (BUS_CHILD_LOCATION_STR(device_get_parent(dev), child,
buf, buflen));
}
if (bhnd_get_region_addr(child, BHND_PORT_DEVICE, 0, 0, &addr, &size)) {
/* No device default port/region */
if (buflen > 0)
*buf = '\0';
return (0);
}
snprintf(buf, buflen, "port0.0=0x%llx", (unsigned long long) addr);
return (0);
}
/**
* Helper function for implementing BUS_SUSPEND_CHILD().
*
* TODO: Power management
*
* If @p child is not a direct child of @p dev, suspension is delegated to
* the @p dev parent.
*/
int
bhnd_generic_suspend_child(device_t dev, device_t child)
{
if (device_get_parent(child) != dev)
BUS_SUSPEND_CHILD(device_get_parent(dev), child);
return bus_generic_suspend_child(dev, child);
}
/**
* Helper function for implementing BUS_RESUME_CHILD().
*
* TODO: Power management
*
* If @p child is not a direct child of @p dev, suspension is delegated to
* the @p dev parent.
*/
int
bhnd_generic_resume_child(device_t dev, device_t child)
{
if (device_get_parent(child) != dev)
BUS_RESUME_CHILD(device_get_parent(dev), child);
return bus_generic_resume_child(dev, child);
}
/**
* Helper function for implementing BHND_BUS_IS_HOSTB_DEVICE().
*
* If a parent device is available, this implementation delegates the
* request to the BHND_BUS_IS_HOSTB_DEVICE() method on the parent of @p dev.
*
* If no parent device is available (i.e. on a the bus root), false
* is returned.
*/
bool
bhnd_generic_is_hostb_device(device_t dev, device_t child) {
if (device_get_parent(dev) != NULL)
return (BHND_BUS_IS_HOSTB_DEVICE(device_get_parent(dev),
child));
return (false);
}
/**
* Helper function for implementing BHND_BUS_IS_HW_DISABLED().
*
* If a parent device is available, this implementation delegates the
* request to the BHND_BUS_IS_HW_DISABLED() method on the parent of @p dev.
*
* If no parent device is available (i.e. on a the bus root), the hardware
* is assumed to be usable and false is returned.
*/
bool
bhnd_generic_is_hw_disabled(device_t dev, device_t child)
{
if (device_get_parent(dev) != NULL)
return (BHND_BUS_IS_HW_DISABLED(device_get_parent(dev), child));
return (false);
}
/**
* Helper function for implementing BHND_BUS_GET_CHIPID().
*
* This implementation delegates the request to the BHND_BUS_GET_CHIPID()
* method on the parent of @p dev.
*/
const struct bhnd_chipid *
bhnd_generic_get_chipid(device_t dev, device_t child) {
return (BHND_BUS_GET_CHIPID(device_get_parent(dev), child));
}
/**
* Helper function for implementing BHND_BUS_ALLOC_RESOURCE().
*
* This simple implementation of BHND_BUS_ALLOC_RESOURCE() determines
* any default values via BUS_GET_RESOURCE_LIST(), and calls
* BHND_BUS_ALLOC_RESOURCE() method of the parent of @p dev.
*
* If no parent device is available, the request is instead delegated to
* BUS_ALLOC_RESOURCE().
*/
struct bhnd_resource *
bhnd_generic_alloc_bhnd_resource(device_t dev, device_t child, int type,
int *rid, rman_res_t start, rman_res_t end, rman_res_t count,
u_int flags)
{
struct bhnd_resource *r;
struct resource_list *rl;
struct resource_list_entry *rle;
bool isdefault;
bool passthrough;
passthrough = (device_get_parent(child) != dev);
isdefault = (start == 0UL && end == ~0UL);
/* the default RID must always be the first device port/region. */
if (!passthrough && *rid == 0) {
int rid0 = bhnd_get_port_rid(child, BHND_PORT_DEVICE, 0, 0);
KASSERT(*rid == rid0,
("rid 0 does not map to the first device port (%d)", rid0));
}
/* Determine locally-known defaults before delegating the request. */
if (!passthrough && isdefault) {
/* fetch resource list from child's bus */
rl = BUS_GET_RESOURCE_LIST(dev, child);
if (rl == NULL)
return (NULL); /* no resource list */
/* look for matching type/rid pair */
rle = resource_list_find(BUS_GET_RESOURCE_LIST(dev, child),
type, *rid);
if (rle == NULL)
return (NULL);
/* set default values */
start = rle->start;
end = rle->end;
count = ulmax(count, rle->count);
}
/* Try to delegate to our parent. */
if (device_get_parent(dev) != NULL) {
return (BHND_BUS_ALLOC_RESOURCE(device_get_parent(dev), child,
type, rid, start, end, count, flags));
}
/* If this is the bus root, use a real bus-allocated resource */
r = malloc(sizeof(struct bhnd_resource), M_BHND, M_NOWAIT);
if (r == NULL)
return NULL;
/* Allocate the bus resource, marking it as 'direct' (not requiring
* any bus window remapping to perform I/O) */
r->direct = true;
r->res = BUS_ALLOC_RESOURCE(dev, child, type, rid, start, end,
count, flags);
if (r->res == NULL) {
free(r, M_BHND);
return NULL;
}
return (r);
}
/**
* Helper function for implementing BHND_BUS_RELEASE_RESOURCE().
*
* This simple implementation of BHND_BUS_RELEASE_RESOURCE() simply calls the
* BHND_BUS_RELEASE_RESOURCE() method of the parent of @p dev.
*
* If no parent device is available, the request is delegated to
* BUS_RELEASE_RESOURCE().
*/
int
bhnd_generic_release_bhnd_resource(device_t dev, device_t child, int type,
int rid, struct bhnd_resource *r)
{
int error;
/* Try to delegate to the parent. */
if (device_get_parent(dev) != NULL)
return (BHND_BUS_RELEASE_RESOURCE(device_get_parent(dev), child,
type, rid, r));
/* Release the resource directly */
if (!r->direct) {
panic("bhnd indirect resource released without "
"bhnd parent bus");
}
error = BUS_RELEASE_RESOURCE(dev, child, type, rid, r->res);
if (error)
return (error);
free(r, M_BHND);
return (0);
}
/**
* Helper function for implementing BHND_BUS_ACTIVATE_RESOURCE().
*
* This simple implementation of BHND_BUS_ACTIVATE_RESOURCE() simply calls the
* BHND_BUS_ACTIVATE_RESOURCE() method of the parent of @p dev.
*
* If no parent device is available, the request is delegated to
* BUS_ACTIVATE_RESOURCE().
*/
int
bhnd_generic_activate_bhnd_resource(device_t dev, device_t child, int type,
int rid, struct bhnd_resource *r)
{
/* Try to delegate to the parent */
if (device_get_parent(dev) != NULL)
return (BHND_BUS_ACTIVATE_RESOURCE(device_get_parent(dev),
child, type, rid, r));
/* Activate the resource directly */
if (!r->direct) {
panic("bhnd indirect resource released without "
"bhnd parent bus");
}
return (BUS_ACTIVATE_RESOURCE(dev, child, type, rid, r->res));
};
/**
* Helper function for implementing BHND_BUS_DEACTIVATE_RESOURCE().
*
* This simple implementation of BHND_BUS_ACTIVATE_RESOURCE() simply calls the
* BHND_BUS_ACTIVATE_RESOURCE() method of the parent of @p dev.
*
* If no parent device is available, the request is delegated to
* BUS_DEACTIVATE_RESOURCE().
*/
int
bhnd_generic_deactivate_bhnd_resource(device_t dev, device_t child, int type,
int rid, struct bhnd_resource *r)
{
if (device_get_parent(dev) != NULL)
return (BHND_BUS_DEACTIVATE_RESOURCE(device_get_parent(dev),
child, type, rid, r));
/* De-activate the resource directly */
if (!r->direct) {
panic("bhnd indirect resource released without "
"bhnd parent bus");
}
return (BUS_DEACTIVATE_RESOURCE(dev, child, type, rid, r->res));
};
/*
* Delegate all indirect I/O to the parent device. When inherited by
* non-bridged bus implementations, resources will never be marked as
* indirect, and these methods should never be called.
*/
static uint8_t
bhnd_read_1(device_t dev, device_t child, struct bhnd_resource *r,
bus_size_t offset)
{
return (BHND_BUS_READ_1(device_get_parent(dev), child, r, offset));
}
static uint16_t
bhnd_read_2(device_t dev, device_t child, struct bhnd_resource *r,
bus_size_t offset)
{
return (BHND_BUS_READ_2(device_get_parent(dev), child, r, offset));
}
static uint32_t
bhnd_read_4(device_t dev, device_t child, struct bhnd_resource *r,
bus_size_t offset)
{
return (BHND_BUS_READ_4(device_get_parent(dev), child, r, offset));
}
static void
bhnd_write_1(device_t dev, device_t child, struct bhnd_resource *r,
bus_size_t offset, uint8_t value)
{
BHND_BUS_WRITE_1(device_get_parent(dev), child, r, offset, value);
}
static void
bhnd_write_2(device_t dev, device_t child, struct bhnd_resource *r,
bus_size_t offset, uint16_t value)
{
BHND_BUS_WRITE_2(device_get_parent(dev), child, r, offset, value);
}
static void
bhnd_write_4(device_t dev, device_t child, struct bhnd_resource *r,
bus_size_t offset, uint32_t value)
{
BHND_BUS_WRITE_4(device_get_parent(dev), child, r, offset, value);
}
static void
bhnd_barrier(device_t dev, device_t child, struct bhnd_resource *r,
bus_size_t offset, bus_size_t length, int flags)
{
BHND_BUS_BARRIER(device_get_parent(dev), child, r, offset, length,
flags);
}
static device_method_t bhnd_methods[] = {
/* Device interface */ \
DEVMETHOD(device_attach, bhnd_generic_attach),
DEVMETHOD(device_detach, bhnd_generic_detach),
DEVMETHOD(device_shutdown, bhnd_generic_shutdown),
DEVMETHOD(device_suspend, bhnd_generic_suspend),
DEVMETHOD(device_resume, bhnd_generic_resume),
/* Bus interface */
DEVMETHOD(bus_probe_nomatch, bhnd_generic_probe_nomatch),
DEVMETHOD(bus_print_child, bhnd_generic_print_child),
DEVMETHOD(bus_child_pnpinfo_str, bhnd_child_pnpinfo_str),
DEVMETHOD(bus_child_location_str, bhnd_child_location_str),
DEVMETHOD(bus_suspend_child, bhnd_generic_suspend_child),
DEVMETHOD(bus_resume_child, bhnd_generic_resume_child),
DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource),
DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
DEVMETHOD(bus_delete_resource, bus_generic_rl_delete_resource),
DEVMETHOD(bus_alloc_resource, bus_generic_rl_alloc_resource),
DEVMETHOD(bus_adjust_resource, bus_generic_adjust_resource),
DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource),
DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
DEVMETHOD(bus_config_intr, bus_generic_config_intr),
DEVMETHOD(bus_bind_intr, bus_generic_bind_intr),
DEVMETHOD(bus_describe_intr, bus_generic_describe_intr),
DEVMETHOD(bus_get_dma_tag, bus_generic_get_dma_tag),
/* BHND interface */
DEVMETHOD(bhnd_bus_alloc_resource, bhnd_generic_alloc_bhnd_resource),
DEVMETHOD(bhnd_bus_release_resource, bhnd_generic_release_bhnd_resource),
DEVMETHOD(bhnd_bus_activate_resource, bhnd_generic_activate_bhnd_resource),
DEVMETHOD(bhnd_bus_activate_resource, bhnd_generic_deactivate_bhnd_resource),
DEVMETHOD(bhnd_bus_get_chipid, bhnd_generic_get_chipid),
DEVMETHOD(bhnd_bus_get_probe_order, bhnd_generic_get_probe_order),
DEVMETHOD(bhnd_bus_read_1, bhnd_read_1),
DEVMETHOD(bhnd_bus_read_2, bhnd_read_2),
DEVMETHOD(bhnd_bus_read_4, bhnd_read_4),
DEVMETHOD(bhnd_bus_write_1, bhnd_write_1),
DEVMETHOD(bhnd_bus_write_2, bhnd_write_2),
DEVMETHOD(bhnd_bus_write_4, bhnd_write_4),
DEVMETHOD(bhnd_bus_barrier, bhnd_barrier),
DEVMETHOD_END
};
devclass_t bhnd_devclass; /**< bhnd bus. */
devclass_t bhnd_hostb_devclass; /**< bhnd bus host bridge. */
devclass_t bhnd_nvram_devclass; /**< bhnd NVRAM device */
DEFINE_CLASS_0(bhnd, bhnd_driver, bhnd_methods, sizeof(struct bhnd_softc));
MODULE_VERSION(bhnd, 1);

576
sys/dev/bhnd/bhnd.h Normal file
View file

@ -0,0 +1,576 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* 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 <sys/types.h>
#include <sys/bus.h>
#include <machine/bus.h>
#include "bhnd_ids.h"
#include "bhnd_types.h"
#include "bhnd_bus_if.h"
extern devclass_t bhnd_devclass;
extern devclass_t bhnd_hostb_devclass;
extern devclass_t bhnd_nvram_devclass;
/**
* bhnd child instance variables
*/
enum bhnd_device_vars {
BHND_IVAR_VENDOR, /**< Designer's JEP-106 manufacturer ID. */
BHND_IVAR_DEVICE, /**< Part number */
BHND_IVAR_HWREV, /**< Core revision */
BHND_IVAR_DEVICE_CLASS, /**< Core class (@sa bhnd_devclass_t) */
BHND_IVAR_VENDOR_NAME, /**< Core vendor name */
BHND_IVAR_DEVICE_NAME, /**< Core name */
BHND_IVAR_CORE_INDEX, /**< Bus-assigned core number */
BHND_IVAR_CORE_UNIT, /**< Bus-assigned core unit number,
assigned sequentially (starting at 0) for
each vendor/device pair. */
};
/**
* bhnd device probe priority bands.
*/
enum {
BHND_PROBE_ROOT = 0, /**< Nexus or host bridge */
BHND_PROBE_BUS = 1000, /**< Busses and bridges */
BHND_PROBE_CPU = 2000, /**< CPU devices */
BHND_PROBE_INTERRUPT = 3000, /**< Interrupt controllers. */
BHND_PROBE_TIMER = 4000, /**< Timers and clocks. */
BHND_PROBE_RESOURCE = 5000, /**< Resource discovery (including NVRAM/SPROM) */
BHND_PROBE_DEFAULT = 6000, /**< Default device priority */
};
/**
* Constants defining fine grained ordering within a BHND_PROBE_* priority band.
*
* Example:
* @code
* BHND_PROBE_BUS + BHND_PROBE_ORDER_FIRST
* @endcode
*/
enum {
BHND_PROBE_ORDER_FIRST = 0,
BHND_PROBE_ORDER_EARLY = 25,
BHND_PROBE_ORDER_MIDDLE = 50,
BHND_PROBE_ORDER_LATE = 75,
BHND_PROBE_ORDER_LAST = 100
};
/*
* Simplified accessors for bhnd device ivars
*/
#define BHND_ACCESSOR(var, ivar, type) \
__BUS_ACCESSOR(bhnd, var, BHND, ivar, type)
BHND_ACCESSOR(vendor, VENDOR, uint16_t);
BHND_ACCESSOR(device, DEVICE, uint16_t);
BHND_ACCESSOR(hwrev, HWREV, uint8_t);
BHND_ACCESSOR(class, DEVICE_CLASS, bhnd_devclass_t);
BHND_ACCESSOR(vendor_name, VENDOR_NAME, const char *);
BHND_ACCESSOR(device_name, DEVICE_NAME, const char *);
BHND_ACCESSOR(core_index, CORE_INDEX, u_int);
BHND_ACCESSOR(core_unit, CORE_UNIT, int);
#undef BHND_ACCESSOR
/**
* Chip Identification
*
* This is read from the ChipCommon ID register; on earlier bhnd(4) devices
* where ChipCommon is unavailable, known values must be supplied.
*/
struct bhnd_chipid {
uint16_t chip_id; /**< chip id (BHND_CHIPID_*) */
uint8_t chip_rev; /**< chip revision */
uint8_t chip_pkg; /**< chip package (BHND_PKGID_*) */
uint8_t chip_type; /**< chip type (BHND_CHIPTYPE_*) */
bhnd_addr_t enum_addr; /**< chip_type-specific enumeration
* address; either the siba(4) base
* core register block, or the bcma(4)
* EROM core address. */
uint8_t ncores; /**< number of cores, if known. 0 if
* not available. */
};
/**
* A bhnd(4) bus resource.
*
* This provides an abstract interface to per-core resources that may require
* bus-level remapping of address windows prior to access.
*/
struct bhnd_resource {
struct resource *res; /**< the system resource. */
bool direct; /**< false if the resource requires
* bus window remapping before it
* is MMIO accessible. */
};
/**
* A bhnd(4) core descriptor.
*/
struct bhnd_core_info {
uint16_t vendor; /**< vendor */
uint16_t device; /**< device */
uint16_t hwrev; /**< hardware revision */
u_int core_idx; /**< bus-assigned core index */
int unit; /**< bus-assigned core unit */
};
/**
* A hardware revision match descriptor.
*/
struct bhnd_hwrev_match {
uint16_t start; /**< first revision, or BHND_HWREV_INVALID
to match on any revision. */
uint16_t end; /**< last revision, or BHND_HWREV_INVALID
to match on any revision. */
};
/**
* Wildcard hardware revision match descriptor.
*/
#define BHND_HWREV_MATCH_ANY { BHND_HWREV_INVALID, BHND_HWREV_INVALID }
/** A core match descriptor. */
struct bhnd_core_match {
uint16_t vendor; /**< required JEP106 device vendor or BHND_MFGID_INVALID. */
uint16_t device; /**< required core ID or BHND_COREID_INVALID */
struct bhnd_hwrev_match hwrev; /**< matching revisions. */
bhnd_devclass_t class; /**< required class or BHND_DEVCLASS_INVALID */
int unit; /**< required core unit, or -1 */
};
/**
* Revision-specific hardware quirk descriptor.
*
* Defines a set of quirk flags applicable to a range of hardware
* revisions.
*/
struct bhnd_device_quirk {
struct bhnd_hwrev_match hwrev; /**< applicable hardware revisions */
uint32_t quirks; /**< applicable quirk flags */
};
/**
* Define a bhnd_device_quirk over a range of hardware revisions.
*
* @param _start The first applicable hardware revision.
* @param _end The last applicable hardware revision, or BHND_HWREV_INVALID
* to match on any revision.
* @param _quirks Quirk flags applicable to this revision range.
*/
#define BHND_QUIRK_HWREV_RANGE(_start, _end, _quirks) \
{ .hwrev = { _start, _end }, .quirks = _quirks }
/**
* Define a bhnd_device_quirk for a specific hardware revision.
*
* @param _hwrev The hardware revision to match on.
* @param _quirks Quirk flags applicable to this revision.
*/
#define BHND_QUIRK_HWREV_EQ(_hwrev, _quirks) \
BHND_QUIRK_HWREV_RANGE(_hwrev, _hwrev, _quirks)
/**
* Define a bhnd_device_quirk for any hardware revision equal or greater
* than @p _start.
*
* @param _start The first hardware revision to match on.
* @param _quirks Quirk flags applicable to this revision.
*/
#define BHND_QUIRK_HWREV_GTE(_start, _quirks) \
BHND_QUIRK_HWREV_RANGE(_start, BHND_HWREV_INVALID, _quirks)
/**
* Define a bhnd_device_quirk for any hardware revision equal or less
* than @p _end.
*
* @param _end The last hardware revision to match on.
* @param _quirks Quirk flags applicable to this revision.
*/
#define BHND_QUIRK_HWREV_LTE(_end, _quirks) \
BHND_QUIRK_HWREV_RANGE(0, _end, _quirks)
/** Mark the end of a bhnd_device_quirk table. */
#define BHND_QUIRK_HWREV_END { BHND_HWREV_MATCH_ANY, 0 }
const char *bhnd_vendor_name(uint16_t vendor);
const char *bhnd_port_type_name(bhnd_port_type port_type);
const char *bhnd_find_core_name(uint16_t vendor,
uint16_t device);
bhnd_devclass_t bhnd_find_core_class(uint16_t vendor,
uint16_t device);
const char *bhnd_core_name(const struct bhnd_core_info *ci);
bhnd_devclass_t bhnd_core_class(const struct bhnd_core_info *ci);
device_t bhnd_match_child(device_t dev,
const struct bhnd_core_match *desc);
device_t bhnd_find_child(device_t dev,
bhnd_devclass_t class, int unit);
const struct bhnd_core_info *bhnd_match_core(
const struct bhnd_core_info *cores,
u_int num_cores,
const struct bhnd_core_match *desc);
const struct bhnd_core_info *bhnd_find_core(
const struct bhnd_core_info *cores,
u_int num_cores, bhnd_devclass_t class);
bool bhnd_core_matches(
const struct bhnd_core_info *core,
const struct bhnd_core_match *desc);
bool bhnd_hwrev_matches(uint16_t hwrev,
const struct bhnd_hwrev_match *desc);
bool bhnd_device_matches(device_t dev,
const struct bhnd_core_match *desc);
struct bhnd_core_info bhnd_get_core_info(device_t dev);
int bhnd_alloc_resources(device_t dev,
struct resource_spec *rs,
struct bhnd_resource **res);
void bhnd_release_resources(device_t dev,
const struct resource_spec *rs,
struct bhnd_resource **res);
struct bhnd_chipid bhnd_parse_chipid(uint32_t idreg,
bhnd_addr_t enum_addr);
int bhnd_read_chipid(device_t dev,
struct resource_spec *rs,
bus_size_t chipc_offset,
struct bhnd_chipid *result);
void bhnd_set_generic_core_desc(device_t dev);
/**
* Return true if @p dev is serving as a host bridge for its parent bhnd
* bus.
*
* @param dev A bhnd bus child device.
*/
static inline bool
bhnd_is_hostb_device(device_t dev) {
return (BHND_BUS_IS_HOSTB_DEVICE(device_get_parent(dev), dev));
}
/**
* Return true if the hardware components required by @p dev are known to be
* unpopulated or otherwise unusable.
*
* In some cases, enumerated devices may have pins that are left floating, or
* the hardware may otherwise be non-functional; this method allows a parent
* device to explicitly specify if a successfully enumerated @p dev should
* be disabled.
*
* @param dev A bhnd bus child device.
*/
static inline bool
bhnd_is_hw_disabled(device_t dev) {
return (BHND_BUS_IS_HW_DISABLED(device_get_parent(dev), dev));
}
/**
* Allocate a resource from a device's parent bhnd(4) bus.
*
* @param dev The device requesting resource ownership.
* @param type The type of resource to allocate. This may be any type supported
* by the standard bus APIs.
* @param rid The bus-specific handle identifying the resource being allocated.
* @param start The start address of the resource.
* @param end The end address of the resource.
* @param count The size of the resource.
* @param flags The flags for the resource to be allocated. These may be any
* values supported by the standard bus APIs.
*
* To request the resource's default addresses, pass @p start and
* @p end values of @c 0UL and @c ~0UL, respectively, and
* a @p count of @c 1.
*
* @retval NULL The resource could not be allocated.
* @retval resource The allocated resource.
*/
static inline struct bhnd_resource *
bhnd_alloc_resource(device_t dev, int type, int *rid, rman_res_t start,
rman_res_t end, rman_res_t count, u_int flags)
{
return BHND_BUS_ALLOC_RESOURCE(device_get_parent(dev), dev, type, rid,
start, end, count, flags);
}
/**
* Allocate a resource from a device's parent bhnd(4) bus, using the
* resource's default start, end, and count values.
*
* @param dev The device requesting resource ownership.
* @param type The type of resource to allocate. This may be any type supported
* by the standard bus APIs.
* @param rid The bus-specific handle identifying the resource being allocated.
* @param flags The flags for the resource to be allocated. These may be any
* values supported by the standard bus APIs.
*
* @retval NULL The resource could not be allocated.
* @retval resource The allocated resource.
*/
static inline struct bhnd_resource *
bhnd_alloc_resource_any(device_t dev, int type, int *rid, u_int flags)
{
return bhnd_alloc_resource(dev, type, rid, 0UL, ~0UL, 1, flags);
}
/**
* Activate a previously allocated bhnd resource.
*
* @param dev The device holding ownership of the allocated resource.
* @param type The type of the resource.
* @param rid The bus-specific handle identifying the resource.
* @param r A pointer to the resource returned by bhnd_alloc_resource or
* BHND_BUS_ALLOC_RESOURCE.
*
* @retval 0 success
* @retval non-zero an error occured while activating the resource.
*/
static inline int
bhnd_activate_resource(device_t dev, int type, int rid,
struct bhnd_resource *r)
{
return BHND_BUS_ACTIVATE_RESOURCE(device_get_parent(dev), dev, type,
rid, r);
}
/**
* Deactivate a previously activated bhnd resource.
*
* @param dev The device holding ownership of the activated resource.
* @param type The type of the resource.
* @param rid The bus-specific handle identifying the resource.
* @param r A pointer to the resource returned by bhnd_alloc_resource or
* BHND_BUS_ALLOC_RESOURCE.
*
* @retval 0 success
* @retval non-zero an error occured while activating the resource.
*/
static inline int
bhnd_deactivate_resource(device_t dev, int type, int rid,
struct bhnd_resource *r)
{
return BHND_BUS_DEACTIVATE_RESOURCE(device_get_parent(dev), dev, type,
rid, r);
}
/**
* Free a resource allocated by bhnd_alloc_resource().
*
* @param dev The device holding ownership of the resource.
* @param type The type of the resource.
* @param rid The bus-specific handle identifying the resource.
* @param r A pointer to the resource returned by bhnd_alloc_resource or
* BHND_ALLOC_RESOURCE.
*
* @retval 0 success
* @retval non-zero an error occured while activating the resource.
*/
static inline int
bhnd_release_resource(device_t dev, int type, int rid,
struct bhnd_resource *r)
{
return BHND_BUS_RELEASE_RESOURCE(device_get_parent(dev), dev, type,
rid, r);
}
/**
* Return true if @p region_num is a valid region on @p port_num of
* @p type attached to @p dev.
*
* @param dev A bhnd bus child device.
* @param type The port type being queried.
* @param port_num The port number being queried.
* @param region_num The region number being queried.
*/
static inline bool
bhnd_is_region_valid(device_t dev, bhnd_port_type type, u_int port_num,
u_int region_num)
{
return (BHND_BUS_IS_REGION_VALID(device_get_parent(dev), dev, type,
port_num, region_num));
}
/**
* Return the number of ports of type @p type attached to @p def.
*
* @param dev A bhnd bus child device.
* @param type The port type being queried.
*/
static inline u_int
bhnd_get_port_count(device_t dev, bhnd_port_type type) {
return (BHND_BUS_GET_PORT_COUNT(device_get_parent(dev), dev, type));
}
/**
* Return the number of memory regions mapped to @p child @p port of
* type @p type.
*
* @param dev A bhnd bus child device.
* @param port The port number being queried.
* @param type The port type being queried.
*/
static inline u_int
bhnd_get_region_count(device_t dev, bhnd_port_type type, u_int port) {
return (BHND_BUS_GET_REGION_COUNT(device_get_parent(dev), dev, type,
port));
}
/**
* Return the resource-ID for a memory region on the given device port.
*
* @param dev A bhnd bus child device.
* @param type The port type.
* @param port The port identifier.
* @param region The identifier of the memory region on @p port.
*
* @retval int The RID for the given @p port and @p region on @p device.
* @retval -1 No such port/region found.
*/
static inline int
bhnd_get_port_rid(device_t dev, bhnd_port_type type, u_int port, u_int region)
{
return BHND_BUS_GET_PORT_RID(device_get_parent(dev), dev, type, port,
region);
}
/**
* Decode a port / region pair on @p dev defined by @p rid.
*
* @param dev A bhnd bus child device.
* @param type The resource type.
* @param rid The resource identifier.
* @param[out] port_type The decoded port type.
* @param[out] port The decoded port identifier.
* @param[out] region The decoded region identifier.
*
* @retval 0 success
* @retval non-zero No matching port/region found.
*/
static inline int
bhnd_decode_port_rid(device_t dev, int type, int rid, bhnd_port_type *port_type,
u_int *port, u_int *region)
{
return BHND_BUS_DECODE_PORT_RID(device_get_parent(dev), dev, type, rid,
port_type, port, region);
}
/**
* Get the address and size of @p region on @p port.
*
* @param dev A bhnd bus child device.
* @param port_type The port type.
* @param port The port identifier.
* @param region The identifier of the memory region on @p port.
* @param[out] region_addr The region's base address.
* @param[out] region_size The region's size.
*
* @retval 0 success
* @retval non-zero No matching port/region found.
*/
static inline int
bhnd_get_region_addr(device_t dev, bhnd_port_type port_type, u_int port,
u_int region, bhnd_addr_t *region_addr, bhnd_size_t *region_size)
{
return BHND_BUS_GET_REGION_ADDR(device_get_parent(dev), dev, port_type,
port, region, region_addr, region_size);
}
/*
* bhnd bus-level equivalents of the bus_(read|write|set|barrier|...)
* macros (compatible with bhnd_resource).
*
* Generated with bhnd/tools/bus_macro.sh
*/
#define bhnd_bus_barrier(r, o, l, f) \
((r)->direct) ? \
bus_barrier((r)->res, (o), (l), (f)) : \
BHND_BUS_BARRIER(device_get_parent(rman_get_device((r)->res)), \
rman_get_device((r)->res), (r), (o), (l), (f))
#define bhnd_bus_read_1(r, o) \
((r)->direct) ? \
bus_read_1((r)->res, (o)) : \
BHND_BUS_READ_1(device_get_parent(rman_get_device((r)->res)), \
rman_get_device((r)->res), (r), (o))
#define bhnd_bus_write_1(r, o, v) \
((r)->direct) ? \
bus_write_1((r)->res, (o), (v)) : \
BHND_BUS_WRITE_1(device_get_parent(rman_get_device((r)->res)), \
rman_get_device((r)->res), (r), (o), (v))
#define bhnd_bus_read_2(r, o) \
((r)->direct) ? \
bus_read_2((r)->res, (o)) : \
BHND_BUS_READ_2(device_get_parent(rman_get_device((r)->res)), \
rman_get_device((r)->res), (r), (o))
#define bhnd_bus_write_2(r, o, v) \
((r)->direct) ? \
bus_write_2((r)->res, (o), (v)) : \
BHND_BUS_WRITE_2(device_get_parent(rman_get_device((r)->res)), \
rman_get_device((r)->res), (r), (o), (v))
#define bhnd_bus_read_4(r, o) \
((r)->direct) ? \
bus_read_4((r)->res, (o)) : \
BHND_BUS_READ_4(device_get_parent(rman_get_device((r)->res)), \
rman_get_device((r)->res), (r), (o))
#define bhnd_bus_write_4(r, o, v) \
((r)->direct) ? \
bus_write_4((r)->res, (o), (v)) : \
BHND_BUS_WRITE_4(device_get_parent(rman_get_device((r)->res)), \
rman_get_device((r)->res), (r), (o), (v))
#endif /* _BHND_BHND_H_ */

458
sys/dev/bhnd/bhnd_bus_if.m Normal file
View file

@ -0,0 +1,458 @@
#-
# Copyright (c) 2015 Landon Fuller <landon@landonf.org>
# 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 <sys/types.h>
#include <sys/bus.h>
#include <sys/rman.h>
#include <dev/bhnd/bhnd_types.h>
INTERFACE bhnd_bus;
#
# bhnd(4) bus interface
#
HEADER {
/* forward declarations */
struct bhnd_core_info;
struct bhnd_chipid;
struct bhnd_resource;
struct bhnd_bus_ctx;
}
CODE {
#include <sys/systm.h>
#include <dev/bhnd/bhndvar.h>
static struct bhnd_chipid *
bhnd_bus_null_get_chipid(device_t dev, device_t child)
{
panic("bhnd_get_chipid unimplemented");
}
static int
bhnd_bus_null_get_port_rid(device_t dev, device_t child,
bhnd_port_type port_type, u_int port, u_int region)
{
return (-1);
}
static int
bhnd_bus_null_decode_port_rid(device_t dev, device_t child, int type,
int rid, bhnd_port_type *port_type, u_int *port, u_int *region)
{
return (ENOENT);
}
static int
bhnd_bus_null_get_region_addr(device_t dev, device_t child,
bhnd_port_type type, u_int port, u_int region, bhnd_addr_t *addr,
bhnd_size_t *size)
{
return (ENOENT);
}
static int
bhnd_bus_null_read_nvram_var(device_t dev, device_t child,
const char *name, void *buf, size_t *size)
{
return (ENOENT);
}
}
/**
* Returns true if @p child is serving as a host bridge for the bhnd
* bus.
*
* The default implementation will walk the parent device tree until
* the root node is hit, returning false.
*
* @param dev The device whose child is being examined.
* @param child The child device.
*/
METHOD bool is_hostb_device {
device_t dev;
device_t child;
} DEFAULT bhnd_generic_is_hostb_device;
/**
* Return true if the hardware components required by @p child are unpopulated
* or otherwise unusable.
*
* In some cases, enumerated devices may have pins that are left floating, or
* the hardware may otherwise be non-functional; this method allows a parent
* device to explicitly specify if a successfully enumerated @p child should
* be disabled.
*
* @param dev The device whose child is being examined.
* @param child The child device.
*/
METHOD bool is_hw_disabled {
device_t dev;
device_t child;
} DEFAULT bhnd_generic_is_hw_disabled;
/**
* Return the probe (and attach) order for @p child.
*
* All devices on the bhnd(4) bus will be probed, attached, or resumed in
* ascending order; they will be suspended, shutdown, and detached in
* descending order.
*
* The following device methods will be dispatched in ascending probe order
* by the bus:
*
* - DEVICE_PROBE()
* - DEVICE_ATTACH()
* - DEVICE_RESUME()
*
* The following device methods will be dispatched in descending probe order
* by the bus:
*
* - DEVICE_SHUTDOWN()
* - DEVICE_DETACH()
* - DEVICE_SUSPEND()
*
* @param dev The device whose child is being examined.
* @param child The child device.
*
* Refer to BHND_PROBE_* and BHND_PROBE_ORDER_* for the standard set of
* priorities.
*/
METHOD int get_probe_order {
device_t dev;
device_t child;
} DEFAULT bhnd_generic_get_probe_order;
/**
* Return the BHND chip identification for the parent bus.
*
* @param dev The device whose child is being examined.
* @param child The child device.
*/
METHOD const struct bhnd_chipid * get_chipid {
device_t dev;
device_t child;
} DEFAULT bhnd_bus_null_get_chipid;
/**
* Reset the device's hardware core.
*
* @param dev The parent of @p child.
* @param child The device to be reset.
* @param flags Device-specific core flags to be supplied on reset.
*
* @retval 0 success
* @retval non-zero error
*/
METHOD int reset_core {
device_t dev;
device_t child;
uint16_t flags;
}
/**
* Suspend a device hardware core.
*
* @param dev The parent of @p child.
* @param child The device to be reset.
*
* @retval 0 success
* @retval non-zero error
*/
METHOD int suspend_core {
device_t dev;
device_t child;
}
/**
* Allocate a bhnd resource.
*
* This method's semantics are functionally identical to the bus API of the same
* name; refer to BUS_ALLOC_RESOURCE for complete documentation.
*/
METHOD struct bhnd_resource * alloc_resource {
device_t dev;
device_t child;
int type;
int *rid;
rman_res_t start;
rman_res_t end;
rman_res_t count;
u_int flags;
} DEFAULT bhnd_generic_alloc_bhnd_resource;
/**
* Release a bhnd resource.
*
* This method's semantics are functionally identical to the bus API of the same
* name; refer to BUS_RELEASE_RESOURCE for complete documentation.
*/
METHOD int release_resource {
device_t dev;
device_t child;
int type;
int rid;
struct bhnd_resource *res;
} DEFAULT bhnd_generic_release_bhnd_resource;
/**
* Activate a bhnd resource.
*
* This method's semantics are functionally identical to the bus API of the same
* name; refer to BUS_ACTIVATE_RESOURCE for complete documentation.
*/
METHOD int activate_resource {
device_t dev;
device_t child;
int type;
int rid;
struct bhnd_resource *r;
} DEFAULT bhnd_generic_activate_bhnd_resource;
/**
* Deactivate a bhnd resource.
*
* This method's semantics are functionally identical to the bus API of the same
* name; refer to BUS_DEACTIVATE_RESOURCE for complete documentation.
*/
METHOD int deactivate_resource {
device_t dev;
device_t child;
int type;
int rid;
struct bhnd_resource *r;
} DEFAULT bhnd_generic_deactivate_bhnd_resource;
/**
* Return true if @p region_num is a valid region on @p port_num of
* @p type attached to @p child.
*
* @param dev The device whose child is being examined.
* @param child The child device.
* @param type The port type being queried.
* @param port_num The port number being queried.
* @param region_num The region number being queried.
*/
METHOD u_int is_region_valid {
device_t dev;
device_t child;
bhnd_port_type type;
u_int port_num;
u_int region_num;
} DEFAULT bhnd_generic_is_region_valid;
/**
* Return the number of ports of type @p type attached to @p child.
*
* @param dev The device whose child is being examined.
* @param child The child device.
* @param type The port type being queried.
*/
METHOD u_int get_port_count {
device_t dev;
device_t child;
bhnd_port_type type;
}
/**
* Return the number of memory regions mapped to @p child @p port of
* type @p type.
*
* @param dev The device whose child is being examined.
* @param child The child device.
* @param port The port number being queried.
* @param type The port type being queried.
*/
METHOD u_int get_region_count {
device_t dev;
device_t child;
bhnd_port_type type;
u_int port;
}
/**
* Return the SYS_RES_MEMORY resource-ID for a port/region pair attached to
* @p child.
*
* @param dev The bus device.
* @param child The bhnd child.
* @param port_type The port type.
* @param port_num The index of the child interconnect port.
* @param region_num The index of the port-mapped address region.
*
* @retval -1 No such port/region found.
*/
METHOD int get_port_rid {
device_t dev;
device_t child;
bhnd_port_type port_type;
u_int port_num;
u_int region_num;
} DEFAULT bhnd_bus_null_get_port_rid;
/**
* Decode a port / region pair on @p child defined by @p type and @p rid.
*
* @param dev The bus device.
* @param child The bhnd child.
* @param type The resource type.
* @param rid The resource ID.
* @param[out] port_type The port's type.
* @param[out] port The port identifier.
* @param[out] region The identifier of the memory region on @p port.
*
* @retval 0 success
* @retval non-zero No matching type/rid found.
*/
METHOD int decode_port_rid {
device_t dev;
device_t child;
int type;
int rid;
bhnd_port_type *port_type;
u_int *port;
u_int *region;
} DEFAULT bhnd_bus_null_decode_port_rid;
/**
* Get the address and size of @p region on @p port.
*
* @param dev The bus device.
* @param child The bhnd child.
* @param port_type The port type.
* @param port The port identifier.
* @param region The identifier of the memory region on @p port.
* @param[out] region_addr The region's base address.
* @param[out] region_size The region's size.
*
* @retval 0 success
* @retval non-zero No matching port/region found.
*/
METHOD int get_region_addr {
device_t dev;
device_t child;
bhnd_port_type port_type;
u_int port;
u_int region;
bhnd_addr_t *region_addr;
bhnd_size_t *region_size;
} DEFAULT bhnd_bus_null_get_region_addr;
/**
* Read an NVRAM variable.
*
* It is the responsibility of the bus to delegate this request to
* the appropriate NVRAM child device, or to a parent bus implementation.
*
* @param dev The bus device.
* @param child The requesting device.
* @param name The NVRAM variable name.
* @param[out] buf On success, the requested value will be written
* to this buffer. This argment may be NULL if
* the value is not desired.
* @param[in,out] size The capacity of @p buf. On success, will be set
* to the actual size of the requested value.
*
* @retval 0 success
* @retval ENOENT The requested variable was not found.
* @retval ENOMEM If @p buf is non-NULL and a buffer of @p size is too
* small to hold the requested value.
* @retval non-zero If reading @p name otherwise fails, a regular unix
* error code will be returned.
*/
METHOD int read_nvram_var {
device_t dev;
device_t child;
const char *name;
void *buf;
size_t *size;
} DEFAULT bhnd_bus_null_read_nvram_var;
/** An implementation of bus_read_1() compatible with bhnd_resource */
METHOD uint8_t read_1 {
device_t dev;
device_t child;
struct bhnd_resource *r;
bus_size_t offset;
}
/** An implementation of bus_read_2() compatible with bhnd_resource */
METHOD uint16_t read_2 {
device_t dev;
device_t child;
struct bhnd_resource *r;
bus_size_t offset;
}
/** An implementation of bus_read_4() compatible with bhnd_resource */
METHOD uint32_t read_4 {
device_t dev;
device_t child;
struct bhnd_resource *r;
bus_size_t offset;
}
/** An implementation of bus_write_1() compatible with bhnd_resource */
METHOD void write_1 {
device_t dev;
device_t child;
struct bhnd_resource *r;
bus_size_t offset;
uint8_t value;
}
/** An implementation of bus_write_2() compatible with bhnd_resource */
METHOD void write_2 {
device_t dev;
device_t child;
struct bhnd_resource *r;
bus_size_t offset;
uint16_t value;
}
/** An implementation of bus_write_4() compatible with bhnd_resource */
METHOD void write_4 {
device_t dev;
device_t child;
struct bhnd_resource *r;
bus_size_t offset;
uint32_t value;
}
/** An implementation of bus_barrier() compatible with bhnd_resource */
METHOD void barrier {
device_t dev;
device_t child;
struct bhnd_resource *r;
bus_size_t offset;
bus_size_t length;
int flags;
}

77
sys/dev/bhnd/bhnd_core.h Normal file
View file

@ -0,0 +1,77 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* Copyright (c) 2010 Broadcom Corporation
*
* This file is derived from the hndsoc.h header distributed with
* Broadcom's initial brcm80211 Linux driver release, as
* contributed to the Linux staging repository.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $FreeBSD$
*/
#ifndef _BHND_BHND_CORE_H_
#define _BHND_BHND_CORE_H_
/* Common core control flags */
#define BHND_CF_BIST_EN 0x8000 /**< ??? */
#define BHND_CF_PME_EN 0x4000 /**< ??? */
#define BHND_CF_CORE_BITS 0x3ffc /**< core specific flag mask */
#define BHND_CF_FGC 0x0002 /**< force clock gating */
#define BHND_CF_CLOCK_EN 0x0001 /**< enable clock */
/* Common core status flags */
#define BHND_SF_BIST_DONE 0x8000 /**< ??? */
#define BHND_SF_BIST_ERROR 0x4000 /**< ??? */
#define BHND_SF_GATED_CLK 0x2000 /**< clock gated */
#define BHND_SF_DMA64 0x1000 /**< supports 64-bit DMA */
#define BHND_SF_CORE_BITS 0x0fff /**< core-specific status mask */
/*
* A register that is common to all cores to
* communicate w/PMU regarding clock control.
*
* TODO: Determine when this register first appeared.
*/
#define BHND_CLK_CTL_ST 0x1e0 /**< clock control and status */
/*
* BHND_CLK_CTL_ST register
*
* Clock Mode Name Description
* High Throughput (HT) Full bandwidth, low latency. Generally supplied
* from PLL.
* Active Low Power (ALP) Register access, low speed DMA.
* Idle Low Power (ILP) No interconnect activity, or if long latency
* is permitted.
*/
#define BHND_CCS_FORCEALP 0x00000001 /**< force ALP request */
#define BHND_CCS_FORCEHT 0x00000002 /**< force HT request */
#define BHND_CCS_FORCEILP 0x00000004 /**< force ILP request */
#define BHND_CCS_ALPAREQ 0x00000008 /**< ALP Avail Request */
#define BHND_CCS_HTAREQ 0x00000010 /**< HT Avail Request */
#define BHND_CCS_FORCEHWREQOFF 0x00000020 /**< Force HW Clock Request Off */
#define BHND_CCS_ERSRC_REQ_MASK 0x00000700 /**< external resource requests */
#define BHND_CCS_ERSRC_REQ_SHIFT 8
#define BHND_CCS_ALPAVAIL 0x00010000 /**< ALP is available */
#define BHND_CCS_HTAVAIL 0x00020000 /**< HT is available */
#define BHND_CCS_BP_ON_APL 0x00040000 /**< RO: Backplane is running on ALP clock */
#define BHND_CCS_BP_ON_HT 0x00080000 /**< RO: Backplane is running on HT clock */
#define BHND_CCS_ERSRC_STS_MASK 0x07000000 /**< external resource status */
#define BHND_CCS_ERSRC_STS_SHIFT 24
#define BHND_CCS0_HTAVAIL 0x00010000 /**< HT avail in chipc and pcmcia on 4328a0 */
#define BHND_CCS0_ALPAVAIL 0x00020000 /**< ALP avail in chipc and pcmcia on 4328a0 */
#endif /* _BHND_BHND_CORE_H_ */

754
sys/dev/bhnd/bhnd_ids.h Normal file
View file

@ -0,0 +1,754 @@
/*-
* Copyright (C) 1999-2013, Broadcom Corporation
*
* This file is derived from the bcmdevs.h header contributed by Broadcom
* to Android's bcmdhd driver module, and the hndsoc.h header distributed with
* with Broadcom's initial brcm80211 Linux driver release, as contributed to
* the Linux staging repository.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $Id: bcmdevs.h 387183 2013-02-24 07:42:07Z $
*
* $FreeBSD$
*/
#ifndef _BHND_BHND_IDS_H_
#define _BHND_BHND_IDS_H_
/*
* JEDEC JEP-106 Core Vendor IDs
*
* These are the JEDEC JEP-106 manufacturer ID representions (with ARM's
* non-standard 4-bit continutation code), as used in ARM's PrimeCell
* identification registers, bcma(4) EROM core descriptors, etc.
*
* @note
* Bus implementations that predate the adoption of ARM IP
* will need to convert bus-specific vendor IDs to their BHND_MFGID
* JEP-106 equivalents.
*
* @par ARM 4-bit Continuation Code
*
* BHND MFGIDs are encoded using ARM's non-standard 4-bit continuation code
* format:
*
* @code{.unparsed}
* [11:8 ][7:0 ]
* [cont code][mfg id]
* @endcode
*
* The 4-bit continuation code field specifies the number of JEP-106
* continuation codes that prefix the manufacturer's ID code. In the case of
* ARM's JEP-106 ID of `0x7F 0x7F 0x7F 0x7F 0x3B`, the four 0x7F continuations
* are encoded as '4' in the 4-bit continuation code field (i.e. 0x43B).
*/
#define BHND_MFGID_ARM 0x043b /**< arm JEP-106 vendor id */
#define BHND_MFGID_BCM 0x04bf /**< broadcom JEP-106 vendor id */
#define BHND_MFGID_MIPS 0x04a7 /**< mips JEP-106 vendor id */
#define BHND_MFGID_INVALID 0x0000 /**< invalid JEP-106 vendor id */
/*
* OCP (Open Core Protocol) Vendor IDs.
*
* OCP-IP assigned vendor codes are used by siba(4)
*/
#define OCP_VENDOR_BCM 0x4243 /**< Broadcom OCP vendor id */
/* PCI vendor IDs */
#define PCI_VENDOR_EPIGRAM 0xfeda
#define PCI_VENDOR_BROADCOM 0x14e4
#define PCI_VENDOR_3COM 0x10b7
#define PCI_VENDOR_NETGEAR 0x1385
#define PCI_VENDOR_DIAMOND 0x1092
#define PCI_VENDOR_INTEL 0x8086
#define PCI_VENDOR_DELL 0x1028
#define PCI_VENDOR_HP 0x103c
#define PCI_VENDOR_HP_COMPAQ 0x0e11
#define PCI_VENDOR_APPLE 0x106b
#define PCI_VENDOR_SI_IMAGE 0x1095 /* Silicon Image, used by Arasan SDIO Host */
#define PCI_VENDOR_BUFFALO 0x1154 /* Buffalo vendor id */
#define PCI_VENDOR_TI 0x104c /* Texas Instruments */
#define PCI_VENDOR_RICOH 0x1180 /* Ricoh */
#define PCI_VENDOR_JMICRON 0x197b
/* PCMCIA vendor IDs */
#define PCMCIA_VENDOR_BROADCOM 0x02d0
/* SDIO vendor IDs */
#define SDIO_VENDOR_BROADCOM 0x00BF
/* USB dongle VID/PIDs */
#define USB_VID_BROADCOM 0x0a5c
#define USB_PID_BCM4328 0xbd12
#define USB_PID_BCM4322 0xbd13
#define USB_PID_BCM4319 0xbd16
#define USB_PID_BCM43236 0xbd17
#define USB_PID_BCM4332 0xbd18
#define USB_PID_BCM4330 0xbd19
#define USB_PID_BCM4334 0xbd1a
#define USB_PID_BCM43239 0xbd1b
#define USB_PID_BCM4324 0xbd1c
#define USB_PID_BCM4360 0xbd1d
#define USB_PID_BCM43143 0xbd1e
#define USB_PID_BCM43242 0xbd1f
#define USB_PID_BCM43342 0xbd21
#define USB_PID_BCM4335 0xbd20
#define USB_PID_BCM4350 0xbd23
#define USB_PID_BCM43341 0xbd22
#define USB_PID_BCM_DNGL_BDC 0x0bdc /* BDC USB device controller IP? */
#define USB_PID_BCM_DNGL_JTAG 0x4a44
/* HW USB BLOCK [CPULESS USB] PIDs */
#define USB_PID_CCM_HWUSB_43239 43239
/* PCI Device IDs */
#define PCI_DEVID_BCM4210 0x1072 /* never used */
#define PCI_DEVID_BCM4230 0x1086 /* never used */
#define PCI_DEVID_BCM4401_ENET 0x170c /* 4401b0 production enet cards */
#define PCI_DEVID_BCM3352 0x3352 /* bcm3352 device id */
#define PCI_DEVID_BCM3360 0x3360 /* bcm3360 device id */
#define PCI_DEVID_BCM4211 0x4211
#define PCI_DEVID_BCM4231 0x4231
#define PCI_DEVID_BCM4301 0x4301 /* 4031 802.11b */
#define PCI_DEVID_BCM4303_D11B 0x4303 /* 4303 802.11b */
#define PCI_DEVID_BCM4306 0x4306 /* 4306 802.11b/g */
#define PCI_DEVID_BCM4307 0x4307 /* 4307 802.11b, 10/100 ethernet, V.92 modem */
#define PCI_DEVID_BCM4311_D11G 0x4311 /* 4311 802.11b/g id */
#define PCI_DEVID_BCM4311_D11DUAL 0x4312 /* 4311 802.11a/b/g id */
#define PCI_DEVID_BCM4311_D11A 0x4313 /* 4311 802.11a id */
#define PCI_DEVID_BCM4328_D11DUAL 0x4314 /* 4328/4312 802.11a/g id */
#define PCI_DEVID_BCM4328_D11G 0x4315 /* 4328/4312 802.11g id */
#define PCI_DEVID_BCM4328_D11A 0x4316 /* 4328/4312 802.11a id */
#define PCI_DEVID_BCM4318_D11G 0x4318 /* 4318 802.11b/g id */
#define PCI_DEVID_BCM4318_D11DUAL 0x4319 /* 4318 802.11a/b/g id */
#define PCI_DEVID_BCM4318_D11A 0x431a /* 4318 802.11a id */
#define PCI_DEVID_BCM4325_D11DUAL 0x431b /* 4325 802.11a/g id */
#define PCI_DEVID_BCM4325_D11G 0x431c /* 4325 802.11g id */
#define PCI_DEVID_BCM4325_D11A 0x431d /* 4325 802.11a id */
#define PCI_DEVID_BCM4306_D11G 0x4320 /* 4306 802.11g */
#define PCI_DEVID_BCM4306_D11A 0x4321 /* 4306 802.11a */
#define PCI_DEVID_BCM4306_UART 0x4322 /* 4306 uart */
#define PCI_DEVID_BCM4306_V90 0x4323 /* 4306 v90 codec */
#define PCI_DEVID_BCM4306_D11DUAL 0x4324 /* 4306 dual A+B */
#define PCI_DEVID_BCM4306_D11G_ID2 0x4325 /* BCM4306_D11G; INF w/loose binding war */
#define PCI_DEVID_BCM4321_D11N 0x4328 /* 4321 802.11n dualband id */
#define PCI_DEVID_BCM4321_D11N2G 0x4329 /* 4321 802.11n 2.4Ghz band id */
#define PCI_DEVID_BCM4321_D11N5G 0x432a /* 4321 802.11n 5Ghz band id */
#define PCI_DEVID_BCM4322_D11N 0x432b /* 4322 802.11n dualband device */
#define PCI_DEVID_BCM4322_D11N2G 0x432c /* 4322 802.11n 2.4GHz device */
#define PCI_DEVID_BCM4322_D11N5G 0x432d /* 4322 802.11n 5GHz device */
#define PCI_DEVID_BCM4329_D11N 0x432e /* 4329 802.11n dualband device */
#define PCI_DEVID_BCM4329_D11N2G 0x432f /* 4329 802.11n 2.4G device */
#define PCI_DEVID_BCM4329_D11N5G 0x4330 /* 4329 802.11n 5G device */
#define PCI_DEVID_BCM4315_D11DUAL 0x4334 /* 4315 802.11a/g id */
#define PCI_DEVID_BCM4315_D11G 0x4335 /* 4315 802.11g id */
#define PCI_DEVID_BCM4315_D11A 0x4336 /* 4315 802.11a id */
#define PCI_DEVID_BCM4319_D11N 0x4337 /* 4319 802.11n dualband device */
#define PCI_DEVID_BCM4319_D11N2G 0x4338 /* 4319 802.11n 2.4G device */
#define PCI_DEVID_BCM4319_D11N5G 0x4339 /* 4319 802.11n 5G device */
#define PCI_DEVID_BCM43231_D11N2G 0x4340 /* 43231 802.11n 2.4GHz device */
#define PCI_DEVID_BCM43221_D11N2G 0x4341 /* 43221 802.11n 2.4GHz device */
#define PCI_DEVID_BCM43222_D11N 0x4350 /* 43222 802.11n dualband device */
#define PCI_DEVID_BCM43222_D11N2G 0x4351 /* 43222 802.11n 2.4GHz device */
#define PCI_DEVID_BCM43222_D11N5G 0x4352 /* 43222 802.11n 5GHz device */
#define PCI_DEVID_BCM43224_D11N 0x4353 /* 43224 802.11n dualband device */
#define PCI_DEVID_BCM43224_D11N_ID_VEN1 0x0576 /* Vendor specific 43224 802.11n db device */
#define PCI_DEVID_BCM43226_D11N 0x4354 /* 43226 802.11n dualband device */
#define PCI_DEVID_BCM43236_D11N 0x4346 /* 43236 802.11n dualband device */
#define PCI_DEVID_BCM43236_D11N2G 0x4347 /* 43236 802.11n 2.4GHz device */
#define PCI_DEVID_BCM43236_D11N5G 0x4348 /* 43236 802.11n 5GHz device */
#define PCI_DEVID_BCM43225_D11N2G 0x4357 /* 43225 802.11n 2.4GHz device */
#define PCI_DEVID_BCM43421_D11N 0xA99D /* 43421 802.11n dualband device */
#define PCI_DEVID_BCM4313_D11N2G 0x4727 /* 4313 802.11n 2.4G device */
#define PCI_DEVID_BCM4330_D11N 0x4360 /* 4330 802.11n dualband device */
#define PCI_DEVID_BCM4330_D11N2G 0x4361 /* 4330 802.11n 2.4G device */
#define PCI_DEVID_BCM4330_D11N5G 0x4362 /* 4330 802.11n 5G device */
#define PCI_DEVID_BCM4336_D11N 0x4343 /* 4336 802.11n 2.4GHz device */
#define PCI_DEVID_BCM6362_D11N 0x435f /* 6362 802.11n dualband device */
#define PCI_DEVID_BCM6362_D11N2G 0x433f /* 6362 802.11n 2.4Ghz band id */
#define PCI_DEVID_BCM6362_D11N5G 0x434f /* 6362 802.11n 5Ghz band id */
#define PCI_DEVID_BCM4331_D11N 0x4331 /* 4331 802.11n dualband id */
#define PCI_DEVID_BCM4331_D11N2G 0x4332 /* 4331 802.11n 2.4Ghz band id */
#define PCI_DEVID_BCM4331_D11N5G 0x4333 /* 4331 802.11n 5Ghz band id */
#define PCI_DEVID_BCM43237_D11N 0x4355 /* 43237 802.11n dualband device */
#define PCI_DEVID_BCM43237_D11N5G 0x4356 /* 43237 802.11n 5GHz device */
#define PCI_DEVID_BCM43227_D11N2G 0x4358 /* 43228 802.11n 2.4GHz device */
#define PCI_DEVID_BCM43228_D11N 0x4359 /* 43228 802.11n DualBand device */
#define PCI_DEVID_BCM43228_D11N5G 0x435a /* 43228 802.11n 5GHz device */
#define PCI_DEVID_BCM43362_D11N 0x4363 /* 43362 802.11n 2.4GHz device */
#define PCI_DEVID_BCM43239_D11N 0x4370 /* 43239 802.11n dualband device */
#define PCI_DEVID_BCM4324_D11N 0x4374 /* 4324 802.11n dualband device */
#define PCI_DEVID_BCM43217_D11N2G 0x43a9 /* 43217 802.11n 2.4GHz device */
#define PCI_DEVID_BCM43131_D11N2G 0x43aa /* 43131 802.11n 2.4GHz device */
#define PCI_DEVID_BCM4314_D11N2G 0x4364 /* 4314 802.11n 2.4G device */
#define PCI_DEVID_BCM43142_D11N2G 0x4365 /* 43142 802.11n 2.4G device */
#define PCI_DEVID_BCM43143_D11N2G 0x4366 /* 43143 802.11n 2.4G device */
#define PCI_DEVID_BCM4334_D11N 0x4380 /* 4334 802.11n dualband device */
#define PCI_DEVID_BCM4334_D11N2G 0x4381 /* 4334 802.11n 2.4G device */
#define PCI_DEVID_BCM4334_D11N5G 0x4382 /* 4334 802.11n 5G device */
#define PCI_DEVID_BCM43342_D11N 0x4383 /* 43342 802.11n dualband device */
#define PCI_DEVID_BCM43342_D11N2G 0x4384 /* 43342 802.11n 2.4G device */
#define PCI_DEVID_BCM43342_D11N5G 0x4385 /* 43342 802.11n 5G device */
#define PCI_DEVID_BCM43341_D11N 0x4386 /* 43341 802.11n dualband device */
#define PCI_DEVID_BCM43341_D11N2G 0x4387 /* 43341 802.11n 2.4G device */
#define PCI_DEVID_BCM43341_D11N5G 0x4388 /* 43341 802.11n 5G device */
#define PCI_DEVID_BCM4360_D11AC 0x43a0
#define PCI_DEVID_BCM4360_D11AC2G 0x43a1
#define PCI_DEVID_BCM4360_D11AC5G 0x43a2
#define PCI_DEVID_BCM4335_D11AC 0x43ae
#define PCI_DEVID_BCM4335_D11AC2G 0x43af
#define PCI_DEVID_BCM4335_D11AC5G 0x43b0
#define PCI_DEVID_BCM4352_D11AC 0x43b1 /* 4352 802.11ac dualband device */
#define PCI_DEVID_BCM4352_D11AC2G 0x43b2 /* 4352 802.11ac 2.4G device */
#define PCI_DEVID_BCM4352_D11AC5G 0x43b3 /* 4352 802.11ac 5G device */
#define PCI_DEVID_PCIXX21_FLASHMEDIA0 0x8033 /* TI PCI xx21 Standard Host Controller */
#define PCI_DEVID_PCIXX21_SDIOH0 0x8034 /* TI PCI xx21 Standard Host Controller */
/* PCI Subsystem Vendor IDs */
#define PCI_SUBVENDOR_BCM943228HMB 0x0607
#define PCI_SUBVENDOR_BCM94313HMGBL 0x0608
#define PCI_SUBVENDOR_BCM94313HMG 0x0609
#define PCI_SUBVENDOR_BCM943142HM 0x0611
/* PCI Subsystem Device IDs */
#define PCI_SUBDEVID_BCM43143_D11N2G 0x4366 /* 43143 802.11n 2.4G device */
#define PCI_SUBDEVID_BCM43242_D11N 0x4367 /* 43242 802.11n dualband device */
#define PCI_SUBDEVID_BCM43242_D11N2G 0x4368 /* 43242 802.11n 2.4G device */
#define PCI_SUBDEVID_BCM43242_D11N5G 0x4369 /* 43242 802.11n 5G device */
#define PCI_SUBDEVID_BCM4350_D11AC 0x43a3
#define PCI_SUBDEVID_BCM4350_D11AC2G 0x43a4
#define PCI_SUBDEVID_BCM4350_D11AC5G 0x43a5
#define PCI_SUBDEVID_BCMGPRS_UART 0x4333 /* Uart id used by 4306/gprs card */
#define PCI_SUBDEVID_BCMGPRS2_UART 0x4344 /* Uart id used by 4306/gprs card */
#define PCI_SUBDEVID_BCM_FPGA_JTAGM 0x43f0 /* FPGA jtagm device id */
#define PCI_SUBDEVID_BCM_JTAGM 0x43f1 /* BCM jtagm device id */
#define PCI_SUBDEVID_BCM_SDIOH_FPGA 0x43f2 /* sdio host fpga */
#define PCI_SUBDEVID_BCM_SDIOH 0x43f3 /* BCM sdio host id */
#define PCI_SUBDEVID_BCM_SDIOD_FPGA 0x43f4 /* sdio device fpga */
#define PCI_SUBDEVID_BCM_SPIH_FPGA 0x43f5 /* PCI SPI Host Controller FPGA */
#define PCI_SUBDEVID_BCM_SPIH 0x43f6 /* Synopsis SPI Host Controller */
#define PCI_SUBDEVID_BCM_MIMO_FPGA 0x43f8 /* FPGA mimo minimacphy device id */
#define PCI_SUBDEVID_BCM_JTAGM2 0x43f9 /* PCI_SUBDEVID_BCM alternate jtagm device id */
#define PCI_SUBDEVID_BCM_SDHCI_FPGA 0x43fa /* Standard SDIO Host Controller FPGA */
#define PCI_SUBDEVID_BCM4402_ENET 0x4402 /* 4402 enet */
#define PCI_SUBDEVID_BCM4402_V90 0x4403 /* 4402 v90 codec */
#define PCI_SUBDEVID_BCM4410 0x4410 /* bcm44xx family pci iline */
#define PCI_SUBDEVID_BCM4412 0x4412 /* bcm44xx family pci enet */
#define PCI_SUBDEVID_BCM4430 0x4430 /* bcm44xx family cardbus iline */
#define PCI_SUBDEVID_BCM4432 0x4432 /* bcm44xx family cardbus enet */
#define PCI_SUBDEVID_BCM4704_ENET 0x4706 /* 4704 enet (Use 47XX_ENET_ID instead!) */
#define PCI_SUBDEVID_BCM4710 0x4710 /* 4710 primary function 0 */
#define PCI_SUBDEVID_BCM47XX_AUDIO 0x4711 /* 47xx audio codec */
#define PCI_SUBDEVID_BCM47XX_V90 0x4712 /* 47xx v90 codec */
#define PCI_SUBDEVID_BCM47XX_ENET 0x4713 /* 47xx enet */
#define PCI_SUBDEVID_BCM47XX_EXT 0x4714 /* 47xx external i/f */
#define PCI_SUBDEVID_BCM47XX_GMAC 0x4715 /* 47xx Unimac based GbE */
#define PCI_SUBDEVID_BCM47XX_USBH 0x4716 /* 47xx usb host */
#define PCI_SUBDEVID_BCM47XX_USBD 0x4717 /* 47xx usb device */
#define PCI_SUBDEVID_BCM47XX_IPSEC 0x4718 /* 47xx ipsec */
#define PCI_SUBDEVID_BCM47XX_ROBO 0x4719 /* 47xx/53xx roboswitch core */
#define PCI_SUBDEVID_BCM47XX_USB20H 0x471a /* 47xx usb 2.0 host */
#define PCI_SUBDEVID_BCM47XX_USB20D 0x471b /* 47xx usb 2.0 device */
#define PCI_SUBDEVID_BCM47XX_ATA100 0x471d /* 47xx parallel ATA */
#define PCI_SUBDEVID_BCM47XX_SATAXOR 0x471e /* 47xx serial ATA & XOR DMA */
#define PCI_SUBDEVID_BCM47XX_GIGETH 0x471f /* 47xx GbE (5700) */
#define PCI_SUBDEVID_BCM4712_MIPS 0x4720 /* 4712 base devid */
#define PCI_SUBDEVID_BCM4716 0x4722 /* 4716 base devid */
#define PCI_SUBDEVID_BCM47XX_USB30H 0x472a /* 47xx usb 3.0 host */
#define PCI_SUBDEVID_BCM47XX_USB30D 0x472b /* 47xx usb 3.0 device */
#define PCI_SUBDEVID_BCM47XX_SMBUS_EMU 0x47fe /* 47xx emulated SMBus device */
#define PCI_SUBDEVID_BCM47XX_XOR_EMU 0x47ff /* 47xx emulated XOR engine */
#define PCI_SUBDEVID_BCM_EPI41210 0xa0fa /* bcm4210 */
#define PCI_SUBDEVID_BCM_EPI41230 0xa10e /* bcm4230 */
#define PCI_SUBDEVID_BCM_JINVANI_SDIOH 0x4743 /* Jinvani SDIO Gold Host */
#define PCI_SUBDEVID_BCM27XX_SDIOH 0x2702 /* PCI_SUBDEVID_BCM27xx Standard SDIO Host */
#define PCI_SUBDEVID_BCM_PCIXX21_FLASHMEDIA 0x803b /* TI PCI xx21 Standard Host Controller */
#define PCI_SUBDEVID_BCM_PCIXX21_SDIOH 0x803c /* TI PCI xx21 Standard Host Controller */
#define PCI_SUBDEVID_BCM_R5C822_SDIOH 0x0822 /* Ricoh Co Ltd R5C822 SD/SDIO/MMC/MS/MSPro Host */
#define PCI_SUBDEVID_BCM_JMICRON_SDIOH 0x2381 /* JMicron Standard SDIO Host Controller */
/* Broadcom ChipCommon Chip IDs */
#define BHND_CHIPID_BCM4306 0x4306 /* 4306 chipcommon chipid */
#define BHND_CHIPID_BCM4311 0x4311 /* 4311 PCIe 802.11a/b/g */
#define BHND_CHIPID_BCM43111 43111 /* 43111 chipcommon chipid (OTP chipid) */
#define BHND_CHIPID_BCM43112 43112 /* 43112 chipcommon chipid (OTP chipid) */
#define BHND_CHIPID_BCM4312 0x4312 /* 4312 chipcommon chipid */
#define BHND_CHIPID_BCM4313 0x4313 /* 4313 chip id */
#define BHND_CHIPID_BCM43131 43131 /* 43131 chip id (OTP chipid) */
#define BHND_CHIPID_BCM4315 0x4315 /* 4315 chip id */
#define BHND_CHIPID_BCM4318 0x4318 /* 4318 chipcommon chipid */
#define BHND_CHIPID_BCM4319 0x4319 /* 4319 chip id */
#define BHND_CHIPID_BCM4320 0x4320 /* 4320 chipcommon chipid */
#define BHND_CHIPID_BCM4321 0x4321 /* 4321 chipcommon chipid */
#define BHND_CHIPID_BCM43217 43217 /* 43217 chip id (OTP chipid) */
#define BHND_CHIPID_BCM4322 0x4322 /* 4322 chipcommon chipid */
#define BHND_CHIPID_BCM43221 43221 /* 43221 chipcommon chipid (OTP chipid) */
#define BHND_CHIPID_BCM43222 43222 /* 43222 chipcommon chipid */
#define BHND_CHIPID_BCM43224 43224 /* 43224 chipcommon chipid */
#define BHND_CHIPID_BCM43225 43225 /* 43225 chipcommon chipid */
#define BHND_CHIPID_BCM43227 43227 /* 43227 chipcommon chipid */
#define BHND_CHIPID_BCM43228 43228 /* 43228 chipcommon chipid */
#define BHND_CHIPID_BCM43226 43226 /* 43226 chipcommon chipid */
#define BHND_CHIPID_BCM43231 43231 /* 43231 chipcommon chipid (OTP chipid) */
#define BHND_CHIPID_BCM43234 43234 /* 43234 chipcommon chipid */
#define BHND_CHIPID_BCM43235 43235 /* 43235 chipcommon chipid */
#define BHND_CHIPID_BCM43236 43236 /* 43236 chipcommon chipid */
#define BHND_CHIPID_BCM43237 43237 /* 43237 chipcommon chipid */
#define BHND_CHIPID_BCM43238 43238 /* 43238 chipcommon chipid */
#define BHND_CHIPID_BCM43239 43239 /* 43239 chipcommon chipid */
#define BHND_CHIPID_BCM43420 43420 /* 43222 chipcommon chipid (OTP, RBBU) */
#define BHND_CHIPID_BCM43421 43421 /* 43224 chipcommon chipid (OTP, RBBU) */
#define BHND_CHIPID_BCM43428 43428 /* 43228 chipcommon chipid (OTP, RBBU) */
#define BHND_CHIPID_BCM43431 43431 /* 4331 chipcommon chipid (OTP, RBBU) */
#define BHND_CHIPID_BCM43460 43460 /* 4360 chipcommon chipid (OTP, RBBU) */
#define BHND_CHIPID_BCM4325 0x4325 /* 4325 chip id */
#define BHND_CHIPID_BCM4328 0x4328 /* 4328 chip id */
#define BHND_CHIPID_BCM4329 0x4329 /* 4329 chipcommon chipid */
#define BHND_CHIPID_BCM4331 0x4331 /* 4331 chipcommon chipid */
#define BHND_CHIPID_BCM4336 0x4336 /* 4336 chipcommon chipid */
#define BHND_CHIPID_BCM43362 43362 /* 43362 chipcommon chipid */
#define BHND_CHIPID_BCM4330 0x4330 /* 4330 chipcommon chipid */
#define BHND_CHIPID_BCM6362 0x6362 /* 6362 chipcommon chipid */
#define BHND_CHIPID_BCM4314 0x4314 /* 4314 chipcommon chipid */
#define BHND_CHIPID_BCM43142 43142 /* 43142 chipcommon chipid */
#define BHND_CHIPID_BCM43143 43143 /* 43143 chipcommon chipid */
#define BHND_CHIPID_BCM4324 0x4324 /* 4324 chipcommon chipid */
#define BHND_CHIPID_BCM43242 43242 /* 43242 chipcommon chipid */
#define BHND_CHIPID_BCM43243 43243 /* 43243 chipcommon chipid */
#define BHND_CHIPID_BCM4334 0x4334 /* 4334 chipcommon chipid */
#define BHND_CHIPID_BCM4335 0x4335 /* 4335 chipcommon chipid */
#define BHND_CHIPID_BCM4360 0x4360 /* 4360 chipcommon chipid */
#define BHND_CHIPID_BCM4352 0x4352 /* 4352 chipcommon chipid */
#define BHND_CHIPID_BCM43526 0xAA06
#define BHND_CHIPID_BCM43341 43341 /* 43341 chipcommon chipid */
#define BHND_CHIPID_BCM43342 43342 /* 43342 chipcommon chipid */
#define BHND_CHIPID_BCM4335 0x4335
#define BHND_CHIPID_BCM4350 0x4350 /* 4350 chipcommon chipid */
#define BHND_CHIPID_BCM4342 4342 /* 4342 chipcommon chipid (OTP, RBBU) */
#define BHND_CHIPID_BCM4402 0x4402 /* 4402 chipid */
#define BHND_CHIPID_BCM4704 0x4704 /* 4704 chipcommon chipid */
#define BHND_CHIPID_BCM4706 0x5300 /* 4706 chipcommon chipid */
#define BHND_CHIPID_BCM4707 53010 /* 4707 chipcommon chipid */
#define BHND_CHIPID_BCM53018 53018 /* 53018 chipcommon chipid */
#define BHND_CHIPID_IS_BCM4707(chipid) \
(((chipid) == BHND_CHIPID_BCM4707) || \
((chipid) == BHND_CHIPID_BCM53018))
#define BHND_CHIPID_BCM4710 0x4710 /* 4710 chipid */
#define BHND_CHIPID_BCM4712 0x4712 /* 4712 chipcommon chipid */
#define BHND_CHIPID_BCM4716 0x4716 /* 4716 chipcommon chipid */
#define BHND_CHIPID_BCM47162 47162 /* 47162 chipcommon chipid */
#define BHND_CHIPID_BCM4748 0x4748 /* 4716 chipcommon chipid (OTP, RBBU) */
#define BHND_CHIPID_BCM4749 0x4749 /* 5357 chipcommon chipid (OTP, RBBU) */
#define BHND_CHIPID_BCM4785 0x4785 /* 4785 chipcommon chipid */
#define BHND_CHIPID_BCM5350 0x5350 /* 5350 chipcommon chipid */
#define BHND_CHIPID_BCM5352 0x5352 /* 5352 chipcommon chipid */
#define BHND_CHIPID_BCM5354 0x5354 /* 5354 chipcommon chipid */
#define BHND_CHIPID_BCM5365 0x5365 /* 5365 chipcommon chipid */
#define BHND_CHIPID_BCM5356 0x5356 /* 5356 chipcommon chipid */
#define BHND_CHIPID_BCM5357 0x5357 /* 5357 chipcommon chipid */
#define BHND_CHIPID_BCM53572 53572 /* 53572 chipcommon chipid */
/* Broadcom ChipCommon Package IDs */
#define BHND_PKGID_BCM4303 2 /* 4303 package id */
#define BHND_PKGID_BCM4309 1 /* 4309 package id */
#define BHND_PKGID_BCM4712LARGE 0 /* 340pin 4712 package id */
#define BHND_PKGID_BCM4712SMALL 1 /* 200pin 4712 package id */
#define BHND_PKGID_BCM4712MID 2 /* 225pin 4712 package id */
#define BHND_PKGID_BCM4328USBD11G 2 /* 4328 802.11g USB package id */
#define BHND_PKGID_BCM4328USBDUAL 3 /* 4328 802.11a/g USB package id */
#define BHND_PKGID_BCM4328SDIOD11G 4 /* 4328 802.11g SDIO package id */
#define BHND_PKGID_BCM4328SDIODUAL 5 /* 4328 802.11a/g SDIO package id */
#define BHND_PKGID_BCM4329_289PIN 0 /* 4329 289-pin package id */
#define BHND_PKGID_BCM4329_182PIN 1 /* 4329N 182-pin package id */
#define BHND_PKGID_BCM5354E 1 /* 5354E package id */
#define BHND_PKGID_BCM4716 8 /* 4716 package id */
#define BHND_PKGID_BCM4717 9 /* 4717 package id */
#define BHND_PKGID_BCM4718 10 /* 4718 package id */
#define BHND_PKGID_BCM5356_NONMODE 1 /* 5356 package without nmode suppport */
#define BHND_PKGID_BCM5358U 8 /* 5358U package id */
#define BHND_PKGID_BCM5358 9 /* 5358 package id */
#define BHND_PKGID_BCM47186 10 /* 47186 package id */
#define BHND_PKGID_BCM5357 11 /* 5357 package id */
#define BHND_PKGID_BCM5356U 12 /* 5356U package id */
#define BHND_PKGID_BCM53572 8 /* 53572 package id */
#define BHND_PKGID_BCM5357C0 8 /* 5357c0 package id (the same as 53572) */
#define BHND_PKGID_BCM47188 9 /* 47188 package id */
#define BHND_PKGID_BCM5358C0 0xa /* 5358c0 package id */
#define BHND_PKGID_BCM5356C0 0xb /* 5356c0 package id */
#define BHND_PKGID_BCM4331TT 8 /* 4331 12x12 package id */
#define BHND_PKGID_BCM4331TN 9 /* 4331 12x9 package id */
#define BHND_PKGID_BCM4331TNA0 0xb /* 4331 12x9 package id */
#define BHND_PKGID_BCM4706L 1 /* 4706L package id */
#define BHND_PKGID_HDLSIM5350 1 /* HDL simulator package id for a 5350 */
#define BHND_PKGID_HDLSIM 14 /* HDL simulator package id */
#define BHND_PKGID_HWSIM 15 /* Hardware simulator package id */
#define BHND_PKGID_BCM43224_FAB_CSM 0x8 /* the chip is manufactured by CSM */
#define BHND_PKGID_BCM43224_FAB_SMIC 0xa /* the chip is manufactured by SMIC */
#define BHND_PKGID_BCM4336_WLBGA 0x8
#define BHND_PKGID_BCM4330_WLBGA 0x0
#define BHND_PKGID_BCM4314PCIE_ARM (8 | 0) /* 4314 QFN PCI package id, bit 3 tie high */
#define BHND_PKGID_BCM4314SDIO (8 | 1) /* 4314 QFN SDIO package id */
#define BHND_PKGID_BCM4314PCIE (8 | 2) /* 4314 QFN PCI (ARM-less) package id */
#define BHND_PKGID_BCM4314SDIO_ARM (8 | 3) /* 4314 QFN SDIO (ARM-less) package id */
#define BHND_PKGID_BCM4314SDIO_FPBGA (8 | 4) /* 4314 FpBGA SDIO package id */
#define BHND_PKGID_BCM4314DEV (8 | 6) /* 4314 Developement package id */
#define BHND_PKGID_BCM4707 1 /* 4707 package id */
#define BHND_PKGID_BCM4708 2 /* 4708 package id */
#define BHND_PKGID_BCM4709 0 /* 4709 package id */
#define BHND_PKGID_BCM4335_WLCSP (0x0) /* WLCSP Module/Mobile SDIO/HSIC. */
#define BHND_PKGID_BCM4335_FCBGA (0x1) /* FCBGA PC/Embeded/Media PCIE/SDIO */
#define BHND_PKGID_BCM4335_WLBGA (0x2) /* WLBGA COB/Mobile SDIO/HSIC. */
#define BHND_PKGID_BCM4335_FCBGAD (0x3) /* FCBGA Debug Debug/Dev All if's. */
#define BHND_PKGID_PKG_MASK_BCM4335 (0x3)
/* Broadcom Core IDs */
#define BHND_COREID_INVALID 0x700 /* Invalid coreid */
#define BHND_COREID_CC 0x800 /* chipcommon core */
#define BHND_COREID_ILINE20 0x801 /* iline20 core */
#define BHND_COREID_SRAM 0x802 /* sram core */
#define BHND_COREID_SDRAM 0x803 /* sdram core */
#define BHND_COREID_PCI 0x804 /* pci core */
#define BHND_COREID_MIPS 0x805 /* mips core */
#define BHND_COREID_ENET 0x806 /* enet mac core */
#define BHND_COREID_CODEC 0x807 /* v90 codec core */
#define BHND_COREID_USB 0x808 /* usb 1.1 host/device core */
#define BHND_COREID_ADSL 0x809 /* ADSL core */
#define BHND_COREID_ILINE100 0x80a /* iline100 core */
#define BHND_COREID_IPSEC 0x80b /* ipsec core */
#define BHND_COREID_UTOPIA 0x80c /* utopia core */
#define BHND_COREID_PCMCIA 0x80d /* pcmcia core */
#define BHND_COREID_SOCRAM 0x80e /* internal memory core */
#define BHND_COREID_MEMC 0x80f /* memc sdram core */
#define BHND_COREID_OFDM 0x810 /* OFDM phy core */
#define BHND_COREID_EXTIF 0x811 /* external interface core */
#define BHND_COREID_D11 0x812 /* 802.11 MAC core */
#define BHND_COREID_APHY 0x813 /* 802.11a phy core */
#define BHND_COREID_BPHY 0x814 /* 802.11b phy core */
#define BHND_COREID_GPHY 0x815 /* 802.11g phy core */
#define BHND_COREID_MIPS33 0x816 /* mips3302 core */
#define BHND_COREID_USB11H 0x817 /* usb 1.1 host core */
#define BHND_COREID_USB11D 0x818 /* usb 1.1 device core */
#define BHND_COREID_USB20H 0x819 /* usb 2.0 host core */
#define BHND_COREID_USB20D 0x81a /* usb 2.0 device core */
#define BHND_COREID_SDIOH 0x81b /* sdio host core */
#define BHND_COREID_ROBO 0x81c /* roboswitch core */
#define BHND_COREID_ATA100 0x81d /* parallel ATA core */
#define BHND_COREID_SATAXOR 0x81e /* serial ATA & XOR DMA core */
#define BHND_COREID_GIGETH 0x81f /* gigabit ethernet core */
#define BHND_COREID_PCIE 0x820 /* pci express core */
#define BHND_COREID_NPHY 0x821 /* 802.11n 2x2 phy core */
#define BHND_COREID_SRAMC 0x822 /* SRAM controller core */
#define BHND_COREID_MINIMAC 0x823 /* MINI MAC/phy core */
#define BHND_COREID_ARM11 0x824 /* ARM 1176 core */
#define BHND_COREID_ARM7S 0x825 /* ARM7tdmi-s core */
#define BHND_COREID_LPPHY 0x826 /* 802.11a/b/g phy core */
#define BHND_COREID_PMU 0x827 /* PMU core */
#define BHND_COREID_SSNPHY 0x828 /* 802.11n single-stream phy core */
#define BHND_COREID_SDIOD 0x829 /* SDIO device core */
#define BHND_COREID_ARMCM3 0x82a /* ARM Cortex M3 core */
#define BHND_COREID_HTPHY 0x82b /* 802.11n 4x4 phy core */
#define BHND_COREID_MIPS74K 0x82c /* mips 74k core */
#define BHND_COREID_GMAC 0x82d /* Gigabit MAC core */
#define BHND_COREID_DMEMC 0x82e /* DDR1/2 memory controller core */
#define BHND_COREID_PCIERC 0x82f /* PCIE Root Complex core */
#define BHND_COREID_OCP 0x830 /* OCP2OCP bridge core */
#define BHND_COREID_SC 0x831 /* shared common core */
#define BHND_COREID_AHB 0x832 /* OCP2AHB bridge core */
#define BHND_COREID_SPIH 0x833 /* SPI host core */
#define BHND_COREID_I2S 0x834 /* I2S core */
#define BHND_COREID_DMEMS 0x835 /* SDR/DDR1 memory controller core */
#define BHND_COREID_UBUS_SHIM 0x837 /* SHIM component in ubus/6362 */
#define BHND_COREID_PCIE2 0x83c /* pci express (gen2) core */
/* ARM/AMBA Core IDs */
#define BHND_COREID_APB_BRIDGE 0x135 /* BP135 AMBA AXI-APB bridge */
#define BHND_COREID_PL301 0x301 /* PL301 AMBA AXI Interconnect */
#define BHND_COREID_EROM 0x366 /* Enumeration ROM */
#define BHND_COREID_OOB_ROUTER 0x367 /* OOB router core ID */
#define BHND_COREID_AXI_UNMAPPED 0xfff /* AXI "Default Slave"; maps all unused address
* ranges, returning DECERR on read or write. */
/* Northstar Plus and BCM4706 Core IDs */
#define BHND_COREID_4706_CC 0x500 /* chipcommon core */
#define BHND_COREID_NS_PCIE2 0x501 /* pci express (gen2) core */
#define BHND_COREID_NS_DMA 0x502 /* dma core */
#define BHND_COREID_NS_SDIO 0x503 /* sdio host core */
#define BHND_COREID_NS_USB20H 0x504 /* usb 2.0 host core */
#define BHND_COREID_NS_USB30H 0x505 /* usb 3.0 host core */
#define BHND_COREID_NS_A9JTAG 0x506 /* ARM Cortex A9 JTAG core */
#define BHND_COREID_NS_DDR23_MEMC 0x507 /* DDR2/3 cadence/denali memory controller core () */
#define BHND_COREID_NS_ROM 0x508 /* device ROM core */
#define BHND_COREID_NS_NAND 0x509 /* NAND flash controller core */
#define BHND_COREID_NS_QSPI 0x50a /* QSPI flash controller core */
#define BHND_COREID_NS_CC_B 0x50b /* chipcommon `b' (auxiliary) core */
#define BHND_COREID_4706_SOCRAM 0x50e /* internal memory core */
#define BHND_COREID_IHOST_ARMCA9 0x510 /* ARM Cortex A9 core */
#define BHND_COREID_4706_GMAC_CMN 0x5dc /* Gigabit MAC common core */
#define BHND_COREID_4706_GMAC 0x52d /* Gigabit MAC core */
#define BHND_COREID_AMEMC 0x52e /* DDR1/2 cadence/denali memory controller core */
/* ARM PrimeCell Peripherial IDs. These were derived from inspection of the
* PrimeCell-compatible BCM4331 cores, but due to lack of documentation, the
* surmised core name/description may be incorrect. */
#define BHND_PRIMEID_EROM 0x364 /* Enumeration ROM's primecell ID */
#define BHND_PRIMEID_SWRAP 0x368 /* PL368 Device Management Interface (Slave) */
#define BHND_PRIMEID_MWRAP 0x369 /* PL369 Device Management Interface (Master) */
/* Core HW Revision Numbers */
#define BHND_HWREV_INVALID 0xFF /* Invalid hardware revision ID */
/* Chip Types */
#define BHND_CHIPTYPE_SIBA 0 /**< siba(4) interconnect */
#define BHND_CHIPTYPE_BCMA 1 /**< bcma(4) interconnect */
#define BHND_CHIPTYPE_UBUS 2 /**< ubus interconnect found in bcm63xx devices */
#define BHND_CHIPTYPE_BCMA_ALT 3 /**< bcma(4) interconnect */
/* Boardflags */
#define BHND_BFL_BTC2WIRE 0x00000001 /* old 2wire Bluetooth coexistence, OBSOLETE */
#define BHND_BFL_BTCOEX 0x00000001 /* Board supports BTCOEX */
#define BHND_BFL_PACTRL 0x00000002 /* Board has gpio 9 controlling the PA */
#define BHND_BFL_AIRLINEMODE 0x00000004 /* Board implements gpio 13 radio disable indication, UNUSED */
#define BHND_BFL_ADCDIV 0x00000008 /* Board has the rssi ADC divider */
#define BHND_BFL_DIS_256QAM 0x00000008
#define BHND_BFL_ENETROBO 0x00000010 /* Board has robo switch or core */
#define BHND_BFL_NOPLLDOWN 0x00000020 /* Not ok to power down the chip pll and oscillator */
#define BHND_BFL_CCKHIPWR 0x00000040 /* Can do high-power CCK transmission */
#define BHND_BFL_ENETADM 0x00000080 /* Board has ADMtek switch */
#define BHND_BFL_ENETVLAN 0x00000100 /* Board has VLAN capability */
#define BHND_BFL_LTECOEX 0x00000200 /* Board has LTE coex capability */
#define BHND_BFL_NOPCI 0x00000400 /* Board leaves PCI floating */
#define BHND_BFL_FEM 0x00000800 /* Board supports the Front End Module */
#define BHND_BFL_EXTLNA 0x00001000 /* Board has an external LNA in 2.4GHz band */
#define BHND_BFL_HGPA 0x00002000 /* Board has a high gain PA */
#define BHND_BFL_BTC2WIRE_ALTGPIO 0x00004000
/* Board's BTC 2wire is in the alternate gpios OBSLETE */
#define BHND_BFL_ALTIQ 0x00008000 /* Alternate I/Q settings */
#define BHND_BFL_NOPA 0x00010000 /* Board has no PA */
#define BHND_BFL_RSSIINV 0x00020000 /* Board's RSSI uses positive slope(not TSSI) */
#define BHND_BFL_PAREF 0x00040000 /* Board uses the PARef LDO */
#define BHND_BFL_3TSWITCH 0x00080000 /* Board uses a triple throw switch shared with BT */
#define BHND_BFL_PHASESHIFT 0x00100000 /* Board can support phase shifter */
#define BHND_BFL_BUCKBOOST 0x00200000 /* Power topology uses BUCKBOOST */
#define BHND_BFL_FEM_BT 0x00400000 /* Board has FEM and switch to share antenna w/ BT */
#define BHND_BFL_RXCHAIN_OFF_BT 0x00400000 /* one rxchain is to be shut off when BT is active */
#define BHND_BFL_NOCBUCK 0x00800000 /* Power topology doesn't use CBUCK */
#define BHND_BFL_CCKFAVOREVM 0x01000000 /* Favor CCK EVM over spectral mask */
#define BHND_BFL_PALDO 0x02000000 /* Power topology uses PALDO */
#define BHND_BFL_LNLDO2_2P5 0x04000000 /* Select 2.5V as LNLDO2 output voltage */
#define BHND_BFL_FASTPWR 0x08000000
#define BHND_BFL_UCPWRCTL_MININDX 0x08000000 /* Enforce min power index to avoid FEM damage */
#define BHND_BFL_EXTLNA_5GHz 0x10000000 /* Board has an external LNA in 5GHz band */
#define BHND_BFL_TRSW_1by2 0x20000000 /* Board has 2 TRSW's in 1by2 designs */
#define BHND_BFL_GAINBOOSTA01 0x20000000 /* 5g Gainboost for core0 and core1 */
#define BHND_BFL_LO_TRSW_R_5GHz 0x40000000 /* In 5G do not throw TRSW to T for clipLO gain */
#define BHND_BFL_ELNA_GAINDEF 0x80000000 /* Backoff InitGain based on elna_2g/5g field
* when this flag is set
*/
#define BHND_BFL_EXTLNA_TX 0x20000000 /* Temp boardflag to indicate to */
/* Boardflags2 */
#define BHND_BFL2_RXBB_INT_REG_DIS 0x00000001 /* Board has an external rxbb regulator */
#define BHND_BFL2_APLL_WAR 0x00000002 /* Flag to implement alternative A-band PLL settings */
#define BHND_BFL2_TXPWRCTRL_EN 0x00000004 /* Board permits enabling TX Power Control */
#define BHND_BFL2_2X4_DIV 0x00000008 /* Board supports the 2X4 diversity switch */
#define BHND_BFL2_5G_PWRGAIN 0x00000010 /* Board supports 5G band power gain */
#define BHND_BFL2_PCIEWAR_OVR 0x00000020 /* Board overrides ASPM and Clkreq settings */
#define BHND_BFL2_CAESERS_BRD 0x00000040 /* Board is Caesers brd (unused by sw) */
#define BHND_BFL2_BTC3WIRE 0x00000080 /* Board support legacy 3 wire or 4 wire */
#define BHND_BFL2_BTCLEGACY 0x00000080 /* Board support legacy 3/4 wire, to replace
* BHND_BFL2_BTC3WIRE
*/
#define BHND_BFL2_SKWRKFEM_BRD 0x00000100 /* 4321mcm93 board uses Skyworks FEM */
#define BHND_BFL2_SPUR_WAR 0x00000200 /* Board has a WAR for clock-harmonic spurs */
#define BHND_BFL2_GPLL_WAR 0x00000400 /* Flag to narrow G-band PLL loop b/w */
#define BHND_BFL2_TRISTATE_LED 0x00000800 /* Tri-state the LED */
#define BHND_BFL2_SINGLEANT_CCK 0x00001000 /* Tx CCK pkts on Ant 0 only */
#define BHND_BFL2_2G_SPUR_WAR 0x00002000 /* WAR to reduce and avoid clock-harmonic spurs in 2G */
#define BHND_BFL2_BPHY_ALL_TXCORES 0x00004000 /* Transmit bphy frames using all tx cores */
#define BHND_BFL2_FCC_BANDEDGE_WAR 0x00008000 /* Activates WAR to improve FCC bandedge performance */
#define BHND_BFL2_GPLL_WAR2 0x00010000 /* Flag to widen G-band PLL loop b/w */
#define BHND_BFL2_IPALVLSHIFT_3P3 0x00020000
#define BHND_BFL2_INTERNDET_TXIQCAL 0x00040000 /* Use internal envelope detector for TX IQCAL */
#define BHND_BFL2_XTALBUFOUTEN 0x00080000 /* Keep the buffered Xtal output from radio on */
/* Most drivers will turn it off without this flag */
/* to save power. */
#define BHND_BFL2_ANAPACTRL_2G 0x00100000 /* 2G ext PAs are controlled by analog PA ctrl lines */
#define BHND_BFL2_ANAPACTRL_5G 0x00200000 /* 5G ext PAs are controlled by analog PA ctrl lines */
#define BHND_BFL2_ELNACTRL_TRSW_2G 0x00400000 /* AZW4329: 2G gmode_elna_gain controls TR Switch */
#define BHND_BFL2_BT_SHARE_ANT0 0x00800000 /* WLAN/BT share antenna 0 */
#define BHND_BFL2_BT_SHARE_BM_BIT0 0x00800000 /* bit 0 of WLAN/BT shared core bitmap */
#define BHND_BFL2_TEMPSENSE_HIGHER 0x01000000 /* The tempsense threshold can sustain higher value
* than programmed. The exact delta is decided by
* driver per chip/boardtype. This can be used
* when tempsense qualification happens after shipment
*/
#define BHND_BFL2_BTC3WIREONLY 0x02000000 /* standard 3 wire btc only. 4 wire not supported */
#define BHND_BFL2_PWR_NOMINAL 0x04000000 /* 0: power reduction on, 1: no power reduction */
#define BHND_BFL2_EXTLNA_PWRSAVE 0x08000000 /* boardflag to enable ucode to apply power save
* ucode control of eLNA during Tx */
#define BHND_BFL2_4313_RADIOREG 0x10000000
/* board rework */
#define BHND_BFL2_DYNAMIC_VMID 0x10000000 /* boardflag to enable dynamic Vmid idle TSSI CAL */
#define BHND_BFL2_SDR_EN 0x20000000 /* SDR enabled or disabled */
#define BHND_BFL2_LNA1BYPFORTR2G 0x40000000 /* acphy, enable lna1 bypass for clip gain, 2g */
#define BHND_BFL2_LNA1BYPFORTR5G 0x80000000 /* acphy, enable lna1 bypass for clip gain, 5g */
/* SROM 11 - 11ac boardflag definitions */
#define BHND_BFL_SROM11_BTCOEX 0x00000001 /* Board supports BTCOEX */
#define BHND_BFL_SROM11_WLAN_BT_SH_XTL 0x00000002 /* bluetooth and wlan share same crystal */
#define BHND_BFL_SROM11_EXTLNA 0x00001000 /* Board has an external LNA in 2.4GHz band */
#define BHND_BFL_SROM11_EXTLNA_5GHz 0x10000000 /* Board has an external LNA in 5GHz band */
#define BHND_BFL_SROM11_GAINBOOSTA01 0x20000000 /* 5g Gainboost for core0 and core1 */
#define BHND_BFL2_SROM11_APLL_WAR 0x00000002 /* Flag to implement alternative A-band PLL settings */
#define BHND_BFL2_SROM11_ANAPACTRL_2G 0x00100000 /* 2G ext PAs are ctrl-ed by analog PA ctrl lines */
#define BHND_BFL2_SROM11_ANAPACTRL_5G 0x00200000 /* 5G ext PAs are ctrl-ed by analog PA ctrl lines */
/* Boardflags3 */
#define BHND_BFL3_FEMCTRL_SUB 0x00000007 /* acphy, subrevs of femctrl on top of srom_femctrl */
#define BHND_BFL3_RCAL_WAR 0x00000008 /* acphy, rcal war active on this board (4335a0) */
#define BHND_BFL3_TXGAINTBLID 0x00000070 /* acphy, txgain table id */
#define BHND_BFL3_TXGAINTBLID_SHIFT 0x4 /* acphy, txgain table id shift bit */
#define BHND_BFL3_TSSI_DIV_WAR 0x00000080 /* acphy, Seperate paparam for 20/40/80 */
#define BHND_BFL3_TSSI_DIV_WAR_SHIFT 0x7 /* acphy, Seperate paparam for 20/40/80 shift bit */
#define BHND_BFL3_FEMTBL_FROM_NVRAM 0x00000100 /* acphy, femctrl table is read from nvram */
#define BHND_BFL3_FEMTBL_FROM_NVRAM_SHIFT 0x8 /* acphy, femctrl table is read from nvram */
#define BHND_BFL3_AGC_CFG_2G 0x00000200 /* acphy, gain control configuration for 2G */
#define BHND_BFL3_AGC_CFG_5G 0x00000400 /* acphy, gain control configuration for 5G */
#define BHND_BFL3_PPR_BIT_EXT 0x00000800 /* acphy, bit position for 1bit extension for ppr */
#define BHND_BFL3_PPR_BIT_EXT_SHIFT 11 /* acphy, bit shift for 1bit extension for ppr */
#define BHND_BFL3_BBPLL_SPR_MODE_DIS 0x00001000 /* acphy, disables bbpll spur modes */
#define BHND_BFL3_RCAL_OTP_VAL_EN 0x00002000 /* acphy, to read rcal_trim value from otp */
#define BHND_BFL3_2GTXGAINTBL_BLANK 0x00004000 /* acphy, blank the first X ticks of 2g gaintbl */
#define BHND_BFL3_2GTXGAINTBL_BLANK_SHIFT 14 /* acphy, blank the first X ticks of 2g gaintbl */
#define BHND_BFL3_5GTXGAINTBL_BLANK 0x00008000 /* acphy, blank the first X ticks of 5g gaintbl */
#define BHND_BFL3_5GTXGAINTBL_BLANK_SHIFT 15 /* acphy, blank the first X ticks of 5g gaintbl */
#define BHND_BFL3_BT_SHARE_BM_BIT1 0x40000000 /* bit 1 of WLAN/BT shared core bitmap */
#define BHND_BFL3_PHASETRACK_MAX_ALPHABETA 0x00010000 /* acphy, to max out alpha,beta to 511 */
#define BHND_BFL3_PHASETRACK_MAX_ALPHABETA_SHIFT 16 /* acphy, to max out alpha,beta to 511 */
#define BHND_BFL3_BT_SHARE_BM_BIT1 0x40000000 /* bit 1 of WLAN/BT shared core bitmap */
#define BHND_BFL3_EN_NONBRCM_TXBF 0x10000000 /* acphy, enable non-brcm TXBF */
#define BHND_BFL3_EN_P2PLINK_TXBF 0x20000000 /* acphy, enable TXBF in p2p links */
/* board specific GPIO assignment, gpio 0-3 are also customer-configurable led */
#define BHND_BOARD_GPIO_BTC3W_IN 0x850 /* bit 4 is RF_ACTIVE, bit 6 is STATUS, bit 11 is PRI */
#define BHND_BOARD_GPIO_BTC3W_OUT 0x020 /* bit 5 is TX_CONF */
#define BHND_BOARD_GPIO_BTCMOD_IN 0x010 /* bit 4 is the alternate BT Coexistence Input */
#define BHND_BOARD_GPIO_BTCMOD_OUT 0x020 /* bit 5 is the alternate BT Coexistence Out */
#define BHND_BOARD_GPIO_BTC_IN 0x080 /* bit 7 is BT Coexistence Input */
#define BHND_BOARD_GPIO_BTC_OUT 0x100 /* bit 8 is BT Coexistence Out */
#define BHND_BOARD_GPIO_PACTRL 0x200 /* bit 9 controls the PA on new 4306 boards */
#define BHND_BOARD_GPIO_12 0x1000 /* gpio 12 */
#define BHND_BOARD_GPIO_13 0x2000 /* gpio 13 */
#define BHND_BOARD_GPIO_BTC4_IN 0x0800 /* gpio 11, coex4, in */
#define BHND_BOARD_GPIO_BTC4_BT 0x2000 /* gpio 12, coex4, bt active */
#define BHND_BOARD_GPIO_BTC4_STAT 0x4000 /* gpio 14, coex4, status */
#define BHND_BOARD_GPIO_BTC4_WLAN 0x8000 /* gpio 15, coex4, wlan active */
#define BHND_BOARD_GPIO_1_WLAN_PWR 0x02 /* throttle WLAN power on X21 board */
#define BHND_BOARD_GPIO_3_WLAN_PWR 0x08 /* throttle WLAN power on X28 board */
#define BHND_BOARD_GPIO_4_WLAN_PWR 0x10 /* throttle WLAN power on X19 board */
#define BHND_GPIO_BTC4W_OUT_4312 0x010 /* bit 4 is BT_IODISABLE */
#define BHND_GPIO_BTC4W_OUT_43224 0x020 /* bit 5 is BT_IODISABLE */
#define BHND_GPIO_BTC4W_OUT_43224_SHARED 0x0e0 /* bit 5 is BT_IODISABLE */
#define BHND_GPIO_BTC4W_OUT_43225 0x0e0 /* bit 5 BT_IODISABLE, bit 6 SW_BT, bit 7 SW_WL */
#define BHND_GPIO_BTC4W_OUT_43421 0x020 /* bit 5 is BT_IODISABLE */
#define BHND_GPIO_BTC4W_OUT_4313 0x060 /* bit 5 SW_BT, bit 6 SW_WL */
#define BHND_GPIO_BTC4W_OUT_4331_SHARED 0x010 /* GPIO 4 */
/* Power Control Defines */
#define BHND_CHIPC_PLL_DELAY 150 /* us pll on delay */
#define BHND_CHIPC_FREF_DELAY 200 /* us fref change delay */
#define BHND_CHIPC_MIN_SLOW_CLK 32 /* us Slow clock period */
#define BHND_CHIPC_XTAL_ON_DELAY 1000 /* us crystal power-on delay */
/* 43341 Boards */
#define BCM943341WLABGS_SSID 0x062d
/* 43342 Boards */
#define BCM943342FCAGBI_SSID 0x0641
/* # of GPIO pins */
#define BHND_BCM43XX_GPIO_NUMPINS 32
/* These values are used by dhd USB host driver. */
#define BHND_USB_RDL_RAM_BASE_4319 0x60000000
#define BHND_USB_RDL_RAM_BASE_4329 0x60000000
#define BHND_USB_RDL_RAM_SIZE_4319 0x48000
#define BHND_USB_RDL_RAM_SIZE_4329 0x48000
#define BHND_USB_RDL_RAM_SIZE_43236 0x70000
#define BHND_USB_RDL_RAM_BASE_43236 0x60000000
#define BHND_USB_RDL_RAM_SIZE_4328 0x60000
#define BHND_USB_RDL_RAM_BASE_4328 0x80000000
#define BHND_USB_RDL_RAM_SIZE_4322 0x60000
#define BHND_USB_RDL_RAM_BASE_4322 0x60000000
#define BHND_USB_RDL_RAM_SIZE_4360 0xA0000
#define BHND_USB_RDL_RAM_BASE_4360 0x60000000
#define BHND_USB_RDL_RAM_SIZE_43242 0x90000
#define BHND_USB_RDL_RAM_BASE_43242 0x60000000
#define BHND_USB_RDL_RAM_SIZE_43143 0x70000
#define BHND_USB_RDL_RAM_BASE_43143 0x60000000
#define BHND_USB_RDL_RAM_SIZE_4350 0xC0000
#define BHND_USB_RDL_RAM_BASE_4350 0x180800
/* generic defs for nvram "muxenab" bits
* Note: these differ for 4335a0. refer bcmchipc.h for specific mux options.
*/
#define BHND_NVRAM_MUXENAB_UART 0x00000001
#define BHND_NVRAM_MUXENAB_GPIO 0x00000002
#define BHND_NVRAM_MUXENAB_ERCX 0x00000004 /* External Radio BT coex */
#define BHND_NVRAM_MUXENAB_JTAG 0x00000008
#define BHND_NVRAM_MUXENAB_HOST_WAKE 0x00000010 /* configure GPIO for SDIO host_wake */
#define BHND_NVRAM_MUXENAB_I2S_EN 0x00000020
#define BHND_NVRAM_MUXENAB_I2S_MASTER 0x00000040
#define BHND_NVRAM_MUXENAB_I2S_FULL 0x00000080
#define BHND_NVRAM_MUXENAB_SFLASH 0x00000100
#define BHND_NVRAM_MUXENAB_RFSWCTRL0 0x00000200
#define BHND_NVRAM_MUXENAB_RFSWCTRL1 0x00000400
#define BHND_NVRAM_MUXENAB_RFSWCTRL2 0x00000800
#define BHND_NVRAM_MUXENAB_SECI 0x00001000
#define BHND_NVRAM_MUXENAB_BT_LEGACY 0x00002000
#define BHND_NVRAM_MUXENAB_HOST_WAKE1 0x00004000 /* configure alternative GPIO for SDIO host_wake */
/* Boot flags */
#define BHND_BOOTFLAG_FLASH_KERNEL_NFLASH 0x00000001
#define BHND_BOOTFLAG_FLASH_BOOT_NFLASH 0x00000002
#endif /* _BHND_BHND_IDS_H_ */

648
sys/dev/bhnd/bhnd_subr.c Normal file
View file

@ -0,0 +1,648 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/bus.h>
#include <sys/systm.h>
#include <machine/bus.h>
#include <sys/rman.h>
#include <machine/resource.h>
#include <dev/bhnd/cores/chipc/chipcreg.h>
#include "bhndreg.h"
#include "bhndvar.h"
/* BHND core device description table. */
static const struct bhnd_core_desc {
uint16_t vendor;
uint16_t device;
bhnd_devclass_t class;
const char *desc;
} bhnd_core_descs[] = {
#define BHND_CDESC(_mfg, _cid, _cls, _desc) \
{ BHND_MFGID_ ## _mfg, BHND_COREID_ ## _cid, \
BHND_DEVCLASS_ ## _cls, _desc }
BHND_CDESC(BCM, CC, CC, "ChipCommon I/O Controller"),
BHND_CDESC(BCM, ILINE20, OTHER, "iLine20 HPNA"),
BHND_CDESC(BCM, SRAM, RAM, "SRAM"),
BHND_CDESC(BCM, SDRAM, RAM, "SDRAM"),
BHND_CDESC(BCM, PCI, PCI, "PCI Bridge"),
BHND_CDESC(BCM, MIPS, CPU, "MIPS Core"),
BHND_CDESC(BCM, ENET, ENET_MAC, "Fast Ethernet MAC"),
BHND_CDESC(BCM, CODEC, OTHER, "V.90 Modem Codec"),
BHND_CDESC(BCM, USB, OTHER, "USB 1.1 Device/Host Controller"),
BHND_CDESC(BCM, ADSL, OTHER, "ADSL Core"),
BHND_CDESC(BCM, ILINE100, OTHER, "iLine100 HPNA"),
BHND_CDESC(BCM, IPSEC, OTHER, "IPsec Accelerator"),
BHND_CDESC(BCM, UTOPIA, OTHER, "UTOPIA ATM Core"),
BHND_CDESC(BCM, PCMCIA, PCCARD, "PCMCIA Bridge"),
BHND_CDESC(BCM, SOCRAM, RAM, "Internal Memory"),
BHND_CDESC(BCM, MEMC, MEMC, "MEMC SDRAM Controller"),
BHND_CDESC(BCM, OFDM, OTHER, "OFDM PHY"),
BHND_CDESC(BCM, EXTIF, OTHER, "External Interface"),
BHND_CDESC(BCM, D11, WLAN, "802.11 MAC/PHY/Radio"),
BHND_CDESC(BCM, APHY, WLAN_PHY, "802.11a PHY"),
BHND_CDESC(BCM, BPHY, WLAN_PHY, "802.11b PHY"),
BHND_CDESC(BCM, GPHY, WLAN_PHY, "802.11g PHY"),
BHND_CDESC(BCM, MIPS33, CPU, "MIPS 3302 Core"),
BHND_CDESC(BCM, USB11H, OTHER, "USB 1.1 Host Controller"),
BHND_CDESC(BCM, USB11D, OTHER, "USB 1.1 Device Core"),
BHND_CDESC(BCM, USB20H, OTHER, "USB 2.0 Host Controller"),
BHND_CDESC(BCM, USB20D, OTHER, "USB 2.0 Device Core"),
BHND_CDESC(BCM, SDIOH, OTHER, "SDIO Host Controller"),
BHND_CDESC(BCM, ROBO, OTHER, "RoboSwitch"),
BHND_CDESC(BCM, ATA100, OTHER, "Parallel ATA Controller"),
BHND_CDESC(BCM, SATAXOR, OTHER, "SATA DMA/XOR Controller"),
BHND_CDESC(BCM, GIGETH, ENET_MAC, "Gigabit Ethernet MAC"),
BHND_CDESC(BCM, PCIE, PCIE, "PCIe Bridge"),
BHND_CDESC(BCM, NPHY, WLAN_PHY, "802.11n 2x2 PHY"),
BHND_CDESC(BCM, SRAMC, MEMC, "SRAM Controller"),
BHND_CDESC(BCM, MINIMAC, OTHER, "MINI MAC/PHY"),
BHND_CDESC(BCM, ARM11, CPU, "ARM1176 CPU"),
BHND_CDESC(BCM, ARM7S, CPU, "ARM7TDMI-S CPU"),
BHND_CDESC(BCM, LPPHY, WLAN_PHY, "802.11a/b/g PHY"),
BHND_CDESC(BCM, PMU, PMU, "PMU"),
BHND_CDESC(BCM, SSNPHY, WLAN_PHY, "802.11n Single-Stream PHY"),
BHND_CDESC(BCM, SDIOD, OTHER, "SDIO Device Core"),
BHND_CDESC(BCM, ARMCM3, CPU, "ARM Cortex-M3 CPU"),
BHND_CDESC(BCM, HTPHY, WLAN_PHY, "802.11n 4x4 PHY"),
BHND_CDESC(BCM, MIPS74K, CPU, "MIPS74k CPU"),
BHND_CDESC(BCM, GMAC, ENET_MAC, "Gigabit MAC core"),
BHND_CDESC(BCM, DMEMC, MEMC, "DDR1/DDR2 Memory Controller"),
BHND_CDESC(BCM, PCIERC, OTHER, "PCIe Root Complex"),
BHND_CDESC(BCM, OCP, SOC_BRIDGE, "OCP to OCP Bridge"),
BHND_CDESC(BCM, SC, OTHER, "Shared Common Core"),
BHND_CDESC(BCM, AHB, SOC_BRIDGE, "OCP to AHB Bridge"),
BHND_CDESC(BCM, SPIH, OTHER, "SPI Host Controller"),
BHND_CDESC(BCM, I2S, OTHER, "I2S Digital Audio Interface"),
BHND_CDESC(BCM, DMEMS, MEMC, "SDR/DDR1 Memory Controller"),
BHND_CDESC(BCM, UBUS_SHIM, OTHER, "BCM6362/UBUS WLAN SHIM"),
BHND_CDESC(BCM, PCIE2, PCIE, "PCIe Bridge (Gen2)"),
BHND_CDESC(ARM, APB_BRIDGE, SOC_BRIDGE, "BP135 AMBA3 AXI to APB Bridge"),
BHND_CDESC(ARM, PL301, SOC_ROUTER, "PL301 AMBA3 Interconnect"),
BHND_CDESC(ARM, EROM, EROM, "PL366 Device Enumeration ROM"),
BHND_CDESC(ARM, OOB_ROUTER, OTHER, "PL367 OOB Interrupt Router"),
BHND_CDESC(ARM, AXI_UNMAPPED, OTHER, "Unmapped Address Ranges"),
BHND_CDESC(BCM, 4706_CC, CC, "ChipCommon I/O Controller"),
BHND_CDESC(BCM, NS_PCIE2, PCIE, "PCIe Bridge (Gen2)"),
BHND_CDESC(BCM, NS_DMA, OTHER, "DMA engine"),
BHND_CDESC(BCM, NS_SDIO, OTHER, "SDIO 3.0 Host Controller"),
BHND_CDESC(BCM, NS_USB20H, OTHER, "USB 2.0 Host Controller"),
BHND_CDESC(BCM, NS_USB30H, OTHER, "USB 3.0 Host Controller"),
BHND_CDESC(BCM, NS_A9JTAG, OTHER, "ARM Cortex A9 JTAG Interface"),
BHND_CDESC(BCM, NS_DDR23_MEMC, MEMC, "Denali DDR2/DD3 Memory Controller"),
BHND_CDESC(BCM, NS_ROM, NVRAM, "System ROM"),
BHND_CDESC(BCM, NS_NAND, NVRAM, "NAND Flash Controller"),
BHND_CDESC(BCM, NS_QSPI, NVRAM, "QSPI Flash Controller"),
BHND_CDESC(BCM, NS_CC_B, CC_B, "ChipCommon B Auxiliary I/O Controller"),
BHND_CDESC(BCM, 4706_SOCRAM, RAM, "Internal Memory"),
BHND_CDESC(BCM, IHOST_ARMCA9, CPU, "ARM Cortex A9 CPU"),
BHND_CDESC(BCM, 4706_GMAC_CMN, ENET, "Gigabit MAC (Common)"),
BHND_CDESC(BCM, 4706_GMAC, ENET_MAC, "Gigabit MAC"),
BHND_CDESC(BCM, AMEMC, MEMC, "Denali DDR1/DDR2 Memory Controller"),
#undef BHND_CDESC
/* Derived from inspection of the BCM4331 cores that provide PrimeCell
* IDs. Due to lack of documentation, the surmised device name/purpose
* provided here may be incorrect. */
{ BHND_MFGID_ARM, BHND_PRIMEID_EROM, BHND_DEVCLASS_OTHER,
"PL364 Device Enumeration ROM" },
{ BHND_MFGID_ARM, BHND_PRIMEID_SWRAP, BHND_DEVCLASS_OTHER,
"PL368 Device Management Interface" },
{ BHND_MFGID_ARM, BHND_PRIMEID_MWRAP, BHND_DEVCLASS_OTHER,
"PL369 Device Management Interface" },
{ 0, 0, 0, NULL }
};
/**
* Return the name for a given JEP106 manufacturer ID.
*
* @param vendor A JEP106 Manufacturer ID, including the non-standard ARM 4-bit
* JEP106 continuation code.
*/
const char *
bhnd_vendor_name(uint16_t vendor)
{
switch (vendor) {
case BHND_MFGID_ARM:
return "ARM";
case BHND_MFGID_BCM:
return "Broadcom";
case BHND_MFGID_MIPS:
return "MIPS";
default:
return "unknown";
}
}
/**
* Return the name of a port type.
*/
const char *
bhnd_port_type_name(bhnd_port_type port_type)
{
switch (port_type) {
case BHND_PORT_DEVICE:
return ("device");
case BHND_PORT_BRIDGE:
return ("bridge");
case BHND_PORT_AGENT:
return ("agent");
}
}
static const struct bhnd_core_desc *
bhnd_find_core_desc(uint16_t vendor, uint16_t device)
{
for (u_int i = 0; bhnd_core_descs[i].desc != NULL; i++) {
if (bhnd_core_descs[i].vendor != vendor)
continue;
if (bhnd_core_descs[i].device != device)
continue;
return (&bhnd_core_descs[i]);
}
return (NULL);
}
/**
* Return a human-readable name for a BHND core.
*
* @param vendor The core designer's JEDEC-106 Manufacturer ID
* @param device The core identifier.
*/
const char *
bhnd_find_core_name(uint16_t vendor, uint16_t device)
{
const struct bhnd_core_desc *desc;
if ((desc = bhnd_find_core_desc(vendor, device)) == NULL)
return ("unknown");
return desc->desc;
}
/**
* Return the device class for a BHND core.
*
* @param vendor The core designer's JEDEC-106 Manufacturer ID
* @param device The core identifier.
*/
bhnd_devclass_t
bhnd_find_core_class(uint16_t vendor, uint16_t device)
{
const struct bhnd_core_desc *desc;
if ((desc = bhnd_find_core_desc(vendor, device)) == NULL)
return (BHND_DEVCLASS_OTHER);
return desc->class;
}
/**
* Return a human-readable name for a BHND core.
*
* @param ci The core's info record.
*/
const char *
bhnd_core_name(const struct bhnd_core_info *ci)
{
return bhnd_find_core_name(ci->vendor, ci->device);
}
/**
* Return the device class for a BHND core.
*
* @param ci The core's info record.
*/
bhnd_devclass_t
bhnd_core_class(const struct bhnd_core_info *ci)
{
return bhnd_find_core_class(ci->vendor, ci->device);
}
/**
* Initialize a core info record with data from from a bhnd-attached @p dev.
*
* @param dev A bhnd device.
* @param core The record to be initialized.
*/
struct bhnd_core_info
bhnd_get_core_info(device_t dev) {
return (struct bhnd_core_info) {
.vendor = bhnd_get_vendor(dev),
.device = bhnd_get_device(dev),
.hwrev = bhnd_get_hwrev(dev),
.core_idx = bhnd_get_core_index(dev),
.unit = bhnd_get_core_unit(dev)
};
}
/**
* Find a @p class child device with @p unit on @p dev.
*
* @param parent The bhnd-compatible bus to be searched.
* @param class The device class to match on.
* @param unit The device unit number; specify -1 to return the first match
* regardless of unit number.
*
* @retval device_t if a matching child device is found.
* @retval NULL if no matching child device is found.
*/
device_t
bhnd_find_child(device_t dev, bhnd_devclass_t class, int unit)
{
struct bhnd_core_match md = {
.vendor = BHND_MFGID_INVALID,
.device = BHND_COREID_INVALID,
.hwrev.start = BHND_HWREV_INVALID,
.hwrev.end = BHND_HWREV_INVALID,
.class = class,
.unit = unit
};
return bhnd_match_child(dev, &md);
}
/**
* Find the first child device on @p dev that matches @p desc.
*
* @param parent The bhnd-compatible bus to be searched.
* @param desc A match descriptor.
*
* @retval device_t if a matching child device is found.
* @retval NULL if no matching child device is found.
*/
device_t
bhnd_match_child(device_t dev, const struct bhnd_core_match *desc)
{
device_t *devlistp;
device_t match;
int devcnt;
int error;
error = device_get_children(dev, &devlistp, &devcnt);
if (error != 0)
return (NULL);
match = NULL;
for (int i = 0; i < devcnt; i++) {
device_t dev = devlistp[i];
if (bhnd_device_matches(dev, desc)) {
match = dev;
goto done;
}
}
done:
free(devlistp, M_TEMP);
return match;
}
/**
* Find the first core in @p cores that matches @p desc.
*
* @param cores The table to search.
* @param num_cores The length of @p cores.
* @param desc A match descriptor.
*
* @retval bhnd_core_info if a matching core is found.
* @retval NULL if no matching core is found.
*/
const struct bhnd_core_info *
bhnd_match_core(const struct bhnd_core_info *cores, u_int num_cores,
const struct bhnd_core_match *desc)
{
for (u_int i = 0; i < num_cores; i++) {
if (bhnd_core_matches(&cores[i], desc))
return &cores[i];
}
return (NULL);
}
/**
* Find the first core in @p cores with the given @p class.
*
* @param cores The table to search.
* @param num_cores The length of @p cores.
* @param desc A match descriptor.
*
* @retval bhnd_core_info if a matching core is found.
* @retval NULL if no matching core is found.
*/
const struct bhnd_core_info *
bhnd_find_core(const struct bhnd_core_info *cores, u_int num_cores,
bhnd_devclass_t class)
{
struct bhnd_core_match md = {
.vendor = BHND_MFGID_INVALID,
.device = BHND_COREID_INVALID,
.hwrev.start = BHND_HWREV_INVALID,
.hwrev.end = BHND_HWREV_INVALID,
.class = class,
.unit = -1
};
return bhnd_match_core(cores, num_cores, &md);
}
/**
* Return true if the @p core matches @p desc.
*
* @param core A bhnd core descriptor.
* @param desc A match descriptor to compare against @p core.
*
* @retval true if @p core matches @p match
* @retval false if @p core does not match @p match.
*/
bool
bhnd_core_matches(const struct bhnd_core_info *core,
const struct bhnd_core_match *desc)
{
if (desc->vendor != BHND_MFGID_INVALID &&
desc->vendor != core->vendor)
return (false);
if (desc->device != BHND_COREID_INVALID &&
desc->device != core->device)
return (false);
if (desc->unit != -1 && desc->unit != core->unit)
return (false);
if (!bhnd_hwrev_matches(core->hwrev, &desc->hwrev))
return (false);
if (desc->hwrev.end != BHND_HWREV_INVALID &&
desc->hwrev.end < core->hwrev)
return (false);
if (desc->class != BHND_DEVCLASS_INVALID &&
desc->class != bhnd_core_class(core))
return (false);
return true;
}
/**
* Return true if the @p hwrev matches @p desc.
*
* @param hwrev A bhnd hardware revision.
* @param desc A match descriptor to compare against @p core.
*
* @retval true if @p hwrev matches @p match
* @retval false if @p hwrev does not match @p match.
*/
bool
bhnd_hwrev_matches(uint16_t hwrev, const struct bhnd_hwrev_match *desc)
{
if (desc->start != BHND_HWREV_INVALID &&
desc->start > hwrev)
return false;
if (desc->end != BHND_HWREV_INVALID &&
desc->end < hwrev)
return false;
return true;
}
/**
* Return true if the @p dev matches @p desc.
*
* @param dev A bhnd device.
* @param desc A match descriptor to compare against @p dev.
*
* @retval true if @p dev matches @p match
* @retval false if @p dev does not match @p match.
*/
bool
bhnd_device_matches(device_t dev, const struct bhnd_core_match *desc)
{
struct bhnd_core_info ci = {
.vendor = bhnd_get_vendor(dev),
.device = bhnd_get_device(dev),
.unit = bhnd_get_core_unit(dev),
.hwrev = bhnd_get_hwrev(dev)
};
return bhnd_core_matches(&ci, desc);
}
/**
* Allocate bhnd(4) resources defined in @p rs from a parent bus.
*
* @param dev The device requesting ownership of the resources.
* @param rs A standard bus resource specification. This will be updated
* with the allocated resource's RIDs.
* @param res On success, the allocated bhnd resources.
*
* @retval 0 success
* @retval non-zero if allocation of any non-RF_OPTIONAL resource fails,
* all allocated resources will be released and a regular
* unix error code will be returned.
*/
int
bhnd_alloc_resources(device_t dev, struct resource_spec *rs,
struct bhnd_resource **res)
{
/* Initialize output array */
for (u_int i = 0; rs[i].type != -1; i++)
res[i] = NULL;
for (u_int i = 0; rs[i].type != -1; i++) {
res[i] = bhnd_alloc_resource_any(dev, rs[i].type, &rs[i].rid,
rs[i].flags);
/* Clean up all allocations on failure */
if (res[i] == NULL && !(rs[i].flags & RF_OPTIONAL)) {
bhnd_release_resources(dev, rs, res);
return (ENXIO);
}
}
return (0);
};
/**
* Release bhnd(4) resources defined in @p rs from a parent bus.
*
* @param dev The device that owns the resources.
* @param rs A standard bus resource specification previously initialized
* by @p bhnd_alloc_resources.
* @param res The bhnd resources to be released.
*/
void
bhnd_release_resources(device_t dev, const struct resource_spec *rs,
struct bhnd_resource **res)
{
for (u_int i = 0; rs[i].type != -1; i++) {
if (res[i] == NULL)
continue;
bhnd_release_resource(dev, rs[i].type, rs[i].rid, res[i]);
res[i] = NULL;
}
}
/**
* Parse the CHIPC_ID_* fields from the ChipCommon CHIPC_ID
* register, returning its bhnd_chipid representation.
*
* @param idreg The CHIPC_ID register value.
* @param enum_addr The enumeration address to include in the result.
*
* @warning
* On early siba(4) devices, the ChipCommon core does not provide
* a valid CHIPC_ID_NUMCORE field. On these ChipCommon revisions
* (see CHIPC_NCORES_MIN_HWREV()), this function will parse and return
* an invalid `ncores` value.
*/
struct bhnd_chipid
bhnd_parse_chipid(uint32_t idreg, bhnd_addr_t enum_addr)
{
struct bhnd_chipid result;
/* Fetch the basic chip info */
result.chip_id = CHIPC_GET_ATTR(idreg, ID_CHIP);
result.chip_pkg = CHIPC_GET_ATTR(idreg, ID_PKG);
result.chip_rev = CHIPC_GET_ATTR(idreg, ID_REV);
result.chip_type = CHIPC_GET_ATTR(idreg, ID_BUS);
result.ncores = CHIPC_GET_ATTR(idreg, ID_NUMCORE);
result.enum_addr = enum_addr;
return (result);
}
/**
* Allocate the resource defined by @p rs via @p dev, use it
* to read the ChipCommon ID register relative to @p chipc_offset,
* then release the resource.
*
* @param dev The device owning @p rs.
* @param rs A resource spec that encompasses the ChipCommon register block.
* @param chipc_offset The offset of the ChipCommon registers within @p rs.
* @param[out] result the chip identification data.
*
* @retval 0 success
* @retval non-zero if the ChipCommon identification data could not be read.
*/
int
bhnd_read_chipid(device_t dev, struct resource_spec *rs,
bus_size_t chipc_offset, struct bhnd_chipid *result)
{
struct resource *res;
uint32_t reg;
int error, rid, rtype;
/* Allocate the ChipCommon window resource and fetch the chipid data */
rid = rs->rid;
rtype = rs->type;
res = bus_alloc_resource_any(dev, rtype, &rid, RF_ACTIVE);
if (res == NULL) {
device_printf(dev,
"failed to allocate bhnd chipc resource\n");
return (ENXIO);
}
/* Fetch the basic chip info */
reg = bus_read_4(res, chipc_offset + CHIPC_ID);
*result = bhnd_parse_chipid(reg, 0x0);
/* Fetch the enum base address */
error = 0;
switch (result->chip_type) {
case BHND_CHIPTYPE_SIBA:
result->enum_addr = BHND_DEFAULT_CHIPC_ADDR;
break;
case BHND_CHIPTYPE_BCMA:
case BHND_CHIPTYPE_BCMA_ALT:
result->enum_addr = bus_read_4(res, chipc_offset +
CHIPC_EROMPTR);
break;
case BHND_CHIPTYPE_UBUS:
device_printf(dev, "unsupported ubus/bcm63xx chip type");
error = ENODEV;
goto cleanup;
default:
device_printf(dev, "unknown chip type %hhu\n",
result->chip_type);
error = ENODEV;
goto cleanup;
}
cleanup:
/* Clean up */
bus_release_resource(dev, rtype, rid, res);
return (error);
}
/**
* Using the bhnd(4) bus-level core information, populate @p dev's device
* description.
*
* @param dev A bhnd-bus attached device.
*/
void
bhnd_set_generic_core_desc(device_t dev)
{
const char *dev_name;
const char *vendor_name;
char *desc;
vendor_name = bhnd_get_vendor_name(dev);
dev_name = bhnd_get_device_name(dev);
asprintf(&desc, M_BHND, "%s %s, rev %hhu",
bhnd_get_vendor_name(dev),
bhnd_get_device_name(dev),
bhnd_get_hwrev(dev));
if (desc != NULL) {
device_set_desc_copy(dev, desc);
free(desc, M_BHND);
} else {
device_set_desc(dev, dev_name);
}
}

97
sys/dev/bhnd/bhnd_types.h Normal file
View file

@ -0,0 +1,97 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
* $FreeBSD$
*/
#ifndef _BHND_BHND_TYPES_H_
#define _BHND_BHND_TYPES_H_
#include <sys/types.h>
/** bhnd(4) device classes. */
typedef enum {
BHND_DEVCLASS_CC, /**< chipcommon i/o controller */
BHND_DEVCLASS_CC_B, /**< chipcommon auxiliary controller */
BHND_DEVCLASS_PMU, /**< pmu controller */
BHND_DEVCLASS_PCI, /**< pci host/device bridge */
BHND_DEVCLASS_PCIE, /**< pcie host/device bridge */
BHND_DEVCLASS_PCCARD, /**< pcmcia host/device bridge */
BHND_DEVCLASS_RAM, /**< internal RAM/SRAM */
BHND_DEVCLASS_MEMC, /**< memory controller */
BHND_DEVCLASS_ENET, /**< 802.3 MAC/PHY */
BHND_DEVCLASS_ENET_MAC, /**< 802.3 MAC */
BHND_DEVCLASS_ENET_PHY, /**< 802.3 PHY */
BHND_DEVCLASS_WLAN, /**< 802.11 MAC/PHY/Radio */
BHND_DEVCLASS_WLAN_MAC, /**< 802.11 MAC */
BHND_DEVCLASS_WLAN_PHY, /**< 802.11 PHY */
BHND_DEVCLASS_CPU, /**< cpu core */
BHND_DEVCLASS_SOC_ROUTER, /**< interconnect router */
BHND_DEVCLASS_SOC_BRIDGE, /**< interconnect host bridge */
BHND_DEVCLASS_EROM, /**< bus device enumeration ROM */
BHND_DEVCLASS_NVRAM, /**< nvram/flash controller */
BHND_DEVCLASS_OTHER, /**< other / unknown */
BHND_DEVCLASS_INVALID /**< no/invalid class */
} bhnd_devclass_t;
/**
* bhnd(4) port types.
*
* Only BHND_PORT_DEVICE is guaranteed to be supported by all bhnd(4) bus
* implementations.
*/
typedef enum {
BHND_PORT_DEVICE = 0, /**< device memory */
BHND_PORT_BRIDGE = 1, /**< bridge memory */
BHND_PORT_AGENT = 2, /**< interconnect agent/wrapper */
} bhnd_port_type;
/** Evaluates to true if @p cls is a device class that can be configured
* as a host bridge device. */
#define BHND_DEVCLASS_SUPPORTS_HOSTB(cls) \
((cls) == BHND_DEVCLASS_PCI || (cls) == BHND_DEVCLASS_PCIE || \
(cls) == BHND_DEVCLASS_PCCARD)
/**
* BHND bus address.
*
* @note While the interconnect may support 64-bit addressing, not
* all bridges and SoC CPUs will.
*/
typedef uint64_t bhnd_addr_t;
#define BHND_ADDR_MAX UINT64_MAX /**< Maximum bhnd_addr_t value */
/** BHND bus size. */
typedef uint64_t bhnd_size_t;
#define BHND_SIZE_MAX UINT64_MAX /**< Maximum bhnd_size_t value */
#endif /* _BHND_BHND_TYPES_H_ */

1943
sys/dev/bhnd/bhndb/bhndb.c Normal file

File diff suppressed because it is too large Load diff

173
sys/dev/bhnd/bhndb/bhndb.h Normal file
View file

@ -0,0 +1,173 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
* $FreeBSD$
*/
#ifndef _BHND_BHNDB_H_
#define _BHND_BHNDB_H_
#include <sys/param.h>
#include <sys/bus.h>
#include <machine/bus.h>
#include <sys/rman.h>
#include <machine/resource.h>
#include <dev/bhnd/bhnd.h>
#include "bhndb_bus_if.h"
extern devclass_t bhndb_devclass;
int bhndb_attach_bridge(device_t parent, device_t *bhndb, int unit);
/**
* bhndb register window types.
*/
typedef enum {
BHNDB_REGWIN_T_CORE, /**< Fixed mapping of a core port region. */
BHNDB_REGWIN_T_SPROM, /**< Fixed mapping of device SPROM */
BHNDB_REGWIN_T_DYN, /**< A dynamically configurable window */
BHNDB_REGWIN_T_INVALID /**< Invalid type */
} bhndb_regwin_type_t;
/**
* Evaluates to true if @p _rt defines a static mapping.
*
* @param _rt A bhndb_regwin_type_t value.
*/
#define BHNDB_REGWIN_T_IS_STATIC(_rt) \
((_rt) == BHNDB_REGWIN_T_CORE || \
(_rt) == BHNDB_REGWIN_T_SPROM)
/**
* bhndb register window definition.
*/
struct bhndb_regwin {
bhndb_regwin_type_t win_type; /**< window type */
bus_size_t win_offset; /**< offset of the window within the resource */
bus_size_t win_size; /**< size of the window */
/** Resource identification */
struct {
int type; /**< resource type */
int rid; /**< resource id */
} res;
union {
/** Core-specific register window (BHNDB_REGWIN_T_CORE). */
struct {
bhnd_devclass_t class; /**< mapped core's class */
u_int unit; /**< mapped core's unit */
bhnd_port_type port_type; /**< mapped port type */
u_int port; /**< mapped port number */
u_int region; /**< mapped region number */
} core;
/** SPROM register window (BHNDB_REGWIN_T_SPROM). */
struct {} sprom;
/** Dynamic register window (BHNDB_REGWIN_T_DYN). */
struct {
bus_size_t cfg_offset; /**< window address config offset. */
} dyn;
};
};
#define BHNDB_REGWIN_TABLE_END { BHNDB_REGWIN_T_INVALID, 0, 0, { 0, 0 } }
/**
* Bridge hardware configuration.
*
* Provides the bridge's register/address mappings, and the resources
* via which those mappings may be accessed.
*/
struct bhndb_hwcfg {
const struct resource_spec *resource_specs;
const struct bhndb_regwin *register_windows;
};
/**
* Hardware specification entry.
*
* Defines a set of match criteria that may be used to determine the
* register map and resource configuration for a bhndb bridge device.
*/
struct bhndb_hw {
const char *name; /**< configuration name */
const struct bhnd_core_match *hw_reqs; /**< match requirements */
u_int num_hw_reqs; /**< number of match requirements */
const struct bhndb_hwcfg *cfg; /**< associated hardware configuration */
};
/**
* bhndb resource allocation priorities.
*/
typedef enum {
/** No direct resources should ever be allocated for this device. */
BHNDB_PRIORITY_NONE = 0,
/** Allocate a direct resource if available after serving all other
* higher-priority requests. */
BHNDB_PRIORITY_LOW = 1,
/** Direct resource allocation is preferred, but not necessary
* for reasonable runtime performance. */
BHNDB_PRIORITY_DEFAULT = 2,
/** Indirect resource allocation would incur high runtime overhead. */
BHNDB_PRIORITY_HIGH = 3
} bhndb_priority_t;
/**
* Port resource priority descriptor.
*/
struct bhndb_port_priority {
bhnd_port_type type; /**< port type. */
u_int port; /**< port */
u_int region; /**< region */
bhndb_priority_t priority; /**< port priority */
};
/**
* Core resource priority descriptor.
*/
struct bhndb_hw_priority {
struct bhnd_core_match match; /**< core match descriptor */
bhndb_priority_t priority; /**< core-level priority */
const struct bhndb_port_priority *ports; /**< port priorities */
u_int num_ports; /**< number of port priority records. */
};
#define BHNDB_HW_PRIORITY_TABLE_END { {}, BHNDB_PRIORITY_NONE, NULL, 0 }
#endif /* _BHND_BHNDB_H_ */

View file

@ -0,0 +1,127 @@
#-
# Copyright (c) 2015 Landon Fuller <landon@landonf.org>
# 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 <sys/types.h>
#include <sys/bus.h>
#
# Parent bus interface required by attached bhndb bridge devices.
#
INTERFACE bhndb_bus;
HEADER {
struct bhnd_core_info;
struct bhndb_hwcfg;
struct bhndb_hw;
};
CODE {
#include <sys/systm.h>
static const struct bhnd_chipid *
bhndb_null_get_chipid(device_t dev, device_t child)
{
return (NULL);
}
static const struct bhndb_hwcfg *
bhndb_null_get_generic_hwcfg(device_t dev, device_t child)
{
panic("bhndb_get_generic_hwcfg unimplemented");
}
static const struct bhndb_hw *
bhndb_null_get_hardware_table(device_t dev, device_t child)
{
panic("bhndb_get_hardware_table unimplemented");
}
static bool
bhndb_null_is_core_disabled(device_t dev, device_t child,
struct bhnd_core_info *core)
{
return (true);
}
}
/**
* Return a generic hardware configuration to be used by
* the bhndb bridge device to enumerate attached devices.
*
* @param dev The parent device.
* @param child The attached bhndb device.
*
* @retval bhndb_hwcfg The configuration to use for bus enumeration.
*/
METHOD const struct bhndb_hwcfg * get_generic_hwcfg {
device_t dev;
device_t child;
} DEFAULT bhndb_null_get_generic_hwcfg;
/**
* Provide chip identification information to be used by a @p child during
* device enumeration.
*
* May return NULL if the device includes a ChipCommon core.
*
* @param dev The parent device.
* @param child The attached bhndb device.
*/
METHOD const struct bhnd_chipid * get_chipid {
device_t dev;
device_t child;
} DEFAULT bhndb_null_get_chipid;
/**
* Return the hardware specification table to be used when identifying the
* bridge's full hardware configuration.
*
* @param dev The parent device.
* @param child The attached bhndb device.
*/
METHOD const struct bhndb_hw * get_hardware_table {
device_t dev;
device_t child;
} DEFAULT bhndb_null_get_hardware_table;
/**
* Return true if the hardware required by @p core is unpopulated or
* otherwise unusable.
*
* In some cases, the core's pins may be left floating, or the hardware
* may otherwise be non-functional; this method allows the parent device
* to explicitly specify whether @p core should be disabled.
*
* @param dev The parent device.
* @param child The attached bhndb device.
* @param core A core discovered on @p child.
*/
METHOD bool is_core_disabled {
device_t dev;
device_t child;
struct bhnd_core_info *core;
} DEFAULT bhndb_null_is_core_disabled;

View file

@ -0,0 +1,195 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <dev/bhnd/bhnd_ids.h>
#include <dev/bhnd/bhndreg.h>
#include <dev/bhnd/bhnd.h>
#include "bhndb_hwdata.h"
/*
* Resource priority specifications shared by all bhndb(4) bridge
* implementations.
*/
/*
* Define a bhndb_port_priority table.
*/
#define BHNDB_PORTS(...) \
.ports = _BHNDB_PORT_ARRAY(__VA_ARGS__), \
.num_ports = nitems(_BHNDB_PORT_ARRAY(__VA_ARGS__))
#define _BHNDB_PORT_ARRAY(...) (const struct bhndb_port_priority[]) { \
__VA_ARGS__ \
}
/*
* Define a core priority record for all cores matching @p devclass and
* @p unit.
*
* If a devclass of BHNDB_DEVCLASS_INVALID is specified, this will match
* on all device classes.
*
* If a unit number of -1 is specified, this will match on all units.
*/
#define BHNDB_CLASS_PRIO(_devclass, _unit, _priority, ...) { \
.match = { \
.vendor = BHND_MFGID_INVALID, \
.device = BHND_COREID_INVALID, \
.hwrev = { BHND_HWREV_INVALID, BHND_HWREV_INVALID }, \
.class = (BHND_DEVCLASS_ ## _devclass), \
.unit = (_unit) \
}, \
.priority = (BHNDB_PRIORITY_ ## _priority), \
BHNDB_PORTS(__VA_ARGS__) \
}
/* Define a port priority record for the type/port/region
* triplet. */
#define BHNDB_PORT_PRIO(_type, _port, _region, _priority) { \
.type = (BHND_PORT_ ## _type), \
.port = _port, \
.region = _region, \
.priority = (BHNDB_PRIORITY_ ## _priority) \
}
/* Define a port priority record for the default (_type, 0, 0) type/port/region
* triplet. */
#define BHNDB_PORT0_PRIO(_type, _priority) \
BHNDB_PORT_PRIO(_type, 0, 0, _priority)
/**
* Generic resource priority configuration usable with all currently supported
* bcma(4)-based PCI devices.
*/
const struct bhndb_hw_priority bhndb_bcma_priority_table[] = {
/*
* Ignorable device classes.
*
* Runtime access to these cores is not required, and no register
* windows should be reserved for these device types.
*/
BHNDB_CLASS_PRIO(SOC_ROUTER, -1, NONE),
BHNDB_CLASS_PRIO(SOC_BRIDGE, -1, NONE),
BHNDB_CLASS_PRIO(EROM, -1, NONE),
BHNDB_CLASS_PRIO(OTHER, -1, NONE),
/*
* Low priority device classes.
*
* These devices do not sit in a performance-critical path and can be
* treated as a low allocation priority.
*/
BHNDB_CLASS_PRIO(CC, -1, LOW,
/* Device Block */
BHNDB_PORT0_PRIO(DEVICE, LOW),
/* CC agent registers are not accessed via the bridge. */
BHNDB_PORT0_PRIO(AGENT, NONE)
),
BHNDB_CLASS_PRIO(PMU, -1, LOW,
/* Device Block */
BHNDB_PORT0_PRIO(DEVICE, LOW),
/* PMU agent registers are not accessed via the bridge. */
BHNDB_PORT0_PRIO(AGENT, NONE)
),
/*
* Default Core Behavior
*
* All other cores are assumed to require effecient runtime access to
* the default device port, and if supported by the bus, an agent port.
*/
BHNDB_CLASS_PRIO(INVALID, -1, DEFAULT,
/* Device Block */
BHNDB_PORT0_PRIO(DEVICE, HIGH),
/* Agent Block */
BHNDB_PORT0_PRIO(AGENT, DEFAULT)
),
BHNDB_HW_PRIORITY_TABLE_END
};
/**
* Generic resource priority configuration usable with all currently supported
* siba(4)-based PCI devices.
*/
const struct bhndb_hw_priority bhndb_siba_priority_table[] = {
/*
* Ignorable device classes.
*
* Runtime access to these cores is not required, and no register
* windows should be reserved for these device types.
*/
BHNDB_CLASS_PRIO(SOC_ROUTER, -1, NONE),
BHNDB_CLASS_PRIO(SOC_BRIDGE, -1, NONE),
BHNDB_CLASS_PRIO(EROM, -1, NONE),
BHNDB_CLASS_PRIO(OTHER, -1, NONE),
/*
* Low priority device classes.
*
* These devices do not sit in a performance-critical path and can be
* treated as a low allocation priority.
*
* Agent ports are marked as 'NONE' on siba(4) devices, as they
* will be fully mappable via register windows shared with the
* device0.0 port.
*/
BHNDB_CLASS_PRIO(CC, -1, LOW,
/* Device Block */
BHNDB_PORT_PRIO(DEVICE, 0, 0, LOW)
),
BHNDB_CLASS_PRIO(PMU, -1, LOW,
/* Device Block */
BHNDB_PORT_PRIO(DEVICE, 0, 0, LOW)
),
/*
* Default Core Behavior
*
* All other cores are assumed to require effecient runtime access to
* the device port.
*/
BHNDB_CLASS_PRIO(INVALID, -1, DEFAULT,
/* Device Block */
BHNDB_PORT_PRIO(DEVICE, 0, 0, HIGH)
),
BHNDB_HW_PRIORITY_TABLE_END
};

View file

@ -0,0 +1,40 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
* $FreeBSD$
*/
#ifndef _BHND_BHNDB_HWDATA_H_
#define _BHND_BHNDB_HWDATA_H_
#include "bhndb.h"
extern const struct bhndb_hw_priority bhndb_bcma_priority_table[];
extern const struct bhndb_hw_priority bhndb_siba_priority_table[];
#endif /* _BHND_BHNDB_HWDATA_H_ */

View file

@ -0,0 +1,184 @@
#-
# Copyright (c) 2015 Landon Fuller <landon@landonf.org>
# 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 <sys/param.h>
#include <sys/bus.h>
#include <machine/bus.h>
#include <sys/rman.h>
#include <machine/resource.h>
#include <dev/bhnd/bhnd.h>
#
# bhndb bridge device interface.
#
INTERFACE bhndb;
HEADER {
struct bhndb_regwin;
struct bhndb_hw;
struct bhndb_hw_priority;
}
CODE {
#include <sys/systm.h>
#include <dev/bhnd/bhndb/bhndbvar.h>
static const struct bhnd_chipid *
bhndb_null_get_chipid(device_t dev, device_t child)
{
panic("bhndb_get_chipid unimplemented");
}
static int
bhndb_null_init_full_config(device_t dev, device_t child,
const struct bhndb_hw_priority *priority_table)
{
panic("bhndb_init_full_config unimplemented");
}
static void
bhndb_null_suspend_resource(device_t dev, device_t child, int type,
struct resource *r)
{
panic("bhndb_suspend_resource unimplemented");
}
static int
bhndb_null_resume_resource(device_t dev, device_t child, int type,
struct resource *r)
{
panic("bhndb_resume_resource unimplemented");
}
static int
bhndb_null_set_window_addr(device_t dev,
const struct bhndb_regwin *rw, bhnd_addr_t addr)
{
panic("bhndb_set_window_addr unimplemented");
}
}
/**
* Return the chip identification information for @p child.
*
* @param dev The parent device of @p child.
* @param child The bhndb-attached device.
*/
METHOD const struct bhnd_chipid * get_chipid {
device_t dev;
device_t child;
} DEFAULT bhndb_null_get_chipid;
/**
* Perform final bridge hardware configuration after @p child has fully
* enumerated its children.
*
* This must be called by any bhndb-attached bus device; this allows the
* bridge to perform final configuration based on the hardware information
* enumerated by the child bus.
*
* When calling this method:
* - Any bus resources previously allocated by @p child must be deallocated.
* - The @p child bus must have performed initial enumeration -- but not
* probe or attachment -- of its children.
*
* @param dev The bridge device.
* @param child The bhnd bus device attached to @p dev.
* @param hw_priority The hardware priority table to be used when determining
* the bridge resource allocation strategy.
*/
METHOD int init_full_config {
device_t dev;
device_t child;
const struct bhndb_hw_priority *priority_table;
} DEFAULT bhndb_null_init_full_config;
/**
* Mark a resource as 'suspended', gauranteeing to the bridge that no
* further use of the resource will be made until BHNDB_RESUME_RESOURCE()
* is called.
*
* Bridge resources consumed by the reference may be released; these will
* be reacquired if BHNDB_RESUME_RESOURCE() completes successfully.
*
* Requests to suspend a suspended resource will be ignored.
*
* @param dev The bridge device.
* @param child The child device requesting resource suspension. This does
* not need to be the owner of @p r.
* @param type The resource type.
* @param r The resource to be suspended.
*/
METHOD void suspend_resource {
device_t dev;
device_t child;
int type;
struct resource *r;
} DEFAULT bhndb_null_suspend_resource;
/**
* Attempt to re-enable a resource previously suspended by
* BHNDB_SUSPEND_RESOURCE().
*
* Bridge resources required by the reference may not be available, in which
* case an error will be returned and the resource mapped by @p r must not be
* used in any capacity.
*
* Requests to resume a non-suspended resource will be ignored.
*
* @param dev The bridge device.
* @param child The child device requesting resource suspension. This does
* not need to be the owner of @p r.
* @param type The resource type.
* @param r The resource to be suspended.
*/
METHOD int resume_resource {
device_t dev;
device_t child;
int type;
struct resource *r;
} DEFAULT bhndb_null_resume_resource;
/**
* Set a given register window's base address.
*
* @param dev The bridge device.
* @param win The register window.
* @param addr The address to be configured for @p win.
*
* @retval 0 success
* @retval ENODEV The provided @p win is not memory-mapped on the bus or does
* not support setting a base address.
* @retval non-zero failure
*/
METHOD int set_window_addr {
device_t dev;
const struct bhndb_regwin *win;
bhnd_addr_t addr;
} DEFAULT bhndb_null_set_window_addr;

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,616 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* Resource specifications and register maps for Broadcom PCI/PCIe cores
* configured as PCI-BHND bridges.
*/
#include <sys/param.h>
#include <sys/bus.h>
#include <machine/bus.h>
#include <sys/rman.h>
#include <machine/resource.h>
#include <dev/pci/pcireg.h>
#include <dev/pci/pcivar.h>
#include "bhndbvar.h"
#include "bhndb_pcireg.h"
static const struct bhndb_hwcfg bhndb_pci_hwcfg_v0;
static const struct bhndb_hwcfg bhndb_pci_hwcfg_v1_pci;
static const struct bhndb_hwcfg bhndb_pci_hwcfg_v1_pcie;
static const struct bhndb_hwcfg bhndb_pci_hwcfg_v2;
static const struct bhndb_hwcfg bhndb_pci_hwcfg_v3;
/**
* Define a bhndb_hw match entry.
*
* @param _name The entry name.
* @param _vers The configuration version associated with this entry.
*/
#define BHNDB_HW_MATCH(_name, _vers, ...) { \
.name = _name, \
.hw_reqs = _BHNDB_HW_REQ_ARRAY(__VA_ARGS__), \
.num_hw_reqs = (sizeof(_BHNDB_HW_REQ_ARRAY(__VA_ARGS__)) / \
sizeof(_BHNDB_HW_REQ_ARRAY(__VA_ARGS__)[0])), \
.cfg = &bhndb_pci_hwcfg_ ## _vers \
}
#define _BHNDB_HW_REQ_ARRAY(...) (struct bhnd_core_match[]) { __VA_ARGS__ }
/**
* Generic PCI-SIBA bridge configuration usable with all known siba(4)-based
* PCI devices; this configuration is adequate for enumerating a bridged
* siba(4) bus to determine the full hardware configuration.
*
* @par Compatibility
* - Compatible with PCI_V0, PCI_V1, PCI_V2, and PCI_V3 devices.
* - Compatible with siba(4) bus enumeration.
* - Compatible with bcma(4) bus enumeration if the ChipCommon core is mapped
* at the default enumeration address (0x18000000).
*/
const struct bhndb_hwcfg bhndb_pci_siba_generic_hwcfg = {
.resource_specs = (const struct resource_spec[]) {
{ SYS_RES_MEMORY, PCIR_BAR(0), RF_ACTIVE },
{ -1, 0, 0 }
},
.register_windows = (const struct bhndb_regwin[]) {
/* bar0+0x0000: configurable backplane window */
{
.win_type = BHNDB_REGWIN_T_DYN,
.win_offset = BHNDB_PCI_V1_BAR0_WIN0_OFFSET,
.win_size = BHNDB_PCI_V1_BAR0_WIN0_SIZE,
.dyn.cfg_offset = BHNDB_PCI_V1_BAR0_WIN0_CONTROL,
.res = { SYS_RES_MEMORY, PCIR_BAR(0) }
},
BHNDB_REGWIN_TABLE_END
},
};
/**
* Generic PCI-BCMA bridge configuration usable with all known bcma(4)-based
* PCI devices; this configuration is adequate for enumerating a bridged
* bcma(4) bus to determine the full hardware configuration.
*
* @par Compatibility
* - Compatible with PCI_V1, PCI_V2, and PCI_V3 devices.
* - Compatible with both siba(4) and bcma(4) bus enumeration.
*/
const struct bhndb_hwcfg bhndb_pci_bcma_generic_hwcfg = {
.resource_specs = (const struct resource_spec[]) {
{ SYS_RES_MEMORY, PCIR_BAR(0), RF_ACTIVE },
{ -1, 0, 0 }
},
.register_windows = (const struct bhndb_regwin[]) {
/* bar0+0x0000: configurable backplane window */
{
.win_type = BHNDB_REGWIN_T_DYN,
.win_offset = BHNDB_PCI_V1_BAR0_WIN0_OFFSET,
.win_size = BHNDB_PCI_V1_BAR0_WIN0_SIZE,
.dyn.cfg_offset = BHNDB_PCI_V1_BAR0_WIN0_CONTROL,
.res = { SYS_RES_MEMORY, PCIR_BAR(0) }
},
/* bar0+0x3000: chipc core registers */
{
.win_type = BHNDB_REGWIN_T_CORE,
.win_offset = BHNDB_PCI_V1_BAR0_CCREGS_OFFSET,
.win_size = BHNDB_PCI_V1_BAR0_CCREGS_SIZE,
.core = {
.class = BHND_DEVCLASS_CC,
.unit = 0,
.port = 0,
.region = 0,
.port_type = BHND_PORT_DEVICE
},
.res = { SYS_RES_MEMORY, PCIR_BAR(0) }
},
BHNDB_REGWIN_TABLE_END
},
};
/**
* Hardware configuration tables for Broadcom HND PCI NICs.
*/
const struct bhndb_hw bhndb_pci_generic_hw_table[] = {
/* PCI/V0 WLAN */
BHNDB_HW_MATCH("PCI/v0 WLAN", v0,
/* PCI Core */
{
.vendor = BHND_MFGID_BCM,
.device = BHND_COREID_PCI,
.hwrev = {
.start = 0,
.end = BHNDB_PCI_V0_MAX_PCI_HWREV
},
.class = BHND_DEVCLASS_PCI,
.unit = 0
},
/* 802.11 Core */
{
.vendor = BHND_MFGID_BCM,
.device = BHND_COREID_INVALID,
.hwrev = {
.start = 0,
.end = BHND_HWREV_INVALID
},
.class = BHND_DEVCLASS_WLAN,
.unit = 0
}
),
/* PCI/V1 WLAN */
BHNDB_HW_MATCH("PCI/v1 WLAN", v1_pci,
/* PCI Core */
{
.vendor = BHND_MFGID_BCM,
.device = BHND_COREID_PCI,
.hwrev = {
.start = BHNDB_PCI_V1_MIN_PCI_HWREV,
.end = BHND_HWREV_INVALID
},
.class = BHND_DEVCLASS_PCI,
.unit = 0
},
/* 802.11 Core */
{
.vendor = BHND_MFGID_BCM,
.device = BHND_COREID_INVALID,
.hwrev = {
.start = 0,
.end = BHND_HWREV_INVALID
},
.class = BHND_DEVCLASS_WLAN,
.unit = 0
}
),
/* PCIE/V1 WLAN */
BHNDB_HW_MATCH("PCIe/v1 WLAN", v1_pcie,
/* PCIe Core */
{
.vendor = BHND_MFGID_BCM,
.device = BHND_COREID_PCIE,
.hwrev = {
.start = 0,
.end = BHND_HWREV_INVALID
},
.class = BHND_DEVCLASS_PCIE,
.unit = 0
},
/* ChipCommon (revision <= 31) */
{
.vendor = BHND_MFGID_BCM,
.device = BHND_COREID_CC,
.hwrev = {
.start = 0,
.end = BHNDB_PCI_V1_MAX_CHIPC_HWREV
},
.class = BHND_DEVCLASS_CC,
.unit = 0
},
/* 802.11 Core */
{
.vendor = BHND_MFGID_BCM,
.device = BHND_COREID_INVALID,
.hwrev = {
.start = 0,
.end = BHND_HWREV_INVALID
},
.class = BHND_DEVCLASS_WLAN,
.unit = 0
}
),
/* PCIE/V2 WLAN */
BHNDB_HW_MATCH("PCIe/v2 WLAN", v2,
/* PCIe Core */
{
.vendor = BHND_MFGID_BCM,
.device = BHND_COREID_PCIE,
.hwrev = { 0, BHND_HWREV_INVALID },
.class = BHND_DEVCLASS_PCIE,
.unit = 0
},
/* ChipCommon (revision >= 32) */
{
.vendor = BHND_MFGID_BCM,
.device = BHND_COREID_CC,
.hwrev = {
.start = BHNDB_PCI_V2_MIN_CHIPC_HWREV,
.end = BHND_HWREV_INVALID
},
.class = BHND_DEVCLASS_CC,
.unit = 0
},
/* 802.11 Core */
{
.vendor = BHND_MFGID_BCM,
.device = BHND_COREID_INVALID,
.hwrev = {
.start = 0,
.end = BHND_HWREV_INVALID
},
.class = BHND_DEVCLASS_WLAN,
.unit = 0
}
),
/* PCIE/V3 WLAN */
BHNDB_HW_MATCH("PCIe-Gen2/v3 WLAN", v3,
/* PCIe Gen2 Core */
{
.vendor = BHND_MFGID_BCM,
.device = BHND_COREID_PCIE2,
.hwrev = {
.start = 0,
.end = BHND_HWREV_INVALID
},
.class = BHND_DEVCLASS_PCIE,
.unit = 0
},
/* 802.11 Core */
{
.vendor = BHND_MFGID_BCM,
.device = BHND_COREID_INVALID,
.hwrev = {
.start = 0,
.end = BHND_HWREV_INVALID
},
.class = BHND_DEVCLASS_WLAN,
.unit = 0
}
),
{ NULL, NULL, 0, NULL }
};
/**
* PCI_V0 hardware configuration.
*
* Applies to:
* - PCI (cid=0x804, revision <= 12)
*/
static const struct bhndb_hwcfg bhndb_pci_hwcfg_v0 = {
.resource_specs = (const struct resource_spec[]) {
{ SYS_RES_MEMORY, PCIR_BAR(0), RF_ACTIVE },
{ -1, 0, 0 }
},
.register_windows = (const struct bhndb_regwin[]) {
/* bar0+0x0000: configurable backplane window */
{
.win_type = BHNDB_REGWIN_T_DYN,
.win_offset = BHNDB_PCI_V0_BAR0_WIN0_OFFSET,
.win_size = BHNDB_PCI_V0_BAR0_WIN0_SIZE,
.dyn.cfg_offset = BHNDB_PCI_V0_BAR0_WIN0_CONTROL,
.res = { SYS_RES_MEMORY, PCIR_BAR(0) }
},
/* bar0+0x1000: sprom shadow */
{
.win_type = BHNDB_REGWIN_T_SPROM,
.win_offset = BHNDB_PCI_V0_BAR0_SPROM_OFFSET,
.win_size = BHNDB_PCI_V0_BAR0_SPROM_SIZE,
.res = { SYS_RES_MEMORY, PCIR_BAR(0) }
},
/* bar0+0x1800: pci core registers */
{
.win_type = BHNDB_REGWIN_T_CORE,
.win_offset = BHNDB_PCI_V0_BAR0_PCIREG_OFFSET,
.win_size = BHNDB_PCI_V0_BAR0_PCIREG_SIZE,
.core = {
.class = BHND_DEVCLASS_PCI,
.unit = 0,
.port = 0,
.region = 0,
.port_type = BHND_PORT_DEVICE
},
.res = { SYS_RES_MEMORY, PCIR_BAR(0) }
},
BHNDB_REGWIN_TABLE_END
},
};
/**
* PCI_V1 (PCI-only) hardware configuration (PCI version)
*
* Applies to:
* - PCI (cid=0x804, revision >= 13)
*/
static const struct bhndb_hwcfg bhndb_pci_hwcfg_v1_pci = {
.resource_specs = (const struct resource_spec[]) {
{ SYS_RES_MEMORY, PCIR_BAR(0), RF_ACTIVE },
{ -1, 0, 0 }
},
.register_windows = (const struct bhndb_regwin[]) {
/* bar0+0x0000: configurable backplane window */
{
.win_type = BHNDB_REGWIN_T_DYN,
.win_offset = BHNDB_PCI_V1_BAR0_WIN0_OFFSET,
.win_size = BHNDB_PCI_V1_BAR0_WIN0_SIZE,
.dyn.cfg_offset = BHNDB_PCI_V1_BAR0_WIN0_CONTROL,
.res = { SYS_RES_MEMORY, PCIR_BAR(0) }
},
/* bar0+0x1000: sprom shadow */
{
.win_type = BHNDB_REGWIN_T_SPROM,
.win_offset = BHNDB_PCI_V1_BAR0_SPROM_OFFSET,
.win_size = BHNDB_PCI_V1_BAR0_SPROM_SIZE,
.res = { SYS_RES_MEMORY, PCIR_BAR(0) }
},
/* bar0+0x2000: pci core registers */
{
.win_type = BHNDB_REGWIN_T_CORE,
.win_offset = BHNDB_PCI_V1_BAR0_PCIREG_OFFSET,
.win_size = BHNDB_PCI_V1_BAR0_PCIREG_SIZE,
.core = {
.class = BHND_DEVCLASS_PCI,
.unit = 0,
.port = 0,
.region = 0,
.port_type = BHND_PORT_DEVICE
},
.res = { SYS_RES_MEMORY, PCIR_BAR(0) }
},
/* bar0+0x3000: chipc core registers */
{
.win_type = BHNDB_REGWIN_T_CORE,
.win_offset = BHNDB_PCI_V1_BAR0_CCREGS_OFFSET,
.win_size = BHNDB_PCI_V1_BAR0_CCREGS_SIZE,
.core = {
.class = BHND_DEVCLASS_CC,
.unit = 0,
.port = 0,
.region = 0,
.port_type = BHND_PORT_DEVICE
},
.res = { SYS_RES_MEMORY, PCIR_BAR(0) }
},
BHNDB_REGWIN_TABLE_END
},
};
/**
* PCI_V1 hardware configuration (PCIE version).
*
* Applies to:
* - PCIE (cid=0x820) with ChipCommon (revision <= 31)
*/
static const struct bhndb_hwcfg bhndb_pci_hwcfg_v1_pcie = {
.resource_specs = (const struct resource_spec[]) {
{ SYS_RES_MEMORY, PCIR_BAR(0), RF_ACTIVE },
{ -1, 0, 0 }
},
.register_windows = (const struct bhndb_regwin[]) {
/* bar0+0x0000: configurable backplane window */
{
.win_type = BHNDB_REGWIN_T_DYN,
.win_offset = BHNDB_PCI_V1_BAR0_WIN0_OFFSET,
.win_size = BHNDB_PCI_V1_BAR0_WIN0_SIZE,
.dyn.cfg_offset = BHNDB_PCI_V1_BAR0_WIN0_CONTROL,
.res = { SYS_RES_MEMORY, PCIR_BAR(0) }
},
/* bar0+0x1000: sprom shadow */
{
.win_type = BHNDB_REGWIN_T_SPROM,
.win_offset = BHNDB_PCI_V1_BAR0_SPROM_OFFSET,
.win_size = BHNDB_PCI_V1_BAR0_SPROM_SIZE,
.res = { SYS_RES_MEMORY, PCIR_BAR(0) }
},
/* bar0+0x2000: pci core registers */
{
.win_type = BHNDB_REGWIN_T_CORE,
.win_offset = BHNDB_PCI_V1_BAR0_PCIREG_OFFSET,
.win_size = BHNDB_PCI_V1_BAR0_PCIREG_SIZE,
.core = {
.class = BHND_DEVCLASS_PCIE,
.unit = 0,
.port = 0,
.region = 0,
.port_type = BHND_PORT_DEVICE
},
.res = { SYS_RES_MEMORY, PCIR_BAR(0) }
},
/* bar0+0x3000: chipc core registers */
{
.win_type = BHNDB_REGWIN_T_CORE,
.win_offset = BHNDB_PCI_V1_BAR0_CCREGS_OFFSET,
.win_size = BHNDB_PCI_V1_BAR0_CCREGS_SIZE,
.core = {
.class = BHND_DEVCLASS_CC,
.unit = 0,
.port = 0,
.region = 0,
.port_type = BHND_PORT_DEVICE
},
.res = { SYS_RES_MEMORY, PCIR_BAR(0) }
},
BHNDB_REGWIN_TABLE_END
},
};
/**
* PCI_V2 hardware configuration.
*
* Applies to:
* - PCIE (cid=0x820) with ChipCommon (revision >= 32)
*/
static const struct bhndb_hwcfg bhndb_pci_hwcfg_v2 = {
.resource_specs = (const struct resource_spec[]) {
{ SYS_RES_MEMORY, PCIR_BAR(0), RF_ACTIVE },
{ -1, 0, 0 }
},
.register_windows = (const struct bhndb_regwin[]) {
/* bar0+0x0000: configurable backplane window */
{
.win_type = BHNDB_REGWIN_T_DYN,
.win_offset = BHNDB_PCI_V2_BAR0_WIN0_OFFSET,
.win_size = BHNDB_PCI_V2_BAR0_WIN0_SIZE,
.dyn.cfg_offset = BHNDB_PCI_V2_BAR0_WIN0_CONTROL,
.res = { SYS_RES_MEMORY, PCIR_BAR(0) }
},
/* bar0+0x1000: configurable backplane window */
{
.win_type = BHNDB_REGWIN_T_DYN,
.win_offset = BHNDB_PCI_V2_BAR0_WIN1_OFFSET,
.win_size = BHNDB_PCI_V2_BAR0_WIN1_SIZE,
.dyn.cfg_offset = BHNDB_PCI_V2_BAR0_WIN1_CONTROL,
.res = { SYS_RES_MEMORY, PCIR_BAR(0) }
},
/* bar0+0x2000: pcie core registers */
{
.win_type = BHNDB_REGWIN_T_CORE,
.win_offset = BHNDB_PCI_V2_BAR0_PCIREG_OFFSET,
.win_size = BHNDB_PCI_V2_BAR0_PCIREG_SIZE,
.core = {
.class = BHND_DEVCLASS_PCIE,
.unit = 0,
.port = 0,
.region = 0,
.port_type = BHND_PORT_DEVICE
},
.res = { SYS_RES_MEMORY, PCIR_BAR(0) }
},
/* bar0+0x3000: chipc core registers */
{
.win_type = BHNDB_REGWIN_T_CORE,
.win_offset = BHNDB_PCI_V2_BAR0_CCREGS_OFFSET,
.win_size = BHNDB_PCI_V2_BAR0_CCREGS_SIZE,
.core = {
.class = BHND_DEVCLASS_CC,
.unit = 0,
.port = 0,
.region = 0,
.port_type = BHND_PORT_DEVICE
},
.res = { SYS_RES_MEMORY, PCIR_BAR(0) }
},
BHNDB_REGWIN_TABLE_END
},
};
/**
* PCI_V3 hardware configuration.
*
* Applies to:
* - PCIE2 (cid=0x83c)
*/
static const struct bhndb_hwcfg bhndb_pci_hwcfg_v3 = {
.resource_specs = (const struct resource_spec[]) {
{ SYS_RES_MEMORY, PCIR_BAR(0), RF_ACTIVE },
{ -1, 0, 0 }
},
.register_windows = (const struct bhndb_regwin[]) {
/* bar0+0x0000: configurable backplane window */
{
.win_type = BHNDB_REGWIN_T_DYN,
.win_offset = BHNDB_PCI_V3_BAR0_WIN0_OFFSET,
.win_size = BHNDB_PCI_V3_BAR0_WIN0_SIZE,
.dyn.cfg_offset = BHNDB_PCI_V3_BAR0_WIN0_CONTROL,
.res = { SYS_RES_MEMORY, PCIR_BAR(0) }
},
/* bar0+0x1000: configurable backplane window */
{
.win_type = BHNDB_REGWIN_T_DYN,
.win_offset = BHNDB_PCI_V3_BAR0_WIN1_OFFSET,
.win_size = BHNDB_PCI_V3_BAR0_WIN1_SIZE,
.dyn.cfg_offset = BHNDB_PCI_V3_BAR0_WIN1_CONTROL,
.res = { SYS_RES_MEMORY, PCIR_BAR(0) }
},
/* bar0+0x2000: pcie core registers */
{
.win_type = BHNDB_REGWIN_T_CORE,
.win_offset = BHNDB_PCI_V3_BAR0_PCIREG_OFFSET,
.win_size = BHNDB_PCI_V3_BAR0_PCIREG_SIZE,
.core = {
.class = BHND_DEVCLASS_PCIE,
.unit = 0,
.port = 0,
.region = 0,
.port_type = BHND_PORT_DEVICE
},
.res = { SYS_RES_MEMORY, PCIR_BAR(0) }
},
/* bar0+0x3000: chipc core registers */
{
.win_type = BHNDB_REGWIN_T_CORE,
.win_offset = BHNDB_PCI_V3_BAR0_CCREGS_OFFSET,
.win_size = BHNDB_PCI_V3_BAR0_CCREGS_SIZE,
.core = {
.class = BHND_DEVCLASS_CC,
.unit = 0,
.port = 0,
.region = 0,
.port_type = BHND_PORT_DEVICE
},
.res = { SYS_RES_MEMORY, PCIR_BAR(0) }
},
BHNDB_REGWIN_TABLE_END
},
};

View file

@ -0,0 +1,42 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
* $FreeBSD$
*/
#ifndef _BHND_BHNDB_PCI_HWDATA_H_
#define _BHND_BHNDB_PCI_HWDATA_H_
#include "bhndb.h"
extern struct bhndb_hw bhndb_pci_generic_hw_table[];
extern const struct bhndb_hwcfg bhndb_pci_bcma_generic_hwcfg;
extern const struct bhndb_hwcfg bhndb_pci_siba_generic_hwcfg;
#endif /* _BHND_BHNDB_PCI_HWDATA_H_ */

View file

@ -0,0 +1,223 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* Copyright (c) 2010 Broadcom Corporation
*
* Portions of this file were derived from the bcmdevs.h header contributed by
* Broadcom to Android's bcmdhd driver module, and the pcicfg.h header
* distributed with Broadcom's initial brcm80211 Linux driver release.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $FreeBSD$
*/
#ifndef _BHND_BHNDB_PCIREG_H_
#define _BHND_BHNDB_PCIREG_H_
/*
* Common PCI/PCIE Bridge Configuration Registers.
*
* = MAJOR CORE REVISIONS =
*
* There have been four revisions to the BAR0/BAR1 memory mappings used
* in BHND PCI/PCIE bridge cores:
*
* == PCI_V0 ==
* Applies to:
* - PCI (cid=0x804, revision <= 12)
* BAR size: 8KB
* Address Map:
* [offset+ size] type description
* [0x0000+0x1000] dynamic mapped backplane address space (window 0).
* [0x1000+0x0800] fixed SPROM shadow
* [0x1800+0x0800] fixed pci core registers
*
* == PCI_V1 ==
* Applies to:
* - PCI (cid=0x804, revision >= 13)
* - PCIE (cid=0x820) with ChipCommon (revision <= 31)
* BAR size: 16KB
* Address Map:
* [offset+ size] type description
* [0x0000+0x1000] dynamic mapped backplane address space (window 0).
* [0x1000+0x1000] fixed SPROM shadow
* [0x2000+0x1000] fixed pci/pcie core registers
* [0x3000+0x1000] fixed chipcommon core registers
*
* == PCI_V2 ==
* Applies to:
* - PCIE (cid=0x820) with ChipCommon (revision >= 32)
* BAR size: 16KB
* Address Map:
* [offset+ size] type description
* [0x0000+0x1000] dynamic mapped backplane address space (window 0).
* [0x1000+0x1000] dynamic mapped backplane address space (window 1).
* [0x2000+0x1000] fixed pci/pcie core registers
* [0x3000+0x1000] fixed chipcommon core registers
*
* == PCI_V3 ==
* Applies to:
* - PCIE Gen 2 (cid=0x83c)
* BAR size: 32KB?
* Address Map:
* [offset+ size] type description
* [0x0000+0x1000] dynamic mapped backplane address space (window 0).
* [0x1000+0x1000] dynamic mapped backplane address space (window 1).
* [0x2000+0x1000] fixed pci/pcie core registers
* [0x3000+0x1000] fixed chipcommon core registers
* [???]
*
* = MINOR CORE REVISIONS =
*
* == PCI Cores Revision >= 3 ==
* - Mapped GPIO CSRs into the PCI config space. Refer to
* BHND_PCI_GPIO_*.
*
* == PCI/PCIE Cores Revision >= 14 ==
* - Mapped the clock CSR into the PCI config space. Refer to
* BHND_PCI_CLK_CTL_ST
*
* = Hardware Bugs =
* == BAR1 ==
*
* The BHND PCI(e) cores hypothetically support an additional memory mapping
* of the backplane address space via BAR1, but this appears to be subject
* to a hardware bug in which BAR1 is initially configured with a 4 byte
* length.
*
* A work-around for this bug may be possible by writing to the PCI core's
* BAR1 config register (0x4e0), but this requires further research -- I've
* found three sources for information on the BAR1 PCI core configuration that
* may be relevant:
* - The QLogix NetXTreme 10GB PCIe NIC seems to use the same PCIE
* core IP block as is used in other BHND devices. The bxe(4) driver
* contains example initialization code and register constants
* that may apply (e.g. GRC_BAR2_CONFIG/PCI_CONFIG_2_BAR2_SIZE).
* - The publicly available Broadcom BCM440X data sheet (440X-PG02-R)
* appears to (partially) document a Broadcom PCI(e) core that has a
* seemingly compatible programming model.
* - The Android bcmdhd driver sources include a possible work-around
* implementation (writing to 0x4e0) in dhd_pcie.c
*/
/* Common PCI/PCIE Config Registers */
#define BHNDB_PCI_SPROM_CONTROL 0x88 /* sprom property control */
#define BHNDB_PCI_BAR1_CONTROL 0x8c /* BAR1 region prefetch/burst control */
#define BHNDB_PCI_INT_STATUS 0x90 /* PCI and other cores interrupts */
#define BHNDB_PCI_INT_MASK 0x94 /* mask of PCI and other cores interrupts */
#define BHNDB_PCI_TO_SB_MB 0x98 /* signal backplane interrupts */
#define BHNDB_PCI_BACKPLANE_ADDR 0xa0 /* address an arbitrary location on the system backplane */
#define BHNDB_PCI_BACKPLANE_DATA 0xa4 /* data at the location specified by above address */
/* PCI (non-PCIe) GPIO/Clock Config Registers */
#define BHNDB_PCI_CLK_CTL 0xa8 /* clock control/status (pci >=rev14) */
#define BHNDB_PCI_GPIO_IN 0xb0 /* gpio input (pci >=rev3) */
#define BHNDB_PCI_GPIO_OUT 0xb4 /* gpio output (pci >=rev3) */
#define BHNDB_PCI_GPIO_OUTEN 0xb8 /* gpio output enable (pci >=rev3) */
/* Hardware revisions used to determine PCI revision */
#define BHNDB_PCI_V0_MAX_PCI_HWREV 12
#define BHNDB_PCI_V1_MIN_PCI_HWREV 13
#define BHNDB_PCI_V1_MAX_CHIPC_HWREV 31
#define BHNDB_PCI_V2_MIN_CHIPC_HWREV 32
/**
* Number of times to retry writing to a PCI window address register.
*
* On siba(4) devices, it's possible that writing a PCI window register may
* not succeed; it's necessary to immediately read the configuration register
* and retry if not set to the desired value.
*/
#define BHNDB_PCI_BARCTRL_WRITE_RETRY 50
/* PCI_V0 */
#define BHNDB_PCI_V0_BAR0_WIN0_CONTROL 0x80 /* backplane address space accessed by BAR0/WIN0 */
#define BHNDB_PCI_V0_BAR1_WIN0_CONTROL 0x84 /* backplane address space accessed by BAR1/WIN0. */
#define BHNDB_PCI_V0_BAR0_SIZE 0x2000 /* 8KB BAR0 */
#define BHNDB_PCI_V0_BAR0_WIN0_OFFSET 0x0 /* bar0 + 0x0 accesses configurable 4K region of backplane address space */
#define BHNDB_PCI_V0_BAR0_WIN0_SIZE 0x1000
#define BHNDB_PCI_V0_BAR0_SPROM_OFFSET 0x1000 /* bar0 + 4K accesses sprom shadow (in pci core) */
#define BHNDB_PCI_V0_BAR0_SPROM_SIZE 0x0800
#define BHNDB_PCI_V0_BAR0_PCIREG_OFFSET 0x1800 /* bar0 + 6K accesses pci core registers */
#define BHNDB_PCI_V0_BAR0_PCIREG_SIZE 0x0800
/* PCI_V1 */
#define BHNDB_PCI_V1_BAR0_WIN0_CONTROL 0x80 /* backplane address space accessed by BAR0/WIN0 */
#define BHNDB_PCI_V1_BAR1_WIN0_CONTROL 0x84 /* backplane address space accessed by BAR1/WIN0. */
#define BHNDB_PCI_V1_BAR0_SIZE 0x4000 /* 16KB BAR0 */
#define BHNDB_PCI_V1_BAR0_WIN0_OFFSET 0x0 /* bar0 + 0x0 accesses configurable 4K region of backplane address space */
#define BHNDB_PCI_V1_BAR0_WIN0_SIZE 0x1000
#define BHNDB_PCI_V1_BAR0_SPROM_OFFSET 0x1000 /* bar0 + 4K accesses sprom shadow (in pci core) */
#define BHNDB_PCI_V1_BAR0_SPROM_SIZE 0x1000
#define BHNDB_PCI_V1_BAR0_PCIREG_OFFSET 0x2000 /* bar0 + 8K accesses pci/pcie core registers */
#define BHNDB_PCI_V1_BAR0_PCIREG_SIZE 0x1000
#define BHNDB_PCI_V1_BAR0_CCREGS_OFFSET 0x3000 /* bar0 + 12K accesses chipc core registers */
#define BHNDB_PCI_V1_BAR0_CCREGS_SIZE 0x1000
/* PCI_V2 */
#define BHNDB_PCI_V2_BAR0_WIN0_CONTROL 0x80 /* backplane address space accessed by BAR0/WIN0 */
#define BHNDB_PCI_V2_BAR1_WIN0_CONTROL 0x84 /* backplane address space accessed by BAR1/WIN0. */
#define BHNDB_PCI_V2_BAR0_WIN1_CONTROL 0xAC /* backplane address space accessed by BAR0/WIN1 */
#define BHNDB_PCI_V2_BAR0_SIZE 0x4000 /* 16KB BAR0 */
#define BHNDB_PCI_V2_BAR0_WIN0_OFFSET 0x0 /* bar0 + 0x0 accesses configurable 4K region of backplane address space */
#define BHNDB_PCI_V2_BAR0_WIN0_SIZE 0x1000
#define BHNDB_PCI_V2_BAR0_WIN1_OFFSET 0x1000 /* bar0 + 4K accesses second 4K window */
#define BHNDB_PCI_V2_BAR0_WIN1_SIZE 0x1000
#define BHNDB_PCI_V2_BAR0_PCIREG_OFFSET 0x2000 /* bar0 + 8K accesses pci/pcie core registers */
#define BHNDB_PCI_V2_BAR0_PCIREG_SIZE 0x1000
#define BHNDB_PCI_V2_BAR0_CCREGS_OFFSET 0x3000 /* bar0 + 12K accesses chipc core registers */
#define BHNDB_PCI_V2_BAR0_CCREGS_SIZE 0x1000
/* PCI_V3 */
#define BHNDB_PCI_V3_BAR0_WIN0_CONTROL 0x80 /* backplane address space accessed by BAR0/WIN0 */
#define BHNDB_PCI_V3_BAR1_WIN0_CONTROL 0x84 /* backplane address space accessed by BAR1/WIN0. */
#define BHNDB_PCI_V3_BAR0_WIN1_CONTROL 0x70 /* backplane address space accessed by BAR0/WIN1 */
#define BHNDB_PCI_V3_BAR0_SIZE 0x8000 /* 32KB BAR0 (?) */
#define BHNDB_PCI_V3_BAR0_WIN0_OFFSET 0x0 /* bar0 + 0x0 accesses configurable 4K region of backplane address space */
#define BHNDB_PCI_V3_BAR0_WIN0_SIZE 0x1000
#define BHNDB_PCI_V3_BAR0_WIN1_OFFSET 0x1000 /* bar0 + 4K accesses second 4K window */
#define BHNDB_PCI_V3_BAR0_WIN1_SIZE 0x1000
#define BHNDB_PCI_V3_BAR0_PCIREG_OFFSET 0x2000 /* bar0 + 8K accesses pci/pcie core registers */
#define BHNDB_PCI_V3_BAR0_PCIREG_SIZE 0x1000
#define BHNDB_PCI_V3_BAR0_CCREGS_OFFSET 0x3000 /* bar0 + 12K accesses chipc core registers */
#define BHNDB_PCI_V3_BAR0_CCREGS_SIZE 0x1000
/* BHNDB_PCI_INT_STATUS */
#define BHNDB_PCI_SBIM_STATUS_SERR 0x4 /* backplane SBErr interrupt status */
/* BHNDB_PCI_INT_MASK */
#define BHNDB_PCI_SBIM_SHIFT 8 /* backplane core interrupt mask bits offset */
#define BHNDB_PCI_SBIM_MASK 0xff00 /* backplane core interrupt mask */
#define BHNDB_PCI_SBIM_MASK_SERR 0x4 /* backplane SBErr interrupt mask */
/* BHNDB_PCI_SPROM_CONTROL */
#define BHNDB_PCI_SPROM_SZ_MSK 0x02 /* SPROM Size Mask */
#define BHNDB_PCI_SPROM_LOCKED 0x08 /* SPROM Locked */
#define BHNDB_PCI_SPROM_BLANK 0x04 /* indicating a blank SPROM */
#define BHNDB_PCI_SPROM_WRITEEN 0x10 /* SPROM write enable */
#define BHNDB_PCI_SPROM_BOOTROM_WE 0x20 /* external bootrom write enable */
#define BHNDB_PCI_SPROM_BACKPLANE_EN 0x40 /* Enable indirect backplane access */
#define BHNDB_PCI_SPROM_OTPIN_USE 0x80 /* device OTP In use */
/* PCI (non-PCIe) BHNDB_PCI_GPIO_OUTEN */
#define BHNDB_PCI_GPIO_SCS 0x10 /* PCI config space bit 4 for 4306c0 slow clock source */
#define BHNDB_PCI_GPIO_HWRAD_OFF 0x20 /* PCI config space GPIO 13 for hw radio disable */
#define BHNDB_PCI_GPIO_XTAL_ON 0x40 /* PCI config space GPIO 14 for Xtal power-up */
#define BHNDB_PCI_GPIO_PLL_OFF 0x80 /* PCI config space GPIO 15 for PLL power-down */
#endif /* _BHND_BHNDB_PCIREG_H_ */

View file

@ -0,0 +1,251 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
* $FreeBSD$
*/
#ifndef _BHND_BHNDB_PCIVAR_H_
#define _BHND_BHNDB_PCIVAR_H_
#include <sys/stdint.h>
#include <dev/bhnd/cores/pci/bhnd_pcivar.h>
#include "bhndbvar.h"
/*
* bhndb(4) PCI driver subclass.
*/
DECLARE_CLASS(bhndb_pci_driver);
struct bhndb_pci_softc;
/*
* An interconnect-specific function implementing BHNDB_SET_WINDOW_ADDR
*/
typedef int (*bhndb_pci_set_regwin_t)(struct bhndb_pci_softc *sc,
const struct bhndb_regwin *rw, bhnd_addr_t addr);
/**
* PCI bridge core identification table.
*/
struct bhndb_pci_id {
uint16_t device; /**< bhnd device ID */
bhnd_pci_regfmt_t regfmt; /**< register format */
struct bhnd_device_quirk *quirks; /**< quirks table */
};
struct bhndb_pci_softc {
struct bhndb_softc bhndb; /**< parent softc */
device_t dev; /**< bridge device */
bhnd_devclass_t pci_devclass; /**< PCI core's devclass */
bhndb_pci_set_regwin_t set_regwin; /**< regwin handler */
/*
* Initialized in BHNDB_INIT_FULL_CONFIG()
*/
device_t mdio; /**< PCIe MDIO device. NULL if not PCIe. */
bhnd_pci_regfmt_t regfmt; /**< device register format */
struct resource *mem_res; /**< pci core's registers (borrowed reference) */
bus_size_t mem_off; /**< offset to the PCI core's registers within `mem_res` . */
struct bhnd_resource bhnd_mem_res; /**< bhnd resource representation of mem_res.
this is a simple 'direct' resource mapping */
uint32_t quirks; /**< BHNDB_PCI(E)_QUIRK flags */
/**
* Driver state specific to BHNDB_PCIE_QUIRK_SDR9_POLARITY.
*/
struct {
/**
* PCIe SerDes RX polarity.
*
* Initialized to the PCIe link's RX polarity
* at attach time. This is used to restore the
* correct polarity on resume */
bool inv;
} sdr9_quirk_polarity;
};
/* Declare a bhndb_pci_id entry */
#define BHNDB_PCI_ID(_device, _desc, ...) { \
BHND_COREID_ ## _device, \
BHND_PCI_REGFMT_ ## _device, \
(struct bhnd_device_quirk[]) { \
__VA_ARGS__ \
} \
}
/*
* PCI/PCIe-Gen1 endpoint-mode device quirks
*/
enum {
/** No quirks */
BHNDB_PCI_QUIRK_NONE = 0,
/**
* BCM4306 chips (and possibly others) do not support the idle
* low-power clock. Clocking must be bootstrapped at attach/resume by
* directly adjusting GPIO registers exposed in the PCI config space,
* and correspondingly, explicitly shutdown at detach/suspend.
*/
BHNDB_PCI_QUIRK_EXT_CLOCK_GATING = (1<<1),
/**
* SBTOPCI_PREF and SBTOPCI_BURST must be set on the
* SSB_PCICORE_SBTOPCI2 register.
*/
BHNDB_PCI_QUIRK_SBTOPCI2_PREF_BURST = (1<<2),
/**
* SBTOPCI_RC_READMULTI must be set on the SSB_PCICORE_SBTOPCI2
* register.
*/
BHNDB_PCI_QUIRK_SBTOPCI2_READMULTI = (1<<3),
/**
* Interrupt masking is handled via the interconnect configuration
* registers (SBINTVEC on siba), rather than the PCI_INT_MASK
* config register.
*/
BHNDB_PCI_QUIRK_SBINTVEC = (1<<4),
/**
* PCI CLKRUN# should be disabled on attach (via CLKRUN_DSBL).
*
* The purpose of this work-around is unclear; there is some
* documentation regarding earlier Broadcom drivers supporting
* a "force CLKRUN#" *enable* registry key for use on mobile
* hardware.
*/
BHNDB_PCI_QUIRK_CLKRUN_DSBL = (1<<5),
/**
* TLP workaround for unmatched address handling is required.
*
* This TLP workaround will enable setting of the PCIe UR status bit
* on memory access to an unmatched address.
*/
BHNDB_PCIE_QUIRK_UR_STATUS_FIX = (1<<6),
/**
* PCI-PM power management must be explicitly enabled via
* the data link control register.
*/
BHNDB_PCIE_QUIRK_PCIPM_REQEN = (1<<7),
/**
* Fix L0s to L0 exit transition on SerDes <= rev9 devices.
*
* On these devices, PCIe/SerDes symbol lock can be lost if the
* reference clock has not fully stabilized during the L0s to L0
* exit transition, triggering an internal reset of the chip.
*
* The SerDes RX CDR phase lock timers and proportional/integral
* filters must be tweaked to ensure the CDR has fully stabilized
* before asserting receive sequencer completion.
*/
BHNDB_PCIE_QUIRK_SDR9_L0s_HANG = (1<<8),
/**
* The idle time for entering L1 low-power state must be
* explicitly set (to 114ns) to fix slow L1->L0 transition issues.
*/
BHNDB_PCIE_QUIRK_L1_IDLE_THRESH = (1<<9),
/**
* The ASPM L1 entry timer should be extended for better performance,
* and restored for better power savings.
*/
BHNDB_PCIE_QUIRK_L1_TIMER_PERF = (1<<10),
/**
* ASPM and ECPM settings must be overridden manually.
*
* The override behavior is controlled by the BHND_BFL2_PCIEWAR_OVR
* flag. If this flag is set, ASPM/CLKREQ should be overridden as
* enabled; otherwise, they should be overridden as disabled.
*
* Attach/Resume:
* - Set SRSH_ASPM_ENB flag in the SPROM ASPM register.
* - Set ASPM L0S/L1 in the PCIER_LINK_CTL register.
* - Set SRSH_CLKREQ_ENB flag in the SPROM CLKREQ_REV5 register.
* - Clear ECPM in the PCIER_LINK_CTL register.
*
* Detach/Suspend:
* -
* - When the device enters D3 state, or system enters S3/S4 state,
* clear ASPM L1 in the PCIER_LINK_CTL register.
*/
BHNDB_PCIE_QUIRK_ASPM_OVR = (1<<11),
/**
* Fix SerDes polarity on SerDes <= rev9 devices.
*
* The SerDes polarity must be saved at device attachment, and
* restored on suspend/resume.
*/
BHNDB_PCIE_QUIRK_SDR9_POLARITY = (1<<12),
/**
* The SerDes PLL override flag (CHIPCTRL_4321_PLL_DOWN) must be set on
* the ChipCommon core on resume.
*/
BHNDB_PCIE_QUIRK_SERDES_NOPLLDOWN = (1<<13),
/**
* On attach and resume, consult the SPROM to determine whether
* the L2/L3-Ready w/o PCI RESET work-around must be applied.
*
* If L23READY_EXIT_NOPRST is not already set in the SPROM, set it
*/
BHNDB_PCIE_QUIRK_SPROM_L23_PCI_RESET = (1<<14),
/**
* The PCIe SerDes supports non-standard extended MDIO register access.
*
* The PCIe SerDes supports access to extended MDIO registers via
* a non-standard Clause 22 address extension mechanism.
*/
BHNDB_PCIE_QUIRK_SD_C22_EXTADDR = (1<<15),
/**
* The PCIe SerDes PLL must be configured to not retry the startup
* sequence upon frequency detection failure on SerDes <= rev9 devices
*
* The issue this workaround resolves has not be determined.
*/
BHNDB_PCIE_QUIRK_SDR9_NO_FREQRETRY = (1<<16),
};
#endif /* _BHND_BHNDB_PCIVAR_H_ */

View file

@ -0,0 +1,239 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
* $FreeBSD$
*/
#ifndef _BHND_BHNDB_PRIVATE_H_
#define _BHND_BHNDB_PRIVATE_H_
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/systm.h>
#include <machine/bus.h>
#include <sys/rman.h>
#include <machine/resource.h>
#include "bhndbvar.h"
/*
* Private bhndb(4) driver definitions.
*/
struct bhndb_dw_alloc;
struct bhndb_region;
struct bhndb_resources;
struct resource *bhndb_find_regwin_resource(
struct bhndb_resources *br,
const struct bhndb_regwin *win);
struct bhndb_resources *bhndb_alloc_resources(device_t dev,
device_t parent_dev,
const struct bhndb_hwcfg *cfg);
void bhndb_free_resources(
struct bhndb_resources *br);
int bhndb_add_resource_region(
struct bhndb_resources *br,
bhnd_addr_t addr, bhnd_size_t size,
bhndb_priority_t priority,
const struct bhndb_regwin *static_regwin);
struct bhndb_region *bhndb_find_resource_region(
struct bhndb_resources *br,
bhnd_addr_t addr, bhnd_size_t size);
struct bhndb_dw_alloc *bhndb_dw_find_resource(
struct bhndb_resources *dr,
struct resource *r);
struct bhndb_dw_alloc *bhndb_dw_find_mapping(
struct bhndb_resources *br,
bhnd_addr_t addr, bhnd_size_t size);
int bhndb_dw_retain(
struct bhndb_resources *br,
struct bhndb_dw_alloc *dwa,
struct resource *res);
void bhndb_dw_release(
struct bhndb_resources *br,
struct bhndb_dw_alloc *dwa,
struct resource *res);
int bhndb_dw_set_addr(device_t dev,
struct bhndb_resources *br,
struct bhndb_dw_alloc *dwa,
bus_addr_t addr, bus_size_t size);
size_t bhndb_regwin_count(
const struct bhndb_regwin *table,
bhndb_regwin_type_t type);
const struct bhndb_regwin *bhndb_regwin_find_type(
const struct bhndb_regwin *table,
bhndb_regwin_type_t type,
bus_size_t min_size);
const struct bhndb_regwin *bhndb_regwin_find_core(
const struct bhndb_regwin *table,
bhnd_devclass_t class, int unit,
bhnd_port_type port_type, u_int port,
u_int region);
const struct bhndb_regwin *bhndb_regwin_find_best(
const struct bhndb_regwin *table,
bhnd_devclass_t class, int unit,
bhnd_port_type port_type, u_int port,
u_int region, bus_size_t min_size);
bool bhndb_regwin_matches_device(
const struct bhndb_regwin *regw,
device_t dev);
const struct bhndb_hw_priority *bhndb_hw_priority_find_device(
const struct bhndb_hw_priority *table,
device_t device);
/**
* Dynamic register window allocation reference.
*/
struct bhndb_dw_rentry {
struct resource *dw_res; /**< child resource */
LIST_ENTRY(bhndb_dw_rentry) dw_link;
};
/**
* A dynamic register window allocation record.
*/
struct bhndb_dw_alloc {
const struct bhndb_regwin *win; /**< window definition */
struct resource *parent_res; /**< enclosing resource */
u_int rnid; /**< region identifier */
rman_res_t target; /**< the current window address, or 0x0 if unknown */
LIST_HEAD(, bhndb_dw_rentry) refs; /**< references */
};
/**
* A bus address region description.
*/
struct bhndb_region {
bhnd_addr_t addr; /**< start of mapped range */
bhnd_size_t size; /**< size of mapped range */
bhndb_priority_t priority; /**< direct resource allocation priority */
const struct bhndb_regwin *static_regwin; /**< fixed mapping regwin, if any */
STAILQ_ENTRY(bhndb_region) link;
};
/**
* BHNDB resource allocation state.
*/
struct bhndb_resources {
device_t dev; /**< bridge device */
const struct bhndb_hwcfg *cfg; /**< hardware configuration */
device_t parent_dev; /**< parent device */
struct resource_spec *res_spec; /**< parent bus resource specs */
struct resource **res; /**< parent bus resources */
STAILQ_HEAD(, bhndb_region) bus_regions; /**< bus region descriptors */
struct bhndb_dw_alloc *dw_alloc; /**< dynamic window allocation records */
size_t dwa_count; /**< number of dynamic windows available. */
uint32_t dwa_freelist; /**< dynamic window free list */
bhndb_priority_t min_prio; /**< minimum resource priority required to
allocate a dynamic window */
};
/**
* Returns true if the all dynamic windows have been exhausted, false
* otherwise.
*
* @param br The resource state to check.
*/
static inline bool
bhndb_dw_exhausted(struct bhndb_resources *br)
{
return (br->dwa_freelist == 0);
}
/**
* Find the next free dynamic window region in @p br.
*
* @param br The resource state to search.
*/
static inline struct bhndb_dw_alloc *
bhndb_dw_next_free(struct bhndb_resources *br)
{
struct bhndb_dw_alloc *dw_free;
if (bhndb_dw_exhausted(br))
return (NULL);
dw_free = &br->dw_alloc[__builtin_ctz(br->dwa_freelist)];
KASSERT(LIST_EMPTY(&dw_free->refs),
("free list out of sync with refs"));
return (dw_free);
}
/**
* Returns true if a dynamic window allocation is marked as free.
*
* @param br The resource state owning @p dwa.
* @param dwa The dynamic window allocation record to be checked.
*/
static inline bool
bhndb_dw_is_free(struct bhndb_resources *br, struct bhndb_dw_alloc *dwa)
{
bool is_free = LIST_EMPTY(&dwa->refs);
KASSERT(is_free == ((br->dwa_freelist & (1 << dwa->rnid)) != 0),
("refs out of sync with free list"));
return (is_free);
}
#define BHNDB_LOCK_INIT(sc) \
mtx_init(&(sc)->sc_mtx, device_get_nameunit((sc)->dev), \
"bhndb resource allocator lock", MTX_DEF)
#define BHNDB_LOCK(sc) mtx_lock(&(sc)->sc_mtx)
#define BHNDB_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx)
#define BHNDB_LOCK_ASSERT(sc, what) mtx_assert(&(sc)->sc_mtx, what)
#define BHNDB_LOCK_DESTROY(sc) mtx_destroy(&(sc)->sc_mtx)
#endif /* _BHND_BHNDB_PRIVATE_H_ */

View file

@ -0,0 +1,889 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/kernel.h>
#include "bhndb_private.h"
#include "bhndbvar.h"
/**
* Attach a BHND bridge device to @p parent.
*
* @param parent A parent PCI device.
* @param[out] bhndb On success, the probed and attached bhndb bridge device.
* @param unit The device unit number, or -1 to select the next available unit
* number.
*
* @retval 0 success
* @retval non-zero Failed to attach the bhndb device.
*/
int
bhndb_attach_bridge(device_t parent, device_t *bhndb, int unit)
{
int error;
*bhndb = device_add_child(parent, devclass_get_name(bhndb_devclass),
unit);
if (*bhndb == NULL)
return (ENXIO);
if (!(error = device_probe_and_attach(*bhndb)))
return (0);
if ((device_delete_child(parent, *bhndb)))
device_printf(parent, "failed to detach bhndb child\n");
return (error);
}
/*
* Call BHNDB_SUSPEND_RESOURCE() for all resources in @p rl.
*/
static void
bhndb_do_suspend_resources(device_t dev, struct resource_list *rl)
{
struct resource_list_entry *rle;
/* Suspend all child resources. */
STAILQ_FOREACH(rle, rl, link) {
/* Skip non-allocated resources */
if (rle->res == NULL)
continue;
BHNDB_SUSPEND_RESOURCE(device_get_parent(dev), dev, rle->type,
rle->res);
}
}
/**
* Helper function for implementing BUS_RESUME_CHILD() on bridged
* bhnd(4) buses.
*
* This implementation of BUS_RESUME_CHILD() uses BUS_GET_RESOURCE_LIST()
* to find the child's resources and call BHNDB_SUSPEND_RESOURCE() for all
* child resources, ensuring that the device's allocated bridge resources
* will be available to other devices during bus resumption.
*
* Before suspending any resources, @p child is suspended by
* calling bhnd_generic_suspend_child().
*
* If @p child is not a direct child of @p dev, suspension is delegated to
* the @p dev parent.
*/
int
bhnd_generic_br_suspend_child(device_t dev, device_t child)
{
struct resource_list *rl;
int error;
if (device_get_parent(child) != dev)
BUS_SUSPEND_CHILD(device_get_parent(dev), child);
if (device_is_suspended(child))
return (EBUSY);
/* Suspend the child device */
if ((error = bhnd_generic_suspend_child(dev, child)))
return (error);
/* Fetch the resource list. If none, there's nothing else to do */
rl = BUS_GET_RESOURCE_LIST(device_get_parent(child), child);
if (rl == NULL)
return (0);
/* Suspend all child resources. */
bhndb_do_suspend_resources(dev, rl);
return (0);
}
/**
* Helper function for implementing BUS_RESUME_CHILD() on bridged
* bhnd(4) bus devices.
*
* This implementation of BUS_RESUME_CHILD() uses BUS_GET_RESOURCE_LIST()
* to find the child's resources and call BHNDB_RESUME_RESOURCE() for all
* child resources, before delegating to bhnd_generic_resume_child().
*
* If resource resumption fails, @p child will not be resumed.
*
* If @p child is not a direct child of @p dev, suspension is delegated to
* the @p dev parent.
*/
int
bhnd_generic_br_resume_child(device_t dev, device_t child)
{
struct resource_list *rl;
struct resource_list_entry *rle;
int error;
if (device_get_parent(child) != dev)
BUS_RESUME_CHILD(device_get_parent(dev), child);
if (!device_is_suspended(child))
return (EBUSY);
/* Fetch the resource list. If none, there's nothing else to do */
rl = BUS_GET_RESOURCE_LIST(device_get_parent(child), child);
if (rl == NULL)
return (bhnd_generic_resume_child(dev, child));
/* Resume all resources */
STAILQ_FOREACH(rle, rl, link) {
/* Skip non-allocated resources */
if (rle->res == NULL)
continue;
error = BHNDB_RESUME_RESOURCE(device_get_parent(dev), dev,
rle->type, rle->res);
if (error) {
/* Put all resources back into a suspend state */
bhndb_do_suspend_resources(dev, rl);
return (error);
}
}
/* Now that all resources are resumed, resume child */
if ((error = bhnd_generic_resume_child(dev, child))) {
/* Put all resources back into a suspend state */
bhndb_do_suspend_resources(dev, rl);
}
return (error);
}
/**
* Find the resource containing @p win.
*
* @param br The bhndb resource state to search.
* @param win A register window.
*
* @retval resource the resource containing @p win.
* @retval NULL if no resource containing @p win can be found.
*/
struct resource *
bhndb_find_regwin_resource(struct bhndb_resources *br,
const struct bhndb_regwin *win)
{
const struct resource_spec *rspecs;
rspecs = br->cfg->resource_specs;
for (u_int i = 0; rspecs[i].type != -1; i++) {
if (win->res.type != rspecs[i].type)
continue;
if (win->res.rid != rspecs[i].rid)
continue;
/* Found declared resource */
return (br->res[i]);
}
device_printf(br->dev,
"missing regwin resource spec (type=%d, rid=%d)\n",
win->res.type, win->res.rid);
return (NULL);
}
/**
* Allocate and initialize a new resource state structure, allocating
* bus resources from @p parent_dev according to @p cfg.
*
* @param dev The bridge device.
* @param parent_dev The parent device from which resources will be allocated.
* @param cfg The hardware configuration to be used.
*/
struct bhndb_resources *
bhndb_alloc_resources(device_t dev, device_t parent_dev,
const struct bhndb_hwcfg *cfg)
{
struct bhndb_resources *r;
const struct bhndb_regwin *win;
bus_size_t last_window_size;
size_t res_num;
u_int rnid;
int error;
bool free_parent_res;
free_parent_res = false;
r = malloc(sizeof(*r), M_BHND, M_NOWAIT|M_ZERO);
if (r == NULL)
return (NULL);
/* Basic initialization */
r->dev = dev;
r->parent_dev = parent_dev;
r->cfg = cfg;
r->min_prio = BHNDB_PRIORITY_NONE;
STAILQ_INIT(&r->bus_regions);
/* Determine our bridge resource count from the hardware config. */
res_num = 0;
for (size_t i = 0; cfg->resource_specs[i].type != -1; i++)
res_num++;
/* Allocate space for a non-const copy of our resource_spec
* table; this will be updated with the RIDs assigned by
* bus_alloc_resources. */
r->res_spec = malloc(sizeof(r->res_spec[0]) * (res_num + 1), M_BHND,
M_NOWAIT);
if (r->res_spec == NULL)
goto failed;
/* Initialize and terminate the table */
for (size_t i = 0; i < res_num; i++)
r->res_spec[i] = cfg->resource_specs[i];
r->res_spec[res_num].type = -1;
/* Allocate space for our resource references */
r->res = malloc(sizeof(r->res[0]) * res_num, M_BHND, M_NOWAIT);
if (r->res == NULL)
goto failed;
/* Allocate resources */
error = bus_alloc_resources(r->parent_dev, r->res_spec, r->res);
if (error) {
device_printf(r->dev,
"could not allocate bridge resources on %s: %d\n",
device_get_nameunit(r->parent_dev), error);
goto failed;
} else {
free_parent_res = true;
}
/* Fetch the dynamic regwin count and verify that it does not exceed
* what is representable via our freelist bitmask. */
r->dwa_count = bhndb_regwin_count(cfg->register_windows,
BHNDB_REGWIN_T_DYN);
if (r->dwa_count >= (8 * sizeof(r->dwa_freelist))) {
device_printf(r->dev, "max dynamic regwin count exceeded\n");
goto failed;
}
/* Allocate the dynamic window allocation table. */
r->dw_alloc = malloc(sizeof(r->dw_alloc[0]) * r->dwa_count, M_BHND,
M_NOWAIT);
if (r->dw_alloc == NULL)
goto failed;
/* Initialize the dynamic window table and freelist. */
r->dwa_freelist = 0;
rnid = 0;
last_window_size = 0;
for (win = cfg->register_windows;
win->win_type != BHNDB_REGWIN_T_INVALID; win++)
{
struct bhndb_dw_alloc *dwa;
/* Skip non-DYN windows */
if (win->win_type != BHNDB_REGWIN_T_DYN)
continue;
/* Validate the window size */
if (win->win_size == 0) {
device_printf(r->dev, "ignoring zero-length dynamic "
"register window\n");
continue;
} else if (last_window_size == 0) {
last_window_size = win->win_size;
} else if (last_window_size != win->win_size) {
/*
* No existing hardware should trigger this.
*
* If you run into this in the future, the dynamic
* window allocator and the resource priority system
* will need to be extended to support multiple register
* window allocation pools.
*/
device_printf(r->dev, "devices that vend multiple "
"dynamic register window sizes are not currently "
"supported\n");
goto failed;
}
dwa = &r->dw_alloc[rnid];
dwa->win = win;
dwa->parent_res = NULL;
dwa->rnid = rnid;
dwa->target = 0x0;
LIST_INIT(&dwa->refs);
/* Find and validate corresponding resource. */
dwa->parent_res = bhndb_find_regwin_resource(r, win);
if (dwa->parent_res == NULL)
goto failed;
if (rman_get_size(dwa->parent_res) < win->win_offset +
win->win_size)
{
device_printf(r->dev, "resource %d too small for "
"register window with offset %llx and size %llx\n",
rman_get_rid(dwa->parent_res),
(unsigned long long) win->win_offset,
(unsigned long long) win->win_size);
error = EINVAL;
goto failed;
}
/* Add to freelist */
r->dwa_freelist |= (1 << rnid);
rnid++;
}
return (r);
failed:
if (free_parent_res)
bus_release_resources(r->parent_dev, r->res_spec, r->res);
if (r->res != NULL)
free(r->res, M_BHND);
if (r->res_spec != NULL)
free(r->res_spec, M_BHND);
if (r->dw_alloc != NULL)
free(r->dw_alloc, M_BHND);
free (r, M_BHND);
return (NULL);
}
/**
* Deallocate the given bridge resource structure and any associated resources.
*
* @param br Resource state to be deallocated.
*/
void
bhndb_free_resources(struct bhndb_resources *br)
{
struct bhndb_region *region, *r_next;
struct bhndb_dw_alloc *dwa;
struct bhndb_dw_rentry *dwr, *dwr_next;
/* No window regions may still be held */
if (__builtin_popcount(br->dwa_freelist) != br->dwa_count) {
device_printf(br->dev, "leaked %llu dynamic register regions\n",
(unsigned long long) br->dwa_count - br->dwa_freelist);
}
/* Release resources allocated through our parent. */
bus_release_resources(br->parent_dev, br->res_spec, br->res);
/* Clean up resource reservations */
for (size_t i = 0; i < br->dwa_count; i++) {
dwa = &br->dw_alloc[i];
LIST_FOREACH_SAFE(dwr, &dwa->refs, dw_link, dwr_next) {
LIST_REMOVE(dwr, dw_link);
free(dwr, M_BHND);
}
}
/* Release bus regions */
STAILQ_FOREACH_SAFE(region, &br->bus_regions, link, r_next) {
STAILQ_REMOVE(&br->bus_regions, region, bhndb_region, link);
free(region, M_BHND);
}
/* Free backing resource state structures */
free(br->res, M_BHND);
free(br->res_spec, M_BHND);
free(br->dw_alloc, M_BHND);
}
/**
* Add a bus region entry to @p r for the given base @p addr and @p size.
*
* @param br The resource state to which the bus region entry will be added.
* @param addr The base address of this region.
* @param size The size of this region.
* @param priority The resource priority to be assigned to allocations
* made within this bus region.
* @param static_regwin If available, a static register window mapping this
* bus region entry. If not available, NULL.
*
* @retval 0 success
* @retval non-zero if adding the bus region fails.
*/
int
bhndb_add_resource_region(struct bhndb_resources *br, bhnd_addr_t addr,
bhnd_size_t size, bhndb_priority_t priority,
const struct bhndb_regwin *static_regwin)
{
struct bhndb_region *reg;
/* Insert in the bus resource list */
reg = malloc(sizeof(*reg), M_BHND, M_NOWAIT);
if (reg == NULL)
return (ENOMEM);
*reg = (struct bhndb_region) {
.addr = addr,
.size = size,
.priority = priority,
.static_regwin = static_regwin
};
STAILQ_INSERT_HEAD(&br->bus_regions, reg, link);
return (0);
}
/**
* Find a bus region that maps @p size bytes at @p addr.
*
* @param br The resource state to search.
* @param addr The requested starting address.
* @param size The requested size.
*
* @retval bhndb_region A region that fully contains the requested range.
* @retval NULL If no mapping region can be found.
*/
struct bhndb_region *
bhndb_find_resource_region(struct bhndb_resources *br, bhnd_addr_t addr,
bhnd_size_t size)
{
struct bhndb_region *region;
STAILQ_FOREACH(region, &br->bus_regions, link) {
/* Request must fit within the region's mapping */
if (addr < region->addr)
continue;
if (addr + size > region->addr + region->size)
continue;
return (region);
}
/* Not found */
return (NULL);
}
/**
* Find the entry matching @p r in @p dwa's references, if any.
*
* @param dwa The dynamic window allocation to search
* @param r The resource to search for in @p dwa.
*/
static struct bhndb_dw_rentry *
bhndb_dw_find_resource_entry(struct bhndb_dw_alloc *dwa, struct resource *r)
{
struct bhndb_dw_rentry *rentry;
LIST_FOREACH(rentry, &dwa->refs, dw_link) {
struct resource *dw_res = rentry->dw_res;
/* Match dev/rid/addr/size */
if (rman_get_device(dw_res) != rman_get_device(r) ||
rman_get_rid(dw_res) != rman_get_rid(r) ||
rman_get_start(dw_res) != rman_get_start(r) ||
rman_get_size(dw_res) != rman_get_size(r))
{
continue;
}
/* Matching allocation found */
return (rentry);
}
return (NULL);
}
/**
* Find the dynamic region allocated for @p r, if any.
*
* @param br The resource state to search.
* @param r The resource to search for.
*
* @retval bhndb_dw_alloc The allocation record for @p r.
* @retval NULL if no dynamic window is allocated for @p r.
*/
struct bhndb_dw_alloc *
bhndb_dw_find_resource(struct bhndb_resources *br, struct resource *r)
{
struct bhndb_dw_alloc *dwa;
for (size_t i = 0; i < br->dwa_count; i++) {
dwa = &br->dw_alloc[i];
/* Skip free dynamic windows */
if (bhndb_dw_is_free(br, dwa))
continue;
/* Matching allocation found? */
if (bhndb_dw_find_resource_entry(dwa, r) != NULL)
return (dwa);
}
return (NULL);
}
/**
* Find an existing dynamic window mapping @p size bytes
* at @p addr. The window may or may not be free.
*
* @param br The resource state to search.
* @param addr The requested starting address.
* @param size The requested size.
*
* @retval bhndb_dw_alloc A window allocation that fully contains the requested
* range.
* @retval NULL If no mapping region can be found.
*/
struct bhndb_dw_alloc *
bhndb_dw_find_mapping(struct bhndb_resources *br, bhnd_addr_t addr,
bhnd_size_t size)
{
struct bhndb_dw_alloc *dwr;
const struct bhndb_regwin *win;
/* Search for an existing dynamic mapping of this address range. */
for (size_t i = 0; i < br->dwa_count; i++) {
dwr = &br->dw_alloc[i];
win = dwr->win;
/* Verify the range */
if (addr < dwr->target)
continue;
if (addr + size > dwr->target + win->win_size)
continue;
/* Found a usable mapping */
return (dwr);
}
/* not found */
return (NULL);
}
/**
* Retain a reference to @p dwa for use by @p res.
*
* @param br The resource state owning @p dwa.
* @param dwa The allocation record to be retained.
* @param res The resource that will own a reference to @p dwa.
*
* @retval 0 success
* @retval ENOMEM Failed to allocate a new reference structure.
*/
int
bhndb_dw_retain(struct bhndb_resources *br, struct bhndb_dw_alloc *dwa,
struct resource *res)
{
struct bhndb_dw_rentry *rentry;
KASSERT(bhndb_dw_find_resource_entry(dwa, res) == NULL,
("double-retain of dynamic window for same resource"));
/* Insert a reference entry; we use M_NOWAIT to allow use from
* within a non-sleepable lock */
rentry = malloc(sizeof(*rentry), M_BHND, M_NOWAIT);
if (rentry == NULL)
return (ENOMEM);
rentry->dw_res = res;
LIST_INSERT_HEAD(&dwa->refs, rentry, dw_link);
/* Update the free list */
br->dwa_freelist &= ~(1 << (dwa->rnid));
return (0);
}
/**
* Release a reference to @p dwa previously retained by @p res. If the
* reference count of @p dwa reaches zero, it will be added to the
* free list.
*
* @param br The resource state owning @p dwa.
* @param dwa The allocation record to be released.
* @param res The resource that currently owns a reference to @p dwa.
*/
void
bhndb_dw_release(struct bhndb_resources *br, struct bhndb_dw_alloc *dwa,
struct resource *r)
{
struct bhndb_dw_rentry *rentry;
/* Find the rentry */
rentry = bhndb_dw_find_resource_entry(dwa, r);
KASSERT(rentry != NULL, ("over release of resource entry"));
LIST_REMOVE(rentry, dw_link);
free(rentry, M_BHND);
/* If this was the last reference, update the free list */
if (LIST_EMPTY(&dwa->refs))
br->dwa_freelist |= (1 << (dwa->rnid));
}
/**
* Attempt to set (or reset) the target address of @p dwa to map @p size bytes
* at @p addr.
*
* This will apply any necessary window alignment and verify that
* the window is capable of mapping the requested range prior to modifying
* therecord.
*
* @param dev The device on which to issue the BHNDB_SET_WINDOW_ADDR() request.
* @param br The resource state owning @p dwa.
* @param dwa The allocation record to be configured.
* @param addr The address to be mapped via @p dwa.
* @param size The number of bytes to be mapped at @p addr.
*
* @retval 0 success
* @retval non-zero no usable register window available.
*/
int
bhndb_dw_set_addr(device_t dev, struct bhndb_resources *br,
struct bhndb_dw_alloc *dwa, bus_addr_t addr, bus_size_t size)
{
const struct bhndb_regwin *rw;
bus_addr_t offset;
int error;
rw = dwa->win;
KASSERT(bhndb_dw_is_free(br, dwa),
("attempting to set the target address on an in-use window"));
/* Page-align the target address */
offset = addr % rw->win_size;
dwa->target = addr - offset;
/* Verify that the window is large enough for the full target */
if (rw->win_size - offset < size)
return (ENOMEM);
/* Update the window target */
error = BHNDB_SET_WINDOW_ADDR(dev, dwa->win, dwa->target);
if (error) {
dwa->target = 0x0;
return (error);
}
return (0);
}
/**
* Return the count of @p type register windows in @p table.
*
* @param table The table to search.
* @param type The required window type, or BHNDB_REGWIN_T_INVALID to
* count all register window types.
*/
size_t
bhndb_regwin_count(const struct bhndb_regwin *table,
bhndb_regwin_type_t type)
{
const struct bhndb_regwin *rw;
size_t count;
count = 0;
for (rw = table; rw->win_type != BHNDB_REGWIN_T_INVALID; rw++) {
if (type == BHNDB_REGWIN_T_INVALID || rw->win_type == type)
count++;
}
return (count);
}
/**
* Search @p table for the first window with the given @p type.
*
* @param table The table to search.
* @param type The required window type.
* @param min_size The minimum window size.
*
* @retval bhndb_regwin The first matching window.
* @retval NULL If no window of the requested type could be found.
*/
const struct bhndb_regwin *
bhndb_regwin_find_type(const struct bhndb_regwin *table,
bhndb_regwin_type_t type, bus_size_t min_size)
{
const struct bhndb_regwin *rw;
for (rw = table; rw->win_type != BHNDB_REGWIN_T_INVALID; rw++)
{
if (rw->win_type == type && rw->win_size >= min_size)
return (rw);
}
return (NULL);
}
/**
* Search @p windows for the first matching core window.
*
* @param table The table to search.
* @param class The required core class.
* @param unit The required core unit, or -1.
* @param port_type The required port type.
* @param port The required port.
* @param region The required region.
*
* @retval bhndb_regwin The first matching window.
* @retval NULL If no matching window was found.
*/
const struct bhndb_regwin *
bhndb_regwin_find_core(const struct bhndb_regwin *table, bhnd_devclass_t class,
int unit, bhnd_port_type port_type, u_int port, u_int region)
{
const struct bhndb_regwin *rw;
for (rw = table; rw->win_type != BHNDB_REGWIN_T_INVALID; rw++)
{
if (rw->win_type != BHNDB_REGWIN_T_CORE)
continue;
if (rw->core.class != class)
continue;
if (unit != -1 && rw->core.unit != unit)
continue;
if (rw->core.port_type != port_type)
continue;
if (rw->core.port != port)
continue;
if (rw->core.region != region)
continue;
return (rw);
}
return (NULL);
}
/**
* Search @p windows for the best available window of at least @p min_size.
*
* Search order:
* - BHND_REGWIN_T_CORE
* - BHND_REGWIN_T_DYN
*
* @param table The table to search.
* @param class The required core class.
* @param unit The required core unit, or -1.
* @param port_type The required port type.
* @param port The required port.
* @param region The required region.
* @param min_size The minimum window size.
*
* @retval bhndb_regwin The first matching window.
* @retval NULL If no matching window was found.
*/
const struct bhndb_regwin *
bhndb_regwin_find_best(const struct bhndb_regwin *table,
bhnd_devclass_t class, int unit, bhnd_port_type port_type, u_int port,
u_int region, bus_size_t min_size)
{
const struct bhndb_regwin *rw;
/* Prefer a fixed core mapping */
rw = bhndb_regwin_find_core(table, class, unit, port_type,
port, region);
if (rw != NULL)
return (rw);
/* Fall back on a generic dynamic window */
return (bhndb_regwin_find_type(table, BHNDB_REGWIN_T_DYN, min_size));
}
/**
* Return true if @p regw defines a static port register window, and
* the mapped port is actually defined on @p dev.
*
* @param regw A register window to match against.
* @param dev A bhnd(4) bus device.
*/
bool
bhndb_regwin_matches_device(const struct bhndb_regwin *regw, device_t dev)
{
/* Only core windows are supported */
if (regw->win_type != BHNDB_REGWIN_T_CORE)
return (false);
/* Device class must match */
if (bhnd_get_class(dev) != regw->core.class)
return (false);
/* Device unit must match */
if (bhnd_get_core_unit(dev) != regw->core.unit)
return (false);
/* The regwin port/region must be defined. */
if (!bhnd_is_region_valid(dev, regw->core.port_type, regw->core.port,
regw->core.region))
{
return (false);
}
/* Matches */
return (true);
}
/**
* Search for a core resource priority descriptor in @p table that matches
* @p device.
*
* @param table The table to search.
* @param device A bhnd(4) bus device.
*/
const struct bhndb_hw_priority *
bhndb_hw_priority_find_device(const struct bhndb_hw_priority *table,
device_t device)
{
const struct bhndb_hw_priority *hp;
for (hp = table; hp->ports != NULL; hp++) {
if (bhnd_device_matches(device, &hp->match))
return (hp);
}
/* not found */
return (NULL);
}

View file

@ -0,0 +1,94 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
* $FreeBSD$
*/
#ifndef _BHND_BHNDBVAR_H_
#define _BHND_BHNDBVAR_H_
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
#include <sys/mutex.h>
#include <sys/rman.h>
#include <dev/bhnd/bhndvar.h>
#include "bhndb.h"
#include "bhndb_if.h"
/*
* Definitions shared by bhndb(4) driver implementations.
*/
DECLARE_CLASS(bhndb_driver);
struct bhndb_resources;
int bhndb_attach(device_t dev, bhnd_devclass_t bridge_devclass);
int bhndb_generic_probe(device_t dev);
int bhndb_generic_detach(device_t dev);
int bhndb_generic_suspend(device_t dev);
int bhndb_generic_resume(device_t dev);
int bhndb_generic_init_full_config(device_t dev, device_t child,
const struct bhndb_hw_priority *hw_prio_table);
int bhnd_generic_br_suspend_child(device_t dev, device_t child);
int bhnd_generic_br_resume_child(device_t dev, device_t child);
/** bhndb child instance state */
struct bhndb_devinfo {
struct resource_list resources; /**< child resources. */
};
/**
* bhndb driver instance state. Must be first member of all subclass
* softc structures.
*/
struct bhndb_softc {
device_t dev; /**< bridge device */
struct bhnd_chipid chipid; /**< chip identification */
bhnd_devclass_t bridge_class; /**< bridge core type */
device_t parent_dev; /**< parent device */
device_t bus_dev; /**< child bhnd(4) bus */
device_t hostb_dev; /**< child host bridge device, or NULL
if the @p bus_dev has not yet
called BHNDB_INIT_FULL_CONFIG() */
struct rman mem_rman; /**< bridged bus memory manager */
struct mtx sc_mtx; /**< resource lock. */
struct bhndb_resources *bus_res; /**< bus resource state */
};
#endif /* _BHND_BHNDBVAR_H_ */

48
sys/dev/bhnd/bhndreg.h Normal file
View file

@ -0,0 +1,48 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
* $FreeBSD$
*/
#ifndef _BHND_BHNDREG_H_
#define _BHND_BHNDREG_H_
/**
* The default address at which the ChipCommon core is mapped on all siba(4)
* devices, and most bcma(4) devices.
*/
#define BHND_DEFAULT_CHIPC_ADDR 0x18000000
/**
* The standard size of a primary BHND_PORT_DEVICE or BHND_PORT_AGENT
* register block.
*/
#define BHND_DEFAULT_CORE_SIZE 0x1000
#endif /* _BHND_BHNDREG_H_ */

106
sys/dev/bhnd/bhndvar.h Normal file
View file

@ -0,0 +1,106 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
* $FreeBSD$
*/
#ifndef _BHND_BHNDVAR_H_
#define _BHND_BHNDVAR_H_
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/malloc.h>
#include "bhnd.h"
/*
* Definitions shared by bhnd(4) bus and bhndb(4) bridge driver implementations.
*/
MALLOC_DECLARE(M_BHND);
DECLARE_CLASS(bhnd_driver);
/**
* bhnd driver instance state. Must be first member of all subclass
* softc structures.
*/
struct bhnd_softc {};
int bhnd_generic_attach(device_t dev);
int bhnd_generic_detach(device_t dev);
int bhnd_generic_shutdown(device_t dev);
int bhnd_generic_resume(device_t dev);
int bhnd_generic_suspend(device_t dev);
int bhnd_generic_get_probe_order(device_t dev,
device_t child);
int bhnd_generic_print_child(device_t dev,
device_t child);
void bhnd_generic_probe_nomatch(device_t dev,
device_t child);
int bhnd_generic_suspend_child(device_t dev,
device_t child);
int bhnd_generic_resume_child(device_t dev,
device_t child);
bool bhnd_generic_is_hostb_device(device_t dev,
device_t child);
bool bhnd_generic_is_hw_disabled(device_t dev,
device_t child);
bool bhnd_generic_is_region_valid(device_t dev,
device_t child, bhnd_port_type type, u_int port,
u_int region);
int bhnd_generic_read_nvram_var(device_t dev,
device_t child, const char *name, void *buf,
size_t *size);
const struct bhnd_chipid *bhnd_generic_get_chipid(device_t dev, device_t child);
struct bhnd_resource *bhnd_generic_alloc_bhnd_resource (device_t dev,
device_t child, int type, int *rid,
rman_res_t start, rman_res_t end, rman_res_t count,
u_int flags);
int bhnd_generic_release_bhnd_resource (device_t dev,
device_t child, int type, int rid,
struct bhnd_resource *r);
int bhnd_generic_activate_bhnd_resource (device_t dev,
device_t child, int type, int rid,
struct bhnd_resource *r);
int bhnd_generic_deactivate_bhnd_resource (device_t dev,
device_t child, int type, int rid,
struct bhnd_resource *r);
#endif /* _BHND_BHNDVAR_H_ */

View file

@ -0,0 +1,46 @@
#-
# Copyright (c) 2016 Landon Fuller <landon@landonf.org>
# 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 <sys/types.h>
#include <sys/bus.h>
#include <dev/bhnd/bhnd.h>
#include <dev/bhnd/nvram/bhnd_nvram.h>
INTERFACE bhnd_chipc;
#
# bhnd(4) ChipCommon interface.
#
/**
* Return the preferred NVRAM data source.
*
* @param dev A bhnd(4) ChipCommon device.
*/
METHOD bhnd_nvram_src_t nvram_src {
device_t dev;
}

View file

@ -0,0 +1,319 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* 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 <sys/cdefs.h>
__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 <sys/param.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/module.h>
#include <sys/systm.h>
#include <machine/bus.h>
#include <sys/rman.h>
#include <machine/resource.h>
#include <dev/bhnd/bhnd.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 }
};
/* Supported device identifiers */
static const struct chipc_device {
uint16_t device;
} chipc_devices[] = {
{ BHND_COREID_CC },
{ BHND_COREID_INVALID }
};
/* Device quirks table */
static struct bhnd_device_quirk chipc_quirks[] = {
BHND_QUIRK_HWREV_RANGE (0, 21, CHIPC_QUIRK_ALWAYS_HAS_SPROM),
BHND_QUIRK_HWREV_EQ (22, CHIPC_QUIRK_SPROM_CHECK_CST_R22),
BHND_QUIRK_HWREV_RANGE (23, 31, CHIPC_QUIRK_SPROM_CHECK_CST_R23),
BHND_QUIRK_HWREV_GTE (35, CHIPC_QUIRK_SUPPORTS_NFLASH),
BHND_QUIRK_HWREV_END
};
/* quirk and capability flag convenience macros */
#define CHIPC_QUIRK(_sc, _name) \
((_sc)->quirks & CHIPC_QUIRK_ ## _name)
#define CHIPC_CAP(_sc, _name) \
((_sc)->caps & CHIPC_ ## _name)
#define CHIPC_ASSERT_QUIRK(_sc, name) \
KASSERT(CHIPC_QUIRK((_sc), name), ("quirk " __STRING(_name) " not set"))
#define CHIPC_ASSERT_CAP(_sc, name) \
KASSERT(CHIPC_CAP((_sc), name), ("capability " __STRING(_name) " not set"))
static int
chipc_probe(device_t dev)
{
const struct chipc_device *id;
for (id = chipc_devices; id->device != BHND_COREID_INVALID; id++)
{
if (bhnd_get_vendor(dev) == BHND_MFGID_BCM &&
bhnd_get_device(dev) == id->device)
{
bhnd_set_generic_core_desc(dev);
return (BUS_PROBE_DEFAULT);
}
}
return (ENXIO);
}
static int
chipc_attach(device_t dev)
{
struct bhnd_device_quirk *dq;
struct chipc_softc *sc;
bhnd_addr_t enum_addr;
uint32_t ccid_reg;
uint8_t chip_type;
int error;
sc = device_get_softc(dev);
sc->dev = dev;
/* Allocate bus resources */
memcpy(sc->rspec, chipc_rspec, sizeof(sc->rspec));
if ((error = bhnd_alloc_resources(dev, sc->rspec, sc->res)))
return (error);
sc->core = sc->res[0];
/* Fetch our chipset identification data */
ccid_reg = bhnd_bus_read_4(sc->core, CHIPC_ID);
chip_type = CHIPC_GET_ATTR(ccid_reg, ID_BUS);
switch (chip_type) {
case BHND_CHIPTYPE_SIBA:
/* enumeration space starts at the ChipCommon register base. */
enum_addr = rman_get_start(sc->core->res);
break;
case BHND_CHIPTYPE_BCMA:
case BHND_CHIPTYPE_BCMA_ALT:
enum_addr = bhnd_bus_read_4(sc->core, CHIPC_EROMPTR);
break;
default:
device_printf(dev, "unsupported chip type %hhu\n", chip_type);
error = ENODEV;
goto cleanup;
}
sc->ccid = bhnd_parse_chipid(ccid_reg, enum_addr);
/* Fetch capability and status register values */
sc->caps = bhnd_bus_read_4(sc->core, CHIPC_CAPABILITIES);
sc->cst = bhnd_bus_read_4(sc->core, CHIPC_CHIPST);
/* Populate the set of applicable quirk flags */
sc->quirks = 0;
for (dq = chipc_quirks; dq->quirks != 0; dq++) {
if (bhnd_hwrev_matches(bhnd_get_hwrev(dev), &dq->hwrev))
sc->quirks |= dq->quirks;
};
// TODO
switch (bhnd_chipc_nvram_src(dev)) {
case BHND_NVRAM_SRC_CIS:
device_printf(dev, "NVRAM source: CIS\n");
break;
case BHND_NVRAM_SRC_SPROM:
device_printf(dev, "NVRAM source: SPROM\n");
break;
case BHND_NVRAM_SRC_OTP:
device_printf(dev, "NVRAM source: OTP\n");
break;
case BHND_NVRAM_SRC_NFLASH:
device_printf(dev, "NVRAM source: NFLASH\n");
break;
case BHND_NVRAM_SRC_NONE:
device_printf(dev, "NVRAM source: NONE\n");
break;
}
return (0);
cleanup:
bhnd_release_resources(dev, sc->rspec, sc->res);
return (error);
}
static int
chipc_detach(device_t dev)
{
struct chipc_softc *sc;
sc = device_get_softc(dev);
bhnd_release_resources(dev, sc->rspec, sc->res);
return (0);
}
static int
chipc_suspend(device_t dev)
{
return (0);
}
static int
chipc_resume(device_t dev)
{
return (0);
}
/**
* Use device-specific ChipStatus flags to determine the preferred NVRAM
* data source.
*/
static bhnd_nvram_src_t
chipc_nvram_src_chipst(struct chipc_softc *sc)
{
uint8_t nvram_sel;
CHIPC_ASSERT_QUIRK(sc, SPROM_CHECK_CHIPST);
if (CHIPC_QUIRK(sc, SPROM_CHECK_CST_R22)) {
// TODO: On these devices, the official driver code always
// assumes SPROM availability if CHIPC_CST_OTP_SEL is not
// set; we must review against the actual behavior of our
// BCM4312 hardware
nvram_sel = CHIPC_GET_ATTR(sc->cst, CST_SPROM_OTP_SEL_R22);
} else if (CHIPC_QUIRK(sc, SPROM_CHECK_CST_R23)) {
nvram_sel = CHIPC_GET_ATTR(sc->cst, CST_SPROM_OTP_SEL_R23);
} else {
panic("invalid CST OTP/SPROM chipc quirk flags");
}
device_printf(sc->dev, "querying chipst for 0x%x, 0x%x\n", sc->ccid.chip_id, sc->cst);
switch (nvram_sel) {
case CHIPC_CST_DEFCIS_SEL:
return (BHND_NVRAM_SRC_CIS);
case CHIPC_CST_SPROM_SEL:
case CHIPC_CST_OTP_PWRDN:
return (BHND_NVRAM_SRC_SPROM);
case CHIPC_CST_OTP_SEL:
return (BHND_NVRAM_SRC_OTP);
default:
device_printf(sc->dev, "unrecognized OTP/SPROM type 0x%hhx",
nvram_sel);
return (BHND_NVRAM_SRC_NONE);
}
}
/**
* Determine the preferred NVRAM data source.
*/
static bhnd_nvram_src_t
chipc_nvram_src(device_t dev)
{
struct chipc_softc *sc;
uint32_t srom_ctrl;
sc = device_get_softc(dev);
/* Very early devices always included a SPROM */
if (CHIPC_QUIRK(sc, ALWAYS_HAS_SPROM))
return (BHND_NVRAM_SRC_SPROM);
/* Most other early devices require checking ChipStatus flags */
if (CHIPC_QUIRK(sc, SPROM_CHECK_CHIPST))
return (chipc_nvram_src_chipst(sc));
/*
* Later chipset revisions standardized the NVRAM capability flags and
* register interfaces.
*
* We check for hardware presence in order of precedence. For example,
* SPROM is is always used in preference to internal OTP if found.
*/
if (CHIPC_CAP(sc, CAP_SPROM)) {
srom_ctrl = bhnd_bus_read_4(sc->core, CHIPC_SPROM_CTRL);
if (srom_ctrl & CHIPC_SRC_PRESENT)
return (BHND_NVRAM_SRC_SPROM);
}
/* Check for OTP */
if (CHIPC_CAP(sc, CAP_OTP_SIZE))
return (BHND_NVRAM_SRC_OTP);
/*
* Finally, Northstar chipsets (and possibly other chipsets?) support
* external NAND flash.
*/
if (CHIPC_QUIRK(sc, SUPPORTS_NFLASH) && CHIPC_CAP(sc, CAP_NFLASH))
return (BHND_NVRAM_SRC_NFLASH);
/* No NVRAM hardware capability declared */
return (BHND_NVRAM_SRC_NONE);
}
static device_method_t chipc_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, chipc_probe),
DEVMETHOD(device_attach, chipc_attach),
DEVMETHOD(device_detach, chipc_detach),
DEVMETHOD(device_suspend, chipc_suspend),
DEVMETHOD(device_resume, chipc_resume),
/* ChipCommon interface */
DEVMETHOD(bhnd_chipc_nvram_src, chipc_nvram_src),
DEVMETHOD_END
};
DEFINE_CLASS_0(bhnd_chipc, chipc_driver, chipc_methods, sizeof(struct chipc_softc));
DRIVER_MODULE(bhnd_chipc, bhnd, chipc_driver, bhnd_chipc_devclass, 0, 0);
MODULE_VERSION(bhnd_chipc, 1);

View file

@ -0,0 +1,51 @@
/*-
* Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
* $FreeBSD$
*/
#ifndef _BHND_CORES_CHIPC_CHIPC_H_
#define _BHND_CORES_CHIPC_CHIPC_H_
#include <dev/bhnd/bhnd.h>
#include <dev/bhnd/nvram/bhnd_nvram.h>
#include "bhnd_chipc_if.h"
/**
* Query a ChipCommon device and return the preferred NVRAM data source.
*
* @param dev A bhnd(4) ChipCommon device.
*/
static inline bhnd_nvram_src_t
bhnd_chipc_nvram_src(device_t dev)
{
return (BHND_CHIPC_NVRAM_SRC(dev));
}
#endif /* _BHND_CORES_CHIPC_CHIPC_H_ */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,94 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
* $FreeBSD$
*/
#ifndef _BHND_CORES_CHIPC_CHIPCVAR_H_
#define _BHND_CORES_CHIPC_CHIPCVAR_H_
#include "chipc.h"
DECLARE_CLASS(bhnd_chipc);
extern devclass_t bhnd_chipc_devclass;
#define CHIPC_MAX_RES 1
#define CHIPC_MAX_RSPEC (CHIPC_MAX_RES+1)
/*
* ChipCommon device quirks / features
*/
enum {
/** No quirks */
CHIPC_QUIRK_NONE = 0,
/**
* The device always provides an external SROM.
*/
CHIPC_QUIRK_ALWAYS_HAS_SPROM = (1<<1),
/**
* SROM availability must be determined through chip-specific
* ChipStatus flags.
*/
CHIPC_QUIRK_SPROM_CHECK_CHIPST = (1<<3),
/**
* Use the rev22 chipstatus register format when determining SPROM
* availability.
*/
CHIPC_QUIRK_SPROM_CHECK_CST_R22 = (1<<4)|CHIPC_QUIRK_SPROM_CHECK_CHIPST,
/**
* Use the rev23 chipstatus register format when determining SPROM
* availability.
*/
CHIPC_QUIRK_SPROM_CHECK_CST_R23 = (1<<5)|CHIPC_QUIRK_SPROM_CHECK_CHIPST,
/**
* External NAND NVRAM is supported, along with the CHIPC_CAP_NFLASH
* capability flag.
*/
CHIPC_QUIRK_SUPPORTS_NFLASH = (1<<6),
};
struct chipc_softc {
device_t dev;
struct resource_spec rspec[CHIPC_MAX_RSPEC];
struct bhnd_resource *res[CHIPC_MAX_RES];
struct bhnd_resource *core; /**< core registers. */
struct bhnd_chipid ccid; /**< chip identification */
uint32_t quirks; /**< CHIPC_QUIRK_* quirk flags */
uint32_t caps; /**< CHIPC_CAP_* capability register flags */
uint32_t cst; /**< CHIPC_CST* status register flags */
};
#endif /* _BHND_CORES_CHIPC_CHIPCVAR_H_ */

View file

@ -0,0 +1,52 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* Broadcom Common PCI Support.
*
* This module provides common implementation shared across the PCI/PCIe
* endpoint and root complex drivers.
*/
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include "bhnd_pcivar.h"
/**
* PCIe MDIO interface device class
*/
devclass_t bhnd_mdio_pci_devclass;
MODULE_VERSION(bhnd_pci, 1);
MODULE_DEPEND(bhnd_pci, pci, 1, 1, 1);

View file

@ -0,0 +1,117 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* Broadcom PCI-BHND Host Bridge.
*
* This driver is used to "eat" PCI(e) cores operating in endpoint mode when
* they're attached to a bhndb_pci driver on the host side.
*/
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/module.h>
#include <sys/systm.h>
#include <machine/bus.h>
#include <sys/rman.h>
#include <machine/resource.h>
#include <dev/bhnd/bhnd.h>
struct bhnd_pci_hostb_softc {
};
static int
bhnd_pci_hostb_probe(device_t dev)
{
/* Ignore non-PCI cores */
switch (bhnd_get_class(dev)){
case BHND_DEVCLASS_PCI:
case BHND_DEVCLASS_PCIE:
break;
default:
return (ENXIO);
}
/* Ignore PCI cores not in host bridge mode. */
if (!bhnd_is_hostb_device(dev))
return (ENXIO);
bhnd_set_generic_core_desc(dev);
return (BUS_PROBE_DEFAULT);
}
static int
bhnd_pci_hostb_attach(device_t dev)
{
return (0);
}
static int
bhnd_pci_hostb_detach(device_t dev)
{
return (0);
}
static int
bhnd_pci_hostb_suspend(device_t dev)
{
return (0);
}
static int
bhnd_pci_hostb_resume(device_t dev)
{
return (0);
}
static device_method_t bhnd_pci_hostb_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, bhnd_pci_hostb_probe),
DEVMETHOD(device_attach, bhnd_pci_hostb_attach),
DEVMETHOD(device_detach, bhnd_pci_hostb_detach),
DEVMETHOD(device_suspend, bhnd_pci_hostb_suspend),
DEVMETHOD(device_resume, bhnd_pci_hostb_resume),
DEVMETHOD_END
};
DEFINE_CLASS_0(bhnd_pci_hostb, bhnd_pci_hostb_driver, bhnd_pci_hostb_methods,
sizeof(struct bhnd_pci_hostb_softc));
DRIVER_MODULE(bhnd_hostb, bhnd, bhnd_pci_hostb_driver, bhnd_hostb_devclass, 0, 0);
MODULE_VERSION(bhnd_pci_hostb, 1);
MODULE_DEPEND(bhnd_pci_hostb, pci, 1, 1, 1);
MODULE_DEPEND(bhnd_pci_hostb, bhnd_pci, 1, 1, 1);

View file

@ -0,0 +1,127 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* Broadcom PCI-BHND Host Bridge.
*
* This driver is used to "eat" PCI(e) cores operating in endpoint mode when
* they're attached to a bhndb_pci driver on the host side.
*/
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/module.h>
#include <machine/bus.h>
#include <sys/rman.h>
#include <machine/resource.h>
#include <dev/bhnd/bhnd.h>
#include "bhnd_pcireg.h"
#include "bhnd_pcibvar.h"
static const struct bhnd_pcib_device {
uint16_t vendor;
uint16_t device;
const char *desc;
} bhnd_pcib_devs[] = {
{ BHND_MFGID_BCM, BHND_COREID_PCI, "BHND Host-PCI bridge" },
{ BHND_MFGID_BCM, BHND_COREID_PCIE, "BHND Host-PCI bridge (PCIe Gen1)" },
{ BHND_MFGID_INVALID, BHND_COREID_INVALID, NULL }
};
static int
bhnd_pcib_probe(device_t dev)
{
const struct bhnd_pcib_device *id;
/* Ignore PCI cores configured in host bridge mode */
if (bhnd_is_hostb_device(dev))
return (ENXIO);
for (id = bhnd_pcib_devs; id->device != BHND_COREID_INVALID; id++) {
if (bhnd_get_vendor(dev) != id->vendor)
continue;
if (bhnd_get_device(dev) != id->device)
continue;
device_set_desc(dev, id->desc);
return (BUS_PROBE_SPECIFIC);
}
return (ENXIO);
}
static int
bhnd_pcib_attach(device_t dev)
{
return (ENXIO);
}
static int
bhnd_pcib_detach(device_t dev)
{
return (ENXIO);
}
static int
bhnd_pcib_suspend(device_t dev)
{
return (ENXIO);
}
static int
bhnd_pcib_resume(device_t dev)
{
return (ENXIO);
}
static device_method_t bhnd_pcib_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, bhnd_pcib_probe),
DEVMETHOD(device_attach, bhnd_pcib_attach),
DEVMETHOD(device_detach, bhnd_pcib_detach),
DEVMETHOD(device_suspend, bhnd_pcib_suspend),
DEVMETHOD(device_resume, bhnd_pcib_resume),
DEVMETHOD_END
};
DEFINE_CLASS_0(bhnd_pcib, bhnd_pcib_driver, bhnd_pcib_methods, sizeof(struct bhnd_pcib_softc));
DRIVER_MODULE(bhnd_pcib, bhnd, bhnd_pcib_driver, bhnd_hostb_devclass, 0, 0);
MODULE_VERSION(bhnd_pcib, 1);
MODULE_DEPEND(bhnd_pcib, pci, 1, 1, 1);
MODULE_DEPEND(bhnd_pcib, bhnd_pci_mdio, 1, 1, 1);

View file

@ -0,0 +1,50 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
* $FreeBSD$
*/
#ifndef _BHND_CORES_PCI_BHND_PCIBVAR_H_
#define _BHND_CORES_PCI_BHND_PCIBVAR_H_
#include "bhnd_pcivar.h"
/* PCI bridge driver-specific state */
#define BHND_PCIB_MAX_RES 2
#define BHND_PCIB_MAX_RSPEC (BHND_PCIB_MAX_RES+1)
struct bhnd_pcib_softc {
device_t dev; /**< pci device */
struct bhnd_resource *core; /**< core registers. */
bhnd_pci_regfmt_t regfmt; /**< device register format */
struct resource_spec rspec[BHND_PCIB_MAX_RSPEC];
struct bhnd_resource *res[BHND_PCIB_MAX_RES];
};
#endif /* _BHND_CORES_PCI_BHND_PCIBVAR_H_ */

View file

@ -0,0 +1,387 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* Copyright (c) 2010 Broadcom Corporation
* All rights reserved.
*
* This file is derived from the hndsoc.h, pci_core.h, and pcie_core.h headers
* distributed with Broadcom's initial brcm80211 Linux driver release, as
* contributed to the Linux staging repository.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $FreeBSD$
*/
#ifndef _BHND_CORES_PCI_BHND_PCIREG_H_
#define _BHND_CORES_PCI_BHND_PCIREG_H_
/*
* PCI/PCIe-Gen1 DMA Constants
*/
#define BHND_PCI_DMA32_TRANSLATION 0x40000000 /* Client Mode sb2pcitranslation2 (1 GB) */
#define BHND_PCI_DMA32_SZ 0x40000000 /* Client Mode sb2pcitranslation2 size in bytes */
#define BHND_PCIE_DMA32_TRANSLATION BHND_PCI_DMA32_TRANSLATION
#define BHND_PCIE_DMA32_SZ BHND_PCI_DMA32_SZ
#define BHND_PCIE_DMA64_L32 0x00000000 /**< 64-bit client mode sb2pcitranslation2 (2 ZettaBytes, low 32 bits) */
#define BHND_PCIE_DMA64_H32 0x80000000 /**< 64-bit client mode sb2pcitranslation2 (2 ZettaBytes, high 32 bits) */
/*
* PCI Core Registers
*/
#define BHND_PCI_CTL 0x000 /**< PCI core control*/
#define BHND_PCI_ARB_CTL 0x010 /**< PCI arbiter control */
#define BHND_PCI_CLKRUN_CTL 0x014 /**< PCI clckrun control (>= rev11) */
#define BHND_PCI_INTR_STATUS 0x020 /**< Interrupt status */
#define BHND_PCI_INTR_MASK 0x024 /**< Interrupt mask */
#define BHND_PCI_SBTOPCI_MBOX 0x028 /**< Sonics to PCI mailbox */
#define BHND_PCI_BCAST_ADDR 0x050 /**< Sonics broadcast address (pci) */
#define BHND_PCI_BCAST_DATA 0x054 /**< Sonics broadcast data (pci) */
#define BHND_PCI_GPIO_IN 0x060 /**< GPIO input (>= rev2) */
#define BHND_PCI_GPIO_OUT 0x064 /**< GPIO output (>= rev2) */
#define BHND_PCI_GPIO_EN 0x068 /**< GPIO output enable (>= rev2) */
#define BHND_PCI_GPIO_CTL 0x06C /**< GPIO control (>= rev2) */
#define BHND_PCI_SBTOPCI0 0x100 /**< Sonics to PCI translation 0 */
#define BHND_PCI_SBTOPCI1 0x104 /**< Sonics to PCI translation 1 */
#define BHND_PCI_SBTOPCI2 0x108 /**< Sonics to PCI translation 2 */
#define BHND_PCI_FUNC0_CFG 0x400 /**< PCI function 0 cfg space (>= rev8) */
#define BHND_PCI_FUNC1_CFG 0x500 /**< PCI function 1 cfg space (>= rev8) */
#define BHND_PCI_FUNC2_CFG 0x600 /**< PCI function 2 cfg space (>= rev8) */
#define BHND_PCI_FUNC3_CFG 0x700 /**< PCI function 3 cfg space (>= rev8) */
#define BHND_PCI_SPROM_SHADOW 0x800 /**< PCI SPROM shadow */
/* BHND_PCI_CTL */
#define BHND_PCI_CTL_RST_OE 0x01 /* When set, drives PCI_RESET out to pin */
#define BHND_PCI_CTL_RST 0x02 /* Value driven out to pin */
#define BHND_PCI_CTL_CLK_OE 0x04 /* When set, drives clock as gated by PCI_CLK out to pin */
#define BHND_PCI_CTL_CLK 0x08 /* Gate for clock driven out to pin */
/* BHND_PCI_ARB_CTL */
#define BHND_PCI_ARB_INT 0x01 /* When set, use an internal arbiter */
#define BHND_PCI_ARB_EXT 0x02 /* When set, use an external arbiter */
/* BHND_PCI_ARB_CTL - ParkID (>= rev8) */
#define BHND_PCI_ARB_PARKID_MASK 0x1c /* Selects which agent is parked on an idle bus */
#define BHND_PCI_ARB_PARKID_SHIFT 2
#define BHND_PCI_ARB_PARKID_EXT0 0 /* External master 0 */
#define BHND_PCI_ARB_PARKID_EXT1 1 /* External master 1 */
#define BHND_PCI_ARB_PARKID_EXT2 2 /* External master 2 */
#define BHND_PCI_ARB_PARKID_EXT3 3 /* External master 3 (rev >= 11) */
#define BHND_PCI_ARB_PARKID_INT_r10 3 /* Internal master (rev < 11) */
#define BHND_PCI_ARB_PARKID_INT_r11 4 /* Internal master (rev >= 11) */
#define BHND_PCI_ARB_PARKID_LAST_r10 4 /* Last active master (rev < 11) */
#define BHND_PCI_ARB_PARKID_LAST_r11 5 /* Last active master (rev >= 11) */
/* BHND_PCI_CLKRUN_CTL */
#define BHND_PCI_CLKRUN_DSBL 0x8000 /* Bit 15 forceClkrun */
/* BHND_PCI_INTR_STATUS / BHND_PCI_INTR_MASK */
#define BHND_PCI_INTR_A 0x01 /* PCI INTA# is asserted */
#define BHND_PCI_INTR_B 0x02 /* PCI INTB# is asserted */
#define BHND_PCI_INTR_SERR 0x04 /* PCI SERR# has been asserted (write one to clear) */
#define BHND_PCI_INTR_PERR 0x08 /* PCI PERR# has been asserted (write one to clear) */
/* BHND_PCI_SBTOPCI_MBOX
* (General) PCI/SB mailbox interrupts, two bits per pci function */
#define BHND_PCI_SBTOPCI_MBOX_F0_0 0x100 /* function 0, int 0 */
#define BHND_PCI_SBTOPCI_MBOX_F0_1 0x200 /* function 0, int 1 */
#define BHND_PCI_SBTOPCI_MBOX_F1_0 0x400 /* function 1, int 0 */
#define BHND_PCI_SBTOPCI_MBOX_F1_1 0x800 /* function 1, int 1 */
#define BHND_PCI_SBTOPCI_MBOX_F2_0 0x1000 /* function 2, int 0 */
#define BHND_PCI_SBTOPCI_MBOX_F2_1 0x2000 /* function 2, int 1 */
#define BHND_PCI_SBTOPCI_MBOX_F3_0 0x4000 /* function 3, int 0 */
#define BHND_PCI_SBTOPCI_MBOX_F3_1 0x8000 /* function 3, int 1 */
/* BHND_PCI_BCAST_ADDR */
#define BHNC_PCI_BCAST_ADDR_MASK 0xFF /* Broadcast register address */
/* Sonics to PCI translation types */
#define BHND_PCI_SBTOPCI0_MASK 0xfc000000
#define BHND_PCI_SBTOPCI1_MASK 0xfc000000
#define BHND_PCI_SBTOPCI2_MASK 0xc0000000
/* Access type bits (0:1) */
#define BHND_PCI_SBTOPCI_MEM 0
#define BHND_PCI_SBTOPCI_IO 1
#define BHND_PCI_SBTOPCI_CFG0 2
#define BHND_PCI_SBTOPCI_CFG1 3
#define BHND_PCI_SBTOPCI_PREF 0x4 /* prefetch enable */
#define BHND_PCI_SBTOPCI_BURST 0x8 /* burst enable */
#define BHND_PCI_SBTOPCI_RC_MASK 0x30 /* read command (>= rev11) */
#define BHND_PCI_SBTOPCI_RC_READ 0x00 /* memory read */
#define BHND_PCI_SBTOPCI_RC_READLINE 0x10 /* memory read line */
#define BHND_PCI_SBTOPCI_RC_READMULTI 0x20 /* memory read multiple */
/* PCI core index in SROM shadow area */
#define BHND_PCI_SRSH_PI_OFFSET 0 /* first word */
#define BHND_PCI_SRSH_PI_MASK 0xf000 /* bit 15:12 */
#define BHND_PCI_SRSH_PI_SHIFT 12 /* bit 15:12 */
/*
* PCIe-Gen1 Core Registers
*/
#define BHND_PCIE_CTL BHND_PCI_CTL /**< PCI core control*/
#define BHND_PCIE_BIST_STATUS 0x00C /**< BIST status */
#define BHND_PCIE_GPIO_SEL 0x010 /**< GPIO select */
#define BHND_PCIE_GPIO_OUT_EN 0x014 /**< GPIO output enable */
#define BHND_PCIE_INTR_STATUS BHND_PCI_INTR_STATUS /**< Interrupt status */
#define BHND_PCIE_INTR_MASK BHND_PCI_INTR_MASK /**< Interrupt mask */
#define BHND_PCIE_SBTOPCI_MBOX BHND_PCI_SBTOPCI_MBOX /**< Sonics to PCI mailbox */
#define BHND_PCIE_SBTOPCI0 BHND_PCI_SBTOPCI0 /**< Sonics to PCI translation 0 */
#define BHND_PCIE_SBTOPCI1 BHND_PCI_SBTOPCI1 /**< Sonics to PCI translation 1 */
#define BHND_PCIE_SBTOPCI2 BHND_PCI_SBTOPCI2 /**< Sonics to PCI translation 2 */
/* indirect pci config space access */
#define BHND_PCIE_CFG_ADDR 0x120 /**< pcie config space address */
#define BHND_PCIE_CFG_DATA 0x124 /**< pcie config space data */
/* mdio register access */
#define BHND_PCIE_MDIO_CTL 0x128 /**< mdio control */
#define BHND_PCIE_MDIO_DATA 0x12C /**< mdio data */
/* indirect protocol phy/dllp/tlp register access */
#define BHND_PCIE_IND_ADDR 0x130 /**< internal protocol register address */
#define BHND_PCIE_IND_DATA 0x134 /**< internal protocol register data */
#define BHND_PCIE_CLKREQEN_CTL 0x138 /**< clkreq rdma control */
#define BHND_PCIE_FUNC0_CFG BHND_PCI_FUNC0_CFG /**< PCI function 0 cfg space */
#define BHND_PCIE_FUNC1_CFG BHND_PCI_FUNC1_CFG /**< PCI function 1 cfg space */
#define BHND_PCIE_FUNC2_CFG BHND_PCI_FUNC2_CFG /**< PCI function 2 cfg space */
#define BHND_PCIE_FUNC3_CFG BHND_PCI_FUNC3_CFG /**< PCI function 3 cfg space */
#define BHND_PCIE_SPROM_SHADOW BHND_PCI_SPROM_SHADOW /**< PCI SPROM shadow */
/* BHND_PCIE_CTL */
#define BHND_PCIE_CTL_RST_OE BHND_PCI_CTL_RST_OE /* When set, drives PCI_RESET out to pin */
#define BHND_PCIE_CTL_RST BHND_PCI_CTL_RST_OE /* Value driven out to pin */
/* BHND_PCI_INTR_STATUS / BHND_PCI_INTR_MASK */
#define BHND_PCIE_INTR_A BHND_PCI_INTR_A /* PCIE INTA message is received */
#define BHND_PCIE_INTR_B BHND_PCI_INTR_B /* PCIE INTB message is received */
#define BHND_PCIE_INTR_FATAL 0x04 /* PCIE INTFATAL message is received */
#define BHND_PCIE_INTR_NFATAL 0x08 /* PCIE INTNONFATAL message is received */
#define BHND_PCIE_INTR_CORR 0x10 /* PCIE INTCORR message is received */
#define BHND_PCIE_INTR_PME 0x20 /* PCIE INTPME message is received */
/* SB to PCIE translation masks */
#define BHND_PCIE_SBTOPCI0_MASK BHND_PCI_SBTOPCI0_MASK
#define BHND_PCIE_SBTOPCI1_MASK BHND_PCI_SBTOPCI1_MASK
#define BHND_PCIE_SBTOPCI2_MASK BHND_PCI_SBTOPCI2_MASK
/* Access type bits (0:1) */
#define BHND_PCIE_SBTOPCI_MEM BHND_PCI_SBTOPCI_MEM
#define BHND_PCIE_SBTOPCI_IO BHND_PCI_SBTOPCI_IO
#define BHND_PCIE_SBTOPCI_CFG0 BHND_PCI_SBTOPCI_CFG0
#define BHND_PCIE_SBTOPCI_CFG1 BHND_PCI_SBTOPCI_CFG1
#define BHND_PCIE_SBTOPCI_PREF BHND_PCI_SBTOPCI_PREF /* prefetch enable */
#define BHND_PCIE_SBTOPCI_BURST BHND_PCI_SBTOPCI_BURST /* burst enable */
/* BHND_PCIE_CFG_ADDR / BHND_PCIE_CFG_DATA */
#define BHND_PCIE_CFG_ADDR_FUNC_MASK 0x7000
#define BHND_PCIE_CFG_ADDR_FUNC_SHIFT 12
#define BHND_PCIE_CFG_ADDR_REG_MASK 0x0FFF
#define BHND_PCIE_CFG_ADDR_REG_SHIFT 0
#define BHND_PCIE_CFG_OFFSET(f, r) \
((((f) & BHND_PCIE_CFG_ADDR_FUNC_MASK) << BHND_PCIE_CFG_ADDR_FUNC_SHIFT) | \
(((r) & BHND_PCIE_CFG_ADDR_FUNC_SHIFT) << BHND_PCIE_CFG_ADDR_REG_SHIFT))
/* PCIE protocol PHY diagnostic registers */
#define BHND_PCIE_PLP_MODEREG 0x200 /* Mode */
#define BHND_PCIE_PLP_STATUSREG 0x204 /* Status */
#define BHND_PCIE_PLP_LTSSMCTRLREG 0x208 /* LTSSM control */
#define BHND_PCIE_PLP_LTLINKNUMREG 0x20c /* Link Training Link number */
#define BHND_PCIE_PLP_LTLANENUMREG 0x210 /* Link Training Lane number */
#define BHND_PCIE_PLP_LTNFTSREG 0x214 /* Link Training N_FTS */
#define BHND_PCIE_PLP_ATTNREG 0x218 /* Attention */
#define BHND_PCIE_PLP_ATTNMASKREG 0x21C /* Attention Mask */
#define BHND_PCIE_PLP_RXERRCTR 0x220 /* Rx Error */
#define BHND_PCIE_PLP_RXFRMERRCTR 0x224 /* Rx Framing Error */
#define BHND_PCIE_PLP_RXERRTHRESHREG 0x228 /* Rx Error threshold */
#define BHND_PCIE_PLP_TESTCTRLREG 0x22C /* Test Control reg */
#define BHND_PCIE_PLP_SERDESCTRLOVRDREG 0x230 /* SERDES Control Override */
#define BHND_PCIE_PLP_TIMINGOVRDREG 0x234 /* Timing param override */
#define BHND_PCIE_PLP_RXTXSMDIAGREG 0x238 /* RXTX State Machine Diag */
#define BHND_PCIE_PLP_LTSSMDIAGREG 0x23C /* LTSSM State Machine Diag */
/* PCIE protocol DLLP diagnostic registers */
#define BHND_PCIE_DLLP_LCREG 0x100 /* Link Control */
#define BHND_PCIE_DLLP_LCREG_PCIPM_EN 0x40 /* Enable PCI-PM power management */
#define BHND_PCIE_DLLP_LSREG 0x104 /* Link Status */
#define BHND_PCIE_DLLP_LAREG 0x108 /* Link Attention */
#define BHND_PCIE_DLLP_LAMASKREG 0x10C /* Link Attention Mask */
#define BHND_PCIE_DLLP_NEXTTXSEQNUMREG 0x110 /* Next Tx Seq Num */
#define BHND_PCIE_DLLP_ACKEDTXSEQNUMREG 0x114 /* Acked Tx Seq Num */
#define BHND_PCIE_DLLP_PURGEDTXSEQNUMREG 0x118 /* Purged Tx Seq Num */
#define BHND_PCIE_DLLP_RXSEQNUMREG 0x11C /* Rx Sequence Number */
#define BHND_PCIE_DLLP_LRREG 0x120 /* Link Replay */
#define BHND_PCIE_DLLP_LACKTOREG 0x124 /* Link Ack Timeout */
#define BHND_PCIE_DLLP_PMTHRESHREG 0x128 /* Power Management Threshold */
#define BHND_PCIE_L0THRESHOLDTIME_MASK 0xFF00 /* bits 0 - 7 */
#define BHND_PCIE_L1THRESHOLDTIME_MASK 0xFF00 /* bits 8 - 15 */
#define BHND_PCIE_L1THRESHOLDTIME_SHIFT 8 /* PCIE_L1THRESHOLDTIME_SHIFT */
#define BHND_PCIE_L1THRESHOLD_WARVAL 0x72 /* WAR value */
#define BHND_PCIE_ASPMTIMER_EXTEND 0x1000000 /* > rev7: enable extend ASPM timer */
#define BHND_PCIE_DLLP_RTRYWPREG 0x12C /* Retry buffer write ptr */
#define BHND_PCIE_DLLP_RTRYRPREG 0x130 /* Retry buffer Read ptr */
#define BHND_PCIE_DLLP_RTRYPPREG 0x134 /* Retry buffer Purged ptr */
#define BHND_PCIE_DLLP_RTRRWREG 0x138 /* Retry buffer Read/Write */
#define BHND_PCIE_DLLP_ECTHRESHREG 0x13C /* Error Count Threshold */
#define BHND_PCIE_DLLP_TLPERRCTRREG 0x140 /* TLP Error Counter */
#define BHND_PCIE_DLLP_ERRCTRREG 0x144 /* Error Counter */
#define BHND_PCIE_DLLP_NAKRXCTRREG 0x148 /* NAK Received Counter */
#define BHND_PCIE_DLLP_TESTREG 0x14C /* Test */
#define BHND_PCIE_DLLP_PKTBIST 0x150 /* Packet BIST */
#define BHND_PCIE_DLLP_PCIE11 0x154 /* DLLP PCIE 1.1 reg */
#define BHND_PCIE_DLLP_LSREG_LINKUP (1 << 16)
/* PCIE protocol TLP diagnostic registers */
#define BHND_PCIE_TLP_CONFIGREG 0x000 /* Configuration */
#define BHND_PCIE_TLP_WORKAROUNDSREG 0x004 /* TLP Workarounds */
#define BHND_PCIE_TLP_WORKAROUND_URBIT 0x8 /* If enabled, UR status bit is set
* on memory access of an unmatched
* address */
#define BHND_PCIE_TLP_WRDMAUPPER 0x010 /* Write DMA Upper Address */
#define BHND_PCIE_TLP_WRDMALOWER 0x014 /* Write DMA Lower Address */
#define BHND_PCIE_TLP_WRDMAREQ_LBEREG 0x018 /* Write DMA Len/ByteEn Req */
#define BHND_PCIE_TLP_RDDMAUPPER 0x01C /* Read DMA Upper Address */
#define BHND_PCIE_TLP_RDDMALOWER 0x020 /* Read DMA Lower Address */
#define BHND_PCIE_TLP_RDDMALENREG 0x024 /* Read DMA Len Req */
#define BHND_PCIE_TLP_MSIDMAUPPER 0x028 /* MSI DMA Upper Address */
#define BHND_PCIE_TLP_MSIDMALOWER 0x02C /* MSI DMA Lower Address */
#define BHND_PCIE_TLP_MSIDMALENREG 0x030 /* MSI DMA Len Req */
#define BHND_PCIE_TLP_SLVREQLENREG 0x034 /* Slave Request Len */
#define BHND_PCIE_TLP_FCINPUTSREQ 0x038 /* Flow Control Inputs */
#define BHND_PCIE_TLP_TXSMGRSREQ 0x03C /* Tx StateMachine and Gated Req */
#define BHND_PCIE_TLP_ADRACKCNTARBLEN 0x040 /* Address Ack XferCnt and ARB Len */
#define BHND_PCIE_TLP_DMACPLHDR0 0x044 /* DMA Completion Hdr 0 */
#define BHND_PCIE_TLP_DMACPLHDR1 0x048 /* DMA Completion Hdr 1 */
#define BHND_PCIE_TLP_DMACPLHDR2 0x04C /* DMA Completion Hdr 2 */
#define BHND_PCIE_TLP_DMACPLMISC0 0x050 /* DMA Completion Misc0 */
#define BHND_PCIE_TLP_DMACPLMISC1 0x054 /* DMA Completion Misc1 */
#define BHND_PCIE_TLP_DMACPLMISC2 0x058 /* DMA Completion Misc2 */
#define BHND_PCIE_TLP_SPTCTRLLEN 0x05C /* Split Controller Req len */
#define BHND_PCIE_TLP_SPTCTRLMSIC0 0x060 /* Split Controller Misc 0 */
#define BHND_PCIE_TLP_SPTCTRLMSIC1 0x064 /* Split Controller Misc 1 */
#define BHND_PCIE_TLP_BUSDEVFUNC 0x068 /* Bus/Device/Func */
#define BHND_PCIE_TLP_RESETCTR 0x06C /* Reset Counter */
#define BHND_PCIE_TLP_RTRYBUF 0x070 /* Retry Buffer value */
#define BHND_PCIE_TLP_TGTDEBUG1 0x074 /* Target Debug Reg1 */
#define BHND_PCIE_TLP_TGTDEBUG2 0x078 /* Target Debug Reg2 */
#define BHND_PCIE_TLP_TGTDEBUG3 0x07C /* Target Debug Reg3 */
#define BHND_PCIE_TLP_TGTDEBUG4 0x080 /* Target Debug Reg4 */
/*
* PCIe-G1 SerDes MDIO Registers (>= rev10)
*/
#define BHND_PCIE_PHYADDR_SD 0x0 /* serdes PHY address */
#define BHND_PCIE_DEVAD_SD 0x1 /* serdes pseudo-devad (PMA) recognized by
the bhnd_mdio_pcie driver */
#define BHND_PCIE_SD_ADDREXT 0x1F /* serdes address extension register */
#define BHND_PCIE_SD_ADDREXT_BLK_MASK 0xFFF0 /* register block mask */
#define BHND_PCIE_SD_ADDREXT_REG_MASK 0x000F /* register address mask */
#define BHND_PCIE_SD_REGS_IEEE0 0x0000 /* IEEE0 AN CTRL block */
#define BHND_PCIE_SD_REGS_IEEE1 0x0010 /* IEEE1 AN ADV block */
#define BHND_PCIE_SD_REGS_BLK0 0x8000 /* ??? */
#define BHND_PCIE_SD_REGS_BLK1 0x8010 /* ??? */
#define BHND_PCIE_SD_REGS_BLK2 0x8020 /* ??? */
#define BHND_PCIE_SD_REGS_BLK3 0x8030 /* ??? */
#define BHND_PCIE_SD_REGS_BLK4 0x8040 /* ??? */
#define BHND_PCIE_SD_REGS_TXPLL 0x8080 /* TXPLL register block */
#define BHND_PCIE_SD_REGS_TXCTRL0 0x8200 /* ??? */
#define BHND_PCIE_SD_REGS_SERDESID 0x8310 /* ??? */
#define BHND_PCIE_SD_REGS_RXCTRL0 0x8400 /* ??? */
/*
* PCIe-G1 SerDes-R9 MDIO Registers (<= rev9)
*
* These register definitions appear to match those provided in the
* "PCI Express SerDes Registers" section of the BCM5761 Ethernet Controller
* Programmer's Reference Guide.
*/
#define BHND_PCIE_PHY_SDR9_PLL 0x1C /* SerDes PLL PHY Address*/
#define BHND_PCIE_SDR9_PLL_CTRL 0x17 /* PLL control reg */
#define BHND_PCIE_SDR9_PLL_CTRL_FREQDET_EN 0x4000 /* bit 14 is FREQDET on */
#define BHND_PCIE_PHY_SDR9_TXRX 0x0F /* SerDes RX/TX PHY Address */
#define BHND_PCIE_SDR9_RX_CTRL 0x11 /* RX ctrl register */
#define BHND_PCIE_SDR9_RX_CTRL_FORCE 0x80 /* rxpolarity_force */
#define BHND_PCIE_SDR9_RX_CTRL_POLARITY_INV 0x40 /* rxpolarity_value (if set, inverse polarity) */
#define BHND_PCIE_SDR9_RX_CDR 0x16 /* RX CDR ctrl register */
#define BHND_PCIE_SDR9_RX_CDR_FREQ_OVR_EN 0x0100 /* freq_override_en flag */
#define BHND_PCIE_SDR9_RX_CDR_FREQ_OVR_MASK 0x00FF /* freq_override_val */
#define BHND_PCIE_SDR9_RX_CDR_FREQ_OVR_SHIFT 0
#define BHND_PCIE_SDR9_RX_CDRBW 0x17 /* RX CDR bandwidth (PLL tuning) */
#define BHND_PCIE_SDR9_RX_CDRBW_INTGTRK_MASK 0x7000 /* integral loop bandwidth (phase tracking mode) */
#define BHND_PCIE_SDR9_RX_CDRBW_INTGTRK_SHIFT 11
#define BHND_PCIE_SDR9_RX_CDRBW_INTGACQ_MASK 0x0700 /* integral loop bandwidth (phase acquisition mode) */
#define BHND_PCIE_SDR9_RX_CDRBW_INTGACQ_SHIFT 8
#define BHND_PCIE_SDR9_RX_CDRBW_PROPTRK_MASK 0x0070 /* proportional loop bandwidth (phase tracking mode) */
#define BHND_PCIE_SDR9_RX_CDRBW_PROPTRK_SHIFT 4
#define BHND_PCIE_SDR9_RX_CDRBW_PROPACQ_MASK 0x0007 /* proportional loop bandwidth (phase acquisition mode) */
#define BHND_PCIE_SDR9_RX_CDRBW_PROPACQ_SHIFT 0
#define BHND_PCIE_SDR9_RX_TIMER1 0x12 /* timer1 register */
#define BHND_PCIE_SDR9_RX_TIMER1_LKTRK_MASK 0xFF00 /* phase tracking delay before asserting RX seq completion (in 16ns units) */
#define BHND_PCIE_SDR9_RX_TIMER1_LKTRK_SHIFT 8
#define BHND_PCIE_SDR9_RX_TIMER1_LKACQ_MASK 0x00FF /* phase acquisition mode time (in 1024ns units) */
#define BHND_PCIE_SDR9_RX_TIMER1_LKACQ_SHIFT 0
/* SPROM offsets */
#define BHND_PCIE_SRSH_PI_OFFSET BHND_PCI_SRSH_PI_OFFSET /**< PCI core index in SROM shadow area */
#define BHND_PCIE_SRSH_PI_MASK BHND_PCI_SRSH_PI_MASK
#define BHND_PCIE_SRSH_PI_SHIFT BHND_PCI_SRSH_PI_SHIFT
#define BHND_PCIE_SRSH_ASPM_OFFSET 8 /* word 4 */
#define BHND_PCIE_SRSH_ASPM_ENB 0x18 /* bit 3, 4 */
#define BHND_PCIE_SRSH_ASPM_L1_ENB 0x10 /* bit 4 */
#define BHND_PCIE_SRSH_ASPM_L0s_ENB 0x8 /* bit 3 */
#define BHND_PCIE_SRSH_PCIE_MISC_CONFIG 10 /* word 5 */
#define BHND_PCIE_SRSH_L23READY_EXIT_NOPRST 0x8000 /* bit 15 */
#define BHND_PCIE_SRSH_CLKREQ_OFFSET_REV5 40 /* word 20 for srom rev <= 5 */
#define BHND_PCIE_SRSH_CLKREQ_OFFSET_REV8 104 /* word 52 for srom rev 8 */
#define BHND_PCIE_SRSH_CLKREQ_ENB 0x0800 /* bit 11 */
#define BHND_PCIE_SRSH_BD_OFFSET 12 /* word 6 */
#define BHND_PCIE_SRSH_AUTOINIT_OFFSET 36 /* auto initialization enable */
/* Linkcontrol reg offset in PCIE Cap */
#define BHND_PCIE_CAP_LINKCTRL_OFFSET 16 /* linkctrl offset in pcie cap */
#define BHND_PCIE_CAP_LCREG_ASPML0s 0x01 /* ASPM L0s in linkctrl */
#define BHND_PCIE_CAP_LCREG_ASPML1 0x02 /* ASPM L1 in linkctrl */
#define BHND_PCIE_CLKREQ_ENAB 0x100 /* CLKREQ Enab in linkctrl */
#define BHND_PCIE_ASPM_ENAB 3 /* ASPM L0s & L1 in linkctrl */
#define BHND_PCIE_ASPM_L1_ENAB 2 /* ASPM L0s & L1 in linkctrl */
#define BHND_PCIE_ASPM_L0s_ENAB 1 /* ASPM L0s & L1 in linkctrl */
#define BHND_PCIE_ASPM_DISAB 0 /* ASPM L0s & L1 in linkctrl */
/* Status reg PCIE_PLP_STATUSREG */
#define BHND_PCIE_PLP_POLARITY_INV 0x10 /* lane polarity is inverted */
#endif /* _BHND_CORES_PCI_BHND_PCIREG_H_ */

View file

@ -0,0 +1,125 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
* $FreeBSD$
*/
#ifndef _BHND_CORES_PCI_BHND_PCIVAR_H_
#define _BHND_CORES_PCI_BHND_PCIVAR_H_
#include <sys/param.h>
#include <sys/bus.h>
/*
* Shared PCI Bridge/PCI Host Bridge definitions.
*/
extern devclass_t bhnd_mdio_pci_devclass;
/* Device register families. */
typedef enum {
BHND_PCI_REGFMT_PCI = 0, /* PCI register definitions */
BHND_PCI_REGFMT_PCIE = 1, /* PCIe-Gen1 register definitions */
} bhnd_pci_regfmt_t;
/* Common BHND_PCI_*_REG_(EXTRACT|INSERT) implementation */
#define _BHND_PCI_REG_EXTRACT(_regval, _mask, _shift) \
((_regval & _mask) >> _shift)
#define _BHND_PCI_REG_INSERT(_regval, _mask, _shift, _setval) \
(((_regval) & ~ _mask) | (((_setval) << _shift) & _mask))
/**
* Extract a register value by applying _MASK and _SHIFT defines.
*
* @param _regv The register value containing the desired attribute
* @param _attr The register attribute name to which to append `_MASK`/`_SHIFT`
* suffixes.
*/
#define BHND_PCI_REG_EXTRACT(_regv, _attr) \
_BHND_PCI_REG_EXTRACT(_regv, _attr ## _MASK, _attr ## _SHIFT)
/**
* Insert a value in @p _regv by applying _MASK and _SHIFT defines.
*
* @param _regv The current register value.
* @param _attr The register attribute name to which to append `_MASK`/`_SHIFT`
* suffixes.
* @param _val The value to be set in @p _regv.
*/
#define BHND_PCI_REG_INSERT(_regv, _attr, _val) \
_BHND_PCI_REG_INSERT(_regv, _attr ## _MASK, _attr ## _SHIFT, _val)
/**
* Extract a value by applying _MASK and _SHIFT defines to the common
* PCI/PCIe register definition @p _regv
*
* @param _regf The PCI core register format (BHNDB_PCI_REGFMT_*).
* @param _regv The register value containing the desired attribute
* @param _attr The register attribute name to which to prepend the register
* definition prefix and append `_MASK`/`_SHIFT` suffixes.
*/
#define BHND_PCI_COMMON_REG_EXTRACT(_regf, _regv, _attr) \
_BHND_PCI_REG_EXTRACT(_regv, \
BHND_PCI_COMMON_REG((_regf), _attr ## _MASK), \
BHND_PCI_COMMON_REG((_regf), _attr ## _SHIFT))
/**
* Insert a register value by applying _MASK and _SHIFT defines to the common
* PCI/PCIe register definition @p _regv
*
* @param _regf The PCI core register format (BHNDB_PCI_REGFMT_*).
* @param _regv The register value containing the desired attribute
* @param _attr The register attribute name to which to prepend the register
* definition prefix and append `_MASK`/`_SHIFT` suffixes.
* @param _val The value to bet set in @p _regv.
*/
#define BHND_PCI_COMMON_REG_INSERT(_regf, _regv, _attr, _val) \
_BHND_PCI_REG_INSERT(_regv, \
BHND_PCI_COMMON_REG((_regf), _attr ## _MASK), \
BHND_PCI_COMMON_REG((_regf), _attr ## _SHIFT), \
_val)
/**
* Evaluates to the offset of a common PCI/PCIe register definition.
*
* This will trigger a compile-time error if the register is not defined
* for all supported PCI/PCIe cores.
*
* This should be optimized down to a constant value if the register constant
* is the same across the register definitions.
*
* @param _regf The PCI core register format (BHNDB_PCI_REGFMT_*).
* @param _name The base name of the register.
*/
#define BHND_PCI_COMMON_REG(_regf, _name) ( \
(_regf) == BHND_PCI_REGFMT_PCI ? BHND_PCI_ ## _name : \
BHND_PCIE_ ## _name \
)
#endif /* _BHND_CORES_PCI_BHND_PCIVAR_H_ */

View file

@ -0,0 +1,384 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/*
* MDIO Driver for PCIe-G1 Cores (All Revisions).
*
* The MDIO interface provides access to the PCIe SerDes management registers.
*/
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/module.h>
#include <sys/systm.h>
#include <machine/bus.h>
#include <sys/rman.h>
#include <machine/resource.h>
#include <dev/bhnd/bhnd.h>
#include "bhnd_pcireg.h"
#include "mdio_pciereg.h"
#include "mdio_pcievar.h"
#define BHND_MDIO_CTL_DELAY 10 /**< usec delay required between
* MDIO_CTL/MDIO_DATA accesses. */
#define BHND_MDIO_RETRY_DELAY 2000 /**< usec delay before retrying
* BHND_MDIOCTL_DONE. */
#define BHND_MDIO_RETRY_COUNT 200 /**< number of times to loop waiting
* for BHND_MDIOCTL_DONE. */
#define BHND_MDIO_READ_4(_sc, _reg) \
bhnd_bus_read_4((_sc)->mem_res, (_sc)->mem_off + (_reg))
#define BHND_MDIO_WRITE_4(_sc, _reg, _val) \
bhnd_bus_write_4((_sc)->mem_res, (_sc)->mem_off + (_reg), (_val))
static int
bhnd_mdio_pcie_probe(device_t dev)
{
device_set_desc(dev, "Broadcom PCIe-G1 MDIO");
device_quiet(dev);
return (BUS_PROBE_DEFAULT);
}
/**
* Helper function that must be called by subclass BHND MDIO drivers
* when implementing DEVICE_ATTACH().
*
* @param dev The bhnd_mdio device.
* @param mem_res A memory resource containing the device resources; this
* @param mem_rid The @p mem_res resource ID, or -1 if this is a borrowed
* reference that the device should not assume ownership of.
* @param offset The offset within @p mem_res at which the MMIO register
* block is defined.
* @param c22ext If true, the MDIO driver will automatically use the PCIe
* SerDes' non-standard extended address mechanism when handling C45 register
* accesses to the PCIe SerDes device (BHND_PCIE_PHYADDR_SD /
* BHND_PCIE_DEVAD_SD).
*/
int bhnd_mdio_pcie_attach(device_t dev, struct bhnd_resource *mem_res,
int mem_rid, bus_size_t offset, bool c22ext)
{
struct bhnd_mdio_pcie_softc *sc = device_get_softc(dev);
sc->dev = dev;
sc->mem_res = mem_res;
sc->mem_rid = mem_rid;
sc->mem_off = offset;
sc->c22ext = c22ext;
BHND_MDIO_PCIE_LOCK_INIT(sc);
return (bus_generic_attach(dev));
}
static int
bhnd_mdio_pcie_detach(device_t dev)
{
struct bhnd_mdio_pcie_softc *sc = device_get_softc(dev);
BHND_MDIO_PCIE_LOCK_DESTROY(sc);
return (0);
}
/* Spin until the MDIO device reports itself as idle, or timeout is reached. */
static int
bhnd_mdio_pcie_wait_idle(struct bhnd_mdio_pcie_softc *sc)
{
uint32_t ctl;
/* Spin waiting for the BUSY flag to clear */
for (int i = 0; i < BHND_MDIO_RETRY_COUNT; i++) {
ctl = BHND_MDIO_READ_4(sc, BHND_MDIO_CTL);
if ((ctl & BHND_MDIOCTL_DONE))
return (0);
DELAY(BHND_MDIO_RETRY_DELAY);
}
return (ETIMEDOUT);
}
/**
* Write an MDIO IOCTL and wait for completion.
*/
static int
bhnd_mdio_pcie_ioctl(struct bhnd_mdio_pcie_softc *sc, uint32_t cmd)
{
BHND_MDIO_PCIE_LOCK_ASSERT(sc, MA_OWNED);
BHND_MDIO_WRITE_4(sc, BHND_MDIO_CTL, cmd);
DELAY(BHND_MDIO_CTL_DELAY);
return (0);
}
/**
* Enable MDIO device
*/
static int
bhnd_mdio_pcie_enable(struct bhnd_mdio_pcie_softc *sc)
{
uint32_t ctl;
/* Enable MDIO clock and preamble mode */
ctl = BHND_MDIOCTL_PREAM_EN|BHND_MDIOCTL_DIVISOR_VAL;
return (bhnd_mdio_pcie_ioctl(sc, ctl));
}
/**
* Disable MDIO device.
*/
static void
bhnd_mdio_pcie_disable(struct bhnd_mdio_pcie_softc *sc)
{
if (bhnd_mdio_pcie_ioctl(sc, 0))
device_printf(sc->dev, "failed to disable MDIO clock\n");
}
/**
* Issue a write command and wait for completion
*/
static int
bhnd_mdio_pcie_cmd_write(struct bhnd_mdio_pcie_softc *sc, uint32_t cmd)
{
int error;
BHND_MDIO_PCIE_LOCK_ASSERT(sc, MA_OWNED);
cmd |= BHND_MDIODATA_START|BHND_MDIODATA_TA|BHND_MDIODATA_CMD_WRITE;
BHND_MDIO_WRITE_4(sc, BHND_MDIO_DATA, cmd);
DELAY(BHND_MDIO_CTL_DELAY);
if ((error = bhnd_mdio_pcie_wait_idle(sc)))
return (error);
return (0);
}
/**
* Issue an an MDIO read command, wait for completion, and return
* the result in @p data_read.
*/
static int
bhnd_mdio_pcie_cmd_read(struct bhnd_mdio_pcie_softc *sc, uint32_t cmd,
uint16_t *data_read)
{
int error;
BHND_MDIO_PCIE_LOCK_ASSERT(sc, MA_OWNED);
cmd |= BHND_MDIODATA_START|BHND_MDIODATA_TA|BHND_MDIODATA_CMD_READ;
BHND_MDIO_WRITE_4(sc, BHND_MDIO_DATA, cmd);
DELAY(BHND_MDIO_CTL_DELAY);
if ((error = bhnd_mdio_pcie_wait_idle(sc)))
return (error);
*data_read = (BHND_MDIO_READ_4(sc, BHND_MDIO_DATA) &
BHND_MDIODATA_DATA_MASK);
return (0);
}
static int
bhnd_mdio_pcie_read(device_t dev, int phy, int reg)
{
struct bhnd_mdio_pcie_softc *sc;
uint32_t cmd;
uint16_t val;
int error;
sc = device_get_softc(dev);
/* Enable MDIO access */
BHND_MDIO_PCIE_LOCK(sc);
bhnd_mdio_pcie_enable(sc);
/* Issue the read */
cmd = BHND_MDIODATA_ADDR(phy, reg);
error = bhnd_mdio_pcie_cmd_read(sc, cmd, &val);
/* Disable MDIO access */
bhnd_mdio_pcie_disable(sc);
BHND_MDIO_PCIE_UNLOCK(sc);
if (error)
return (~0U);
return (val);
}
static int
bhnd_mdio_pcie_write(device_t dev, int phy, int reg, int val)
{
struct bhnd_mdio_pcie_softc *sc;
uint32_t cmd;
int error;
sc = device_get_softc(dev);
/* Enable MDIO access */
BHND_MDIO_PCIE_LOCK(sc);
bhnd_mdio_pcie_enable(sc);
/* Issue the write */
cmd = BHND_MDIODATA_ADDR(phy, reg) | (val & BHND_MDIODATA_DATA_MASK);
error = bhnd_mdio_pcie_cmd_write(sc, cmd);
/* Disable MDIO access */
bhnd_mdio_pcie_disable(sc);
BHND_MDIO_PCIE_UNLOCK(sc);
return (error);
}
static int
bhnd_mdio_pcie_read_ext(device_t dev, int phy, int devaddr, int reg)
{
struct bhnd_mdio_pcie_softc *sc;
uint32_t cmd;
uint16_t blk, val;
uint8_t blk_reg;
int error;
if (devaddr == MDIO_DEVADDR_NONE)
return (MDIO_READREG(dev, phy, reg));
sc = device_get_softc(dev);
/* Extended register access is only supported for the SerDes device,
* using the non-standard C22 extended address mechanism */
if (!sc->c22ext)
return (~0U);
if (phy != BHND_PCIE_PHYADDR_SD || devaddr != BHND_PCIE_DEVAD_SD)
return (~0U);
/* Enable MDIO access */
BHND_MDIO_PCIE_LOCK(sc);
bhnd_mdio_pcie_enable(sc);
/* Determine the block and register values */
blk = (reg & BHND_PCIE_SD_ADDREXT_BLK_MASK);
blk_reg = (reg & BHND_PCIE_SD_ADDREXT_REG_MASK);
/* Write the block address to the address extension register */
cmd = BHND_MDIODATA_ADDR(phy, BHND_PCIE_SD_ADDREXT) |
(blk & BHND_MDIODATA_DATA_MASK);
if ((error = bhnd_mdio_pcie_cmd_write(sc, cmd)))
goto cleanup;
/* Issue the read */
cmd = BHND_MDIODATA_ADDR(phy, blk_reg);
error = bhnd_mdio_pcie_cmd_read(sc, cmd, &val);
cleanup:
bhnd_mdio_pcie_disable(sc);
BHND_MDIO_PCIE_UNLOCK(sc);
if (error)
return (~0U);
return (val);
}
static int
bhnd_mdio_pcie_write_ext(device_t dev, int phy, int devaddr, int reg,
int val)
{
struct bhnd_mdio_pcie_softc *sc;
uint32_t cmd;
uint16_t blk;
uint8_t blk_reg;
int error;
if (devaddr == MDIO_DEVADDR_NONE)
return (MDIO_READREG(dev, phy, reg));
sc = device_get_softc(dev);
/* Extended register access is only supported for the SerDes device,
* using the non-standard C22 extended address mechanism */
if (!sc->c22ext)
return (~0U);
if (phy != BHND_PCIE_PHYADDR_SD || devaddr != BHND_PCIE_DEVAD_SD)
return (~0U);
/* Enable MDIO access */
BHND_MDIO_PCIE_LOCK(sc);
bhnd_mdio_pcie_enable(sc);
/* Determine the block and register values */
blk = (reg & BHND_PCIE_SD_ADDREXT_BLK_MASK);
blk_reg = (reg & BHND_PCIE_SD_ADDREXT_REG_MASK);
/* Write the block address to the address extension register */
cmd = BHND_MDIODATA_ADDR(phy, BHND_PCIE_SD_ADDREXT) |
(blk & BHND_MDIODATA_DATA_MASK);
if ((error = bhnd_mdio_pcie_cmd_write(sc, cmd)))
goto cleanup;
/* Issue the write */
cmd = BHND_MDIODATA_ADDR(phy, blk_reg) |
(val & BHND_MDIODATA_DATA_MASK);
error = bhnd_mdio_pcie_cmd_write(sc, cmd);
cleanup:
bhnd_mdio_pcie_disable(sc);
BHND_MDIO_PCIE_UNLOCK(sc);
return (error);
}
static device_method_t bhnd_mdio_pcie_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, bhnd_mdio_pcie_probe),
DEVMETHOD(device_detach, bhnd_mdio_pcie_detach),
/* MDIO interface */
DEVMETHOD(mdio_readreg, bhnd_mdio_pcie_read),
DEVMETHOD(mdio_writereg, bhnd_mdio_pcie_write),
DEVMETHOD(mdio_readextreg, bhnd_mdio_pcie_read_ext),
DEVMETHOD(mdio_writeextreg, bhnd_mdio_pcie_write_ext),
DEVMETHOD_END
};
DEFINE_CLASS_0(bhnd_mdio_pcie, bhnd_mdio_pcie_driver, bhnd_mdio_pcie_methods, sizeof(struct bhnd_mdio_pcie_softc));

View file

@ -0,0 +1,57 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* Copyright (c) 2010 Broadcom Corporation
* All rights reserved.
*
* This file is derived from the pcie_core.h header distributed with Broadcom's
* initial brcm80211 Linux driver release, as contributed to the Linux staging
* repository.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $FreeBSD$
*/
#ifndef _BHND_CORES_PCI_MDIO_PCIEREG_H_
#define _BHND_CORES_PCI_MDIO_PCIEREG_H_
/* MDIO register offsets */
#define BHND_MDIO_CTL 0x0 /**< mdio control */
#define BHND_MDIO_DATA 0x4 /**< mdio data */
/* MDIO control */
#define BHND_MDIOCTL_DIVISOR_MASK 0x7f /* clock divisor mask */
#define BHND_MDIOCTL_DIVISOR_VAL 0x2 /* default clock divisor */
#define BHND_MDIOCTL_PREAM_EN 0x80 /* enable preamble mode */
#define BHND_MDIOCTL_DONE 0x100 /* tranaction completed */
/* MDIO Data */
#define BHND_MDIODATA_PHYADDR_MASK 0x0f800000 /* phy addr */
#define BHND_MDIODATA_PHYADDR_SHIFT 23
#define BHND_MDIODATA_REGADDR_MASK 0x007c0000 /* reg/dev addr */
#define BHND_MDIODATA_REGADDR_SHIFT 18
#define BHND_MDIODATA_DATA_MASK 0x0000ffff /* data */
#define BHND_MDIODATA_TA 0x00020000 /* slave turnaround time */
#define BHND_MDIODATA_START 0x40000000 /* start of transaction */
#define BHND_MDIODATA_CMD_WRITE 0x10000000 /* write command */
#define BHND_MDIODATA_CMD_READ 0x20000000 /* read command */
#define BHND_MDIODATA_ADDR(_phyaddr, _regaddr) ( \
(((_phyaddr) << BHND_MDIODATA_PHYADDR_SHIFT) & \
BHND_MDIODATA_PHYADDR_MASK) | \
(((_regaddr) << BHND_MDIODATA_REGADDR_SHIFT) & \
BHND_MDIODATA_REGADDR_MASK) \
)
#endif /* _BHND_CORES_PCI_MDIO_PCIEREG_H_ */

View file

@ -0,0 +1,69 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
* $FreeBSD$
*/
#ifndef _BHND_CORES_PCI_MDIO_PCIEVAR_H_
#define _BHND_CORES_PCI_MDIO_PCIEVAR_H_
#include <dev/mdio/mdio.h>
#include "mdio_if.h"
DECLARE_CLASS(bhnd_mdio_pcie_driver);
int bhnd_mdio_pcie_attach(device_t dev, struct bhnd_resource *mem_res,
int mem_rid, bus_size_t offset, bool c22ext);
struct bhnd_mdio_pcie_softc {
device_t dev; /**< mdio device */
struct mtx sc_mtx; /**< mdio register lock */
struct bhnd_resource *mem_res; /**< parent pcie registers */
int mem_rid; /**< MDIO register resID, or
-1 if mem_res reference is
borrowed. */
bus_size_t mem_off; /**< mdio register offset */
bool c22ext; /**< automatically rewrite C45
register requests made
to the PCIe SerDes slave
to use its non-standard
C22 address extension
mechanism. */
};
#define BHND_MDIO_PCIE_LOCK_INIT(sc) \
mtx_init(&(sc)->sc_mtx, device_get_nameunit((sc)->dev), \
"bhnd_pci_mdio register lock", MTX_DEF)
#define BHND_MDIO_PCIE_LOCK(sc) mtx_lock(&(sc)->sc_mtx)
#define BHND_MDIO_PCIE_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx)
#define BHND_MDIO_PCIE_LOCK_ASSERT(sc, what) mtx_assert(&(sc)->sc_mtx, what)
#define BHND_MDIO_PCIE_LOCK_DESTROY(sc) mtx_destroy(&(sc)->sc_mtx)
#endif /* _BHND_CORES_PCI_MDIO_PCIEVAR_H_ */

View file

@ -0,0 +1,65 @@
/*-
* Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
* $FreeBSD$
*/
#ifndef _BHND_NVRAM_BHND_NVRAM_H_
#define _BHND_NVRAM_BHND_NVRAM_H_
/**
* NVRAM data sources supported by bhnd(4) devices.
*/
typedef enum {
BHND_NVRAM_SRC_CIS, /**< Default CIS source; this may
* apply, for example, to PCMCIA cards
* vending Broadcom NVRAM data via
* their standard CIS table. */
BHND_NVRAM_SRC_OTP, /**< On-chip one-time-programmable
* memory. */
BHND_NVRAM_SRC_NFLASH, /**< External flash device accessible
* via on-chip flash core, such
* as the NAND/QSPI controller cores
* used on Northstar devices to access
* NVRAM. */
BHND_NVRAM_SRC_SPROM, /**< External serial EEPROM. */
BHND_NVRAM_SRC_NONE /**< No NVRAM source is directly
* attached. This is used on devices
* attached via PCI(e) to BHND SoCs,
* where to avoid unnecessary flash
* hardware, NVRAM configuration for
* individual devices is provided by
* hardware attached to the SoC
* itself.
*/
} bhnd_nvram_src_t;
#endif /* _BHND_NVRAM_BHND_NVRAM_H_ */

View file

@ -0,0 +1,64 @@
#-
# Copyright (c) 2016 Landon Fuller <landon@landonf.org>
# 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 <sys/types.h>
#include <sys/bus.h>
#include <dev/bhnd/bhnd.h>
INTERFACE bhnd_nvram;
#
# bhnd(4) NVRAM device interface.
#
# Provides a shared interface to HND NVRAM, OTP, and SPROM devices that provide
# access to a common set of hardware/device configuration variables.
#
/**
* Read an NVRAM variable.
*
* @param dev The NVRAM device.
* @param name The NVRAM variable name.
* @param[out] buf On success, the requested value will be written
* to this buffer. This argment may be NULL if
* the value is not desired.
* @param[in,out] size The capacity of @p buf. On success, will be set
* to the actual size of the requested value.
*
* @retval 0 success
* @retval ENOENT The requested variable was not found.
* @retval ENOMEM If @p buf is non-NULL and a buffer of @p size is too
* small to hold the requested value.
* @retval non-zero If reading @p name otherwise fails, a regular unix
* error code will be returned.
*/
METHOD int getvar {
device_t dev;
const char *name;
void *buf;
size_t *size;
};

679
sys/dev/bhnd/siba/siba.c Normal file
View file

@ -0,0 +1,679 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/systm.h>
#include <machine/bus.h>
#include <dev/bhnd/cores/chipc/chipcreg.h>
#include "sibareg.h"
#include "sibavar.h"
int
siba_probe(device_t dev)
{
device_set_desc(dev, "SIBA BHND bus");
return (BUS_PROBE_DEFAULT);
}
int
siba_attach(device_t dev)
{
struct siba_devinfo *dinfo;
device_t *devs;
int ndevs;
int error;
// TODO: We need to set the initiator timeout for the
// core that will be issuing requests to non-memory locations.
//
// In the case of a bridged device, this is the hostb core.
// On a non-bridged device, this will be the CPU.
/* Fetch references to the siba SIBA_CFG* blocks for all
* registered devices */
if ((error = device_get_children(dev, &devs, &ndevs)))
return (error);
for (int i = 0; i < ndevs; i++) {
struct siba_addrspace *addrspace;
struct siba_port *port;
dinfo = device_get_ivars(devs[i]);
KASSERT(!device_is_suspended(devs[i]),
("siba(4) stateful suspend handling requires that devices "
"not be suspended before siba_attach()"));
/* Fetch the core register address space */
port = siba_dinfo_get_port(dinfo, BHND_PORT_DEVICE, 0);
if (port == NULL) {
error = ENXIO;
goto cleanup;
}
addrspace = siba_find_port_addrspace(port, SIBA_ADDRSPACE_CORE);
if (addrspace == NULL) {
error = ENXIO;
goto cleanup;
}
/*
* Map the per-core configuration blocks
*/
KASSERT(dinfo->core_id.num_cfg_blocks <= SIBA_CFG_NUM_MAX,
("config block count %u out of range",
dinfo->core_id.num_cfg_blocks));
for (u_int cfgidx = 0; cfgidx < dinfo->core_id.num_cfg_blocks;
cfgidx++)
{
rman_res_t r_start, r_count, r_end;
/* Determine the config block's address range; configuration
* blocks are allocated starting at SIBA_CFG0_OFFSET,
* growing downwards. */
r_start = addrspace->sa_base + SIBA_CFG0_OFFSET;
r_start -= cfgidx * SIBA_CFG_SIZE;
r_count = SIBA_CFG_SIZE;
r_end = r_start + r_count - 1;
/* Allocate the config resource */
dinfo->cfg_rid[cfgidx] = 0;
dinfo->cfg[cfgidx] = bhnd_alloc_resource(dev,
SYS_RES_MEMORY, &dinfo->cfg_rid[cfgidx], r_start,
r_end, r_count, RF_ACTIVE);
if (dinfo->cfg[cfgidx] == NULL) {
device_printf(dev, "failed allocating CFG_%u for "
"core %d\n", cfgidx, i);
error = ENXIO;
goto cleanup;
}
};
}
cleanup:
free(devs, M_BHND);
if (error)
return (error);
/* Delegate remainder to standard bhnd method implementation */
return (bhnd_generic_attach(dev));
}
int
siba_detach(device_t dev)
{
return (bhnd_generic_detach(dev));
}
static int
siba_read_ivar(device_t dev, device_t child, int index, uintptr_t *result)
{
const struct siba_devinfo *dinfo;
const struct bhnd_core_info *cfg;
dinfo = device_get_ivars(child);
cfg = &dinfo->core_id.core_info;
switch (index) {
case BHND_IVAR_VENDOR:
*result = cfg->vendor;
return (0);
case BHND_IVAR_DEVICE:
*result = cfg->device;
return (0);
case BHND_IVAR_HWREV:
*result = cfg->hwrev;
return (0);
case BHND_IVAR_DEVICE_CLASS:
*result = bhnd_core_class(cfg);
return (0);
case BHND_IVAR_VENDOR_NAME:
*result = (uintptr_t) bhnd_vendor_name(cfg->vendor);
return (0);
case BHND_IVAR_DEVICE_NAME:
*result = (uintptr_t) bhnd_core_name(cfg);
return (0);
case BHND_IVAR_CORE_INDEX:
*result = cfg->core_idx;
return (0);
case BHND_IVAR_CORE_UNIT:
*result = cfg->unit;
return (0);
default:
return (ENOENT);
}
}
static int
siba_write_ivar(device_t dev, device_t child, int index, uintptr_t value)
{
switch (index) {
case BHND_IVAR_VENDOR:
case BHND_IVAR_DEVICE:
case BHND_IVAR_HWREV:
case BHND_IVAR_DEVICE_CLASS:
case BHND_IVAR_VENDOR_NAME:
case BHND_IVAR_DEVICE_NAME:
case BHND_IVAR_CORE_INDEX:
case BHND_IVAR_CORE_UNIT:
return (EINVAL);
default:
return (ENOENT);
}
}
static void
siba_child_deleted(device_t dev, device_t child)
{
struct siba_devinfo *dinfo = device_get_ivars(child);
if (dinfo != NULL)
siba_free_dinfo(dev, dinfo);
}
static struct resource_list *
siba_get_resource_list(device_t dev, device_t child)
{
struct siba_devinfo *dinfo = device_get_ivars(child);
return (&dinfo->resources);
}
static int
siba_reset_core(device_t dev, device_t child, uint16_t flags)
{
struct siba_devinfo *dinfo;
if (device_get_parent(child) != dev)
BHND_BUS_RESET_CORE(device_get_parent(dev), child, flags);
dinfo = device_get_ivars(child);
/* Can't reset the core without access to the CFG0 registers */
if (dinfo->cfg[0] == NULL)
return (ENODEV);
// TODO - perform reset
return (ENXIO);
}
static int
siba_suspend_core(device_t dev, device_t child)
{
struct siba_devinfo *dinfo;
if (device_get_parent(child) != dev)
BHND_BUS_SUSPEND_CORE(device_get_parent(dev), child);
dinfo = device_get_ivars(child);
/* Can't suspend the core without access to the CFG0 registers */
if (dinfo->cfg[0] == NULL)
return (ENODEV);
// TODO - perform suspend
return (ENXIO);
}
static u_int
siba_get_port_count(device_t dev, device_t child, bhnd_port_type type)
{
struct siba_devinfo *dinfo;
/* delegate non-bus-attached devices to our parent */
if (device_get_parent(child) != dev)
return (BHND_BUS_GET_PORT_COUNT(device_get_parent(dev), child,
type));
dinfo = device_get_ivars(child);
/* We advertise exactly one port of any type */
if (siba_dinfo_get_port(dinfo, type, 0) != NULL)
return (1);
return (0);
}
static u_int
siba_get_region_count(device_t dev, device_t child, bhnd_port_type type,
u_int port_num)
{
struct siba_devinfo *dinfo;
struct siba_port *port;
/* delegate non-bus-attached devices to our parent */
if (device_get_parent(child) != dev)
return (BHND_BUS_GET_REGION_COUNT(device_get_parent(dev), child,
type, port_num));
dinfo = device_get_ivars(child);
port = siba_dinfo_get_port(dinfo, type, port_num);
if (port == NULL)
return (0);
return (port->sp_num_addrs);
}
static int
siba_get_port_rid(device_t dev, device_t child, bhnd_port_type port_type,
u_int port_num, u_int region_num)
{
struct siba_devinfo *dinfo;
struct siba_port *port;
struct siba_addrspace *addrspace;
/* delegate non-bus-attached devices to our parent */
if (device_get_parent(child) != dev)
return (BHND_BUS_GET_PORT_RID(device_get_parent(dev), child,
port_type, port_num, region_num));
dinfo = device_get_ivars(child);
port = siba_dinfo_get_port(dinfo, port_type, port_num);
if (port == NULL)
return (-1);
STAILQ_FOREACH(addrspace, &port->sp_addrs, sa_link) {
if (addrspace->sa_region_num == region_num)
return (addrspace->sa_rid);
}
/* not found */
return (-1);
}
static int
siba_decode_port_rid(device_t dev, device_t child, int type, int rid,
bhnd_port_type *port_type, u_int *port_num, u_int *region_num)
{
struct siba_devinfo *dinfo;
struct siba_port *port;
struct siba_addrspace *addrspace;
/* delegate non-bus-attached devices to our parent */
if (device_get_parent(child) != dev)
return (BHND_BUS_DECODE_PORT_RID(device_get_parent(dev), child,
type, rid, port_type, port_num, region_num));
dinfo = device_get_ivars(child);
/* Ports are always memory mapped */
if (type != SYS_RES_MEMORY)
return (EINVAL);
/* Starting with the most likely device list, search all three port
* lists */
bhnd_port_type types[] = {
BHND_PORT_DEVICE,
BHND_PORT_AGENT,
BHND_PORT_BRIDGE
};
for (int i = 0; i < nitems(types); i++) {
port = siba_dinfo_get_port(dinfo, types[i], 0);
if (port == NULL)
continue;
STAILQ_FOREACH(addrspace, &port->sp_addrs, sa_link) {
if (addrspace->sa_rid != rid)
continue;
*port_type = port->sp_type;
*port_num = port->sp_num;
*region_num = addrspace->sa_region_num;
}
}
return (ENOENT);
}
static int
siba_get_region_addr(device_t dev, device_t child, bhnd_port_type port_type,
u_int port_num, u_int region_num, bhnd_addr_t *addr, bhnd_size_t *size)
{
struct siba_devinfo *dinfo;
struct siba_port *port;
struct siba_addrspace *addrspace;
/* delegate non-bus-attached devices to our parent */
if (device_get_parent(child) != dev) {
return (BHND_BUS_GET_REGION_ADDR(device_get_parent(dev), child,
port_type, port_num, region_num, addr, size));
}
dinfo = device_get_ivars(child);
port = siba_dinfo_get_port(dinfo, port_type, port_num);
if (port == NULL)
return (ENOENT);
STAILQ_FOREACH(addrspace, &port->sp_addrs, sa_link) {
if (addrspace->sa_region_num != region_num)
continue;
*addr = addrspace->sa_base;
*size = addrspace->sa_size;
return (0);
}
return (ENOENT);
}
/**
* Register all address space mappings for @p di.
*
* @param dev The siba bus device.
* @param di The device info instance on which to register all address
* space entries.
* @param r A resource mapping the enumeration table block for @p di.
*/
static int
siba_register_addrspaces(device_t dev, struct siba_devinfo *di,
struct resource *r)
{
struct siba_core_id *cid;
uint32_t addr;
uint32_t size;
u_int region_num;
int error;
cid = &di->core_id;
/* Region numbers must be assigned in order, but our siba address
* space IDs may be sparsely allocated; thus, we track
* the region index seperately. */
region_num = 0;
/* Register the device address space entries */
for (uint8_t sid = 0; sid < di->core_id.num_addrspace; sid++) {
uint32_t adm;
u_int adm_offset;
uint32_t bus_reserved;
/* Determine the register offset */
adm_offset = siba_admatch_offset(sid);
if (adm_offset == 0) {
device_printf(dev, "addrspace %hhu is unsupported", sid);
return (ENODEV);
}
/* Fetch the address match register value */
adm = bus_read_4(r, adm_offset);
/* Skip disabled entries */
if (adm & SIBA_AM_ADEN)
continue;
/* Parse the value */
if ((error = siba_parse_admatch(adm, &addr, &size))) {
device_printf(dev, "failed to decode address "
" match register value 0x%x\n", adm);
return (error);
}
/* If this is the device's core/enumeration addrespace,
* reserve the Sonics configuration register blocks for the
* use of our bus. */
bus_reserved = 0;
if (sid == SIBA_ADDRSPACE_CORE)
bus_reserved = cid->num_cfg_blocks * SIBA_CFG_SIZE;
/* Append the region info */
error = siba_append_dinfo_region(di, BHND_PORT_DEVICE, 0,
region_num, sid, addr, size, bus_reserved);
if (error)
return (error);
region_num++;
}
return (0);
}
/**
* Scan the core table and add all valid discovered cores to
* the bus.
*
* @param dev The siba bus device.
* @param chipid The chip identifier, if the device does not provide a
* ChipCommon core. Should o NULL otherwise.
*/
int
siba_add_children(device_t dev, const struct bhnd_chipid *chipid)
{
struct bhnd_chipid ccid;
struct bhnd_core_info *cores;
struct siba_devinfo *dinfo;
struct resource *r;
int rid;
int error;
dinfo = NULL;
cores = NULL;
r = NULL;
/*
* Try to determine the number of device cores via the ChipCommon
* identification registers.
*
* A small number of very early devices do not include a ChipCommon
* core, in which case our caller must supply the chip identification
* information via a non-NULL chipid parameter.
*/
if (chipid == NULL) {
uint32_t idhigh, ccreg;
uint16_t vendor, device;
uint8_t ccrev;
/* Map the first core's register block. If the ChipCommon core
* exists, it will always be the first core. */
rid = 0;
r = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
SIBA_CORE_ADDR(0), SIBA_CORE_SIZE,
SIBA_CORE_ADDR(0) + SIBA_CORE_SIZE - 1,
RF_ACTIVE);
/* Identify the core */
idhigh = bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDHIGH));
vendor = SIBA_REG_GET(idhigh, IDH_VENDOR);
device = SIBA_REG_GET(idhigh, IDH_DEVICE);
ccrev = SIBA_IDH_CORE_REV(idhigh);
if (vendor != OCP_VENDOR_BCM || device != BHND_COREID_CC) {
device_printf(dev,
"cannot identify device: no chipcommon core "
"found\n");
error = ENXIO;
goto cleanup;
}
/* Identify the chipset */
ccreg = bus_read_4(r, CHIPC_ID);
ccid = bhnd_parse_chipid(ccreg, SIBA_ENUM_ADDR);
if (!CHIPC_NCORES_MIN_HWREV(ccrev)) {
switch (device) {
case BHND_CHIPID_BCM4306:
ccid.ncores = 6;
break;
case BHND_CHIPID_BCM4704:
ccid.ncores = 9;
break;
case BHND_CHIPID_BCM5365:
/*
* BCM5365 does support ID_NUMCORE in at least
* some of its revisions, but for unknown
* reasons, Broadcom's drivers always exclude
* the ChipCommon revision (0x5) used by BCM5365
* from the set of revisions supporting
* ID_NUMCORE, and instead supply a fixed value.
*
* Presumably, at least some of these devices
* shipped with a broken ID_NUMCORE value.
*/
ccid.ncores = 7;
break;
default:
device_printf(dev, "unable to determine core "
"count for unrecognized chipset 0x%hx\n",
ccid.chip_id);
error = ENXIO;
goto cleanup;
}
}
chipid = &ccid;
bus_release_resource(dev, SYS_RES_MEMORY, rid, r);
}
/* Allocate our temporary core table and enumerate all cores */
cores = malloc(sizeof(*cores) * chipid->ncores, M_BHND, M_NOWAIT);
if (cores == NULL)
return (ENOMEM);
/* Add all cores. */
for (u_int i = 0; i < chipid->ncores; i++) {
struct siba_core_id cid;
device_t child;
uint32_t idhigh, idlow;
rman_res_t r_count, r_end, r_start;
/* Map the core's register block */
rid = 0;
r_start = SIBA_CORE_ADDR(i);
r_count = SIBA_CORE_SIZE;
r_end = r_start + SIBA_CORE_SIZE - 1;
r = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, r_start,
r_end, r_count, RF_ACTIVE);
if (r == NULL) {
error = ENXIO;
goto cleanup;
}
/* Read the core info */
idhigh = bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDHIGH));
idlow = bus_read_4(r, SB0_REG_ABS(SIBA_CFG0_IDLOW));
cid = siba_parse_core_id(idhigh, idlow, i, 0);
cores[i] = cid.core_info;
/* Determine unit number */
for (u_int j = 0; j < i; j++) {
if (cores[j].vendor == cores[i].vendor &&
cores[j].device == cores[i].device)
cores[i].unit++;
}
/* Allocate per-device bus info */
dinfo = siba_alloc_dinfo(dev, &cid);
if (dinfo == NULL) {
error = ENXIO;
goto cleanup;
}
/* Register the core's address space(s). */
if ((error = siba_register_addrspaces(dev, dinfo, r)))
goto cleanup;
/* Add the child device */
child = device_add_child(dev, NULL, -1);
if (child == NULL) {
error = ENXIO;
goto cleanup;
}
/* The child device now owns the dinfo pointer */
device_set_ivars(child, dinfo);
dinfo = NULL;
/* If pins are floating or the hardware is otherwise
* unpopulated, the device shouldn't be used. */
if (bhnd_is_hw_disabled(child))
device_disable(child);
/* Release our resource */
bus_release_resource(dev, SYS_RES_MEMORY, rid, r);
r = NULL;
}
cleanup:
if (cores != NULL)
free(cores, M_BHND);
if (dinfo != NULL)
siba_free_dinfo(dev, dinfo);
if (r != NULL)
bus_release_resource(dev, SYS_RES_MEMORY, rid, r);
return (error);
}
static device_method_t siba_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, siba_probe),
DEVMETHOD(device_attach, siba_attach),
DEVMETHOD(device_detach, siba_detach),
/* Bus interface */
DEVMETHOD(bus_child_deleted, siba_child_deleted),
DEVMETHOD(bus_read_ivar, siba_read_ivar),
DEVMETHOD(bus_write_ivar, siba_write_ivar),
DEVMETHOD(bus_get_resource_list, siba_get_resource_list),
/* BHND interface */
DEVMETHOD(bhnd_bus_reset_core, siba_reset_core),
DEVMETHOD(bhnd_bus_suspend_core, siba_suspend_core),
DEVMETHOD(bhnd_bus_get_port_count, siba_get_port_count),
DEVMETHOD(bhnd_bus_get_region_count, siba_get_region_count),
DEVMETHOD(bhnd_bus_get_port_rid, siba_get_port_rid),
DEVMETHOD(bhnd_bus_decode_port_rid, siba_decode_port_rid),
DEVMETHOD(bhnd_bus_get_region_addr, siba_get_region_addr),
DEVMETHOD_END
};
DEFINE_CLASS_1(bhnd, siba_driver, siba_methods, sizeof(struct siba_softc), bhnd_driver);
MODULE_VERSION(siba, 1);
MODULE_DEPEND(siba, bhnd, 1, 1, 1);

49
sys/dev/bhnd/siba/siba.h Normal file
View file

@ -0,0 +1,49 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
* $FreeBSD$
*/
#ifndef _SIBA_SIBA_H_
#define _SIBA_SIBA_H_
#include <sys/types.h>
#include <sys/bus.h>
#include <sys/malloc.h>
#include <sys/queue.h>
#include <sys/rman.h>
#include <dev/bhnd/bhndvar.h>
/*
* Broadcom Sonics Silicon backplane types and data structures.
*/
DECLARE_CLASS(siba_driver);
#endif /* _SIBA_SIBA_H_ */

View file

@ -0,0 +1,171 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/bus.h>
#include <sys/module.h>
#include <dev/bhnd/bhnd_ids.h>
#include <dev/bhnd/bhndb/bhndbvar.h>
#include <dev/bhnd/bhndb/bhndb_hwdata.h>
#include "sibavar.h"
/*
* Supports attachment of siba(4) bus devices via a bhndb bridge.
*/
static int
siba_bhndb_probe(device_t dev)
{
const struct bhnd_chipid *cid;
/* Check bus type */
cid = BHNDB_GET_CHIPID(device_get_parent(dev), dev);
if (cid->chip_type != BHND_CHIPTYPE_SIBA)
return (ENXIO);
/* Delegate to default probe implementation */
return (siba_probe(dev));
}
static int
siba_bhndb_attach(device_t dev)
{
const struct bhnd_chipid *chipid;
int error;
/* Enumerate our children. */
chipid = BHNDB_GET_CHIPID(device_get_parent(dev), dev);
if ((error = siba_add_children(dev, chipid)))
return (error);
/* Initialize full bridge configuration */
error = BHNDB_INIT_FULL_CONFIG(device_get_parent(dev), dev,
bhndb_siba_priority_table);
if (error)
return (error);
/* Call our superclass' implementation */
return (siba_attach(dev));
}
/* Suspend all references to the device's cfg register blocks */
static void
siba_bhndb_suspend_cfgblocks(device_t dev, struct siba_devinfo *dinfo) {
for (u_int i = 0; i < dinfo->core_id.num_cfg_blocks; i++) {
if (dinfo->cfg[i] == NULL)
continue;
BHNDB_SUSPEND_RESOURCE(device_get_parent(dev), dev,
SYS_RES_MEMORY, dinfo->cfg[i]->res);
}
}
static int
siba_bhndb_suspend_child(device_t dev, device_t child)
{
struct siba_devinfo *dinfo;
int error;
if (device_get_parent(child) != dev)
BUS_SUSPEND_CHILD(device_get_parent(dev), child);
dinfo = device_get_ivars(child);
/* Suspend the child */
if ((error = bhnd_generic_br_suspend_child(dev, child)))
return (error);
/* Suspend resource references to the child's config registers */
siba_bhndb_suspend_cfgblocks(dev, dinfo);
return (0);
}
static int
siba_bhndb_resume_child(device_t dev, device_t child)
{
struct siba_devinfo *dinfo;
int error;
if (device_get_parent(child) != dev)
BUS_SUSPEND_CHILD(device_get_parent(dev), child);
if (!device_is_suspended(child))
return (EBUSY);
dinfo = device_get_ivars(child);
/* Resume all resource references to the child's config registers */
for (u_int i = 0; i < dinfo->core_id.num_cfg_blocks; i++) {
if (dinfo->cfg[i] == NULL)
continue;
error = BHNDB_RESUME_RESOURCE(device_get_parent(dev), dev,
SYS_RES_MEMORY, dinfo->cfg[i]->res);
if (error) {
siba_bhndb_suspend_cfgblocks(dev, dinfo);
return (error);
}
}
/* Resume the child */
if ((error = bhnd_generic_br_resume_child(dev, child))) {
siba_bhndb_suspend_cfgblocks(dev, dinfo);
return (error);
}
return (0);
}
static device_method_t siba_bhndb_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, siba_bhndb_probe),
DEVMETHOD(device_attach, siba_bhndb_attach),
/* Bus interface */
DEVMETHOD(bus_suspend_child, siba_bhndb_suspend_child),
DEVMETHOD(bus_resume_child, siba_bhndb_resume_child),
DEVMETHOD_END
};
DEFINE_CLASS_1(bhnd, siba_bhndb_driver, siba_bhndb_methods,
sizeof(struct siba_softc), siba_driver);
DRIVER_MODULE(siba_bhndb, bhndb, siba_bhndb_driver, bhnd_devclass, NULL, NULL);
MODULE_VERSION(siba_bhndb, 1);
MODULE_DEPEND(siba_bhndb, siba, 1, 1, 1);
MODULE_DEPEND(siba_bhndb, bhndb, 1, 1, 1);

View file

@ -0,0 +1,453 @@
/*-
* Copyright (c) 2007 Bruce M. Simpson.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/rman.h>
#include <sys/malloc.h>
#include <machine/bus.h>
#include <dev/bhnd/bhnd_ids.h>
#include <dev/bhnd/cores/bhnd_chipcreg.h>
#include "sibareg.h"
#include "sibavar.h"
/*
* Supports siba(4) attachment to a MIPS nexus bus.
*
* This driver is a direct port of Bruce M. Simpson' original siba(4) to the
* bhnd(4) bus infrastructure.
*/
/*
* TODO: De-mipsify this code.
* TODO: cpu clock calculation. -> move to siba_cc instance
* TODO: Hardwire IRQs for attached cores on siba at probe time.
* TODO: Support detach.
* TODO: Power management.
* TODO: code cleanup.
* TODO: Support deployments of siba other than as a system bus.
*/
#ifndef MIPS_MEM_RID
#define MIPS_MEM_RID 0x20
#endif
extern int rman_debug;
static struct rman mem_rman; /* XXX move to softc */
static int siba_debug = 1;
static const char descfmt[] = "Sonics SiliconBackplane rev %s";
#define SIBA_DEVDESCLEN sizeof(descfmt) + 8
static int siba_nexus_activate_resource(device_t, device_t, int, int,
struct resource *);
static struct resource *
siba_nexus_alloc_resource(device_t, device_t, int, int *,
rman_res_t, rman_res_t, rman_res_t, u_int);
static int siba_nexus_attach(device_t);
#ifdef notyet
static uint8_t siba_nexus_getirq(uint16_t);
#endif
static int siba_nexus_probe(device_t);
struct siba_nexus_softc {
struct siba_softc parent_sc;
device_t siba_dev; /* Device ID */
struct bhnd_chipid siba_cid;
struct resource *siba_mem_res;
bus_space_tag_t siba_mem_bt;
bus_space_handle_t siba_mem_bh;
bus_addr_t siba_maddr;
bus_size_t siba_msize;
};
// TODO - depends on bhnd(4) IRQ support
#ifdef notyet
/*
* On the Sentry5, the system bus IRQs are the same as the
* MIPS IRQs. Particular cores are hardwired to certain IRQ lines.
*/
static uint8_t
siba_nexus_getirq(uint16_t devid)
{
uint8_t irq;
switch (devid) {
case BHND_COREID_CC:
irq = 0;
break;
case BHND_COREID_ENET:
irq = 1;
break;
case BHND_COREID_IPSEC:
irq = 2;
break;
case BHND_COREID_USB:
irq = 3;
break;
case BHND_COREID_PCI:
irq = 4;
break;
#if 0
/*
* 5 is reserved for the MIPS on-chip timer interrupt;
* it is hard-wired by the tick driver.
*/
case BHND_COREID_MIPS:
case BHND_COREID_MIPS33:
irq = 5;
break;
#endif
default:
irq = 0xFF; /* this core does not need an irq */
break;
}
return (irq);
}
#endif
static int
siba_nexus_probe(device_t dev)
{
struct siba_nexus_softc *sc = device_get_softc(dev);
struct bhnd_core_info cc;
uint32_t idhi, idlo;
int error, rid;
sc->siba_dev = dev;
//rman_debug = 1; /* XXX */
/*
* Read the ChipCommon info using the hints the kernel
* was compiled with.
*/
rid = MIPS_MEM_RID;
sc->siba_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
RF_ACTIVE);
if (sc->siba_mem_res == NULL) {
device_printf(dev, "unable to allocate probe aperture\n");
return (ENXIO);
}
sc->siba_mem_bt = rman_get_bustag(sc->siba_mem_res);
sc->siba_mem_bh = rman_get_bushandle(sc->siba_mem_res);
sc->siba_maddr = rman_get_start(sc->siba_mem_res);
sc->siba_msize = rman_get_size(sc->siba_mem_res);
if (siba_debug) {
device_printf(dev, "start %08x len %08x\n",
sc->siba_maddr, sc->siba_msize);
}
idlo = bus_read_4(sc->siba_mem_res, SIBA_IDLOW);
idhi = bus_read_4(sc->siba_mem_res, SIBA_IDHIGH);
cc = siba_parse_core_info(idhi, 0, 0);
if (siba_debug) {
device_printf(dev, "idhi = %08x\n", idhi);
device_printf(dev, " chipcore id = %08x\n", cc.device);
}
/*
* For now, check that the first core is the ChipCommon core.
*/
if (bhnd_core_class(&cc) != BHND_DEVCLASS_CC) {
if (siba_debug)
device_printf(dev, "first core is not ChipCommon\n");
return (ENXIO);
}
/*
* Determine backplane revision and set description string.
*/
uint32_t rev;
char *revp;
char descbuf[SIBA_DEVDESCLEN];
rev = SIBA_REG_GET(idlo, IDL_SBREV);
revp = "unknown";
if (rev == SIBA_IDL_SBREV_2_2)
revp = "2.2";
else if (rev == SIBA_IDL_SBREV_2_3)
revp = "2.3";
(void)snprintf(descbuf, sizeof(descbuf), descfmt, revp);
device_set_desc_copy(dev, descbuf);
/*
* Determine how many cores are present on this siba bus, so
* that we may map them all.
*/
uint32_t ccidreg;
ccidreg = bus_read_4(sc->siba_mem_res, CHIPC_ID);
sc->siba_cid = bhnd_parse_chipid(ccidreg, sc->siba_maddr);
if (siba_debug) {
device_printf(dev, "ccid = %08x, cc_id = %04x, cc_rev = %04x\n",
ccidreg, sc->siba_cid.chip_id, sc->siba_cid.chip_rev);
}
if (sc->siba_cid.ncores == 0)
sc->siba_cid.ncores = siba_get_ncores(&sc->siba_cid);
if (siba_debug) {
device_printf(dev, "%d cores detected.\n", sc->siba_cid.ncores);
}
/*
* Now we know how many cores are on this siba, release the
* mapping and allocate a new mapping spanning all cores on the bus.
*/
rid = MIPS_MEM_RID;
error = bus_release_resource(dev, SYS_RES_MEMORY, rid,
sc->siba_mem_res);
if (error != 0) {
device_printf(dev, "error %d releasing resource\n", error);
return (ENXIO);
}
return (0);
}
static int
siba_nexus_attach(device_t dev)
{
struct siba_nexus_softc *sc = device_get_softc(dev);
uint32_t total;
int error, rid;
if (siba_debug)
printf("%s: entry\n", __func__);
/* Enumerate the bus. */
if ((error = siba_add_children(dev, &sc->siba_cid)))
return (error);
/* Allocate full core aperture */
total = sc->siba_cid.ncores;
sc->siba_mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
sc->siba_maddr, sc->siba_maddr + total - 1, total, RF_ACTIVE);
if (sc->siba_mem_res == NULL) {
device_printf(dev, "unable to allocate entire aperture\n");
return (ENXIO);
}
sc->siba_mem_bt = rman_get_bustag(sc->siba_mem_res);
sc->siba_mem_bh = rman_get_bushandle(sc->siba_mem_res);
sc->siba_maddr = rman_get_start(sc->siba_mem_res);
sc->siba_msize = rman_get_size(sc->siba_mem_res);
if (siba_debug) {
device_printf(dev, "after remapping: start %08x len %08x\n",
sc->siba_maddr, sc->siba_msize);
}
bus_set_resource(dev, SYS_RES_MEMORY, rid, sc->siba_maddr,
sc->siba_msize);
/*
* We need a manager for the space we claim on nexus to
* satisfy requests from children.
* We need to keep the source reservation we took because
* otherwise it may be claimed elsewhere.
* XXX move to softc
*/
mem_rman.rm_start = sc->siba_maddr;
mem_rman.rm_end = sc->siba_maddr + sc->siba_msize - 1;
mem_rman.rm_type = RMAN_ARRAY;
mem_rman.rm_descr = "SiBa I/O memory addresses";
if (rman_init(&mem_rman) != 0 ||
rman_manage_region(&mem_rman, mem_rman.rm_start,
mem_rman.rm_end) != 0) {
panic("%s: mem_rman", __func__);
}
return (siba_attach(dev));
}
static const struct bhnd_chipid *
siba_nexus_get_chipid(device_t dev, device_t child) {
struct siba_nexus_softc *sc = device_get_softc(dev);
return (&sc->siba_cid);
}
static struct resource *
siba_nexus_alloc_resource(device_t bus, device_t child, int type, int *rid,
rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
{
struct resource *rv;
struct resource_list *rl;
struct resource_list_entry *rle;
int isdefault, needactivate;
#if 0
if (siba_debug)
printf("%s: entry\n", __func__);
#endif
isdefault = (start == 0UL && end == ~0UL && count == 1);
needactivate = flags & RF_ACTIVE;
rl = BUS_GET_RESOURCE_LIST(bus, child);
rle = NULL;
if (isdefault) {
rle = resource_list_find(rl, type, *rid);
if (rle == NULL)
return (NULL);
if (rle->res != NULL)
panic("%s: resource entry is busy", __func__);
start = rle->start;
end = rle->end;
count = rle->count;
}
/*
* If the request is for a resource which we manage,
* attempt to satisfy the allocation ourselves.
*/
if (type == SYS_RES_MEMORY &&
start >= mem_rman.rm_start && end <= mem_rman.rm_end) {
rv = rman_reserve_resource(&mem_rman, start, end, count,
flags, child);
if (rv == 0) {
printf("%s: could not reserve resource\n", __func__);
return (0);
}
rman_set_rid(rv, *rid);
if (needactivate) {
if (bus_activate_resource(child, type, *rid, rv)) {
printf("%s: could not activate resource\n",
__func__);
rman_release_resource(rv);
return (0);
}
}
return (rv);
}
/*
* Pass the request to the parent, usually MIPS nexus.
*/
if (siba_debug)
printf("%s: proxying request to parent\n", __func__);
return (resource_list_alloc(rl, bus, child, type, rid,
start, end, count, flags));
}
/*
* The parent bus is responsible for resource activation; in the
* case of MIPS, this boils down to setting the virtual address and
* bus handle by mapping the physical address into KSEG1.
*/
static int
siba_nexus_activate_resource(device_t bus, device_t child, int type, int rid,
struct resource *r)
{
return (BUS_ACTIVATE_RESOURCE(device_get_parent(bus), child, type,
rid, r));
}
// TODO - depends on bhnd(4) IRQ support
#ifdef notyet
static struct siba_devinfo *
siba_nexus_setup_devinfo(device_t dev, uint8_t idx)
{
struct siba_nexus_softc *sc = device_get_softc(dev);
struct siba_devinfo *sdi;
uint32_t idlo, idhi, rev;
uint16_t vendorid, devid;
bus_addr_t baseaddr;
sdi = malloc(sizeof(*sdi), M_DEVBUF, M_WAITOK | M_ZERO);
resource_list_init(&sdi->sdi_rl);
idlo = siba_mips_read_4(sc, idx, SIBA_IDLOW);
idhi = siba_mips_read_4(sc, idx, SIBA_IDHIGH);
vendorid = (idhi & SIBA_IDHIGH_VENDORMASK) >>
SIBA_IDHIGH_VENDOR_SHIFT;
devid = ((idhi & 0x8ff0) >> 4);
rev = (idhi & SIBA_IDHIGH_REVLO);
rev |= (idhi & SIBA_IDHIGH_REVHI) >> SIBA_IDHIGH_REVHI_SHIFT;
sdi->sdi_vid = vendorid;
sdi->sdi_devid = devid;
sdi->sdi_rev = rev;
sdi->sdi_idx = idx;
sdi->sdi_irq = siba_getirq(devid);
/*
* Determine memory window on bus and irq if one is needed.
*/
baseaddr = sc->siba_maddr + (idx * SIBA_CORE_SIZE);
resource_list_add(&sdi->sdi_rl, SYS_RES_MEMORY,
MIPS_MEM_RID, /* XXX */
baseaddr, baseaddr + SIBA_CORE_LEN - 1, SIBA_CORE_LEN);
if (sdi->sdi_irq != 0xff) {
resource_list_add(&sdi->sdi_rl, SYS_RES_IRQ,
0, sdi->sdi_irq, sdi->sdi_irq, 1);
}
return (sdi);
}
#endif
static device_method_t siba_nexus_methods[] = {
/* Device interface */
DEVMETHOD(device_attach, siba_nexus_attach),
DEVMETHOD(device_probe, siba_nexus_probe),
/* Bus interface */
DEVMETHOD(bus_activate_resource,siba_nexus_activate_resource),
DEVMETHOD(bus_alloc_resource, siba_nexus_alloc_resource),
DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
/* bhnd interface */
DEVMETHOD(bhnd_get_chipid, siba_nexus_get_chipid),
DEVMETHOD_END
};
DEFINE_CLASS_1(bhnd, siba_nexus_driver, siba_nexus_methods,
sizeof(struct siba_nexus_softc), siba_driver);
DRIVER_MODULE(siba_nexus, nexus, siba_driver, bhnd_devclass, 0, 0);

View file

@ -0,0 +1,372 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/limits.h>
#include <sys/systm.h>
#include <machine/bus.h>
#include <machine/resource.h>
#include <dev/bhnd/bhndvar.h>
#include "sibareg.h"
#include "sibavar.h"
/**
* Map a siba(4) OCP vendor code to its corresponding JEDEC JEP-106 vendor
* code.
*
* @param ocp_vendor An OCP vendor code.
* @return The BHND_MFGID constant corresponding to @p ocp_vendor, or
* BHND_MFGID_INVALID if the OCP vendor is unknown.
*/
uint16_t
siba_get_bhnd_mfgid(uint16_t ocp_vendor)
{
switch (ocp_vendor) {
case OCP_VENDOR_BCM:
return (BHND_MFGID_BCM);
default:
return (BHND_MFGID_INVALID);
}
}
/**
* Parse the SIBA_IDH_* fields from the per-core identification
* registers, returning a siba_core_id representation.
*
* @param idhigh The SIBA_R0_IDHIGH register.
* @param idlow The SIBA_R0_IDLOW register.
* @param core_id The core id (index) to include in the result.
* @param unit The unit number to include in the result.
*/
struct siba_core_id
siba_parse_core_id(uint32_t idhigh, uint32_t idlow, u_int core_idx, int unit)
{
uint16_t ocp_vendor;
uint8_t sonics_rev;
uint8_t num_addrspace;
uint8_t num_cfg;
ocp_vendor = SIBA_REG_GET(idhigh, IDH_VENDOR);
sonics_rev = SIBA_REG_GET(idlow, IDL_SBREV);
num_addrspace = SIBA_REG_GET(idlow, IDL_NRADDR) + 1 /* + enum block */;
/* Determine the number of sonics config register blocks */
num_cfg = SIBA_CFG_NUM_2_2;
if (sonics_rev >= SIBA_IDL_SBREV_2_3)
num_cfg = SIBA_CFG_NUM_2_3;
return (struct siba_core_id) {
.core_info = {
.vendor = siba_get_bhnd_mfgid(ocp_vendor),
.device = SIBA_REG_GET(idhigh, IDH_DEVICE),
.hwrev = SIBA_IDH_CORE_REV(idhigh),
.core_idx = core_idx,
.unit = unit
},
.sonics_vendor = ocp_vendor,
.sonics_rev = sonics_rev,
.num_addrspace = num_addrspace,
.num_cfg_blocks = num_cfg
};
}
/**
* Initialize new port descriptor.
*
* @param port_num Port number.
* @param port_type Port type.
*/
static void
siba_init_port(struct siba_port *port, bhnd_port_type port_type, u_int port_num)
{
port->sp_num = port_num;
port->sp_type = port_type;
port->sp_num_addrs = 0;
STAILQ_INIT(&port->sp_addrs);
}
/**
* Deallocate all resources associated with the given port descriptor.
*
* @param port Port descriptor to be deallocated.
*/
static void
siba_release_port(struct siba_port *port) {
struct siba_addrspace *as, *as_next;
STAILQ_FOREACH_SAFE(as, &port->sp_addrs, sa_link, as_next) {
free(as, M_BHND);
}
}
/**
* Allocate and initialize new device info structure, copying the
* provided core id.
*
* @param dev The requesting bus device.
* @param core Device core info.
*/
struct siba_devinfo *
siba_alloc_dinfo(device_t bus, const struct siba_core_id *core_id)
{
struct siba_devinfo *dinfo;
dinfo = malloc(sizeof(struct siba_devinfo), M_BHND, M_NOWAIT);
if (dinfo == NULL)
return NULL;
dinfo->core_id = *core_id;
for (u_int i = 0; i < nitems(dinfo->cfg); i++) {
dinfo->cfg[i] = NULL;
dinfo->cfg_rid[i] = -1;
}
siba_init_port(&dinfo->device_port, BHND_PORT_DEVICE, 0);
resource_list_init(&dinfo->resources);
return dinfo;
}
/**
* Return the @p dinfo port instance for @p type, or NULL.
*
* @param dinfo The siba device info.
* @param type The requested port type.
*
* @retval siba_port If @p port_type and @p port_num are defined on @p dinfo.
* @retval NULL If the requested port is not defined on @p dinfo.
*/
struct siba_port *
siba_dinfo_get_port(struct siba_devinfo *dinfo, bhnd_port_type port_type,
u_int port_num)
{
/* We only define a single port for any given type. */
if (port_num != 0)
return (NULL);
switch (port_type) {
case BHND_PORT_DEVICE:
return (&dinfo->device_port);
case BHND_PORT_BRIDGE:
return (NULL);
case BHND_PORT_AGENT:
return (NULL);
}
}
/**
* Find an address space with @p sid on @p port.
*
* @param port The port to search for a matching address space.
* @param sid The siba-assigned address space ID to search for.
*/
struct siba_addrspace *
siba_find_port_addrspace(struct siba_port *port, uint8_t sid)
{
struct siba_addrspace *addrspace;
STAILQ_FOREACH(addrspace, &port->sp_addrs, sa_link) {
if (addrspace->sa_sid == sid)
return (addrspace);
}
/* not found */
return (NULL);
}
/**
* Append a new address space entry to @p port_num of type @p port_type
* in @p dinfo.
*
* The range will also be registered in @p dinfo resource list.
*
* @param dinfo The device info entry to update.
* @param port_type The port type.
* @param port_num The port number.
* @param region_num The region index number.
* @param sid The siba-assigned core-unique address space identifier.
* @param base The mapping's base address.
* @param size The mapping size.
* @param bus_reserved Number of bytes to reserve in @p size for bus use
* when registering the resource list entry. This is used to reserve bus
* access to the core's SIBA_CFG* register blocks.
*
* @retval 0 success
* @retval non-zero An error occurred appending the entry.
*/
int
siba_append_dinfo_region(struct siba_devinfo *dinfo, bhnd_port_type port_type,
u_int port_num, u_int region_num, uint8_t sid, uint32_t base, uint32_t size,
uint32_t bus_reserved)
{
struct siba_addrspace *sa;
struct siba_port *port;
/* Verify that base + size will not overflow */
if (UINT32_MAX - size < base)
return (ERANGE);
/* Must not be 0-length */
if (size == 0)
return (EINVAL);
/* Determine target port */
port = siba_dinfo_get_port(dinfo, port_type, port_num);
if (port == NULL)
return (EINVAL);
/* Allocate new addrspace entry */
sa = malloc(sizeof(*sa), M_BHND, M_NOWAIT|M_ZERO);
if (sa == NULL)
return (ENOMEM);
sa->sa_base = base;
sa->sa_size = size;
sa->sa_sid = sid;
sa->sa_region_num = region_num;
/* Populate the resource list */
size -= bus_reserved;
sa->sa_rid = resource_list_add_next(&dinfo->resources, SYS_RES_MEMORY,
base, base + size - 1, size);
/* Append to target port */
STAILQ_INSERT_TAIL(&port->sp_addrs, sa, sa_link);
port->sp_num_addrs++;
return (0);
}
/**
* Deallocate the given device info structure and any associated resources.
*
* @param dev The requesting bus device.
* @param dinfo Device info to be deallocated.
*/
void
siba_free_dinfo(device_t dev, struct siba_devinfo *dinfo)
{
siba_release_port(&dinfo->device_port);
resource_list_free(&dinfo->resources);
/* Free all mapped configuration blocks */
for (u_int i = 0; i < nitems(dinfo->cfg); i++) {
if (dinfo->cfg[i] == NULL)
continue;
bhnd_release_resource(dev, SYS_RES_MEMORY, dinfo->cfg_rid[i],
dinfo->cfg[i]);
dinfo->cfg[i] = NULL;
dinfo->cfg_rid[i] = -1;
}
free(dinfo, M_BHND);
}
/**
* Return the core-enumeration-relative offset for the @p addrspace
* SIBA_R0_ADMATCH* register.
*
* @param addrspace The address space index.
*
* @retval non-zero success
* @retval 0 the given @p addrspace index is not supported.
*/
u_int
siba_admatch_offset(uint8_t addrspace)
{
switch (addrspace) {
case 0:
return SB0_REG_ABS(SIBA_CFG0_ADMATCH0);
case 1:
return SB0_REG_ABS(SIBA_CFG0_ADMATCH1);
case 2:
return SB0_REG_ABS(SIBA_CFG0_ADMATCH2);
case 3:
return SB0_REG_ABS(SIBA_CFG0_ADMATCH3);
default:
return (0);
}
}
/**
* Parse a SIBA_R0_ADMATCH* register.
*
* @param addrspace The address space index.
* @param am The address match register value to be parsed.
* @param[out] addr The parsed address.
* @param[out] size The parsed size.
*
* @retval 0 success
* @retval non-zero a parse error occured.
*/
int
siba_parse_admatch(uint32_t am, uint32_t *addr, uint32_t *size)
{
u_int am_type;
/* Negative encoding is not supported. This is not used on any
* currently known devices*/
if (am & SIBA_AM_ADNEG)
return (EINVAL);
/* Extract the base address and size */
am_type = SIBA_REG_GET(am, AM_TYPE);
switch (am_type) {
case 0:
*addr = am & SIBA_AM_BASE0_MASK;
*size = 1 << (SIBA_REG_GET(am, AM_ADINT0) + 1);
break;
case 1:
*addr = am & SIBA_AM_BASE1_MASK;
*size = 1 << (SIBA_REG_GET(am, AM_ADINT1) + 1);
break;
case 2:
*addr = am & SIBA_AM_BASE2_MASK;
*size = 1 << (SIBA_REG_GET(am, AM_ADINT2) + 1);
break;
default:
return (EINVAL);
}
return (0);
}

266
sys/dev/bhnd/siba/sibareg.h Normal file
View file

@ -0,0 +1,266 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* Copyright (c) 2010 Broadcom Corporation
*
* This file was derived from the sbconfig.h header distributed with
* Broadcom's initial brcm80211 Linux driver release, as
* contributed to the Linux staging repository.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* $FreeBSD$
*/
#ifndef _BHND_SIBA_SIBAREG_
#define _BHND_SIBA_SIBAREG_
#include <dev/bhnd/bhndreg.h>
/*
* Broadcom SIBA Configuration Space Registers.
*
* Backplane configuration registers common to siba(4) core register
* blocks.
*/
/**
* Extract a config attribute by applying _MASK and _SHIFT defines.
*
* @param _reg The register value containing the desired attribute
* @param _attr The BCMA EROM attribute name (e.g. ENTRY_ISVALID), to be
* concatenated with the `SB` prefix and `_MASK`/`_SHIFT` suffixes.
*/
#define SIBA_REG_GET(_entry, _attr) \
((_entry & SIBA_ ## _attr ## _MASK) \
>> SIBA_ ## _attr ## _SHIFT)
#define SIBA_ENUM_ADDR BHND_DEFAULT_CHIPC_ADDR /**< enumeration space */
#define SIBA_ENUM_SIZE 0x00100000 /**< size of the enumeration space */
#define SIBA_CORE_SIZE BHND_DEFAULT_CORE_SIZE /**< per-core register block size */
#define SIBA_MAX_CORES \
(SIBA_ENUM_SIZE/SIBA_CORE_SIZE) /**< Maximum number of cores */
#define SIBA_ADDRSPACE_CORE 0 /**< address space identifier of the
core enumeration block. */
/**< Evaluates to the bus address of the @p idx core register block */
#define SIBA_CORE_ADDR(idx) \
(SIBA_ENUM_ADDR + ((idx) * SIBA_CORE_SIZE))
/*
* Sonics configuration registers are mapped to each core's enumeration
* space, at the end of the 4kb device register block, in reverse
* order:
*
* [0x0000-0x0dff] core registers
* [0x0e00-0x0eff] SIBA_R1 registers (sonics >= 2.3)
* [0x0f00-0x0fff] SIBA_R0 registers
*/
#define SIBA_CFG0_OFFSET 0xf00 /**< first configuration block */
#define SIBA_CFG1_OFFSET 0xe00 /**< second configuration block (sonics >= 2.3) */
#define SIBA_CFG_SIZE 0x100 /**< cfg register block size */
/* Return the SIBA_CORE_ADDR-relative offset for a SIBA_CFG* register. */
#define SB0_REG_ABS(off) ((off) + SIBA_CFG0_OFFSET)
#define SB1_REG_ABS(off) ((off) + SIBA_CFG1_OFFSET)
/* SIBA_CFG0 registers */
#define SIBA_CFG0_IPSFLAG 0x08 /**< initiator port ocp slave flag */
#define SIBA_CFG0_TPSFLAG 0x18 /**< target port ocp slave flag */
#define SIBA_CFG0_TMERRLOGA 0x48 /**< sonics >= 2.3 */
#define SIBA_CFG0_TMERRLOG 0x50 /**< sonics >= 2.3 */
#define SIBA_CFG0_ADMATCH3 0x60 /**< address match3 */
#define SIBA_CFG0_ADMATCH2 0x68 /**< address match2 */
#define SIBA_CFG0_ADMATCH1 0x70 /**< address match1 */
#define SIBA_CFG0_IMSTATE 0x90 /**< initiator agent state */
#define SIBA_CFG0_INTVEC 0x94 /**< interrupt mask */
#define SIBA_CFG0_TMSTATELOW 0x98 /**< target state */
#define SIBA_CFG0_TMSTATEHIGH 0x9c /**< target state */
#define SIBA_CFG0_BWA0 0xa0 /**< bandwidth allocation table0 */
#define SIBA_CFG0_IMCONFIGLOW 0xa8 /**< initiator configuration */
#define SIBA_CFG0_IMCONFIGHIGH 0xac /**< initiator configuration */
#define SIBA_CFG0_ADMATCH0 0xb0 /**< address match0 */
#define SIBA_CFG0_TMCONFIGLOW 0xb8 /**< target configuration */
#define SIBA_CFG0_TMCONFIGHIGH 0xbc /**< target configuration */
#define SIBA_CFG0_BCONFIG 0xc0 /**< broadcast configuration */
#define SIBA_CFG0_BSTATE 0xc8 /**< broadcast state */
#define SIBA_CFG0_ACTCNFG 0xd8 /**< activate configuration */
#define SIBA_CFG0_FLAGST 0xe8 /**< current sbflags */
#define SIBA_CFG0_IDLOW 0xf8 /**< identification */
#define SIBA_CFG0_IDHIGH 0xfc /**< identification */
/* SIBA_CFG1 registers (sonics >= 2.3) */
#define SIBA_CFG1_IMERRLOGA 0xa8 /**< (sonics >= 2.3) */
#define SIBA_CFG1_IMERRLOG 0xb0 /**< sbtmerrlog (sonics >= 2.3) */
#define SIBA_CFG1_TMPORTCONNID0 0xd8 /**< sonics >= 2.3 */
#define SIBA_CFG1_TMPORTLOCK0 0xf8 /**< sonics >= 2.3 */
/* sbipsflag */
#define SIBA_IPS_INT1_MASK 0x3f /* which sbflags get routed to mips interrupt 1 */
#define SIBA_IPS_INT1_SHIFT 0
#define SIBA_IPS_INT2_MASK 0x3f00 /* which sbflags get routed to mips interrupt 2 */
#define SIBA_IPS_INT2_SHIFT 8
#define SIBA_IPS_INT3_MASK 0x3f0000 /* which sbflags get routed to mips interrupt 3 */
#define SIBA_IPS_INT3_SHIFT 16
#define SIBA_IPS_INT4_MASK 0x3f000000 /* which sbflags get routed to mips interrupt 4 */
#define SIBA_IPS_INT4_SHIFT 24
/* sbtpsflag */
#define SIBA_TPS_NUM0_MASK 0x3f /* interrupt sbFlag # generated by this core */
#define SIBA_TPS_F0EN0 0x40 /* interrupt is always sent on the backplane */
/* sbtmerrlog */
#define SIBA_TMEL_CM 0x00000007 /* command */
#define SIBA_TMEL_CI 0x0000ff00 /* connection id */
#define SIBA_TMEL_EC 0x0f000000 /* error code */
#define SIBA_TMEL_ME 0x80000000 /* multiple error */
/* sbimstate */
#define SIBA_IM_PC 0xf /* pipecount */
#define SIBA_IM_AP_MASK 0x30 /* arbitration policy */
#define SIBA_IM_AP_BOTH 0x00 /* use both timeslaces and token */
#define SIBA_IM_AP_TS 0x10 /* use timesliaces only */
#define SIBA_IM_AP_TK 0x20 /* use token only */
#define SIBA_IM_AP_RSV 0x30 /* reserved */
#define SIBA_IM_IBE 0x20000 /* inbanderror */
#define SIBA_IM_TO 0x40000 /* timeout */
#define SIBA_IM_BY 0x01800000 /* busy (sonics >= 2.3) */
#define SIBA_IM_RJ 0x02000000 /* reject (sonics >= 2.3) */
/* sbtmstatelow */
#define SIBA_TML_RESET 0x0001 /* reset */
#define SIBA_TML_REJ_MASK 0x0006 /* reject field */
#define SIBA_TML_REJ 0x0002 /* reject */
#define SIBA_TML_TMPREJ 0x0004 /* temporary reject, for error recovery */
#define SIBA_TML_SICF_SHIFT 16 /* Shift to locate the SI control flags in sbtml */
/* sbtmstatehigh */
#define SIBA_TMH_SERR 0x0001 /* serror */
#define SIBA_TMH_INT 0x0002 /* interrupt */
#define SIBA_TMH_BUSY 0x0004 /* busy */
#define SIBA_TMH_TO 0x0020 /* timeout (sonics >= 2.3) */
#define SIBA_TMH_SISF_SHIFT 16 /* Shift to locate the SI status flags in sbtmh */
/* sbbwa0 */
#define SIBA_BWA_TAB0_MASK 0xffff /* lookup table 0 */
#define SIBA_BWA_TAB1_MASK 0xffff /* lookup table 1 */
#define SIBA_BWA_TAB1_SHIFT 16
/* sbimconfiglow */
#define SIBA_IMCL_STO_MASK 0x7 /* service timeout */
#define SIBA_IMCL_RTO_MASK 0x70 /* request timeout */
#define SIBA_IMCL_RTO_SHIFT 4
#define SIBA_IMCL_CID_MASK 0xff0000 /* connection id */
#define SIBA_IMCL_CID_SHIFT 16
/* sbimconfighigh */
#define SIBA_IMCH_IEM_MASK 0xc /* inband error mode */
#define SIBA_IMCH_TEM_MASK 0x30 /* timeout error mode */
#define SIBA_IMCH_TEM_SHIFT 4
#define SIBA_IMCH_BEM_MASK 0xc0 /* bus error mode */
#define SIBA_IMCH_BEM_SHIFT 6
/* sbadmatch0 */
#define SIBA_AM_TYPE_MASK 0x3 /* address type */
#define SIBA_AM_TYPE_SHIFT 0x0
#define SIBA_AM_AD64 0x4 /* reserved */
#define SIBA_AM_ADINT0_MASK 0xf8 /* type0 size */
#define SIBA_AM_ADINT0_SHIFT 3
#define SIBA_AM_ADINT1_MASK 0x1f8 /* type1 size */
#define SIBA_AM_ADINT1_SHIFT 3
#define SIBA_AM_ADINT2_MASK 0x1f8 /* type2 size */
#define SIBA_AM_ADINT2_SHIFT 3
#define SIBA_AM_ADEN 0x400 /* enable */
#define SIBA_AM_ADNEG 0x800 /* negative decode */
#define SIBA_AM_BASE0_MASK 0xffffff00 /* type0 base address */
#define SIBA_AM_BASE0_SHIFT 8
#define SIBA_AM_BASE1_MASK 0xfffff000 /* type1 base address for the core */
#define SIBA_AM_BASE1_SHIFT 12
#define SIBA_AM_BASE2_MASK 0xffff0000 /* type2 base address for the core */
#define SIBA_AM_BASE2_SHIFT 16
/* sbtmconfiglow */
#define SIBA_TMCL_CD_MASK 0xff /* clock divide */
#define SIBA_TMCL_CO_MASK 0xf800 /* clock offset */
#define SIBA_TMCL_CO_SHIFT 11
#define SIBA_TMCL_IF_MASK 0xfc0000 /* interrupt flags */
#define SIBA_TMCL_IF_SHIFT 18
#define SIBA_TMCL_IM_MASK 0x3000000 /* interrupt mode */
#define SIBA_TMCL_IM_SHIFT 24
/* sbtmconfighigh */
#define SIBA_TMCH_BM_MASK 0x3 /* busy mode */
#define SIBA_TMCH_RM_MASK 0x3 /* retry mode */
#define SIBA_TMCH_RM_SHIFT 2
#define SIBA_TMCH_SM_MASK 0x30 /* stop mode */
#define SIBA_TMCH_SM_SHIFT 4
#define SIBA_TMCH_EM_MASK 0x300 /* sb error mode */
#define SIBA_TMCH_EM_SHIFT 8
#define SIBA_TMCH_IM_MASK 0xc00 /* int mode */
#define SIBA_TMCH_IM_SHIFT 10
/* sbbconfig */
#define SIBA_BC_LAT_MASK 0x3 /* sb latency */
#define SIBA_BC_MAX0_MASK 0xf0000 /* maxccntr0 */
#define SIBA_BC_MAX0_SHIFT 16
#define SIBA_BC_MAX1_MASK 0xf00000 /* maxccntr1 */
#define SIBA_BC_MAX1_SHIFT 20
/* sbbstate */
#define SIBA_BS_SRD 0x1 /* st reg disable */
#define SIBA_BS_HRD 0x2 /* hold reg disable */
/* sbidlow */
#define SIBA_IDL_CS_MASK 0x3 /* config space */
#define SIBA_IDL_CS_SHIFT 0
#define SIBA_IDL_NRADDR_MASK 0x38 /* # address ranges supported */
#define SIBA_IDL_NRADDR_SHIFT 3
#define SIBA_IDL_SYNCH 0x40 /* sync */
#define SIBA_IDL_INIT 0x80 /* initiator */
#define SIBA_IDL_MINLAT_MASK 0xf00 /* minimum backplane latency */
#define SIBA_IDL_MINLAT_SHIFT 8
#define SIBA_IDL_MAXLAT_MASK 0xf000 /* maximum backplane latency */
#define SIBA_IDL_MAXLAT_SHIFT 12
#define SIBA_IDL_FIRST_MASK 0x10000 /* this initiator is first */
#define SIBA_IDL_FIRST_SHIFT 16
#define SIBA_IDL_CW_MASK 0xc0000 /* cycle counter width */
#define SIBA_IDL_CW_SHIFT 18
#define SIBA_IDL_TP_MASK 0xf00000 /* target ports */
#define SIBA_IDL_TP_SHIFT 20
#define SIBA_IDL_IP_MASK 0xf000000 /* initiator ports */
#define SIBA_IDL_IP_SHIFT 24
#define SIBA_IDL_SBREV_MASK 0xf0000000 /* sonics backplane revision code */
#define SIBA_IDL_SBREV_SHIFT 28
#define SIBA_IDL_SBREV_2_2 0x0 /* version 2.2 or earlier */
#define SIBA_IDL_SBREV_2_3 0x1 /* version 2.3 */
/* sbidhigh */
#define SIBA_IDH_RC_MASK 0x000f /* revision code */
#define SIBA_IDH_RCE_MASK 0x7000 /* revision code extension field */
#define SIBA_IDH_RCE_SHIFT 8
#define SIBA_IDH_DEVICE_MASK 0x8ff0 /* core code */
#define SIBA_IDH_DEVICE_SHIFT 4
#define SIBA_IDH_VENDOR_MASK 0xffff0000 /* vendor code */
#define SIBA_IDH_VENDOR_SHIFT 16
#define SIBA_IDH_CORE_REV(sbidh) \
(SIBA_REG_GET((sbidh), IDH_RCE) | ((sbidh) & SIBA_IDH_RC_MASK))
#define SIBA_COMMIT 0xfd8 /* update buffered registers value */
#endif /* _BHND_SIBA_SIBAREG_ */

150
sys/dev/bhnd/siba/sibavar.h Normal file
View file

@ -0,0 +1,150 @@
/*-
* Copyright (c) 2015 Landon Fuller <landon@landonf.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer,
* without modification.
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
* similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
* redistribution must be conditioned upon including a substantially
* similar Disclaimer requirement for further binary redistribution.
*
* NO WARRANTY
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGES.
*
* $FreeBSD$
*/
#ifndef _SIBA_SIBAVAR_H_
#define _SIBA_SIBAVAR_H_
#include <sys/param.h>
#include <sys/bus.h>
#include <sys/limits.h>
#include <machine/bus.h>
#include <sys/rman.h>
#include "siba.h"
/*
* Internal definitions shared by siba(4) driver implementations.
*/
struct siba_addrspace;
struct siba_devinfo;
struct siba_port;
struct siba_core_id;
int siba_probe(device_t dev);
int siba_attach(device_t dev);
int siba_detach(device_t dev);
uint16_t siba_get_bhnd_mfgid(uint16_t ocp_vendor);
struct siba_core_id siba_parse_core_id(uint32_t idhigh, uint32_t idlow,
u_int core_idx, int unit);
int siba_add_children(device_t bus,
const struct bhnd_chipid *chipid);
struct siba_devinfo *siba_alloc_dinfo(device_t dev,
const struct siba_core_id *core_id);
void siba_free_dinfo(device_t dev,
struct siba_devinfo *dinfo);
struct siba_port *siba_dinfo_get_port(struct siba_devinfo *dinfo,
bhnd_port_type port_type, u_int port_num);
struct siba_addrspace *siba_find_port_addrspace(struct siba_port *port,
uint8_t sid);
int siba_append_dinfo_region(struct siba_devinfo *dinfo,
bhnd_port_type port_type, u_int port_num,
u_int region_num, uint8_t sid, uint32_t base,
uint32_t size, uint32_t bus_reserved);
u_int siba_admatch_offset(uint8_t addrspace);
int siba_parse_admatch(uint32_t am, uint32_t *addr,
uint32_t *size);
/* Sonics configuration register blocks */
#define SIBA_CFG_NUM_2_2 1 /**< sonics <= 2.2 maps SIBA_CFG0. */
#define SIBA_CFG_NUM_2_3 2 /**< sonics <= 2.3 maps SIBA_CFG0 and SIBA_CFG1 */
#define SIBA_CFG_NUM_MAX SIBA_CFG_NUM_2_3 /**< maximum number of supported config
register blocks */
/** siba(4) address space descriptor */
struct siba_addrspace {
uint32_t sa_base; /**< base address */
uint32_t sa_size; /**< size */
u_int sa_region_num; /**< bhnd region id */
uint8_t sa_sid; /**< siba-assigned address space ID */
int sa_rid; /**< bus resource id */
STAILQ_ENTRY(siba_addrspace) sa_link;
};
/** siba(4) port descriptor */
struct siba_port {
bhnd_port_type sp_type; /**< port type */
u_int sp_num; /**< port number */
u_int sp_num_addrs; /**< number of address space mappings */
STAILQ_HEAD(, siba_addrspace) sp_addrs; /**< address spaces mapped to this port */
};
/**
* siba(4) per-core identification info.
*/
struct siba_core_id {
struct bhnd_core_info core_info; /**< standard bhnd(4) core info */
uint16_t sonics_vendor; /**< OCP vendor identifier used to generate
* the JEDEC-106 bhnd(4) vendor identifier. */
uint8_t sonics_rev; /**< sonics backplane revision code */
uint8_t num_addrspace; /**< number of address ranges mapped to
this core. */
uint8_t num_cfg_blocks; /**< number of Sonics configuration register
blocks mapped to the core's enumeration
space */
};
/**
* siba(4) per-device info
*/
struct siba_devinfo {
struct resource_list resources; /**< per-core memory regions. */
struct siba_core_id core_id; /**< core identification info */
struct siba_port device_port; /**< device port holding ownership
* of all siba address space
* entries for this core. */
/** SIBA_CFG* register blocks */
struct bhnd_resource *cfg[SIBA_CFG_NUM_MAX];
/** SIBA_CFG* resource IDs */
int cfg_rid[SIBA_CFG_NUM_MAX];
};
/** siba(4) per-instance state */
struct siba_softc {
struct bhnd_softc bhnd_sc; /**< bhnd state */
};
#endif /* _SIBA_SIBAVAR_H_ */

84
sys/dev/bhnd/tools/bus_macro.sh Executable file
View file

@ -0,0 +1,84 @@
#!/bin/sh
#
# Copyright (c) 2015 Landon Fuller <landon@landonf.org>
# Copyright (c) 2004-2005 Poul-Henning Kamp.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# $FreeBSD$
#
# Generate the bhnd resource macros at the bottom of dev/bhnd/bhnd.h
#
# Derived from PHK's tools/bus_macros.sh
#
macro () {
n=${1}
bus_n=$(echo $n | tr "[:lower:]" "[:upper:]")
shift
echo -n "#define bhnd_bus_${n}(r"
for i
do
echo -n ", ${i}"
done
echo ") \\"
echo " ((r)->direct) ? \\"
echo -n " bus_${n}((r)->res"
for i
do
echo -n ", (${i})"
done
echo ") : \\"
echo -n " BHND_BUS_${bus_n}("
echo "device_get_parent(rman_get_device((r)->res)), \\"
echo -n " rman_get_device((r)->res), (r)"
for i
do
echo -n ", (${i})"
done
echo ")"
}
macro barrier o l f
# We only support a subset of the bus I/O methods; this may
# be expanded when/if additional functions are required.
for w in 1 2 4 #8
do
# macro copy_region_$w so dh do c
# macro copy_region_stream_$w ?
# macro peek_$w
for s in "" #stream_
do
macro read_$s$w o
# macro read_multi_$s$w o d c
# macro read_region_$s$w o d c
# macro set_multi_$s$w o v c
# macro set_region_$s$w o v c
macro write_$s$w o v
# macro write_multi_$s$w o d c
# macro write_region_$s$w o d c
done
done