bhnd(4): Perform explicit chipc child enumeration.
Replaces use of DEVICE_IDENTIFY with explicit enumeration of chipc child devices using the chipc capability structure. This is a precursor to PMU support, which requires more complex resource assignment handling than achievable with the static device name-based hints table. Reviewed by: Michael Zhilin <mizkha@gmail.com> (Broadcom MIPS support) Approved by: re (gjb), adrian (mentor) Differential Revision: https://reviews.freebsd.org/D6896
This commit is contained in:
parent
1902276e19
commit
0c91e8927d
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=302189
@ -55,6 +55,12 @@ CODE {
|
||||
panic("bhnd_bus_get_chipid unimplemented");
|
||||
}
|
||||
|
||||
static bhnd_attach_type
|
||||
bhnd_bus_null_get_attach_type(device_t dev, device_t child)
|
||||
{
|
||||
panic("bhnd_bus_get_attach_type unimplemented");
|
||||
}
|
||||
|
||||
static int
|
||||
bhnd_bus_null_read_board_info(device_t dev, device_t child,
|
||||
struct bhnd_board_info *info)
|
||||
@ -197,7 +203,7 @@ METHOD const struct bhnd_chipid * get_chipid {
|
||||
METHOD bhnd_attach_type get_attach_type {
|
||||
device_t dev;
|
||||
device_t child;
|
||||
} DEFAULT bhnd_bus_generic_get_attach_type;
|
||||
} DEFAULT bhnd_bus_null_get_attach_type;
|
||||
|
||||
/**
|
||||
* Attempt to read the BHND board identification from the parent bus.
|
||||
|
@ -1159,21 +1159,3 @@ bhnd_bus_generic_deactivate_resource(device_t dev, device_t child,
|
||||
return (EINVAL);
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function for implementing BHND_BUS_GET_ATTACH_TYPE().
|
||||
*
|
||||
* This implementation of BHND_BUS_GET_ATTACH_TYPE() simply calls the
|
||||
* BHND_BUS_GET_ATTACH_TYPE() method of the parent of @p dev.
|
||||
*/
|
||||
bhnd_attach_type
|
||||
bhnd_bus_generic_get_attach_type(device_t dev, device_t child)
|
||||
{
|
||||
/* iterate from cores via bhnd to bridge or SoC */
|
||||
if (device_get_parent(dev) != NULL)
|
||||
return (BHND_BUS_GET_ATTACH_TYPE(device_get_parent(dev),
|
||||
child));
|
||||
|
||||
panic("bhnd_bus_get_attach_type unimplemented");
|
||||
/* Unreachable */
|
||||
return (BHND_ATTACH_ADAPTER);
|
||||
}
|
||||
|
@ -36,32 +36,16 @@ INTERFACE bhnd_chipc;
|
||||
#
|
||||
|
||||
HEADER {
|
||||
#include <dev/bhnd/nvram/bhnd_nvram.h>
|
||||
/* forward declarations */
|
||||
struct chipc_caps;
|
||||
struct chipc_caps *bhnd_chipc_generic_get_caps(device_t dev);
|
||||
}
|
||||
|
||||
CODE {
|
||||
|
||||
/**
|
||||
* Helper function for implementing BHND_CHIPC_GET_CAPS().
|
||||
*
|
||||
* This implementation of BHND_CHIPC_GET_CAPS() simply calls the
|
||||
* BHND_CHIPC_GET_CAPS() method of the parent of @p dev.
|
||||
*/
|
||||
struct chipc_caps*
|
||||
bhnd_chipc_generic_get_caps(device_t dev)
|
||||
static struct chipc_caps *
|
||||
bhnd_chipc_null_get_caps(device_t dev)
|
||||
{
|
||||
|
||||
if (device_get_parent(dev) != NULL)
|
||||
return (BHND_CHIPC_GET_CAPS(device_get_parent(dev)));
|
||||
|
||||
panic("bhnd_chipc_generic_get_caps unimplemented");
|
||||
/* Unreachable */
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -91,7 +75,7 @@ METHOD void write_chipctrl {
|
||||
*/
|
||||
METHOD struct chipc_caps * get_caps {
|
||||
device_t dev;
|
||||
} DEFAULT bhnd_chipc_generic_get_caps;
|
||||
} DEFAULT bhnd_chipc_null_get_caps;
|
||||
|
||||
/**
|
||||
* Enable hardware access to the SPROM/OTP source.
|
||||
@ -114,12 +98,3 @@ METHOD int enable_sprom {
|
||||
METHOD void disable_sprom {
|
||||
device_t dev;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the flash configuration register value
|
||||
*
|
||||
* @param dev A bhnd(4) ChipCommon device
|
||||
*/
|
||||
METHOD uint32_t get_flash_cfg {
|
||||
device_t dev;
|
||||
}
|
||||
|
@ -54,22 +54,6 @@ __FBSDID("$FreeBSD$");
|
||||
#define CHIPC_VALID_SPROM_SRC(_src) \
|
||||
((_src) == BHND_NVRAM_SRC_SPROM || (_src) == BHND_NVRAM_SRC_OTP)
|
||||
|
||||
static void
|
||||
chipc_sprom_identify(driver_t *driver, device_t parent)
|
||||
{
|
||||
struct chipc_caps *caps;
|
||||
|
||||
caps = BHND_CHIPC_GET_CAPS(parent);
|
||||
if (!CHIPC_VALID_SPROM_SRC(caps->nvram_src))
|
||||
return;
|
||||
|
||||
if (device_find_child(parent, "bhnd_nvram", 0) != NULL)
|
||||
return;
|
||||
|
||||
if (BUS_ADD_CHILD(parent, 0, "bhnd_nvram", 0) == NULL)
|
||||
device_printf(parent, "add bhnd_nvram failed\n");
|
||||
}
|
||||
|
||||
static int
|
||||
chipc_sprom_probe(device_t dev)
|
||||
{
|
||||
@ -113,7 +97,6 @@ chipc_sprom_attach(device_t dev)
|
||||
|
||||
static device_method_t chipc_sprom_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_identify, chipc_sprom_identify),
|
||||
DEVMETHOD(device_probe, chipc_sprom_probe),
|
||||
DEVMETHOD(device_attach, chipc_sprom_attach),
|
||||
DEVMETHOD_END
|
||||
|
@ -37,25 +37,8 @@ __FBSDID("$FreeBSD$");
|
||||
* 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.
|
||||
*
|
||||
* The purpose of this driver is memory resource management for ChipCommon drivers
|
||||
* like UART, PMU, flash. ChipCommon core has several memory regions.
|
||||
*
|
||||
* ChipCommon driver has memory resource manager. Driver
|
||||
* gets information about BHND core ports/regions and map them
|
||||
* into drivers' resources.
|
||||
*
|
||||
* Here is overview of mapping:
|
||||
*
|
||||
* ------------------------------------------------------
|
||||
* | Port.Region| Purpose |
|
||||
* ------------------------------------------------------
|
||||
* | 0.0 | PMU, SPI(0x40), UART(0x300) |
|
||||
* | 1.0 | ? |
|
||||
* | 1.1 | MMIO flash (SPI & CFI) |
|
||||
* ------------------------------------------------------
|
||||
* identification, bus enumeration, UARTs, clocks, watchdog interrupts,
|
||||
* GPIO, flash, etc.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
@ -76,6 +59,7 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include "chipcreg.h"
|
||||
#include "chipcvar.h"
|
||||
|
||||
#include "chipc_private.h"
|
||||
|
||||
devclass_t bhnd_chipc_devclass; /**< bhnd(4) chipcommon device class */
|
||||
@ -123,49 +107,10 @@ static struct bhnd_device_quirk chipc_quirks[] = {
|
||||
BHND_DEVICE_QUIRK_END
|
||||
};
|
||||
|
||||
// FIXME: IRQ shouldn't be hard-coded
|
||||
#define CHIPC_MIPS_IRQ 2
|
||||
|
||||
/*
|
||||
* Here is resource configuration hints for child devices
|
||||
*
|
||||
* [Flash] There are 2 flash resources:
|
||||
* - resource ID (rid) = 0: memory-mapped flash memory
|
||||
* - resource ID (rid) = 1: memory-mapped flash registers (i.e for SPI)
|
||||
*
|
||||
* [UART] Uses IRQ and memory resources:
|
||||
* - resource ID (rid) = 0: memory-mapped registers
|
||||
* - IRQ resource ID (rid) = 0: shared IRQ line for Tx/Rx.
|
||||
*/
|
||||
|
||||
static const struct chipc_hint {
|
||||
const char *name;
|
||||
int unit;
|
||||
int type;
|
||||
int rid;
|
||||
rman_res_t base; /* relative to parent resource */
|
||||
rman_res_t size;
|
||||
u_int port; /* ignored if SYS_RES_IRQ */
|
||||
u_int region;
|
||||
} chipc_hints[] = {
|
||||
// FIXME: cfg/spi port1.1 mapping on siba(4) SoCs
|
||||
// FIXME: IRQ shouldn't be hardcoded
|
||||
/* device unit type rid base size port,region */
|
||||
{ "bhnd_nvram", 0, SYS_RES_MEMORY, 0, CHIPC_SPROM_OTP, CHIPC_SPROM_OTP_SIZE, 0,0 },
|
||||
{ "uart", 0, SYS_RES_MEMORY, 0, CHIPC_UART0_BASE, CHIPC_UART_SIZE, 0,0 },
|
||||
{ "uart", 0, SYS_RES_IRQ, 0, 2, 1 },
|
||||
{ "uart", 1, SYS_RES_MEMORY, 0, CHIPC_UART1_BASE, CHIPC_UART_SIZE, 0,0 },
|
||||
{ "uart", 1, SYS_RES_IRQ, 0, 2, 1 },
|
||||
{ "spi", 0, SYS_RES_MEMORY, 0, 0, RM_MAX_END, 1,1 },
|
||||
{ "spi", 0, SYS_RES_MEMORY, 1, CHIPC_SFLASH_BASE, CHIPC_SFLASH_SIZE, 0,0 },
|
||||
{ "cfi", 0, SYS_RES_MEMORY, 0, 0, RM_MAX_END, 1,1},
|
||||
{ "cfi", 0, SYS_RES_MEMORY, 1, CHIPC_SFLASH_BASE, CHIPC_SFLASH_SIZE, 0,0 },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
|
||||
static int chipc_try_activate_resource(
|
||||
struct chipc_softc *sc, device_t child,
|
||||
int type, int rid, struct resource *r,
|
||||
bool req_direct);
|
||||
static int chipc_add_children(struct chipc_softc *sc);
|
||||
|
||||
static bhnd_nvram_src chipc_find_nvram_src(struct chipc_softc *sc,
|
||||
struct chipc_caps *caps);
|
||||
@ -175,6 +120,11 @@ static int chipc_read_caps(struct chipc_softc *sc,
|
||||
static bool chipc_should_enable_sprom(
|
||||
struct chipc_softc *sc);
|
||||
|
||||
static int chipc_try_activate_resource(
|
||||
struct chipc_softc *sc, device_t child,
|
||||
int type, int rid, struct resource *r,
|
||||
bool req_direct);
|
||||
|
||||
static int chipc_init_rman(struct chipc_softc *sc);
|
||||
static void chipc_free_rman(struct chipc_softc *sc);
|
||||
static struct rman *chipc_get_rman(struct chipc_softc *sc,
|
||||
@ -210,9 +160,6 @@ static int
|
||||
chipc_attach(device_t dev)
|
||||
{
|
||||
struct chipc_softc *sc;
|
||||
bhnd_addr_t enum_addr;
|
||||
uint32_t ccid_reg;
|
||||
uint8_t chip_type;
|
||||
int error;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
@ -231,7 +178,7 @@ chipc_attach(device_t dev)
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* Allocate the region containing our core registers */
|
||||
/* Allocate the region containing the chipc register block */
|
||||
if ((sc->core_region = chipc_find_region_by_rid(sc, 0)) == NULL) {
|
||||
error = ENXIO;
|
||||
goto failed;
|
||||
@ -242,30 +189,10 @@ chipc_attach(device_t dev)
|
||||
if (error) {
|
||||
sc->core_region = NULL;
|
||||
goto failed;
|
||||
} else {
|
||||
sc->core = sc->core_region->cr_res;
|
||||
}
|
||||
|
||||
/* Fetch our chipset identification data */
|
||||
ccid_reg = bhnd_bus_read_4(sc->core, CHIPC_ID);
|
||||
chip_type = CHIPC_GET_BITS(ccid_reg, CHIPC_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 failed;
|
||||
}
|
||||
|
||||
sc->ccid = bhnd_parse_chipid(ccid_reg, enum_addr);
|
||||
/* Save a direct reference to our chipc registers */
|
||||
sc->core = sc->core_region->cr_res;
|
||||
|
||||
/* Fetch and parse capability register(s) */
|
||||
if ((error = chipc_read_caps(sc, &sc->caps)))
|
||||
@ -274,8 +201,10 @@ chipc_attach(device_t dev)
|
||||
if (bootverbose)
|
||||
chipc_print_caps(sc->dev, &sc->caps);
|
||||
|
||||
/* Probe and attach children */
|
||||
bus_generic_probe(dev);
|
||||
/* Attach all supported child devices */
|
||||
if ((error = chipc_add_children(sc)))
|
||||
goto failed;
|
||||
|
||||
if ((error = bus_generic_attach(dev)))
|
||||
goto failed;
|
||||
|
||||
@ -313,6 +242,119 @@ chipc_detach(device_t dev)
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
chipc_add_children(struct chipc_softc *sc)
|
||||
{
|
||||
device_t child;
|
||||
const char *flash_bus;
|
||||
int error;
|
||||
|
||||
/* SPROM/OTP */
|
||||
if (sc->caps.nvram_src == BHND_NVRAM_SRC_SPROM ||
|
||||
sc->caps.nvram_src == BHND_NVRAM_SRC_OTP)
|
||||
{
|
||||
child = BUS_ADD_CHILD(sc->dev, 0, "bhnd_nvram", -1);
|
||||
if (child == NULL) {
|
||||
device_printf(sc->dev, "failed to add nvram device\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* Both OTP and external SPROM are mapped at CHIPC_SPROM_OTP */
|
||||
error = chipc_set_resource(sc, child, SYS_RES_MEMORY, 0,
|
||||
CHIPC_SPROM_OTP, CHIPC_SPROM_OTP_SIZE, 0, 0);
|
||||
if (error)
|
||||
return (error);
|
||||
}
|
||||
|
||||
#ifdef notyet
|
||||
/*
|
||||
* PMU/SLOWCLK/INSTACLK
|
||||
*
|
||||
* On AOB ("Always on Bus") devices, a PMU core (if it exists) is
|
||||
* enumerated directly by the bhnd(4) bus -- not chipc.
|
||||
*
|
||||
* Otherwise, we always add a PMU child device, and let the
|
||||
* chipc bhnd_pmu drivers probe for it. If the core supports an
|
||||
* earlier non-PMU clock/power register interface, one of the instaclk,
|
||||
* powerctl, or null bhnd_pmu drivers will claim the device.
|
||||
*/
|
||||
if (!sc->caps.aob || (sc->caps.aob && !sc->caps.pmu)) {
|
||||
child = BUS_ADD_CHILD(sc->dev, 0, "bhnd_pmu", -1);
|
||||
if (child == NULL) {
|
||||
device_printf(sc->dev, "failed to add pmu\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* Associate the applicable register block */
|
||||
error = 0;
|
||||
if (sc->caps.pmu) {
|
||||
error = chipc_set_resource(sc, child, SYS_RES_MEMORY, 0,
|
||||
CHIPC_PMU, CHIPC_PMU_SIZE, 0, 0);
|
||||
} else if (sc->caps.power_control) {
|
||||
error = chipc_set_resource(sc, child, SYS_RES_MEMORY, 0,
|
||||
CHIPC_PWRCTL, CHIPC_PWRCTL_SIZE, 0, 0);
|
||||
}
|
||||
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
}
|
||||
#endif /* notyet */
|
||||
|
||||
/* All remaining devices are SoC-only */
|
||||
if (bhnd_get_attach_type(sc->dev) != BHND_ATTACH_NATIVE)
|
||||
return (0);
|
||||
|
||||
/* UARTs */
|
||||
for (u_int i = 0; i < min(sc->caps.num_uarts, CHIPC_UART_MAX); i++) {
|
||||
child = BUS_ADD_CHILD(sc->dev, 0, "uart", -1);
|
||||
if (child == NULL) {
|
||||
device_printf(sc->dev, "failed to add uart%u\n", i);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* Shared IRQ */
|
||||
error = bus_set_resource(child, SYS_RES_IRQ, 0, CHIPC_MIPS_IRQ,
|
||||
1);
|
||||
if (error) {
|
||||
device_printf(sc->dev, "failed to set uart%u irq %u\n",
|
||||
i, CHIPC_MIPS_IRQ);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/* UART registers are mapped sequentially */
|
||||
error = chipc_set_resource(sc, child, SYS_RES_MEMORY, 0,
|
||||
CHIPC_UART(i), CHIPC_UART_SIZE, 0, 0);
|
||||
if (error)
|
||||
return (error);
|
||||
}
|
||||
|
||||
/* Flash */
|
||||
flash_bus = chipc_flash_bus_name(sc->caps.flash_type);
|
||||
if (flash_bus != NULL) {
|
||||
child = BUS_ADD_CHILD(sc->dev, 0, flash_bus, -1);
|
||||
if (child == NULL) {
|
||||
device_printf(sc->dev, "failed to add %s device\n",
|
||||
flash_bus);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* flash memory mapping */
|
||||
error = chipc_set_resource(sc, child, SYS_RES_MEMORY, 0,
|
||||
0, RM_MAX_END, 1, 1);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
/* flashctrl registers */
|
||||
error = chipc_set_resource(sc, child, SYS_RES_MEMORY, 1,
|
||||
CHIPC_SFLASH_BASE, CHIPC_SFLASH_SIZE, 0, 0);
|
||||
if (error)
|
||||
return (error);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the NVRAM data source for this device.
|
||||
*
|
||||
@ -411,7 +453,6 @@ chipc_read_caps(struct chipc_softc *sc, struct chipc_caps *caps)
|
||||
|
||||
/* Determine flash type and parameters */
|
||||
caps->cfi_width = 0;
|
||||
|
||||
switch (CHIPC_GET_BITS(cap_reg, CHIPC_CAP_FLASH)) {
|
||||
case CHIPC_CAP_SFLASH_ST:
|
||||
caps->flash_type = CHIPC_SFLASH_ST;
|
||||
@ -420,6 +461,7 @@ chipc_read_caps(struct chipc_softc *sc, struct chipc_caps *caps)
|
||||
caps->flash_type = CHIPC_SFLASH_AT;
|
||||
break;
|
||||
case CHIPC_CAP_NFLASH:
|
||||
/* unimplemented */
|
||||
caps->flash_type = CHIPC_NFLASH;
|
||||
break;
|
||||
case CHIPC_CAP_PFLASH:
|
||||
@ -548,33 +590,16 @@ chipc_child_location_str(device_t dev, device_t child, char *buf,
|
||||
static device_t
|
||||
chipc_add_child(device_t dev, u_int order, const char *name, int unit)
|
||||
{
|
||||
struct chipc_softc *sc;
|
||||
struct chipc_devinfo *dinfo;
|
||||
const struct chipc_hint *hint;
|
||||
device_t child;
|
||||
devclass_t child_dc;
|
||||
int error;
|
||||
int busrel_unit;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
child = device_add_child_ordered(dev, order, name, unit);
|
||||
if (child == NULL)
|
||||
return (NULL);
|
||||
|
||||
/* system-wide device unit */
|
||||
unit = device_get_unit(child);
|
||||
child_dc = device_get_devclass(child);
|
||||
|
||||
busrel_unit = 0;
|
||||
for (int i = 0; i < unit; i++) {
|
||||
device_t tmp;
|
||||
|
||||
tmp = devclass_get_device(child_dc, i);
|
||||
if (tmp != NULL && (device_get_parent(tmp) == dev))
|
||||
busrel_unit++;
|
||||
}
|
||||
|
||||
/* bus-wide device unit (override unit for further hint matching) */
|
||||
unit = busrel_unit;
|
||||
|
||||
dinfo = malloc(sizeof(struct chipc_devinfo), M_BHND, M_NOWAIT);
|
||||
if (dinfo == NULL) {
|
||||
device_delete_child(dev, child);
|
||||
@ -584,93 +609,7 @@ chipc_add_child(device_t dev, u_int order, const char *name, int unit)
|
||||
resource_list_init(&dinfo->resources);
|
||||
device_set_ivars(child, dinfo);
|
||||
|
||||
/* Hint matching requires a device name */
|
||||
if (name == NULL)
|
||||
return (child);
|
||||
|
||||
/* Use hint table to set child resources */
|
||||
for (hint = chipc_hints; hint->name != NULL; hint++) {
|
||||
bhnd_addr_t region_addr;
|
||||
bhnd_size_t region_size;
|
||||
|
||||
/* Check device name */
|
||||
if (strcmp(hint->name, name) != 0)
|
||||
continue;
|
||||
|
||||
/* Check device unit */
|
||||
if (hint->unit >= 0 && unit != hint->unit)
|
||||
continue;
|
||||
|
||||
switch (hint->type) {
|
||||
case SYS_RES_IRQ:
|
||||
/* Add child resource */
|
||||
error = bus_set_resource(child, hint->type, hint->rid,
|
||||
hint->base, hint->size);
|
||||
if (error) {
|
||||
device_printf(dev,
|
||||
"bus_set_resource() failed for %s: %d\n",
|
||||
device_get_nameunit(child), error);
|
||||
goto failed;
|
||||
}
|
||||
break;
|
||||
|
||||
case SYS_RES_MEMORY:
|
||||
/* Fetch region address and size */
|
||||
error = bhnd_get_region_addr(dev, BHND_PORT_DEVICE,
|
||||
hint->port, hint->region, ®ion_addr,
|
||||
®ion_size);
|
||||
if (error) {
|
||||
device_printf(dev,
|
||||
"lookup of %s%u.%u failed: %d\n",
|
||||
bhnd_port_type_name(BHND_PORT_DEVICE),
|
||||
hint->port, hint->region, error);
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* Verify requested range is mappable */
|
||||
if (hint->base > region_size ||
|
||||
(hint->size != RM_MAX_END &&
|
||||
(hint->size > region_size ||
|
||||
region_size - hint->base < hint->size )))
|
||||
{
|
||||
device_printf(dev,
|
||||
"%s%u.%u region cannot map requested range "
|
||||
"%#jx+%#jx\n",
|
||||
bhnd_port_type_name(BHND_PORT_DEVICE),
|
||||
hint->port, hint->region, hint->base,
|
||||
hint->size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add child resource. If hint doesn't define the end
|
||||
* of resource window (RX_MAX_END), use end of region.
|
||||
*/
|
||||
|
||||
error = bus_set_resource(child,
|
||||
hint->type,
|
||||
hint->rid, region_addr + hint->base,
|
||||
(hint->size == RM_MAX_END) ?
|
||||
region_size - hint->base :
|
||||
hint->size);
|
||||
if (error) {
|
||||
device_printf(dev,
|
||||
"bus_set_resource() failed for %s: %d\n",
|
||||
device_get_nameunit(child), error);
|
||||
goto failed;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
device_printf(child, "unknown hint resource type: %d\n",
|
||||
hint->type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return (child);
|
||||
|
||||
failed:
|
||||
device_delete_child(dev, child);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -705,7 +644,7 @@ chipc_rman_init_regions (struct chipc_softc *sc, bhnd_port_type type,
|
||||
u_int num_regions;
|
||||
int error;
|
||||
|
||||
num_regions = bhnd_get_region_count(sc->dev, port, port);
|
||||
num_regions = bhnd_get_region_count(sc->dev, type, port);
|
||||
for (u_int region = 0; region < num_regions; region++) {
|
||||
/* Allocate new region record */
|
||||
cr = chipc_alloc_region(sc, type, port, region);
|
||||
@ -1349,15 +1288,6 @@ chipc_get_caps(device_t dev)
|
||||
return (&sc->caps);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
chipc_get_flash_cfg(device_t dev)
|
||||
{
|
||||
struct chipc_softc *sc;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
return (bhnd_bus_read_4(sc->core, CHIPC_FLASH_CFG));
|
||||
}
|
||||
|
||||
static device_method_t chipc_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_probe, chipc_probe),
|
||||
@ -1399,7 +1329,6 @@ static device_method_t chipc_methods[] = {
|
||||
DEVMETHOD(bhnd_chipc_enable_sprom, chipc_enable_sprom_pins),
|
||||
DEVMETHOD(bhnd_chipc_disable_sprom, chipc_disable_sprom_pins),
|
||||
DEVMETHOD(bhnd_chipc_get_caps, chipc_get_caps),
|
||||
DEVMETHOD(bhnd_chipc_get_flash_cfg, chipc_get_flash_cfg),
|
||||
|
||||
DEVMETHOD_END
|
||||
};
|
||||
|
@ -40,90 +40,39 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <machine/bus.h>
|
||||
|
||||
#include <dev/bhnd/bhnd_debug.h>
|
||||
#include <dev/cfi/cfi_var.h>
|
||||
|
||||
#include "bhnd_chipc_if.h"
|
||||
#include "chipc_slicer.h"
|
||||
|
||||
#include "chipcreg.h"
|
||||
#include "chipcvar.h"
|
||||
|
||||
/*
|
||||
* **************************** PROTOTYPES ****************************
|
||||
*/
|
||||
|
||||
static void chipc_cfi_identify(driver_t *driver, device_t parent);
|
||||
static int chipc_cfi_probe(device_t dev);
|
||||
static int chipc_cfi_attach(device_t dev);
|
||||
|
||||
/*
|
||||
* **************************** IMPLEMENTATION ************************
|
||||
*/
|
||||
|
||||
static void
|
||||
chipc_cfi_identify(driver_t *driver, device_t parent)
|
||||
{
|
||||
struct chipc_caps *caps;
|
||||
|
||||
if (device_find_child(parent, cfi_driver_name, -1) != NULL)
|
||||
return;
|
||||
|
||||
caps = BHND_CHIPC_GET_CAPS(parent);
|
||||
if (caps == NULL)
|
||||
return;
|
||||
|
||||
if (caps->flash_type != CHIPC_PFLASH_CFI)
|
||||
return;
|
||||
|
||||
BUS_ADD_CHILD(parent, 0, cfi_driver_name, -1);
|
||||
return;
|
||||
}
|
||||
#include "chipc_slicer.h"
|
||||
|
||||
static int
|
||||
chipc_cfi_probe(device_t dev)
|
||||
{
|
||||
int error;
|
||||
int enabled;
|
||||
int byteswap;
|
||||
uint32_t flash_config;
|
||||
struct cfi_softc *sc;
|
||||
int error;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
flash_config = BHND_CHIPC_GET_FLASH_CFG(device_get_parent(dev));
|
||||
|
||||
enabled = (flash_config & CHIPC_CF_EN);
|
||||
byteswap = (flash_config & CHIPC_CF_BS);
|
||||
|
||||
if (enabled == 0)
|
||||
device_disable(dev);
|
||||
|
||||
BHND_DEBUG_DEV(dev, "trying attach flash enabled=%d swapbytes=%d",
|
||||
enabled, byteswap);
|
||||
|
||||
sc->sc_width = 0;
|
||||
error = cfi_probe(dev);
|
||||
if (error == 0)
|
||||
device_set_desc(dev, "ChipCommon CFI");
|
||||
if ((error = cfi_probe(dev)) > 0)
|
||||
return (error);
|
||||
|
||||
device_set_desc(dev, "Broadcom ChipCommon CFI");
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
chipc_cfi_attach(device_t dev)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = cfi_attach(dev);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
flash_register_slicer(chipc_slicer_cfi);
|
||||
return (0);
|
||||
chipc_register_slicer(CHIPC_PFLASH_CFI);
|
||||
return (cfi_attach(dev));
|
||||
}
|
||||
|
||||
static device_method_t chipc_cfi_methods[] = {
|
||||
/* device interface */
|
||||
DEVMETHOD(device_identify, chipc_cfi_identify),
|
||||
DEVMETHOD(device_probe, chipc_cfi_probe),
|
||||
DEVMETHOD(device_attach, chipc_cfi_attach),
|
||||
DEVMETHOD(device_detach, cfi_detach),
|
||||
@ -138,4 +87,3 @@ static driver_t chipc_cfi_driver = {
|
||||
};
|
||||
|
||||
DRIVER_MODULE(cfi, bhnd_chipc, chipc_cfi_driver, cfi_devclass, 0, 0);
|
||||
|
||||
|
@ -55,6 +55,11 @@ int chipc_init_child_resource(struct resource *r,
|
||||
struct resource *parent,
|
||||
bhnd_size_t offset, bhnd_size_t size);
|
||||
|
||||
int chipc_set_resource(struct chipc_softc *sc,
|
||||
device_t child, int type, int rid,
|
||||
rman_res_t start, rman_res_t count, u_int port,
|
||||
u_int region);
|
||||
|
||||
struct chipc_region *chipc_alloc_region(struct chipc_softc *sc,
|
||||
bhnd_port_type type, u_int port,
|
||||
u_int region);
|
||||
|
@ -54,58 +54,88 @@ __FBSDID("$FreeBSD$");
|
||||
#include <dev/cfi/cfi_var.h>
|
||||
#include "chipc_spi.h"
|
||||
|
||||
static int chipc_slicer_walk(device_t dev, struct resource* res,
|
||||
static int chipc_slicer_walk(device_t dev, struct resource *res,
|
||||
struct flash_slice *slices, int *nslices);
|
||||
|
||||
void
|
||||
chipc_register_slicer(chipc_flash flash_type)
|
||||
{
|
||||
switch (flash_type) {
|
||||
case CHIPC_SFLASH_AT:
|
||||
case CHIPC_SFLASH_ST:
|
||||
flash_register_slicer(chipc_slicer_spi);
|
||||
break;
|
||||
case CHIPC_PFLASH_CFI:
|
||||
flash_register_slicer(chipc_slicer_cfi);
|
||||
break;
|
||||
default:
|
||||
/* Unsupported */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
chipc_slicer_cfi(device_t dev, struct flash_slice *slices, int *nslices)
|
||||
{
|
||||
struct cfi_softc *sc;
|
||||
device_t parent;
|
||||
|
||||
if (strcmp("cfi", device_get_name(dev)) != 0)
|
||||
return (0);
|
||||
/* must be CFI flash */
|
||||
if (device_get_devclass(dev) != devclass_find("cfi"))
|
||||
return (ENXIO);
|
||||
|
||||
/* must be attached to chipc */
|
||||
if ((parent = device_get_parent(dev)) == NULL) {
|
||||
BHND_ERROR_DEV(dev, "no found ChipCommon device");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
if (device_get_devclass(parent) != devclass_find("bhnd_chipc")) {
|
||||
BHND_ERROR_DEV(dev, "no found ChipCommon device");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
return (chipc_slicer_walk(dev, sc->sc_res, slices, nslices));
|
||||
}
|
||||
|
||||
int
|
||||
chipc_slicer_spi(device_t dev, struct flash_slice *slices, int *nslices)
|
||||
{
|
||||
/* flash(mx25l) <- spibus <- chipc_spi */
|
||||
device_t spibus;
|
||||
device_t chipc_spi;
|
||||
struct chipc_spi_softc *sc;
|
||||
device_t chipc, spi, spibus;
|
||||
|
||||
BHND_DEBUG_DEV(dev, "initting SPI slicer: %s", device_get_name(dev));
|
||||
|
||||
if (strcmp("mx25l", device_get_name(dev)) != 0)
|
||||
return (EINVAL);
|
||||
|
||||
/* must be SPI-attached flash */
|
||||
spibus = device_get_parent(dev);
|
||||
if (spibus == NULL) {
|
||||
BHND_ERROR_DEV(dev, "no found ChipCommon SPI BUS device");
|
||||
return (EINVAL);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
chipc_spi = device_get_parent(spibus);
|
||||
if (chipc_spi == NULL) {
|
||||
BHND_ERROR_DEV(spibus, "no found ChipCommon SPI device");
|
||||
return (EINVAL);
|
||||
spi = device_get_parent(spibus);
|
||||
if (spi == NULL) {
|
||||
BHND_ERROR_DEV(dev, "no found ChipCommon SPI device");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
sc = device_get_softc(chipc_spi);
|
||||
chipc = device_get_parent(spi);
|
||||
if (device_get_devclass(chipc) != devclass_find("bhnd_chipc")) {
|
||||
BHND_ERROR_DEV(dev, "no found ChipCommon device");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
return (chipc_slicer_walk(dev, sc->sc_res, slices, nslices));
|
||||
sc = device_get_softc(spi);
|
||||
return (chipc_slicer_walk(dev, sc->sc_flash_res, slices, nslices));
|
||||
}
|
||||
|
||||
/*
|
||||
* Main processing part
|
||||
*/
|
||||
static int
|
||||
chipc_slicer_walk(device_t dev, struct resource* res,
|
||||
struct flash_slice *slices, int *nslices)
|
||||
chipc_slicer_walk(device_t dev, struct resource *res,
|
||||
struct flash_slice *slices, int *nslices)
|
||||
{
|
||||
uint32_t fw_len;
|
||||
uint32_t fs_ofs;
|
||||
|
@ -34,10 +34,13 @@
|
||||
|
||||
#include <sys/slicer.h>
|
||||
|
||||
#include "chipcvar.h"
|
||||
|
||||
#define TRX_MAGIC 0x30524448
|
||||
#define CFE_MAGIC 0x43464531
|
||||
#define NVRAM_MAGIC 0x48534C46
|
||||
|
||||
void chipc_register_slicer(chipc_flash flash_type);
|
||||
int chipc_slicer_spi(device_t dev, struct flash_slice *slices,
|
||||
int *nslices);
|
||||
int chipc_slicer_cfi(device_t dev, struct flash_slice *slices,
|
||||
|
@ -1,5 +1,6 @@
|
||||
/*-
|
||||
* Copyright (c) 2016 Michael Zhilin <mizhka@gmail.com>
|
||||
* Copyright (c) 2016 Landon Fuller <landonf@FreeBSD.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@ -41,135 +42,134 @@ __FBSDID("$FreeBSD$");
|
||||
#include <machine/bus.h>
|
||||
|
||||
#include <dev/bhnd/bhndvar.h>
|
||||
/*
|
||||
* SPI BUS interface
|
||||
*/
|
||||
|
||||
#include <dev/spibus/spi.h>
|
||||
|
||||
#include "bhnd_chipc_if.h"
|
||||
|
||||
#include "spibus_if.h"
|
||||
|
||||
#include "chipcreg.h"
|
||||
#include "chipcvar.h"
|
||||
#include "chipc_spi.h"
|
||||
#include "bhnd_chipc_if.h"
|
||||
|
||||
/*
|
||||
* Flash slicer
|
||||
*/
|
||||
#include "chipc_slicer.h"
|
||||
|
||||
/*
|
||||
* **************************** PROTOTYPES ****************************
|
||||
*/
|
||||
#include "chipc_spi.h"
|
||||
|
||||
static void chipc_spi_identify(driver_t *driver, device_t parent);
|
||||
static int chipc_spi_probe(device_t dev);
|
||||
static int chipc_spi_attach(device_t dev);
|
||||
static int chipc_spi_detach(device_t dev);
|
||||
static int chipc_spi_transfer(device_t dev, device_t child,
|
||||
struct spi_command *cmd);
|
||||
static int chipc_spi_txrx(struct chipc_spi_softc *sc, uint8_t in,
|
||||
uint8_t* out);
|
||||
static int chipc_spi_wait(struct chipc_spi_softc *sc);
|
||||
|
||||
/*
|
||||
* **************************** IMPLEMENTATION ************************
|
||||
*/
|
||||
|
||||
static void
|
||||
chipc_spi_identify(driver_t *driver, device_t parent)
|
||||
{
|
||||
struct chipc_caps *caps;
|
||||
device_t spidev;
|
||||
device_t spibus;
|
||||
device_t flash;
|
||||
char* flash_name;
|
||||
int err;
|
||||
|
||||
flash_name = NULL;
|
||||
|
||||
if (device_find_child(parent, "spi", -1) != NULL)
|
||||
return;
|
||||
|
||||
caps = BHND_CHIPC_GET_CAPS(parent);
|
||||
if (caps == NULL) {
|
||||
BHND_ERROR_DEV(parent, "can't retrieve ChipCommon capabilities");
|
||||
return;
|
||||
}
|
||||
|
||||
switch (caps->flash_type) {
|
||||
case CHIPC_SFLASH_AT:
|
||||
flash_name = "at45d";
|
||||
break;
|
||||
case CHIPC_SFLASH_ST:
|
||||
flash_name = "mx25l";
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
spidev = BUS_ADD_CHILD(parent, 0, "spi", -1);
|
||||
if (spidev == NULL) {
|
||||
BHND_ERROR_DEV(parent, "can't add chipc_spi to ChipCommon");
|
||||
return;
|
||||
}
|
||||
|
||||
err = device_probe_and_attach(spidev);
|
||||
if (err) {
|
||||
BHND_ERROR_DEV(spidev, "failed attach chipc_spi: %d", err);
|
||||
return;
|
||||
}
|
||||
|
||||
spibus = device_find_child(spidev, "spibus", -1);
|
||||
if (spibus == NULL) {
|
||||
BHND_ERROR_DEV(spidev, "can't find spibus under chipc_spi");
|
||||
return;
|
||||
}
|
||||
|
||||
flash = BUS_ADD_CHILD(spibus, 0, flash_name, -1);
|
||||
if (flash == NULL) {
|
||||
BHND_ERROR_DEV(spibus, "can't add %s to spibus", flash_name);
|
||||
return;
|
||||
}
|
||||
|
||||
err = device_probe_and_attach(flash);
|
||||
if (err)
|
||||
BHND_ERROR_DEV(flash, "failed attach flash %s: %d", flash_name,
|
||||
err);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
chipc_spi_probe(device_t dev)
|
||||
{
|
||||
device_set_desc(dev, "ChipCommon SPI");
|
||||
return (BUS_PROBE_DEFAULT);
|
||||
device_set_desc(dev, "Broadcom ChipCommon SPI");
|
||||
return (BUS_PROBE_NOWILDCARD);
|
||||
}
|
||||
|
||||
struct resource_spec spec_mem[] = {
|
||||
{SYS_RES_MEMORY, 0, RF_ACTIVE},
|
||||
{SYS_RES_MEMORY, 1, RF_ACTIVE},
|
||||
{ -1, -1, 0 }
|
||||
};
|
||||
|
||||
static int
|
||||
chipc_spi_attach(device_t dev)
|
||||
{
|
||||
int err;
|
||||
struct chipc_spi_softc *sc;
|
||||
struct resource *mem[2];
|
||||
struct chipc_caps *ccaps;
|
||||
device_t flash_dev;
|
||||
device_t spibus;
|
||||
const char *flash_name;
|
||||
int error;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
err = bus_alloc_resources(dev, spec_mem, mem);
|
||||
if (err != 0)
|
||||
|
||||
/* Allocate SPI controller registers */
|
||||
sc->sc_rid = 1;
|
||||
sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rid,
|
||||
RF_ACTIVE);
|
||||
if (sc->sc_res == NULL) {
|
||||
device_printf(dev, "failed to allocate device registers\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
sc->sc_res = mem[0];
|
||||
sc->sc_mem_res = mem[1];
|
||||
/* Allocate flash shadow region */
|
||||
sc->sc_flash_rid = 0;
|
||||
sc->sc_flash_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
|
||||
&sc->sc_flash_rid, RF_ACTIVE);
|
||||
if (sc->sc_flash_res == NULL) {
|
||||
device_printf(dev, "failed to allocate flash region\n");
|
||||
error = ENXIO;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
flash_register_slicer(chipc_slicer_spi);
|
||||
device_add_child(dev, "spibus", 0);
|
||||
return (bus_generic_attach(dev));
|
||||
/*
|
||||
* Add flash device
|
||||
*
|
||||
* XXX: This should be replaced with a DEVICE_IDENTIFY implementation
|
||||
* in chipc-specific subclasses of the mx25l and at45d drivers.
|
||||
*/
|
||||
if ((spibus = device_add_child(dev, "spibus", -1)) == NULL) {
|
||||
device_printf(dev, "failed to add spibus\n");
|
||||
error = ENXIO;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
/* Let spibus perform full attach before we try to call
|
||||
* BUS_ADD_CHILD() */
|
||||
if ((error = bus_generic_attach(dev)))
|
||||
goto failed;
|
||||
|
||||
/* Determine flash type and add the flash child */
|
||||
ccaps = BHND_CHIPC_GET_CAPS(device_get_parent(dev));
|
||||
flash_name = chipc_sflash_device_name(ccaps->flash_type);
|
||||
if (flash_name != NULL) {
|
||||
flash_dev = BUS_ADD_CHILD(spibus, 0, flash_name, -1);
|
||||
if (flash_dev == NULL) {
|
||||
device_printf(dev, "failed to add %s\n", flash_name);
|
||||
error = ENXIO;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
chipc_register_slicer(ccaps->flash_type);
|
||||
|
||||
if ((error = device_probe_and_attach(flash_dev))) {
|
||||
device_printf(dev, "failed to attach %s: %d\n",
|
||||
flash_name, error);
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
|
||||
failed:
|
||||
device_delete_children(dev);
|
||||
|
||||
if (sc->sc_res != NULL)
|
||||
bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rid,
|
||||
sc->sc_res);
|
||||
|
||||
if (sc->sc_flash_res != NULL)
|
||||
bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_flash_rid,
|
||||
sc->sc_flash_res);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
chipc_spi_detach(device_t dev)
|
||||
{
|
||||
struct chipc_spi_softc *sc;
|
||||
int error;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
if ((error = bus_generic_detach(dev)))
|
||||
return (error);
|
||||
|
||||
bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rid, sc->sc_res);
|
||||
bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_flash_rid,
|
||||
sc->sc_flash_res);
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -184,7 +184,7 @@ chipc_spi_wait(struct chipc_spi_softc *sc)
|
||||
if (i > 0)
|
||||
return (0);
|
||||
|
||||
BHND_DEBUG_DEV(sc->dev, "busy");
|
||||
BHND_DEBUG_DEV(sc->sc_dev, "busy");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
@ -256,13 +256,11 @@ chipc_spi_transfer(device_t dev, device_t child, struct spi_command *cmd)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* **************************** METADATA ************************
|
||||
*/
|
||||
static device_method_t chipc_spi_methods[] = {
|
||||
DEVMETHOD(device_identify, chipc_spi_identify),
|
||||
DEVMETHOD(device_probe, chipc_spi_probe),
|
||||
DEVMETHOD(device_attach, chipc_spi_attach),
|
||||
DEVMETHOD(device_detach, chipc_spi_detach),
|
||||
|
||||
/* SPI */
|
||||
DEVMETHOD(spibus_transfer, chipc_spi_transfer),
|
||||
DEVMETHOD_END
|
||||
@ -277,4 +275,4 @@ static driver_t chipc_spi_driver = {
|
||||
static devclass_t chipc_spi_devclass;
|
||||
|
||||
DRIVER_MODULE(chipc_spi, bhnd_chipc, chipc_spi_driver, chipc_spi_devclass,
|
||||
0, 0);
|
||||
0, 0);
|
||||
|
@ -62,28 +62,26 @@
|
||||
#define CHIPC_SPI_FLASHDATA 0x08
|
||||
|
||||
struct chipc_spi_softc {
|
||||
device_t dev;
|
||||
device_t sc_dev;
|
||||
struct resource *sc_res; /**< SPI registers */
|
||||
int sc_rid;
|
||||
|
||||
/* SPI registers */
|
||||
struct resource *sc_mem_res;
|
||||
|
||||
/* MMIO flash */
|
||||
struct resource *sc_res;
|
||||
struct resource *sc_flash_res; /**< flash shadow */
|
||||
int sc_flash_rid;
|
||||
};
|
||||
|
||||
/* register space access macros */
|
||||
#define SPI_BARRIER_WRITE(sc) bus_barrier((sc)->sc_mem_res, 0, 0, \
|
||||
#define SPI_BARRIER_WRITE(sc) bus_barrier((sc)->sc_res, 0, 0, \
|
||||
BUS_SPACE_BARRIER_WRITE)
|
||||
#define SPI_BARRIER_READ(sc) bus_barrier((sc)->sc_mem_res, 0, 0, \
|
||||
#define SPI_BARRIER_READ(sc) bus_barrier((sc)->sc_res, 0, 0, \
|
||||
BUS_SPACE_BARRIER_READ)
|
||||
#define SPI_BARRIER_RW(sc) bus_barrier((sc)->sc_mem_res, 0, 0, \
|
||||
BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE)
|
||||
#define SPI_BARRIER_RW(sc) bus_barrier((sc)->sc_res, 0, 0, \
|
||||
BUS_SPACE_BARRIER_READ | \
|
||||
BUS_SPACE_BARRIER_WRITE)
|
||||
|
||||
#define SPI_WRITE(sc, reg, val) do { \
|
||||
bus_write_4(sc->sc_mem_res, (reg), (val)); \
|
||||
} while (0)
|
||||
#define SPI_WRITE(sc, reg, val) bus_write_4(sc->sc_res, (reg), (val));
|
||||
|
||||
#define SPI_READ(sc, reg) bus_read_4(sc->sc_mem_res, (reg))
|
||||
#define SPI_READ(sc, reg) bus_read_4(sc->sc_res, (reg))
|
||||
|
||||
#define SPI_SET_BITS(sc, reg, bits) \
|
||||
SPI_WRITE(sc, reg, SPI_READ(sc, (reg)) | (bits))
|
||||
|
@ -37,6 +37,93 @@ __FBSDID("$FreeBSD$");
|
||||
#include "chipc_private.h"
|
||||
#include "chipcvar.h"
|
||||
|
||||
/**
|
||||
* Return a human-readable name for the given flash @p type.
|
||||
*/
|
||||
const char *
|
||||
chipc_flash_name(chipc_flash type)
|
||||
{
|
||||
switch (type) {
|
||||
case CHIPC_PFLASH_CFI:
|
||||
return ("CFI Flash");
|
||||
|
||||
case CHIPC_SFLASH_ST:
|
||||
case CHIPC_SFLASH_AT:
|
||||
return ("SPI Flash");
|
||||
|
||||
case CHIPC_QSFLASH_ST:
|
||||
case CHIPC_QSFLASH_AT:
|
||||
return ("QSPI Flash");
|
||||
|
||||
case CHIPC_NFLASH:
|
||||
case CHIPC_NFLASH_4706:
|
||||
return ("NAND");
|
||||
|
||||
case CHIPC_FLASH_NONE:
|
||||
default:
|
||||
return ("unknown");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the bus device class used by flash @p type,
|
||||
* or NULL if @p type is unsupported.
|
||||
*/
|
||||
const char *
|
||||
chipc_flash_bus_name(chipc_flash type)
|
||||
{
|
||||
switch (type) {
|
||||
case CHIPC_PFLASH_CFI:
|
||||
return ("cfi");
|
||||
|
||||
case CHIPC_SFLASH_ST:
|
||||
case CHIPC_SFLASH_AT:
|
||||
return ("spi");
|
||||
|
||||
case CHIPC_QSFLASH_ST:
|
||||
case CHIPC_QSFLASH_AT:
|
||||
/* unimplemented; spi? */
|
||||
return (NULL);
|
||||
|
||||
case CHIPC_NFLASH:
|
||||
case CHIPC_NFLASH_4706:
|
||||
/* unimplemented; nandbus? */
|
||||
return (NULL);
|
||||
|
||||
case CHIPC_FLASH_NONE:
|
||||
default:
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the flash device class for SPI flash @p type,
|
||||
* or NULL if @p type does not use SPI, or is unsupported.
|
||||
*/
|
||||
const char *
|
||||
chipc_sflash_device_name(chipc_flash type)
|
||||
{
|
||||
switch (type) {
|
||||
case CHIPC_SFLASH_ST:
|
||||
return ("mx25l");
|
||||
|
||||
case CHIPC_SFLASH_AT:
|
||||
return ("at45d");
|
||||
|
||||
case CHIPC_QSFLASH_ST:
|
||||
case CHIPC_QSFLASH_AT:
|
||||
/* unimplemented */
|
||||
return (NULL);
|
||||
|
||||
case CHIPC_PFLASH_CFI:
|
||||
case CHIPC_NFLASH:
|
||||
case CHIPC_NFLASH_4706:
|
||||
case CHIPC_FLASH_NONE:
|
||||
default:
|
||||
return (NULL);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize child resource @p r with a virtual address, tag, and handle
|
||||
* copied from @p parent, adjusted to contain only the range defined by
|
||||
@ -74,6 +161,72 @@ chipc_init_child_resource(struct resource *r,
|
||||
return (0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate a resource with a given resource ID, relative to the given
|
||||
* port and region.
|
||||
*
|
||||
* This function behaves identically to bus_set_resource() for all resource
|
||||
* types other than SYS_RES_MEMORY.
|
||||
*
|
||||
* For SYS_RES_MEMORY resources, the specified @p region's address and size
|
||||
* will be fetched from the bhnd(4) bus, and bus_set_resource() will be called
|
||||
* with @p start added the region's actual base address.
|
||||
*
|
||||
* To use the default region values for @p start and @p count, specify
|
||||
* a @p start value of 0ul, and an end value of RMAN_MAX_END
|
||||
*
|
||||
* @param sc chipc driver state.
|
||||
* @param child The device to set the resource on.
|
||||
* @param type The resource type.
|
||||
* @param rid The resource ID.
|
||||
* @param start The resource start address (if SYS_RES_MEMORY, this is
|
||||
* relative to @p region's base address).
|
||||
* @param count The length of the resource.
|
||||
* @param port The mapping port number (ignored if not SYS_RES_MEMORY).
|
||||
* @param region The mapping region number (ignored if not SYS_RES_MEMORY).
|
||||
*/
|
||||
int
|
||||
chipc_set_resource(struct chipc_softc *sc, device_t child, int type, int rid,
|
||||
rman_res_t start, rman_res_t count, u_int port, u_int region)
|
||||
{
|
||||
bhnd_addr_t region_addr;
|
||||
bhnd_size_t region_size;
|
||||
bool isdefault;
|
||||
int error;
|
||||
|
||||
if (type != SYS_RES_MEMORY)
|
||||
return (bus_set_resource(child, type, rid, start, count));
|
||||
|
||||
isdefault = RMAN_IS_DEFAULT_RANGE(start, count);
|
||||
|
||||
/* Fetch region address and size */
|
||||
error = bhnd_get_region_addr(sc->dev, BHND_PORT_DEVICE, port,
|
||||
region, ®ion_addr, ®ion_size);
|
||||
if (error) {
|
||||
device_printf(sc->dev,
|
||||
"lookup of %s%u.%u failed: %d\n",
|
||||
bhnd_port_type_name(BHND_PORT_DEVICE), port, region, error);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/* Populate defaults */
|
||||
if (isdefault) {
|
||||
start = 0;
|
||||
count = region_size;
|
||||
}
|
||||
|
||||
/* Verify requested range is mappable */
|
||||
if (start > region_size || region_size - start < count) {
|
||||
device_printf(sc->dev,
|
||||
"%s%u.%u region cannot map requested range %#jx+%#jx\n",
|
||||
bhnd_port_type_name(BHND_PORT_DEVICE), port, region, start,
|
||||
count);
|
||||
return (ERANGE);
|
||||
}
|
||||
|
||||
return (bus_set_resource(child, type, rid, region_addr + start, count));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Print a capability structure.
|
||||
|
@ -175,8 +175,8 @@
|
||||
|
||||
#define CHIPC_UART_BASE 0x300
|
||||
#define CHIPC_UART_SIZE 0x100
|
||||
#define CHIPC_UART0_BASE CHIPC_UART_BASE
|
||||
#define CHIPC_UART1_BASE (CHIPC_UART_BASE + CHIPC_UART_SIZE)
|
||||
#define CHIPC_UART_MAX 3 /**< max UART blocks */
|
||||
#define CHIPC_UART(_n) (CHIPC_UART_BASE + (CHIPC_UART_SIZE*_n))
|
||||
|
||||
/* PMU registers (rev >= 20) */
|
||||
#define CHIPC_PMU_BASE 0x600
|
||||
|
@ -59,6 +59,10 @@ typedef enum {
|
||||
CHIPC_NFLASH_4706 = 7 /**< BCM4706 NAND flash */
|
||||
} chipc_flash;
|
||||
|
||||
const char *chipc_flash_name(chipc_flash type);
|
||||
const char *chipc_flash_bus_name(chipc_flash type);
|
||||
const char *chipc_sflash_device_name(chipc_flash type);
|
||||
|
||||
/**
|
||||
* ChipCommon capability flags;
|
||||
*/
|
||||
@ -69,15 +73,16 @@ struct chipc_caps {
|
||||
uint8_t uart_gpio; /**< UARTs own GPIO pins 12-15 */
|
||||
|
||||
uint8_t extbus_type; /**< ExtBus type (CHIPC_CAP_EXTBUS_*) */
|
||||
chipc_flash flash_type; /**< Flash type */
|
||||
bhnd_nvram_src nvram_src; /**< identified NVRAM source */
|
||||
|
||||
chipc_flash flash_type; /**< flash type */
|
||||
uint8_t cfi_width; /**< CFI bus width, 0 if unknown or CFI
|
||||
not present */
|
||||
|
||||
bhnd_nvram_src nvram_src; /**< identified NVRAM source */
|
||||
bus_size_t sprom_offset; /**< Offset to SPROM data within
|
||||
SPROM/OTP, 0 if unknown or not
|
||||
present */
|
||||
uint8_t otp_size; /**< OTP (row?) size, 0 if not present */
|
||||
uint8_t cfi_width; /**< CFI bus width, 0 if unknown or CFI
|
||||
not present */
|
||||
|
||||
uint8_t pll_type; /**< PLL type */
|
||||
bool power_control; /**< Power control available */
|
||||
@ -200,7 +205,6 @@ struct chipc_softc {
|
||||
struct bhnd_resource *core; /**< core registers. */
|
||||
struct chipc_region *core_region; /**< region containing core registers */
|
||||
|
||||
struct bhnd_chipid ccid; /**< chip identification */
|
||||
uint32_t quirks; /**< chipc quirk flags */
|
||||
struct chipc_caps caps; /**< chipc capabilities */
|
||||
|
||||
|
@ -45,84 +45,29 @@ __FBSDID("$FreeBSD$");
|
||||
#include <dev/uart/uart_bus.h>
|
||||
#include <dev/uart/uart_cpu.h>
|
||||
|
||||
#include <dev/bhnd/cores/chipc/chipcvar.h>
|
||||
|
||||
#include "uart_if.h"
|
||||
#include "bhnd_chipc_if.h"
|
||||
|
||||
#include "bcm_socinfo.h"
|
||||
|
||||
static int uart_chipc_probe(device_t dev);
|
||||
|
||||
extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs;
|
||||
|
||||
static void
|
||||
uart_chipc_identify(driver_t *driver, device_t parent)
|
||||
{
|
||||
struct chipc_caps *caps;
|
||||
|
||||
if (device_find_child(parent, "uart", -1) != NULL)
|
||||
return;
|
||||
|
||||
caps = BHND_CHIPC_GET_CAPS(parent);
|
||||
|
||||
if (caps == NULL) {
|
||||
device_printf(parent, "error: can't retrieve ChipCommon "
|
||||
"capabilities\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (caps->num_uarts == 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
* TODO: add more than one UART
|
||||
*/
|
||||
BUS_ADD_CHILD(parent, 0, "uart", -1);
|
||||
}
|
||||
|
||||
static int
|
||||
uart_chipc_probe(device_t dev)
|
||||
{
|
||||
struct uart_softc *sc;
|
||||
struct resource *res;
|
||||
int rid;
|
||||
int err;
|
||||
|
||||
rid = 0;
|
||||
res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
|
||||
if (res == NULL) {
|
||||
device_printf(dev, "can't allocate main resource\n");
|
||||
return (ENXIO);
|
||||
}
|
||||
struct bcm_socinfo *socinfo;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
sc->sc_class = &uart_ns8250_class;
|
||||
sc->sc_sysdev = SLIST_FIRST(&uart_sysdevs);
|
||||
if (sc->sc_sysdev == NULL) {
|
||||
device_printf(dev, "missing sysdev\n");
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
bcopy(&sc->sc_sysdev->bas, &sc->sc_bas, sizeof(sc->sc_bas));
|
||||
|
||||
sc->sc_sysdev->bas.bst = rman_get_bustag(res);
|
||||
sc->sc_sysdev->bas.bsh = rman_get_bushandle(res);
|
||||
sc->sc_bas.bst = sc->sc_sysdev->bas.bst;
|
||||
sc->sc_bas.bsh = sc->sc_sysdev->bas.bsh;
|
||||
|
||||
err = bus_release_resource(dev, SYS_RES_MEMORY, rid, res);
|
||||
if (err) {
|
||||
device_printf(dev, "can't release resource [%d]\n", rid);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
/* We use internal SoC clock generator with non-standart freq MHz */
|
||||
return (uart_bus_probe(dev, 0, sc->sc_sysdev->bas.rclk, 0, 0));
|
||||
/* TODO: UART rate should be calculated from CPU clock speed
|
||||
* as fetched from bhnd bus */
|
||||
socinfo = bcm_get_socinfo();
|
||||
return (uart_bus_probe(dev, 0, socinfo->uartrate, 0, 0));
|
||||
}
|
||||
|
||||
static device_method_t uart_chipc_methods[] = {
|
||||
/* Device interface */
|
||||
DEVMETHOD(device_identify, uart_chipc_identify),
|
||||
DEVMETHOD(device_probe, uart_chipc_probe),
|
||||
DEVMETHOD(device_attach, uart_bus_attach),
|
||||
DEVMETHOD(device_detach, uart_bus_detach),
|
||||
|
Loading…
Reference in New Issue
Block a user