[bhnd] Integrate bhnd_chipc's BUS_ADD_CHILD() with a child resource mapping table.

This adds support for automatically configuring bhnd_chipc bus children
with associated resources, using an internal 'hints' table based directly
on Michael Zhilin's chipc resource mapping work.

The bhnd_sprom_chipc driver has been converted to use DEVICE_IDENTIFY()
with the new resource table.

This should be nearly drop-in compatible with the child device drivers
in D6250.

Submitted by:	Landon Fuller <landonf@landonf.org>
Reviewed by:	Michael Zhilin <mizhka@gmail.com>
Differential Revision:	https://reviews.freebsd.org/D6525
This commit is contained in:
Adrian Chadd 2016-05-26 00:43:08 +00:00
parent 40cb6df5f3
commit 785df0cb3f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=300702
3 changed files with 127 additions and 54 deletions

View File

@ -46,9 +46,23 @@ __FBSDID("$FreeBSD$");
#include <dev/bhnd/nvram/bhnd_nvram.h>
#include <dev/bhnd/nvram/bhnd_spromvar.h>
#include "bhnd_chipc_if.h"
#include "bhnd_nvram_if.h"
#include "chipc.h"
static void
chipc_sprom_identify(driver_t *driver, device_t parent)
{
if (bhnd_chipc_nvram_src(parent) != BHND_NVRAM_SRC_SPROM)
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)
{
@ -87,6 +101,7 @@ 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

View File

@ -98,6 +98,32 @@ static struct bhnd_device_quirk chipc_quirks[] = {
BHND_DEVICE_QUIRK_END
};
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
/* 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, 0, RM_MAX_END },
{ "uart", 1, SYS_RES_MEMORY, 0, CHIPC_UART1_BASE, CHIPC_UART_SIZE, 0,0 },
{ "uart", 1, SYS_RES_IRQ, 0, 0, RM_MAX_END },
{ "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,
@ -106,7 +132,6 @@ static int chipc_try_activate_resource(
static int chipc_read_caps(struct chipc_softc *sc,
struct chipc_caps *caps);
static int chipc_nvram_attach(struct chipc_softc *sc);
static bhnd_nvram_src_t chipc_nvram_identify(struct chipc_softc *sc);
static bool chipc_should_enable_sprom(
struct chipc_softc *sc);
@ -210,12 +235,11 @@ chipc_attach(device_t dev)
if (bootverbose)
chipc_print_caps(sc->dev, &sc->caps);
/* Identify NVRAM source and add child device. */
/* Identify NVRAM source */
sc->nvram_src = chipc_nvram_identify(sc);
if ((error = chipc_nvram_attach(sc)))
goto failed;
/* Standard bus probe */
/* Probe and attach children */
bus_generic_probe(dev);
if ((error = bus_generic_attach(dev)))
goto failed;
@ -334,51 +358,6 @@ chipc_read_caps(struct chipc_softc *sc, struct chipc_caps *caps)
return (0);
}
/**
* If supported, add an appropriate NVRAM child device.
*/
static int
chipc_nvram_attach(struct chipc_softc *sc)
{
device_t nvram_dev;
rman_res_t start;
int error;
switch (sc->nvram_src) {
case BHND_NVRAM_SRC_OTP:
// TODO OTP support
device_printf(sc->dev, "OTP nvram source unsupported\n");
return (0);
case BHND_NVRAM_SRC_SPROM:
/* Add OTP/SPROM device */
nvram_dev = BUS_ADD_CHILD(sc->dev, 0, "bhnd_nvram", -1);
if (nvram_dev == NULL) {
device_printf(sc->dev, "failed to add NVRAM device\n");
return (ENXIO);
}
start = rman_get_start(sc->core->res) + CHIPC_SPROM_OTP;
error = bus_set_resource(nvram_dev, SYS_RES_MEMORY, 0, start,
CHIPC_SPROM_OTP_SIZE);
return (error);
case BHND_NVRAM_SRC_FLASH:
// TODO flash support
device_printf(sc->dev, "flash nvram source unsupported\n");
return (0);
case BHND_NVRAM_SRC_UNKNOWN:
/* Handled externally */
return (0);
default:
device_printf(sc->dev, "invalid nvram source: %u\n",
sc->nvram_src);
return (ENXIO);
}
}
/**
* Determine the NVRAM data source for this device.
*
@ -500,7 +479,9 @@ static device_t
chipc_add_child(device_t dev, u_int order, const char *name, int unit)
{
struct chipc_devinfo *dinfo;
const struct chipc_hint *hint;
device_t child;
int error;
child = device_add_child_ordered(dev, order, name, unit);
if (child == NULL)
@ -513,10 +494,81 @@ 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;
if (strcmp(hint->name, name) != 0)
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, &region_addr,
&region_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 > 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 */
error = bus_set_resource(child, hint->type,
hint->rid, region_addr + 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

View File

@ -61,6 +61,8 @@
#define CHIPC_JTAGDR 0x38
#define CHIPC_JTAGCTRL 0x3c
#define CHIPC_SFLASH_BASE 0x40
#define CHIPC_SFLASH_SIZE 12
#define CHIPC_SFLASHCTRL 0x40
#define CHIPC_SFLASHADDR 0x44
#define CHIPC_SFLASHDATA 0x48
@ -171,11 +173,15 @@
#define CHIPC_CLK_CTL_ST 0x1E0
#define CHIPC_SPROM_HWWAR 0x19
#define CHIPC_UART0 0x300
#define CHIPC_UART1 0x400
#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)
/* PMU registers (rev >= 20) */
#define CHIPC_PMU_BASE 0x600
#define CHIPC_PMU_SIZE 0x70
#define CHIPC_PMU_CTRL 0x600
#define CHIPC_PMU_CAP 0x604
#define CHIPC_PMU_ST 0x608