aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/bhnd
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/bhnd')
-rw-r--r--sys/dev/bhnd/bcma/bcma_erom.c292
-rw-r--r--sys/dev/bhnd/bcma/bcma_eromvar.h21
-rw-r--r--sys/dev/bhnd/bhnd_ids.h6
-rw-r--r--sys/dev/bhnd/bhnd_subr.c37
-rw-r--r--sys/dev/bhnd/cores/chipc/chipcreg.h10
5 files changed, 309 insertions, 57 deletions
diff --git a/sys/dev/bhnd/bcma/bcma_erom.c b/sys/dev/bhnd/bcma/bcma_erom.c
index db8e875cfbfd..2089159dd807 100644
--- a/sys/dev/bhnd/bcma/bcma_erom.c
+++ b/sys/dev/bhnd/bcma/bcma_erom.c
@@ -65,10 +65,18 @@ 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);
+static int erom_region_to_port_type(struct bcma_erom *erom,
+ uint8_t region_type, bhnd_port_type *port_type);
-#define EROM_LOG(erom, fmt, ...) \
- device_printf(erom->dev, "erom[0x%llx]: " fmt, \
- (unsigned long long) (erom->offset), ##__VA_ARGS__);
+#define EROM_LOG(erom, fmt, ...) do { \
+ if (erom->dev != NULL) { \
+ device_printf(erom->dev, "erom[0x%llx]: " fmt, \
+ (unsigned long long) (erom->offset), ##__VA_ARGS__);\
+ } else { \
+ printf("erom[0x%llx]: " fmt, \
+ (unsigned long long) (erom->offset), ##__VA_ARGS__);\
+ } \
+} while(0)
/**
* Open an EROM table for reading.
@@ -82,11 +90,37 @@ static int erom_seek_next(struct bcma_erom *erom, uint8_t etype);
* @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)
+bcma_erom_open(struct bcma_erom *erom, struct resource *r,
+ bus_size_t offset)
+{
+ return (bhnd_erom_bus_space_open(erom, rman_get_device(r),
+ rman_get_bustag(r), rman_get_bushandle(r), offset));
+
+ return (0);
+}
+
+/**
+ * Open an EROM table for reading using the provided bus space tag and
+ * handle.
+ *
+ * @param[out] erom On success, will be populated with a valid EROM
+ * read state.
+ * @param dev The owning device, or NULL if none.
+ * @param bst EROM table bus space tag.
+ * @param bsh EROM table bus space handle.
+ * @param offset Offset of the EROM core from @p resource.
+ *
+ * @retval 0 success
+ * @retval non-zero if the erom table could not be opened.
+ */
+int
+bhnd_erom_bus_space_open(struct bcma_erom *erom, device_t dev,
+ bus_space_tag_t bst, bus_space_handle_t bsh, bus_size_t offset)
{
/* Initialize the EROM reader */
- erom->dev = rman_get_device(r);
- erom->r = r;
+ erom->dev = dev;
+ erom->bst = bst;
+ erom->bsh = bsh;
erom->start = offset + BCMA_EROM_TABLE_START;
erom->offset = 0;
@@ -145,7 +179,8 @@ bcma_erom_peek32(struct bcma_erom *erom, uint32_t *entry)
return (EINVAL);
}
- *entry = bus_read_4(erom->r, erom->start + erom->offset);
+ *entry = bus_space_read_4(erom->bst, erom->bsh,
+ erom->start + erom->offset);
return (0);
}
@@ -300,6 +335,20 @@ bcma_erom_reset(struct bcma_erom *erom)
}
/**
+ * Seek to the next core entry.
+ *
+ * @param erom EROM read state.
+ * @retval 0 success
+ * @retval ENOENT The end of the EROM table was reached.
+ * @retval non-zero Reading or parsing failed.
+ */
+int
+bcma_erom_seek_next_core(struct bcma_erom *erom)
+{
+ return (erom_seek_next(erom, BCMA_EROM_ENTRY_TYPE_CORE));
+}
+
+/**
* Seek to the requested core entry.
*
* @param erom EROM read state.
@@ -387,6 +436,153 @@ bcma_erom_parse_core(struct bcma_erom *erom, struct bcma_erom_core *core)
}
/**
+ * Seek to a region record associated with @p core_index.
+ *
+ * @param erom EROM read state.
+ * @param core_index The index of the core record to be searched.
+ * @param port_type The port type to search for.
+ * @param port_num The port number to search for.
+ * @param region_num The region number to search for.
+ * @retval 0 success
+ * @retval ENOENT The requested region was not found.
+ * @retval non-zero Reading or parsing failed.
+ */
+int
+bcma_erom_seek_core_sport_region(struct bcma_erom *erom, u_int core_index,
+ bhnd_port_type port_type, u_int port_num, u_int region_num)
+{
+ struct bcma_erom_core core;
+ uint32_t entry;
+ uint8_t region_port, region_type;
+ bool found;
+ int error;
+
+ if ((error = bcma_erom_seek_core_index(erom, core_index)))
+ return (error);
+
+ if ((error = bcma_erom_parse_core(erom, &core)))
+ return (error);
+
+ /* Skip master ports */
+ for (u_long i = 0; i < core.num_mport; i++) {
+ if ((error = erom_skip_mport(erom)))
+ return (error);
+ }
+
+ /* Seek to the region block for the given port type */
+ found = false;
+ while (1) {
+ bhnd_port_type p_type;
+ uint8_t r_type;
+
+ if ((error = bcma_erom_peek32(erom, &entry)))
+ return (error);
+
+ if (!BCMA_EROM_ENTRY_IS(entry, REGION))
+ return (ENOENT);
+
+ /* Expected region type? */
+ r_type = BCMA_EROM_GET_ATTR(entry, REGION_TYPE);
+ if ((error = erom_region_to_port_type(erom, r_type, &p_type)))
+ return (error);
+
+ if (p_type == port_type) {
+ found = true;
+ break;
+ }
+
+ /* Skip to next entry */
+ if ((error = erom_skip_sport_region(erom)))
+ return (error);
+ }
+
+ if (!found)
+ return (ENOENT);
+
+ /* Found the appropriate port type block; now find the region records
+ * for the given port number */
+ found = false;
+ for (u_int i = 0; i <= port_num; i++) {
+ bhnd_port_type p_type;
+
+ if ((error = bcma_erom_peek32(erom, &entry)))
+ return (error);
+
+ if (!BCMA_EROM_ENTRY_IS(entry, REGION))
+ return (ENOENT);
+
+ /* Fetch the type/port of the first region entry */
+ region_type = BCMA_EROM_GET_ATTR(entry, REGION_TYPE);
+ region_port = BCMA_EROM_GET_ATTR(entry, REGION_PORT);
+
+ /* Have we found the region entries for the desired port? */
+ if (i == port_num) {
+ error = erom_region_to_port_type(erom, region_type,
+ &p_type);
+ if (error)
+ return (error);
+
+ if (p_type == port_type)
+ found = true;
+
+ break;
+ }
+
+ /* Otherwise, seek to next block of region records */
+ while (1) {
+ uint8_t next_type, next_port;
+
+ if ((error = erom_skip_sport_region(erom)))
+ return (error);
+
+ if ((error = bcma_erom_peek32(erom, &entry)))
+ return (error);
+
+ if (!BCMA_EROM_ENTRY_IS(entry, REGION))
+ return (ENOENT);
+
+ next_type = BCMA_EROM_GET_ATTR(entry, REGION_TYPE);
+ next_port = BCMA_EROM_GET_ATTR(entry, REGION_PORT);
+
+ if (next_type != region_type ||
+ next_port != region_port)
+ break;
+ }
+ }
+
+ if (!found)
+ return (ENOENT);
+
+ /* Finally, search for the requested region number */
+ for (u_int i = 0; i <= region_num; i++) {
+ uint8_t next_port, next_type;
+
+ if ((error = bcma_erom_peek32(erom, &entry)))
+ return (error);
+
+ if (!BCMA_EROM_ENTRY_IS(entry, REGION))
+ return (ENOENT);
+
+ /* Check for the end of the region block */
+ next_type = BCMA_EROM_GET_ATTR(entry, REGION_TYPE);
+ next_port = BCMA_EROM_GET_ATTR(entry, REGION_PORT);
+
+ if (next_type != region_type ||
+ next_port != region_port)
+ break;
+
+ if (i == region_num)
+ return (0);
+
+ if ((error = erom_skip_sport_region(erom)))
+ return (error);
+ }
+
+ /* Not found */
+ return (ENOENT);
+}
+
+/**
* Read the next master port descriptor from the EROM table.
*
* @param erom EROM read state.
@@ -492,6 +688,25 @@ bcma_erom_parse_sport_region(struct bcma_erom *erom,
}
/**
+ * Convert a bcma_erom_core record to its bhnd_core_info representation.
+ *
+ * @param core EROM core record to convert.
+ * @param core_idx The core index of @p core.
+ * @param core_unit The core unit of @p core.
+ * @param[out] info The populated bhnd_core_info representation.
+ */
+void
+bcma_erom_to_core_info(const struct bcma_erom_core *core, u_int core_idx,
+ int core_unit, struct bhnd_core_info *info)
+{
+ info->vendor = core->vendor;
+ info->device = core->device;
+ info->hwrev = core->rev;
+ info->core_idx = core_idx;
+ info->unit = core_unit;
+}
+
+/**
* 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.
@@ -545,7 +760,8 @@ bcma_erom_get_core_info(struct bcma_erom *erom,
/* Parse all core descriptors */
bcma_erom_reset(erom);
for (u_int i = 0; i < count; i++) {
- struct bcma_erom_core core;
+ struct bcma_erom_core core;
+ int unit;
/* Parse the core */
error = erom_seek_next(erom, BCMA_EROM_ENTRY_TYPE_CORE);
@@ -555,20 +771,17 @@ bcma_erom_get_core_info(struct bcma_erom *erom,
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 */
+ unit = 0;
for (u_int j = 0; j < i; j++) {
if (buffer[i].vendor == buffer[j].vendor &&
buffer[i].device == buffer[j].device)
- buffer[i].unit++;
+ unit++;
}
+
+ /* Convert to a bhnd info record */
+ bcma_erom_to_core_info(&core, i, unit, &buffer[i]);
}
cleanup:
@@ -585,6 +798,33 @@ cleanup:
return (error);
}
+/**
+ * Map an EROM region type to its corresponding port type.
+ *
+ * @param region_type Region type value.
+ * @param[out] port_type On success, the corresponding port type.
+ */
+static int
+erom_region_to_port_type(struct bcma_erom *erom, uint8_t region_type,
+ bhnd_port_type *port_type)
+{
+ switch (region_type) {
+ case BCMA_EROM_REGION_TYPE_DEVICE:
+ *port_type = BHND_PORT_DEVICE;
+ return (0);
+ case BCMA_EROM_REGION_TYPE_BRIDGE:
+ *port_type = BHND_PORT_BRIDGE;
+ return (0);
+ case BCMA_EROM_REGION_TYPE_MWRAP:
+ case BCMA_EROM_REGION_TYPE_SWRAP:
+ *port_type = BHND_PORT_AGENT;
+ return (0);
+ default:
+ EROM_LOG(erom, "unsupported region type %hhx\n",
+ region_type);
+ return (EINVAL);
+ }
+}
/**
* Register all MMIO region descriptors for the given slave port.
@@ -608,24 +848,10 @@ erom_corecfg_fill_port_regions(struct bcma_erom *erom,
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);
- }
+ if ((error = erom_region_to_port_type(erom, region_type, &port_type)))
+ return (error);
/* Fetch the list to be populated */
sports = bcma_corecfg_get_port_list(corecfg, port_type);
diff --git a/sys/dev/bhnd/bcma/bcma_eromvar.h b/sys/dev/bhnd/bcma/bcma_eromvar.h
index 6c99939bbbca..292352c62199 100644
--- a/sys/dev/bhnd/bcma/bcma_eromvar.h
+++ b/sys/dev/bhnd/bcma/bcma_eromvar.h
@@ -40,10 +40,11 @@
* 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 */
+ device_t dev; /**< EROM parent device */
+ bus_space_tag_t bst; /**< EROM table bus space */
+ bus_space_handle_t bsh; /**< EROM table bus handle */
+ bus_size_t start; /**< EROM table offset */
+ bus_size_t offset; /**< current read offset */
};
/** EROM core descriptor. */
@@ -78,22 +79,34 @@ struct bcma_erom_sport_region {
int bcma_erom_open(struct bcma_erom *erom, struct resource *r,
bus_size_t offset);
+int bhnd_erom_bus_space_open(struct bcma_erom *erom, device_t owner,
+ bus_space_tag_t bst, bus_space_handle_t bsh,
+ 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_next_core(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_seek_core_sport_region(struct bcma_erom *erom,
+ u_int core_index, bhnd_port_type port_type, u_int port_num,
+ u_int region_num);
+
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);
+void bcma_erom_to_core_info(const struct bcma_erom_core *core,
+ u_int core_idx, int core_unit, struct bhnd_core_info *info);
+
int bcma_erom_get_core_info(struct bcma_erom *erom,
struct bhnd_core_info **cores,
u_int *num_cores);
diff --git a/sys/dev/bhnd/bhnd_ids.h b/sys/dev/bhnd/bhnd_ids.h
index 9a3d807e46ae..6945c7650cb5 100644
--- a/sys/dev/bhnd/bhnd_ids.h
+++ b/sys/dev/bhnd/bhnd_ids.h
@@ -535,6 +535,12 @@
#define BHND_CHIPTYPE_UBUS 2 /**< ubus interconnect found in bcm63xx devices */
#define BHND_CHIPTYPE_BCMA_ALT 3 /**< bcma(4) interconnect */
+/** Evaluates to true if @p _type uses a BCMA EROM table */
+#define BHND_CHIPTYPE_HAS_EROM(_type) \
+ ((_type) == BHND_CHIPTYPE_BCMA || \
+ (_type) == BHND_CHIPTYPE_BCMA_ALT || \
+ (_type) == BHND_CHIPTYPE_UBUS)
+
/* Boardflags */
#define BHND_BFL_BTC2WIRE 0x00000001 /* old 2wire Bluetooth coexistence, OBSOLETE */
#define BHND_BFL_BTCOEX 0x00000001 /* Board supports BTCOEX */
diff --git a/sys/dev/bhnd/bhnd_subr.c b/sys/dev/bhnd/bhnd_subr.c
index fbbd841fc564..03d1b5a625ce 100644
--- a/sys/dev/bhnd/bhnd_subr.c
+++ b/sys/dev/bhnd/bhnd_subr.c
@@ -834,12 +834,16 @@ bhnd_read_chipid(device_t dev, struct resource_spec *rs,
bus_size_t chipc_offset, struct bhnd_chipid *result)
{
struct resource *res;
+ bhnd_addr_t enum_addr;
uint32_t reg;
+ uint8_t chip_type;
int error, rid, rtype;
- /* Allocate the ChipCommon window resource and fetch the chipid data */
rid = rs->rid;
rtype = rs->type;
+ error = 0;
+
+ /* Allocate the ChipCommon window resource and fetch the chipid data */
res = bus_alloc_resource_any(dev, rtype, &rid, RF_ACTIVE);
if (res == NULL) {
device_printf(dev,
@@ -849,30 +853,23 @@ bhnd_read_chipid(device_t dev, struct resource_spec *rs,
/* Fetch the basic chip info */
reg = bus_read_4(res, chipc_offset + CHIPC_ID);
- *result = bhnd_parse_chipid(reg, 0x0);
+ chip_type = CHIPC_GET_BITS(reg, CHIPC_ID_BUS);
- /* 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);
+ /* Fetch the EROMPTR */
+ if (BHND_CHIPTYPE_HAS_EROM(chip_type)) {
+ enum_addr = bus_read_4(res, chipc_offset + CHIPC_EROMPTR);
+ } else if (chip_type == BHND_CHIPTYPE_SIBA) {
+ /* siba(4) uses the ChipCommon base address as the enumeration
+ * address */
+ enum_addr = rman_get_start(res) + chipc_offset;
+ } else {
+ device_printf(dev, "unknown chip type %hhu\n", chip_type);
error = ENODEV;
goto cleanup;
}
+ *result = bhnd_parse_chipid(reg, enum_addr);
+
cleanup:
/* Clean up */
bus_release_resource(dev, rtype, rid, res);
diff --git a/sys/dev/bhnd/cores/chipc/chipcreg.h b/sys/dev/bhnd/cores/chipc/chipcreg.h
index 6004b6f93079..ee7dff2276a1 100644
--- a/sys/dev/bhnd/cores/chipc/chipcreg.h
+++ b/sys/dev/bhnd/cores/chipc/chipcreg.h
@@ -35,6 +35,16 @@
* the core count via the chip identification register. */
#define CHIPC_NCORES_MIN_HWREV(hwrev) ((hwrev) == 4 || (hwrev) >= 6)
+/** Evaluates to true if the given ChipCommon core revision supports
+ * the CHIPC_CAPABILITIES_EXT register */
+#define CHIPC_HWREV_HAS_CAP_EXT(hwrev) ((hwrev) >= 35)
+
+/** Evaluates to true if the chipcommon core (determined from the provided
+ * @p _chipid (CHIPC_ID) register value) provides a pointer to the enumeration
+ * table via CHIPC_EROMPTR */
+#define CHIPC_HAS_EROMPTR(_chipid) \
+ (CHIPC_GET_BITS((_chipid), CHIPC_ID_BUS) != BHND_CHIPTYPE_SIBA)
+
#define CHIPC_GET_FLAG(_value, _flag) (((_value) & _flag) != 0)
#define CHIPC_GET_BITS(_value, _field) \
((_value & _field ## _MASK) >> _field ## _SHIFT)