Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F144620296
D6471.1775826454.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
95 KB
Referenced Files
None
Subscribers
None
D6471.1775826454.diff
View Options
Index: sys/conf/files
===================================================================
--- sys/conf/files
+++ sys/conf/files
@@ -1139,6 +1139,7 @@
dev/bhnd/bcma/bcma_subr.c optional bhndbus | bcma
dev/bhnd/cores/chipc/chipc.c optional bhndbus | bhnd
dev/bhnd/cores/chipc/bhnd_chipc_if.m optional bhndbus | bhnd
+dev/bhnd/cores/chipc/bhnd_sprom_chipc.c optional bhndbus | bhnd
dev/bhnd/cores/pci/bhnd_pci.c optional bhndbus pci | bhnd pci
dev/bhnd/cores/pci/bhnd_pci_hostb.c optional bhndbus pci | bhndb pci
dev/bhnd/cores/pci/bhnd_pcib.c optional bhnd_pcib bhnd pci
@@ -1147,6 +1148,7 @@
dev/bhnd/cores/pcie2/bhnd_pcie2b.c optional bhnd_pcie2b bhnd pci
dev/bhnd/nvram/bhnd_nvram_if.m optional bhndbus | bhnd
dev/bhnd/nvram/bhnd_sprom.c optional bhndbus | bhnd
+dev/bhnd/nvram/bhnd_sprom_subr.c optional bhndbus | bhnd
dev/bhnd/nvram/nvram_subr.c optional bhndbus | bhnd
dev/bhnd/siba/siba.c optional bhndbus | siba
dev/bhnd/siba/siba_bhndb.c optional bhndbus | siba bhndb
Index: sys/dev/bhnd/bhnd_subr.c
===================================================================
--- sys/dev/bhnd/bhnd_subr.c
+++ sys/dev/bhnd/bhnd_subr.c
@@ -797,11 +797,11 @@
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.chip_id = CHIPC_GET_BITS(idreg, CHIPC_ID_CHIP);
+ result.chip_pkg = CHIPC_GET_BITS(idreg, CHIPC_ID_PKG);
+ result.chip_rev = CHIPC_GET_BITS(idreg, CHIPC_ID_REV);
+ result.chip_type = CHIPC_GET_BITS(idreg, CHIPC_ID_BUS);
+ result.ncores = CHIPC_GET_BITS(idreg, CHIPC_ID_NUMCORE);
result.enum_addr = enum_addr;
@@ -1020,15 +1020,11 @@
if (device_get_devclass(dev) != bhnd_devclass)
return (NULL);
- /* Look for a ChipCommon device */
+ /* Look for a ChipCommon-attached NVRAM device */
if ((chipc = bhnd_find_child(dev, BHND_DEVCLASS_CC, -1)) != NULL) {
- bhnd_nvram_src_t src;
-
- /* Query the NVRAM source and determine whether it's
- * accessible via the ChipCommon device */
- src = BHND_CHIPC_NVRAM_SRC(chipc);
- if (BHND_NVRAM_SRC_CC(src))
- return (chipc);
+ nvram = device_find_child(chipc, "bhnd_nvram", 0);
+ if (nvram != NULL)
+ return (nvram);
}
/* Not found */
Index: sys/dev/bhnd/bhndb/bhndb_pci_sprom.c
===================================================================
--- sys/dev/bhnd/bhndb/bhndb_pci_sprom.c
+++ sys/dev/bhnd/bhndb/bhndb_pci_sprom.c
@@ -53,29 +53,15 @@
#include <dev/bhnd/nvram/bhnd_spromvar.h>
#include "bhnd_nvram_if.h"
+
#include "bhndb_pcireg.h"
#include "bhndb_pcivar.h"
-struct bhndb_pci_sprom_softc {
- device_t dev;
- struct bhnd_resource *sprom_res; /**< SPROM resource */
- int sprom_rid; /**< SPROM RID */
- struct bhnd_sprom shadow; /**< SPROM shadow */
- struct mtx mtx; /**< SPROM shadow mutex */
-};
-
-#define SPROM_LOCK_INIT(sc) \
- mtx_init(&(sc)->mtx, device_get_nameunit((sc)->dev), \
- "BHND PCI SPROM lock", MTX_DEF)
-#define SPROM_LOCK(sc) mtx_lock(&(sc)->mtx)
-#define SPROM_UNLOCK(sc) mtx_unlock(&(sc)->mtx)
-#define SPROM_LOCK_ASSERT(sc, what) mtx_assert(&(sc)->mtx, what)
-#define SPROM_LOCK_DESTROY(sc) mtx_destroy(&(sc)->mtx)
-
static int
bhndb_pci_sprom_probe(device_t dev)
{
device_t bridge, bus;
+ int error;
/* Our parent must be a PCI-BHND bridge with an attached bhnd bus */
bridge = device_get_parent(dev);
@@ -86,125 +72,23 @@
if (bus == NULL)
return (ENXIO);
- /* Found */
- device_set_desc(dev, "PCI-BHNDB SPROM/OTP");
- if (!bootverbose)
- device_quiet(dev);
+ /* Defer to default driver implementation */
+ if ((error = bhnd_sprom_probe(dev)) > 0)
+ return (error);
- /* Refuse wildcard attachments */
return (BUS_PROBE_NOWILDCARD);
}
-static int
-bhndb_pci_sprom_attach(device_t dev)
-{
- struct bhndb_pci_sprom_softc *sc;
- int error;
-
- sc = device_get_softc(dev);
- sc->dev = dev;
-
- /* Allocate SPROM resource */
- sc->sprom_rid = 0;
- sc->sprom_res = bhnd_alloc_resource_any(dev, SYS_RES_MEMORY,
- &sc->sprom_rid, RF_ACTIVE);
- if (sc->sprom_res == NULL) {
- device_printf(dev, "failed to allocate resources\n");
- return (ENXIO);
- }
-
- /* Initialize SPROM shadow */
- if ((error = bhnd_sprom_init(&sc->shadow, sc->sprom_res, 0))) {
- device_printf(dev, "unrecognized SPROM format\n");
- goto failed;
- }
-
- /* Initialize mutex */
- SPROM_LOCK_INIT(sc);
-
- return (0);
-
-failed:
- bhnd_release_resource(dev, SYS_RES_MEMORY, sc->sprom_rid,
- sc->sprom_res);
- return (error);
-}
-
-static int
-bhndb_pci_sprom_resume(device_t dev)
-{
- return (0);
-}
-
-static int
-bhndb_pci_sprom_suspend(device_t dev)
-{
- return (0);
-}
-
-static int
-bhndb_pci_sprom_detach(device_t dev)
-{
- struct bhndb_pci_sprom_softc *sc;
-
- sc = device_get_softc(dev);
-
- bhnd_release_resource(dev, SYS_RES_MEMORY, sc->sprom_rid,
- sc->sprom_res);
- bhnd_sprom_fini(&sc->shadow);
- SPROM_LOCK_DESTROY(sc);
-
- return (0);
-}
-
-static int
-bhndb_pci_sprom_getvar(device_t dev, const char *name, void *buf, size_t *len)
-{
- struct bhndb_pci_sprom_softc *sc;
- int error;
-
- sc = device_get_softc(dev);
-
- SPROM_LOCK(sc);
- error = bhnd_sprom_getvar(&sc->shadow, name, buf, len);
- SPROM_UNLOCK(sc);
-
- return (error);
-}
-
-static int
-bhndb_pci_sprom_setvar(device_t dev, const char *name, const void *buf,
- size_t len)
-{
- struct bhndb_pci_sprom_softc *sc;
- int error;
-
- sc = device_get_softc(dev);
-
- SPROM_LOCK(sc);
- error = bhnd_sprom_setvar(&sc->shadow, name, buf, len);
- SPROM_UNLOCK(sc);
-
- return (error);
-}
static device_method_t bhndb_pci_sprom_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, bhndb_pci_sprom_probe),
- DEVMETHOD(device_attach, bhndb_pci_sprom_attach),
- DEVMETHOD(device_resume, bhndb_pci_sprom_resume),
- DEVMETHOD(device_suspend, bhndb_pci_sprom_suspend),
- DEVMETHOD(device_detach, bhndb_pci_sprom_detach),
-
- /* NVRAM interface */
- DEVMETHOD(bhnd_nvram_getvar, bhndb_pci_sprom_getvar),
- DEVMETHOD(bhnd_nvram_setvar, bhndb_pci_sprom_setvar),
-
DEVMETHOD_END
};
-DEFINE_CLASS_0(bhnd_nvram, bhndb_pci_sprom_driver, bhndb_pci_sprom_methods, sizeof(struct bhndb_pci_sprom_softc));
+DEFINE_CLASS_1(bhnd_nvram, bhndb_pci_sprom_driver, bhndb_pci_sprom_methods, sizeof(struct bhnd_sprom_softc), bhnd_sprom_driver);
DRIVER_MODULE(bhndb_pci_sprom, bhndb, bhndb_pci_sprom_driver, bhnd_nvram_devclass, NULL, NULL);
MODULE_DEPEND(bhndb_pci_sprom, bhnd, 1, 1, 1);
+MODULE_DEPEND(bhndb_pci_sprom, bhnd_sprom, 1, 1, 1);
MODULE_VERSION(bhndb_pci_sprom, 1);
Index: sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m
===================================================================
--- sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m
+++ sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m
@@ -36,6 +36,11 @@
# bhnd(4) ChipCommon interface.
#
+HEADER {
+ /* forward declarations */
+ struct chipc_caps;
+}
+
/**
* Return the preferred NVRAM data source.
*
@@ -63,3 +68,35 @@
uint32_t value;
uint32_t mask;
}
+
+/**
+ * Return a borrowed reference to ChipCommon's capability
+ * table.
+ *
+ * @param dev A bhnd(4) ChipCommon device
+ */
+METHOD struct chipc_caps * get_caps {
+ device_t dev;
+}
+
+/**
+ * Enable hardware access to the SPROM.
+ *
+ * @param sc chipc driver state.
+ *
+ * @retval 0 success
+ * @retval EBUSY If enabling the hardware may conflict with
+ * other active devices.
+ */
+METHOD int enable_sprom {
+ device_t dev;
+}
+
+/**
+ * Release hardware access to the SPROM.
+ *
+ * @param sc chipc driver state.
+ */
+METHOD void disable_sprom {
+ device_t dev;
+}
Index: sys/dev/bhnd/cores/chipc/bhnd_sprom_chipc.c
===================================================================
--- /dev/null
+++ sys/dev/bhnd/cores/chipc/bhnd_sprom_chipc.c
@@ -0,0 +1,101 @@
+/*-
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * ChipCommon SPROM driver.
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/limits.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+
+#include <dev/bhnd/bhnd.h>
+#include <dev/bhnd/nvram/bhnd_nvram.h>
+#include <dev/bhnd/nvram/bhnd_spromvar.h>
+
+#include "bhnd_chipc_if.h"
+#include "bhnd_nvram_if.h"
+
+static int
+chipc_sprom_probe(device_t dev)
+{
+ device_t chipc;
+ int error;
+
+ chipc = device_get_parent(dev);
+
+ /* Only match on SPROM devices */
+ if (BHND_CHIPC_NVRAM_SRC(chipc) != BHND_NVRAM_SRC_SPROM)
+ return (ENXIO);
+
+ /* Defer to default driver implementation */
+ if ((error = bhnd_sprom_probe(dev)) > 0)
+ return (error);
+
+ return (BUS_PROBE_NOWILDCARD);
+}
+
+static int
+chipc_sprom_attach(device_t dev)
+{
+ device_t chipc;
+ int error;
+
+ /* Request that ChipCommon enable access to SPROM hardware before
+ * delegating attachment (and SPROM parsing) to the common driver */
+ chipc = device_get_parent(dev);
+ if ((error = BHND_CHIPC_ENABLE_SPROM(chipc)))
+ return (error);
+
+ error = bhnd_sprom_attach(dev);
+ BHND_CHIPC_DISABLE_SPROM(chipc);
+ return (error);
+}
+
+static device_method_t chipc_sprom_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, chipc_sprom_probe),
+ DEVMETHOD(device_attach, chipc_sprom_attach),
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_1(bhnd_nvram, chipc_sprom_driver, chipc_sprom_methods, sizeof(struct bhnd_sprom_softc), bhnd_sprom_driver);
+DRIVER_MODULE(bhnd_chipc_sprom, bhnd_chipc, chipc_sprom_driver, bhnd_nvram_devclass, NULL, NULL);
+
+MODULE_DEPEND(bhnd_chipc_sprom, bhnd, 1, 1, 1);
+MODULE_DEPEND(bhnd_chipc_sprom, bhnd_chipc, 1, 1, 1);
+MODULE_DEPEND(bhnd_chipc_sprom, bhnd_sprom, 1, 1, 1);
+MODULE_VERSION(bhnd_chipc_sprom, 1);
Index: sys/dev/bhnd/cores/chipc/chipc.h
===================================================================
--- sys/dev/bhnd/cores/chipc/chipc.h
+++ sys/dev/bhnd/cores/chipc/chipc.h
@@ -48,4 +48,4 @@
return (BHND_CHIPC_NVRAM_SRC(dev));
}
-#endif /* _BHND_CORES_CHIPC_CHIPC_H_ */
\ No newline at end of file
+#endif /* _BHND_CORES_CHIPC_CHIPC_H_ */
Index: sys/dev/bhnd/cores/chipc/chipc.c
===================================================================
--- sys/dev/bhnd/cores/chipc/chipc.c
+++ sys/dev/bhnd/cores/chipc/chipc.c
@@ -1,5 +1,6 @@
/*-
- * Copyright (c) 2015 Landon Fuller <landon@landonf.org>
+ * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
+ * Copyright (c) 2016 Michael Zhilin <mizhka@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -42,8 +43,11 @@
#include <sys/param.h>
#include <sys/kernel.h>
+#include <sys/lock.h>
#include <sys/bus.h>
+#include <sys/malloc.h>
#include <sys/module.h>
+#include <sys/mutex.h>
#include <sys/systm.h>
#include <machine/bus.h>
@@ -51,19 +55,13 @@
#include <machine/resource.h>
#include <dev/bhnd/bhnd.h>
-
-#include "bhnd_nvram_if.h"
+#include <dev/bhnd/bhndvar.h>
#include "chipcreg.h"
#include "chipcvar.h"
devclass_t bhnd_chipc_devclass; /**< bhnd(4) chipcommon device class */
-static const struct resource_spec chipc_rspec[CHIPC_MAX_RSPEC] = {
- { SYS_RES_MEMORY, 0, RF_ACTIVE },
- { -1, -1, 0 }
-};
-
static struct bhnd_device_quirk chipc_quirks[];
static struct bhnd_chip_quirk chipc_chip_quirks[];
@@ -77,7 +75,10 @@
/* Device quirks table */
static struct bhnd_device_quirk chipc_quirks[] = {
{ BHND_HWREV_GTE (32), CHIPC_QUIRK_SUPPORTS_SPROM },
- { BHND_HWREV_GTE (35), CHIPC_QUIRK_SUPPORTS_NFLASH },
+ { BHND_HWREV_GTE (35), CHIPC_QUIRK_SUPPORTS_CAP_EXT },
+ { BHND_HWREV_EQ (38), CHIPC_QUIRK_4706_NFLASH }, /*BCM5357 ?*/
+ { BHND_HWREV_GTE (49), CHIPC_QUIRK_IPX_OTPLAYOUT_SIZE },
+
BHND_DEVICE_QUIRK_END
};
@@ -111,15 +112,54 @@
{{ BHND_CHIP_IR(43602, HWREV_LTE(2)) },
CHIPC_QUIRK_4360_FEM_MUX_SPROM },
+ /* BCM4706 */
+ {{ BHND_CHIP_ID(4306) },
+ CHIPC_QUIRK_4706_NFLASH },
+
BHND_CHIP_QUIRK_END
};
+static int chipc_read_caps(struct chipc_softc *sc,
+ struct chipc_caps *caps);
+static void chipc_print_caps(device_t dev,
+ struct chipc_caps *caps);
+
+static struct chipc_region *chipc_alloc_region(struct chipc_softc *sc,
+ bhnd_port_type type, u_int port,
+ u_int region);
+static void chipc_free_region(struct chipc_softc *sc,
+ struct chipc_region *cr);
+static struct chipc_region *chipc_find_region(struct chipc_softc *sc,
+ rman_res_t start, rman_res_t end);
+static struct chipc_region *chipc_find_region_by_rid(struct chipc_softc *sc,
+ int rid);
+
+int chipc_retain_region(struct chipc_softc *sc,
+ struct chipc_region *cr, int flags);
+int chipc_release_region(struct chipc_softc *sc,
+ struct chipc_region *cr, int flags);
+
+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,
+ int type);
+
+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);
+
/* 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)
+ ((_sc)->caps._name)
#define CHIPC_ASSERT_QUIRK(_sc, name) \
KASSERT(CHIPC_QUIRK((_sc), name), ("quirk " __STRING(_name) " not set"))
@@ -127,12 +167,6 @@
#define CHIPC_ASSERT_CAP(_sc, name) \
KASSERT(CHIPC_CAP((_sc), name), ("capability " __STRING(_name) " not set"))
-static bhnd_nvram_src_t chipc_nvram_identify(struct chipc_softc *sc);
-static int chipc_sprom_init(struct chipc_softc *);
-static int chipc_enable_sprom_pins(struct chipc_softc *);
-static int chipc_disable_sprom_pins(struct chipc_softc *);
-
-
static int
chipc_probe(device_t dev)
{
@@ -146,6 +180,119 @@
return (BUS_PROBE_DEFAULT);
}
+static void
+chipc_print_caps(device_t dev, struct chipc_caps *caps)
+{
+#define CC_TFS(_flag) (caps->_flag ? "yes" : "no")
+
+ device_printf(dev, "MIPSEB: %-3s | BP64: %s\n",
+ CC_TFS(mipseb), CC_TFS(backplane_64));
+ device_printf(dev, "UARTs: %-3hhu | UGPIO: %s\n",
+ caps->num_uarts, CC_TFS(uart_gpio));
+ // XXX: hitting a kvprintf bug with '%#02x' not prefixing '0x' in
+ // some cases, and not apply the field width in others
+ device_printf(dev, "UARTClk: 0x%02x | Flash: %u\n",
+ caps->uart_clock, caps->flash_type);
+ device_printf(dev, "SPROM: %-3s | OTP: %s\n",
+ CC_TFS(sprom), CC_TFS(otp_size));
+ device_printf(dev, "CFIsz: 0x%02x | OTPsz: 0x%02x\n",
+ caps->cfi_width, caps->otp_size);
+ device_printf(dev, "ExtBus: 0x%02x | PwCtl: %s\n",
+ caps->extbus_type, CC_TFS(power_control));
+ device_printf(dev, "PLL: 0x%02x | JTAGM: %s\n",
+ caps->pll_type, CC_TFS(jtag_master));
+ device_printf(dev, "PMU: %-3s | ECI: %s\n",
+ CC_TFS(pmu), CC_TFS(eci));
+ device_printf(dev, "SECI: %-3s | GSIO: %s\n",
+ CC_TFS(seci), CC_TFS(gsio));
+ device_printf(dev, "AOB: %-3s | BootROM: %s\n",
+ CC_TFS(aob), CC_TFS(boot_rom));
+
+#undef CC_TFS
+}
+
+/* Read and parse chipc capabilities */
+int
+chipc_read_caps(struct chipc_softc *sc, struct chipc_caps *caps)
+{
+ uint32_t cap_reg;
+ uint32_t cap_ext_reg;
+ uint32_t regval;
+
+ /* Fetch cap registers */
+ cap_reg = bhnd_bus_read_4(sc->core, CHIPC_CAPABILITIES);
+ cap_ext_reg = 0;
+ if (CHIPC_QUIRK(sc, SUPPORTS_CAP_EXT))
+ cap_ext_reg = bhnd_bus_read_4(sc->core, CHIPC_CAPABILITIES_EXT);
+
+ /* Extract values */
+ caps->num_uarts = CHIPC_GET_BITS(cap_reg, CHIPC_CAP_NUM_UART);
+ caps->mipseb = CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_MIPSEB);
+ caps->uart_gpio = CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_UARTGPIO);
+ caps->uart_clock = CHIPC_GET_BITS(cap_reg, CHIPC_CAP_UCLKSEL);
+
+ caps->extbus_type = CHIPC_GET_BITS(cap_reg, CHIPC_CAP_EXTBUS);
+ caps->power_control = CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_PWR_CTL);
+ caps->jtag_master = CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_JTAGP);
+
+ caps->pll_type = CHIPC_GET_BITS(cap_reg, CHIPC_CAP_PLL);
+ caps->backplane_64 = CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_BKPLN64);
+ caps->boot_rom = CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_ROM);
+ caps->pmu = CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_PMU);
+ caps->eci = CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_ECI);
+ caps->sprom = CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_SPROM);
+ caps->otp_size = CHIPC_GET_BITS(cap_reg, CHIPC_CAP_OTP_SIZE);
+
+ caps->seci = CHIPC_GET_FLAG(cap_ext_reg, CHIPC_CAP2_SECI);
+ caps->gsio = CHIPC_GET_FLAG(cap_ext_reg, CHIPC_CAP2_GSIO);
+ caps->aob = CHIPC_GET_FLAG(cap_ext_reg, CHIPC_CAP2_AOB);
+
+ /* Fetch OTP size for later IPX controller revisions */
+ if (CHIPC_QUIRK(sc, IPX_OTPLAYOUT_SIZE)) {
+ regval = bhnd_bus_read_4(sc->core, CHIPC_OTPLAYOUT);
+ caps->otp_size = CHIPC_GET_BITS(regval, CHIPC_OTPL_SIZE);
+ }
+
+ /* Determine flash type and paramters */
+ caps->cfi_width = 0;
+
+ switch (CHIPC_GET_BITS(cap_reg, CHIPC_CAP_FLASH)) {
+ case CHIPC_CAP_SFLASH_ST:
+ caps->flash_type = CHIPC_SFLASH_ST;
+ break;
+ case CHIPC_CAP_SFLASH_AT:
+ caps->flash_type = CHIPC_SFLASH_AT;
+ break;
+ case CHIPC_CAP_NFLASH:
+ caps->flash_type = CHIPC_NFLASH;
+ break;
+ case CHIPC_CAP_PFLASH:
+ caps->flash_type = CHIPC_PFLASH_CFI;
+
+ /* determine cfi width */
+ regval = bhnd_bus_read_4(sc->core, CHIPC_FLASH_CFG);
+ if (CHIPC_GET_FLAG(regval, CHIPC_FLASH_CFG_DS))
+ caps->cfi_width = 2;
+ else
+ caps->cfi_width = 1;
+
+ break;
+ case CHIPC_CAP_FLASH_NONE:
+ caps->flash_type = CHIPC_FLASH_NONE;
+ break;
+
+ }
+
+ /* Handle 4706_NFLASH fallback */
+ if (CHIPC_QUIRK(sc, 4706_NFLASH) &&
+ CHIPC_GET_FLAG(cap_reg, CHIPC_CAP_4706_NFLASH))
+ {
+ caps->flash_type = CHIPC_NFLASH_4706;
+ }
+
+ return (0);
+}
+
static int
chipc_attach(device_t dev)
{
@@ -159,19 +306,36 @@
sc->dev = dev;
sc->quirks = bhnd_device_quirks(dev, chipc_devices,
sizeof(chipc_devices[0]));
-
+ sc->sprom_refcnt = 0;
+
CHIPC_LOCK_INIT(sc);
+ STAILQ_INIT(&sc->mem_regions);
- /* Allocate bus resources */
- memcpy(sc->rspec, chipc_rspec, sizeof(sc->rspec));
- if ((error = bhnd_alloc_resources(dev, sc->rspec, sc->res)))
- return (error);
+ /* Set up resource management */
+ if ((error = chipc_init_rman(sc))) {
+ device_printf(sc->dev,
+ "failed to initialize chipc resource state: %d\n", error);
+ goto failed;
+ }
+
+ /* Allocate the region containing our core registers */
+ if ((sc->core_region = chipc_find_region_by_rid(sc, 0)) == NULL) {
+ error = ENXIO;
+ goto failed;
+ }
+
+ error = chipc_retain_region(sc, sc->core_region,
+ RF_ALLOCATED|RF_ACTIVE);
+ if (error) {
+ sc->core_region = NULL;
+ goto failed;
+ } else {
+ sc->core = sc->core_region->cr_res;
+ }
- 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);
+ chip_type = CHIPC_GET_BITS(ccid_reg, CHIPC_ID_BUS);
switch (chip_type) {
case BHND_CHIPTYPE_SIBA:
@@ -185,44 +349,36 @@
default:
device_printf(dev, "unsupported chip type %hhu\n", chip_type);
error = ENODEV;
- goto cleanup;
+ goto failed;
}
sc->ccid = bhnd_parse_chipid(ccid_reg, enum_addr);
- /* Fetch capability and status register values */
- sc->caps = bhnd_bus_read_4(sc->core, CHIPC_CAPABILITIES);
- sc->cst = bhnd_bus_read_4(sc->core, CHIPC_CHIPST);
-
- /* Identify NVRAM source */
- sc->nvram_src = chipc_nvram_identify(sc);
-
- /* Read NVRAM data */
- switch (sc->nvram_src) {
- case BHND_NVRAM_SRC_OTP:
- // TODO (requires access to OTP hardware)
- device_printf(sc->dev, "NVRAM-OTP unsupported\n");
- break;
+ /* Fetch and parse capability register(s) */
+ if ((error = chipc_read_caps(sc, &sc->caps)))
+ goto failed;
- case BHND_NVRAM_SRC_NFLASH:
- // TODO (requires access to NFLASH hardware)
- device_printf(sc->dev, "NVRAM-NFLASH unsupported\n");
- break;
+ if (bootverbose)
+ chipc_print_caps(sc->dev, &sc->caps);
- case BHND_NVRAM_SRC_SPROM:
- if ((error = chipc_sprom_init(sc)))
- goto cleanup;
- break;
+ /* Identify NVRAM source and add child device. */
+ sc->nvram_src = chipc_nvram_identify(sc);
+ if ((error = chipc_nvram_attach(sc)))
+ goto failed;
- case BHND_NVRAM_SRC_UNKNOWN:
- /* Handled externally */
- break;
- }
+ /* Standard bus probe */
+ if ((error = bus_generic_attach(dev)))
+ goto failed;
return (0);
-cleanup:
- bhnd_release_resources(dev, sc->rspec, sc->res);
+failed:
+ if (sc->core_region != NULL) {
+ chipc_release_region(sc, sc->core_region,
+ RF_ALLOCATED|RF_ACTIVE);
+ }
+
+ chipc_free_rman(sc);
CHIPC_LOCK_DESTROY(sc);
return (error);
}
@@ -231,9 +387,15 @@
chipc_detach(device_t dev)
{
struct chipc_softc *sc;
+ int error;
sc = device_get_softc(dev);
- bhnd_release_resources(dev, sc->rspec, sc->res);
+
+ if ((error = bus_generic_detach(dev)))
+ return (error);
+
+ chipc_release_region(sc, sc->core_region, RF_ALLOCATED|RF_ACTIVE);
+ chipc_free_rman(sc);
bhnd_sprom_fini(&sc->sprom);
CHIPC_LOCK_DESTROY(sc);
@@ -244,57 +406,893 @@
static int
chipc_suspend(device_t dev)
{
- return (0);
+ return (bus_generic_suspend(dev));
}
static int
chipc_resume(device_t dev)
{
+ return (bus_generic_resume(dev));
+}
+
+static void
+chipc_probe_nomatch(device_t dev, device_t child)
+{
+ struct resource_list *rl;
+ const char *name;
+
+ name = device_get_name(child);
+ if (name == NULL)
+ name = "unknown device";
+
+ device_printf(dev, "<%s> at", name);
+
+ rl = BUS_GET_RESOURCE_LIST(dev, child);
+ if (rl != NULL) {
+ resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
+ resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
+ }
+
+ printf(" (no driver attached)\n");
+}
+
+static int
+chipc_print_child(device_t dev, device_t child)
+{
+ struct resource_list *rl;
+ int retval = 0;
+
+ retval += bus_print_child_header(dev, child);
+
+ rl = BUS_GET_RESOURCE_LIST(dev, child);
+ if (rl != NULL) {
+ retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY,
+ "%#jx");
+ retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ,
+ "%jd");
+ }
+
+ retval += bus_print_child_domain(dev, child);
+ retval += bus_print_child_footer(dev, child);
+
+ return (retval);
+}
+
+static int
+chipc_child_pnpinfo_str(device_t dev, device_t child, char *buf,
+ size_t buflen)
+{
+ if (buflen == 0)
+ return (EOVERFLOW);
+
+ *buf = '\0';
return (0);
}
+static int
+chipc_child_location_str(device_t dev, device_t child, char *buf,
+ size_t buflen)
+{
+ if (buflen == 0)
+ return (EOVERFLOW);
+
+ *buf = '\0';
+ return (ENXIO);
+}
+
+static device_t
+chipc_add_child(device_t dev, u_int order, const char *name, int unit)
+{
+ struct chipc_devinfo *dinfo;
+ device_t child;
+
+ child = device_add_child_ordered(dev, order, name, unit);
+ if (child == NULL)
+ return (NULL);
+
+ dinfo = malloc(sizeof(struct chipc_devinfo), M_BHND, M_NOWAIT);
+ if (dinfo == NULL) {
+ device_delete_child(dev, child);
+ return (NULL);
+ }
+
+ resource_list_init(&dinfo->resources);
+
+ device_set_ivars(child, dinfo);
+
+ return (child);
+}
+
+static void
+chipc_child_deleted(device_t dev, device_t child)
+{
+ struct chipc_devinfo *dinfo = device_get_ivars(child);
+
+ if (dinfo != NULL) {
+ resource_list_free(&dinfo->resources);
+ free(dinfo, M_BHND);
+ }
+
+ device_set_ivars(child, NULL);
+}
+
+static struct resource_list *
+chipc_get_resource_list(device_t dev, device_t child)
+{
+ struct chipc_devinfo *dinfo = device_get_ivars(child);
+ return (&dinfo->resources);
+}
+
+
+/* Allocate region records for the given port, and add the port's memory
+ * range to the mem_rman */
+static int
+chipc_rman_init_regions (struct chipc_softc *sc, bhnd_port_type type,
+ u_int port)
+{
+ struct chipc_region *cr;
+ rman_res_t start, end;
+ u_int num_regions;
+ int error;
+
+ num_regions = bhnd_get_region_count(sc->dev, port, port);
+ for (u_int region = 0; region < num_regions; region++) {
+ /* Allocate new region record */
+ cr = chipc_alloc_region(sc, type, port, region);
+ if (cr == NULL)
+ return (ENODEV);
+
+ /* Can't manage regions that cannot be allocated */
+ if (cr->cr_rid < 0) {
+ BHND_DEBUG_DEV(sc->dev, "no rid for chipc region "
+ "%s%u.%u", bhnd_port_type_name(type), port, region);
+ chipc_free_region(sc, cr);
+ continue;
+ }
+
+ /* Add to rman's managed range */
+ start = cr->cr_addr;
+ end = cr->cr_end;
+ if ((error = rman_manage_region(&sc->mem_rman, start, end))) {
+ chipc_free_region(sc, cr);
+ return (error);
+ }
+
+ /* Add to region list */
+ STAILQ_INSERT_TAIL(&sc->mem_regions, cr, cr_link);
+ }
+
+ return (0);
+}
+
+/* Initialize memory state for all chipc port regions */
+static int
+chipc_init_rman(struct chipc_softc *sc)
+{
+ u_int num_ports;
+ int error;
+
+ /* Port types for which we'll register chipc_region mappings */
+ bhnd_port_type types[] = {
+ BHND_PORT_DEVICE
+ };
+
+ /* Initialize resource manager */
+ sc->mem_rman.rm_start = 0;
+ sc->mem_rman.rm_end = BUS_SPACE_MAXADDR;
+ sc->mem_rman.rm_type = RMAN_ARRAY;
+ sc->mem_rman.rm_descr = "ChipCommon Device Memory";
+ if ((error = rman_init(&sc->mem_rman))) {
+ device_printf(sc->dev, "could not initialize mem_rman: %d\n",
+ error);
+ return (error);
+ }
+
+ /* Populate per-port-region state */
+ for (u_int i = 0; i < nitems(types); i++) {
+ num_ports = bhnd_get_port_count(sc->dev, types[i]);
+ for (u_int port = 0; port < num_ports; port++) {
+ error = chipc_rman_init_regions(sc, types[i], port);
+ if (error) {
+ device_printf(sc->dev,
+ "region init failed for %s%u: %d\n",
+ bhnd_port_type_name(types[i]), port,
+ error);
+
+ goto failed;
+ }
+ }
+ }
+
+ return (0);
+
+failed:
+ chipc_free_rman(sc);
+ return (error);
+}
+
+/* Free memory management state */
+static void
+chipc_free_rman(struct chipc_softc *sc)
+{
+ struct chipc_region *cr, *cr_next;
+
+ STAILQ_FOREACH_SAFE(cr, &sc->mem_regions, cr_link, cr_next)
+ chipc_free_region(sc, cr);
+
+ rman_fini(&sc->mem_rman);
+}
+
/**
- * Initialize local SPROM shadow, if required.
+ * Return the rman instance for a given resource @p type, if any.
*
- * @param sc chipc driver state.
+ * @param sc The chipc device state.
+ * @param type The resource type (e.g. SYS_RES_MEMORY, SYS_RES_IRQ, ...)
*/
-static int
-chipc_sprom_init(struct chipc_softc *sc)
+static struct rman *
+chipc_get_rman(struct chipc_softc *sc, int type)
+{
+ switch (type) {
+ case SYS_RES_MEMORY:
+ return (&sc->mem_rman);
+
+ case SYS_RES_IRQ:
+ /* IRQs can be used with RF_SHAREABLE, so we don't perform
+ * any local proxying of resource requests. */
+ return (NULL);
+
+ default:
+ return (NULL);
+ };
+}
+
+/**
+ * Allocate and initialize new region record.
+ *
+ * @param sc Driver instance state.
+ * @param type The port type to query.
+ * @param port The port number to query.
+ * @param region The region number to query.
+ */
+static struct chipc_region *
+chipc_alloc_region(struct chipc_softc *sc, bhnd_port_type type,
+ u_int port, u_int region)
{
- int error;
+ struct chipc_region *cr;
+ int error;
- KASSERT(sc->nvram_src == BHND_NVRAM_SRC_SPROM,
- ("non-SPROM source (%u)\n", sc->nvram_src));
+ /* Don't bother allocating a chipc_region if init will fail */
+ if (!bhnd_is_region_valid(sc->dev, type, port, region))
+ return (NULL);
- /* Enable access to the SPROM */
- CHIPC_LOCK(sc);
- if ((error = chipc_enable_sprom_pins(sc)))
- goto failed;
+ /* Allocate and initialize region info */
+ cr = malloc(sizeof(*cr), M_BHND, M_NOWAIT);
+ if (cr == NULL)
+ return (NULL);
- /* Initialize SPROM parser */
- error = bhnd_sprom_init(&sc->sprom, sc->core, CHIPC_SPROM_OTP);
- if (error) {
- device_printf(sc->dev, "SPROM identification failed: %d\n",
- error);
+ cr->cr_port_type = type;
+ cr->cr_port_num = port;
+ cr->cr_region_num = region;
+ cr->cr_res = NULL;
+ cr->cr_refs = 0;
+ cr->cr_act_refs = 0;
- chipc_disable_sprom_pins(sc);
+ error = bhnd_get_region_addr(sc->dev, type, port, region, &cr->cr_addr,
+ &cr->cr_count);
+ if (error) {
+ device_printf(sc->dev,
+ "fetching chipc region address failed: %d\n", error);
goto failed;
}
- /* Drop access to the SPROM lines */
- if ((error = chipc_disable_sprom_pins(sc))) {
- bhnd_sprom_fini(&sc->sprom);
- goto failed;
+ cr->cr_end = cr->cr_addr + cr->cr_count - 1;
+
+ /* Note that not all regions have an assigned rid, in which case
+ * this will return -1 */
+ cr->cr_rid = bhnd_get_port_rid(sc->dev, type, port, region);
+ return (cr);
+
+failed:
+ device_printf(sc->dev, "chipc region alloc failed for %s%u.%u\n",
+ bhnd_port_type_name(type), port, region);
+ free(cr, M_BHND);
+ return (NULL);
+}
+
+/**
+ * Deallocate the given region record and its associated resource, if any.
+ *
+ * @param sc Driver instance state.
+ * @param cr Region record to be deallocated.
+ */
+static void
+chipc_free_region(struct chipc_softc *sc, struct chipc_region *cr)
+{
+ KASSERT(cr->cr_refs == 0,
+ ("chipc %s%u.%u region has %u active references",
+ bhnd_port_type_name(cr->cr_port_type), cr->cr_port_num,
+ cr->cr_region_num, cr->cr_refs));
+
+ if (cr->cr_res != NULL) {
+ bhnd_release_resource(sc->dev, SYS_RES_MEMORY, cr->cr_rid,
+ cr->cr_res);
}
- CHIPC_UNLOCK(sc);
+ free(cr, M_BHND);
+}
+
+/**
+ * Locate the region mapping the given range, if any. Returns NULL if no
+ * valid region is found.
+ *
+ * @param sc Driver instance state.
+ * @param start start of address range.
+ * @param end end of address range.
+ */
+static struct chipc_region *
+chipc_find_region(struct chipc_softc *sc, rman_res_t start, rman_res_t end)
+{
+ struct chipc_region *cr;
+
+ if (start > end)
+ return (NULL);
+
+ STAILQ_FOREACH(cr, &sc->mem_regions, cr_link) {
+ if (start < cr->cr_addr || end > cr->cr_end)
+ continue;
+
+ /* Found */
+ return (cr);
+ }
+
+ /* Not found */
+ return (NULL);
+}
+
+/**
+ * Locate a region mapping by its bhnd-assigned resource id (as returned by
+ * bhnd_get_port_rid).
+ *
+ * @param sc Driver instance state.
+ * @param rid Resource ID to query for.
+ */
+static struct chipc_region *
+chipc_find_region_by_rid(struct chipc_softc *sc, int rid)
+{
+ struct chipc_region *cr;
+ int port_rid;
+
+ STAILQ_FOREACH(cr, &sc->mem_regions, cr_link) {
+ port_rid = bhnd_get_port_rid(sc->dev, cr->cr_port_type,
+ cr->cr_port_num, cr->cr_region_num);
+ if (port_rid == -1 || port_rid != rid)
+ continue;
+
+ /* Found */
+ return (cr);
+ }
+
+ /* Not found */
+ return (NULL);
+}
+
+/* Retain a reference to the region, allocating/activating if necessary */
+int
+chipc_retain_region(struct chipc_softc *sc, struct chipc_region *cr, int flags)
+{
+ int error;
+
+ KASSERT(!(flags &~ (RF_ACTIVE|RF_ALLOCATED)), ("unsupported flags"));
+
+ CHIPC_LOCK(sc);
+
+ /* Handle allocation */
+ if (flags & RF_ALLOCATED) {
+ /* If this is the first reference, allocate the resource */
+ if (cr->cr_refs == 0) {
+ KASSERT(cr->cr_res == NULL,
+ ("non-NULL resource has refcount"));
+
+ cr->cr_res = bhnd_alloc_resource(sc->dev,
+ SYS_RES_MEMORY, &cr->cr_rid, cr->cr_addr,
+ cr->cr_end, cr->cr_count, 0);
+
+ if (cr->cr_res == NULL) {
+ CHIPC_UNLOCK(sc);
+ return (ENXIO);
+ }
+ }
+
+ /* Increment allocation refcount */
+ cr->cr_refs++;
+ }
+
+
+ /* Handle activation */
+ if (flags & RF_ACTIVE) {
+ KASSERT(cr->cr_refs > 0,
+ ("cannot activate unallocated resource"));
+
+ /* If this is the first reference, activate the resource */
+ if (cr->cr_act_refs == 0) {
+ error = bhnd_activate_resource(sc->dev, SYS_RES_MEMORY,
+ cr->cr_rid, cr->cr_res);
+ if (error) {
+ /* Drop any allocation reference acquired
+ * above */
+ CHIPC_UNLOCK(sc);
+ chipc_release_region(sc, cr,
+ flags &~ RF_ACTIVE);
+ return (error);
+ }
+ }
+
+ /* Increment activation refcount */
+ cr->cr_act_refs++;
+ }
+
+ CHIPC_UNLOCK(sc);
return (0);
+}
-failed:
+int
+chipc_release_region(struct chipc_softc *sc, struct chipc_region *cr,
+ int flags)
+{
+ int error;
+
+ CHIPC_LOCK(sc);
+ error = 0;
+
+ if (flags & RF_ACTIVE) {
+ KASSERT(cr->cr_act_refs > 0, ("RF_ACTIVE over-released"));
+ KASSERT(cr->cr_act_refs <= cr->cr_refs,
+ ("RF_ALLOCATED released with RF_ACTIVE held"));
+
+ /* If this is the last reference, deactivate the resource */
+ if (cr->cr_act_refs == 1) {
+ error = bhnd_deactivate_resource(sc->dev,
+ SYS_RES_MEMORY, cr->cr_rid, cr->cr_res);
+ if (error)
+ goto done;
+ }
+
+ /* Drop our activation refcount */
+ cr->cr_act_refs--;
+ }
+
+ if (flags & RF_ALLOCATED) {
+ KASSERT(cr->cr_refs > 0, ("overrelease of refs"));
+
+ /* If this is the last reference, release the resource */
+ if (cr->cr_refs == 1) {
+ error = bhnd_release_resource(sc->dev,
+ SYS_RES_MEMORY, cr->cr_rid, cr->cr_res);
+ if (error)
+ goto done;
+
+ cr->cr_res = NULL;
+ cr->cr_rid = -1;
+ }
+
+ /* Drop our allocation refcount */
+ cr->cr_refs--;
+ }
+
+done:
CHIPC_UNLOCK(sc);
return (error);
}
+static struct resource *
+chipc_alloc_resource(device_t dev, device_t child, int type,
+ int *rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
+{
+ struct chipc_softc *sc;
+ struct chipc_region *cr;
+ struct resource_list_entry *rle;
+ struct resource *rv;
+ struct rman *rm;
+ int error;
+ bool passthrough, isdefault;
+
+ sc = device_get_softc(dev);
+ passthrough = (device_get_parent(child) != dev);
+ isdefault = RMAN_IS_DEFAULT_RANGE(start, end);
+ rle = NULL;
+
+ /* Fetch the resource manager, delegate request if necessary */
+ rm = chipc_get_rman(sc, type);
+ if (rm == NULL) {
+ /* Requested resource type is delegated to our parent */
+ rv = bus_generic_rl_alloc_resource(dev, child, type, rid,
+ start, end, count, flags);
+ return (rv);
+ }
+
+ /* Populate defaults */
+ if (!passthrough && isdefault) {
+ /* Fetch the resource list entry. */
+ rle = resource_list_find(BUS_GET_RESOURCE_LIST(dev, child),
+ type, *rid);
+ if (rle == NULL) {
+ device_printf(dev,
+ "default resource %#x type %d for child %s "
+ "not found\n", *rid, type,
+ device_get_nameunit(child));
+ return (NULL);
+ }
+
+ if (rle->res != NULL) {
+ device_printf(dev,
+ "resource entry %#x type %d for child %s is busy\n",
+ *rid, type, device_get_nameunit(child));
+
+ return (NULL);
+ }
+
+ start = rle->start;
+ end = rle->end;
+ count = ulmax(count, rle->count);
+ }
+
+ /* Locate a mapping region */
+ if ((cr = chipc_find_region(sc, start, end)) == NULL) {
+ /* Resource requests outside our shared port regions can be
+ * delegated to our parent. */
+ rv = bus_generic_rl_alloc_resource(dev, child, type, rid,
+ start, end, count, flags);
+ return (rv);
+ }
+
+ /* Try to retain a region reference */
+ if ((error = chipc_retain_region(sc, cr, RF_ALLOCATED))) {
+ CHIPC_UNLOCK(sc);
+ return (NULL);
+ }
+
+ /* Make our rman reservation */
+ rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE,
+ child);
+ if (rv == NULL) {
+ chipc_release_region(sc, cr, RF_ALLOCATED);
+ return (NULL);
+ }
+
+ rman_set_rid(rv, *rid);
+
+ /* Activate */
+ if (flags & RF_ACTIVE) {
+ error = bus_activate_resource(child, type, *rid, rv);
+ if (error) {
+ device_printf(dev,
+ "failed to activate entry %#x type %d for "
+ "child %s: %d\n",
+ *rid, type, device_get_nameunit(child), error);
+
+ chipc_release_region(sc, cr, RF_ALLOCATED);
+ rman_release_resource(rv);
+
+ return (NULL);
+ }
+ }
+
+ /* Update child's resource list entry */
+ if (rle != NULL) {
+ rle->res = rv;
+ rle->start = rman_get_start(rv);
+ rle->end = rman_get_end(rv);
+ rle->count = rman_get_size(rv);
+ }
+
+ return (rv);
+}
+
+static int
+chipc_release_resource(device_t dev, device_t child, int type, int rid,
+ struct resource *r)
+{
+ struct chipc_softc *sc;
+ struct chipc_region *cr;
+ struct rman *rm;
+ int error;
+
+ sc = device_get_softc(dev);
+
+ /* Handled by parent bus? */
+ rm = chipc_get_rman(sc, type);
+ if (rm == NULL || !rman_is_region_manager(r, rm)) {
+ return (bus_generic_rl_release_resource(dev, child, type, rid,
+ r));
+ }
+
+ /* Locate the mapping region */
+ cr = chipc_find_region(sc, rman_get_start(r), rman_get_end(r));
+ if (cr == NULL)
+ return (EINVAL);
+
+ /* Deactivate resources */
+ if (rman_get_flags(r) & RF_ACTIVE) {
+ error = BUS_DEACTIVATE_RESOURCE(dev, child, type, rid, r);
+ if (error)
+ return (error);
+ }
+
+ if ((error = rman_release_resource(r)))
+ return (error);
+
+ /* Drop allocation reference */
+ chipc_release_region(sc, cr, RF_ALLOCATED);
+
+ return (0);
+}
+
+static int
+chipc_adjust_resource(device_t dev, device_t child, int type,
+ struct resource *r, rman_res_t start, rman_res_t end)
+{
+ struct chipc_softc *sc;
+ struct chipc_region *cr;
+ struct rman *rm;
+
+ sc = device_get_softc(dev);
+
+ /* Handled by parent bus? */
+ rm = chipc_get_rman(sc, type);
+ if (rm == NULL || !rman_is_region_manager(r, rm)) {
+ return (bus_generic_adjust_resource(dev, child, type, r, start,
+ end));
+ }
+
+ /* The range is limited to the existing region mapping */
+ cr = chipc_find_region(sc, rman_get_start(r), rman_get_end(r));
+ if (cr == NULL)
+ return (EINVAL);
+
+ if (end <= start)
+ return (EINVAL);
+
+ if (start < cr->cr_addr || end > cr->cr_end)
+ return (EINVAL);
+
+ /* Range falls within the existing region */
+ return (rman_adjust_resource(r, start, end));
+}
+
+/**
+ * Initialize child resource @p r with a virtual address, tag, and handle
+ * copied from @p parent, adjusted to contain only the range defined by
+ * @p offsize and @p size.
+ *
+ * @param r The register to be initialized.
+ * @param parent The parent bus resource that fully contains the subregion.
+ * @param offset The subregion offset within @p parent.
+ * @param size The subregion size.
+ */
+static int
+chipc_init_child_resource(struct resource *r,
+ struct resource *parent, bhnd_size_t offset, bhnd_size_t size)
+{
+ bus_space_handle_t bh, child_bh;
+ bus_space_tag_t bt;
+ uintptr_t vaddr;
+ int error;
+
+ /* Fetch the parent resource's bus values */
+ vaddr = (uintptr_t) rman_get_virtual(parent);
+ bt = rman_get_bustag(parent);
+ bh = rman_get_bushandle(parent);
+
+ /* Configure child resource with offset-adjusted values */
+ vaddr += offset;
+ error = bus_space_subregion(bt, bh, offset, size, &child_bh);
+ if (error)
+ return (error);
+
+ rman_set_virtual(r, (void *) vaddr);
+ rman_set_bustag(r, bt);
+ rman_set_bushandle(r, child_bh);
+
+ return (0);
+}
+
+/**
+ * Retain an RF_ACTIVE reference to the region mapping @p r, and
+ * configure @p r with its subregion values.
+ *
+ * @param sc Driver instance state.
+ * @param child Requesting child device.
+ * @param type resource type of @p r.
+ * @param rid resource id of @p r
+ * @param r resource to be activated.
+ * @param req_direct If true, failure to allocate a direct bhnd resource
+ * will be treated as an error. If false, the resource will not be marked
+ * as RF_ACTIVE if bhnd direct resource allocation fails.
+ */
+static int
+chipc_try_activate_resource(struct chipc_softc *sc, device_t child, int type,
+ int rid, struct resource *r, bool req_direct)
+{
+ struct rman *rm;
+ struct chipc_region *cr;
+ bhnd_size_t cr_offset;
+ rman_res_t r_start, r_end, r_size;
+ int error;
+
+ rm = chipc_get_rman(sc, type);
+ if (rm == NULL || !rman_is_region_manager(r, rm))
+ return (EINVAL);
+
+ r_start = rman_get_start(r);
+ r_end = rman_get_end(r);
+ r_size = rman_get_size(r);
+
+ /* Find the corresponding chipc region */
+ cr = chipc_find_region(sc, r_start, r_end);
+ if (cr == NULL)
+ return (EINVAL);
+
+ /* Calculate subregion offset within the chipc region */
+ cr_offset = r_start - cr->cr_addr;
+
+ /* Retain (and activate, if necessary) the chipc region */
+ if ((error = chipc_retain_region(sc, cr, RF_ACTIVE)))
+ return (error);
+
+ /* Configure child resource with its subregion values. */
+ if (cr->cr_res->direct) {
+ error = chipc_init_child_resource(r, cr->cr_res->res,
+ cr_offset, r_size);
+ if (error)
+ goto cleanup;
+
+ /* Mark active */
+ if ((error = rman_activate_resource(r)))
+ goto cleanup;
+ } else if (req_direct) {
+ error = ENOMEM;
+ goto cleanup;
+ }
+
+ return (0);
+
+cleanup:
+ chipc_release_region(sc, cr, RF_ACTIVE);
+ return (error);
+}
+
+static int
+chipc_activate_bhnd_resource(device_t dev, device_t child, int type,
+ int rid, struct bhnd_resource *r)
+{
+ struct chipc_softc *sc;
+ struct rman *rm;
+ int error;
+
+ sc = device_get_softc(dev);
+
+ /* Delegate non-locally managed resources to parent */
+ rm = chipc_get_rman(sc, type);
+ if (rm == NULL || !rman_is_region_manager(r->res, rm)) {
+ return (bhnd_bus_generic_activate_resource(dev, child, type,
+ rid, r));
+ }
+
+ /* Try activating the chipc region resource */
+ error = chipc_try_activate_resource(sc, child, type, rid, r->res,
+ false);
+ if (error)
+ return (error);
+
+ /* Mark the child resource as direct according to the returned resource
+ * state */
+ if (rman_get_flags(r->res) & RF_ACTIVE)
+ r->direct = true;
+
+ return (0);
+}
+
+static int
+chipc_activate_resource(device_t dev, device_t child, int type, int rid,
+ struct resource *r)
+{
+ struct chipc_softc *sc;
+ struct rman *rm;
+
+ sc = device_get_softc(dev);
+
+ /* Delegate non-locally managed resources to parent */
+ rm = chipc_get_rman(sc, type);
+ if (rm == NULL || !rman_is_region_manager(r, rm)) {
+ return (bus_generic_activate_resource(dev, child, type, rid,
+ r));
+ }
+
+ /* Try activating the chipc region-based resource */
+ return (chipc_try_activate_resource(sc, child, type, rid, r, true));
+}
+
+/**
+ * Default bhndb(4) implementation of BUS_DEACTIVATE_RESOURCE().
+ */
+static int
+chipc_deactivate_resource(device_t dev, device_t child, int type,
+ int rid, struct resource *r)
+{
+ struct chipc_softc *sc;
+ struct chipc_region *cr;
+ struct rman *rm;
+ int error;
+
+ sc = device_get_softc(dev);
+
+ /* Handled by parent bus? */
+ rm = chipc_get_rman(sc, type);
+ if (rm == NULL || !rman_is_region_manager(r, rm)) {
+ return (bus_generic_deactivate_resource(dev, child, type, rid,
+ r));
+ }
+
+ /* Find the corresponding chipc region */
+ cr = chipc_find_region(sc, rman_get_start(r), rman_get_end(r));
+ if (cr == NULL)
+ return (EINVAL);
+
+ /* Mark inactive */
+ if ((error = rman_deactivate_resource(r)))
+ return (error);
+
+ /* Drop associated RF_ACTIVE reference */
+ chipc_release_region(sc, cr, RF_ACTIVE);
+
+ 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.
*
@@ -317,27 +1315,75 @@
* 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)) {
+ if (CHIPC_CAP(sc, 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))
+ if (CHIPC_CAP(sc, otp_size) != 0)
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);
+ /* Check for flash */
+ if (CHIPC_CAP(sc, flash_type) != CHIPC_FLASH_NONE)
+ return (BHND_NVRAM_SRC_FLASH);
/* No NVRAM hardware capability declared */
return (BHND_NVRAM_SRC_UNKNOWN);
}
+/**
+ * Examine bus state and make a best effort determination of whether it's
+ * likely safe to enable the muxed SPROM pins.
+ *
+ * On devices that do not use SPROM pin muxing, always returns true.
+ *
+ * @param sc chipc driver state.
+ */
+static bool
+chipc_should_enable_sprom(struct chipc_softc *sc)
+{
+ device_t *devs;
+ device_t hostb;
+ device_t parent;
+ int devcount;
+ int error;
+ bool result;
+
+ mtx_assert(&Giant, MA_OWNED); /* for newbus */
+
+ /* Nothing to do? */
+ if (!CHIPC_QUIRK(sc, MUX_SPROM))
+ return (true);
+
+ parent = device_get_parent(sc->dev);
+ hostb = bhnd_find_hostb_device(parent);
+
+ if ((error = device_get_children(parent, &devs, &devcount)))
+ return (false);
+
+ /* Reject any active devices other than ChipCommon, or the
+ * host bridge (if any). */
+ result = true;
+ for (int i = 0; i < devcount; i++) {
+ if (devs[i] == hostb || devs[i] == sc->dev)
+ continue;
+
+ if (!device_is_attached(devs[i]))
+ continue;
+
+ if (device_is_suspended(devs[i]))
+ continue;
+
+ /* Active device; assume SPROM is busy */
+ result = false;
+ break;
+ }
+
+ free(devs, M_TEMP);
+ return (result);
+}
/**
* If required by this device, enable access to the SPROM.
@@ -345,16 +1391,34 @@
* @param sc chipc driver state.
*/
static int
-chipc_enable_sprom_pins(struct chipc_softc *sc)
+chipc_enable_sprom_pins(device_t dev)
{
- uint32_t cctrl;
-
- CHIPC_LOCK_ASSERT(sc, MA_OWNED);
+ struct chipc_softc *sc;
+ uint32_t cctrl;
+ int error;
+
+ sc = device_get_softc(dev);
/* Nothing to do? */
if (!CHIPC_QUIRK(sc, MUX_SPROM))
return (0);
+ /* Make sure we're holding Giant for newbus */
+ mtx_lock(&Giant);
+ CHIPC_LOCK(sc);
+
+ /* Already enabled? */
+ if (sc->sprom_refcnt >= 1) {
+ error = 0;
+ goto finished;
+ }
+
+ /* Check whether bus is busy */
+ if (!chipc_should_enable_sprom(sc)) {
+ error = EBUSY;
+ goto finished;
+ }
+
cctrl = bhnd_bus_read_4(sc->core, CHIPC_CHIPCTRL);
/* 4331 devices */
@@ -368,7 +1432,8 @@
cctrl &= ~CHIPC_CCTRL4331_EXTPA_EN2;
bhnd_bus_write_4(sc->core, CHIPC_CHIPCTRL, cctrl);
- return (0);
+ error = 0;
+ goto finished;
}
/* 4360 devices */
@@ -378,7 +1443,17 @@
/* Refuse to proceed on unsupported devices with muxed SPROM pins */
device_printf(sc->dev, "muxed sprom lines on unrecognized device\n");
- return (ENXIO);
+ error = ENXIO;
+
+finished:
+ /* Bump the reference count */
+ if (error == 0)
+ sc->sprom_refcnt++;
+
+ CHIPC_UNLOCK(sc);
+ mtx_unlock(&Giant);
+
+ return (error);
}
/**
@@ -387,16 +1462,25 @@
*
* @param sc chipc driver state.
*/
-static int
-chipc_disable_sprom_pins(struct chipc_softc *sc)
+static void
+chipc_disable_sprom_pins(device_t dev)
{
- uint32_t cctrl;
+ struct chipc_softc *sc;
+ uint32_t cctrl;
- CHIPC_LOCK_ASSERT(sc, MA_OWNED);
+ sc = device_get_softc(dev);
/* Nothing to do? */
if (!CHIPC_QUIRK(sc, MUX_SPROM))
- return (0);
+ return;
+
+ CHIPC_LOCK(sc);
+
+ /* Check reference count, skip disable if in-use. */
+ KASSERT(sc->sprom_refcnt > 0, ("sprom refcnt overrelease"));
+ sc->sprom_refcnt--;
+ if (sc->sprom_refcnt > 0)
+ goto finished;
cctrl = bhnd_bus_read_4(sc->core, CHIPC_CHIPCTRL);
@@ -411,17 +1495,16 @@
cctrl |= CHIPC_CCTRL4331_EXTPA_EN2;
bhnd_bus_write_4(sc->core, CHIPC_CHIPCTRL, cctrl);
- return (0);
+ goto finished;
}
/* 4360 devices */
if (CHIPC_QUIRK(sc, 4360_FEM_MUX_SPROM)) {
/* Unimplemented */
}
-
- /* Refuse to proceed on unsupported devices with muxed SPROM pins */
- device_printf(sc->dev, "muxed sprom lines on unrecognized device\n");
- return (ENXIO);
+
+finished:
+ CHIPC_UNLOCK(sc);
}
static bhnd_nvram_src_t
@@ -431,64 +1514,6 @@
return (sc->nvram_src);
}
-static int
-chipc_nvram_getvar(device_t dev, const char *name, void *buf, size_t *len)
-{
- struct chipc_softc *sc;
- int error;
-
- sc = device_get_softc(dev);
-
- switch (sc->nvram_src) {
- case BHND_NVRAM_SRC_SPROM:
- CHIPC_LOCK(sc);
- error = bhnd_sprom_getvar(&sc->sprom, name, buf, len);
- CHIPC_UNLOCK(sc);
- return (error);
-
- case BHND_NVRAM_SRC_OTP:
- case BHND_NVRAM_SRC_NFLASH:
- /* Currently unsupported */
- return (ENXIO);
-
- case BHND_NVRAM_SRC_UNKNOWN:
- return (ENODEV);
- }
-
- /* Unknown NVRAM source */
- return (ENODEV);
-}
-
-static int
-chipc_nvram_setvar(device_t dev, const char *name, const void *buf,
- size_t len)
-{
- struct chipc_softc *sc;
- int error;
-
- sc = device_get_softc(dev);
-
- switch (sc->nvram_src) {
- case BHND_NVRAM_SRC_SPROM:
- CHIPC_LOCK(sc);
- error = bhnd_sprom_setvar(&sc->sprom, name, buf, len);
- CHIPC_UNLOCK(sc);
- return (error);
-
- case BHND_NVRAM_SRC_OTP:
- case BHND_NVRAM_SRC_NFLASH:
- /* Currently unsupported */
- return (ENXIO);
-
- case BHND_NVRAM_SRC_UNKNOWN:
- default:
- return (ENODEV);
- }
-
- /* Unknown NVRAM source */
- return (ENODEV);
-}
-
static void
chipc_write_chipctrl(device_t dev, uint32_t value, uint32_t mask)
{
@@ -513,14 +1538,40 @@
DEVMETHOD(device_detach, chipc_detach),
DEVMETHOD(device_suspend, chipc_suspend),
DEVMETHOD(device_resume, chipc_resume),
-
+
+ /* Bus interface */
+ DEVMETHOD(bus_probe_nomatch, chipc_probe_nomatch),
+ DEVMETHOD(bus_print_child, chipc_print_child),
+ DEVMETHOD(bus_child_pnpinfo_str, chipc_child_pnpinfo_str),
+ DEVMETHOD(bus_child_location_str, chipc_child_location_str),
+
+ DEVMETHOD(bus_add_child, chipc_add_child),
+ DEVMETHOD(bus_child_deleted, chipc_child_deleted),
+
+ 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, chipc_alloc_resource),
+ DEVMETHOD(bus_release_resource, chipc_release_resource),
+ DEVMETHOD(bus_adjust_resource, chipc_adjust_resource),
+ DEVMETHOD(bus_activate_resource, chipc_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, chipc_deactivate_resource),
+ DEVMETHOD(bus_get_resource_list, chipc_get_resource_list),
+
+ 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),
+
+ /* BHND bus inteface */
+ DEVMETHOD(bhnd_bus_activate_resource, chipc_activate_bhnd_resource),
+
/* ChipCommon interface */
DEVMETHOD(bhnd_chipc_nvram_src, chipc_nvram_src),
DEVMETHOD(bhnd_chipc_write_chipctrl, chipc_write_chipctrl),
-
- /* NVRAM interface */
- DEVMETHOD(bhnd_nvram_getvar, chipc_nvram_getvar),
- DEVMETHOD(bhnd_nvram_setvar, chipc_nvram_setvar),
+ DEVMETHOD(bhnd_chipc_enable_sprom, chipc_enable_sprom_pins),
+ DEVMETHOD(bhnd_chipc_disable_sprom, chipc_disable_sprom_pins),
DEVMETHOD_END
};
Index: sys/dev/bhnd/cores/chipc/chipcreg.h
===================================================================
--- sys/dev/bhnd/cores/chipc/chipcreg.h
+++ sys/dev/bhnd/cores/chipc/chipcreg.h
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2015 Landon Fuller <landon@landonf.org>
+ * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
* Copyright (c) 2010 Broadcom Corporation
* All rights reserved.
*
@@ -25,66 +25,189 @@
#ifndef _BHND_CORES_CHIPC_CHIPCREG_H_
#define _BHND_CORES_CHIPC_CHIPCREG_H_
-#define CHIPC_CHIPID_SIZE 0x100 /**< size of the register block
- containing the chip
- identification registers. */
+#define CHIPC_CHIPID_SIZE 0x100 /**< size of the register block
+ containing the chip
+ identification registers
+ required during bus
+ enumeration */
/** Evaluates to true if the given ChipCommon core revision provides
* the core count via the chip identification register. */
#define CHIPC_NCORES_MIN_HWREV(hwrev) ((hwrev) == 4 || (hwrev) >= 6)
-#define CHIPC_GET_ATTR(_entry, _attr) \
- ((_entry & CHIPC_ ## _attr ## _MASK) >> CHIPC_ ## _attr ## _SHIFT)
+#define CHIPC_GET_FLAG(_value, _flag) (((_value) & _flag) != 0)
+#define CHIPC_GET_BITS(_value, _field) \
+ ((_value & _field ## _MASK) >> _field ## _SHIFT)
-#define CHIPC_ID 0x0
+#define CHIPC_ID 0x00
#define CHIPC_CAPABILITIES 0x04
-#define CHIPC_OTPST 0x10
-#define CHIPC_CHIPCTRL 0x28 /**< chip control */
-#define CHIPC_CHIPST 0x2c /**< chip status */
+#define CHIPC_CORECTRL 0x08 /* rev >= 1 */
+#define CHIPC_BIST 0x0C
+
+#define CHIPC_OTPST 0x10 /**< otp status */
+#define CHIPC_OTPCTRL 0x14 /**< otp control */
+#define CHIPC_OTPPROG 0x18
+#define CHIPC_OTPLAYOUT 0x1C /**< otp layout (rev >= 23) */
+
+#define CHIPC_INTST 0x20 /**< interrupt status */
+#define CHIPC_INTM 0x24 /**< interrupt mask */
+
+#define CHIPC_CHIPCTRL 0x28 /**< chip control (rev >= 11) */
+#define CHIPC_CHIPST 0x2C /**< chip status (rev >= 11) */
+
#define CHIPC_JTAGCMD 0x30
#define CHIPC_JTAGIR 0x34
#define CHIPC_JTAGDR 0x38
#define CHIPC_JTAGCTRL 0x3c
-#define CHIPC_GPIOPU 0x58
-#define CHIPC_GPIOPD 0x5c
+
+#define CHIPC_SFLASHCTRL 0x40
+#define CHIPC_SFLASHADDR 0x44
+#define CHIPC_SFLASHDATA 0x48
+
+/* siba backplane configuration broadcast (siba-only) */
+#define CHIPC_SBBCAST_ADDR 0x50
+#define CHIPC_SBBCAST_DATA 0x54
+
+#define CHIPC_GPIOPU 0x58 /**< pull-up mask (rev >= 20) */
+#define CHIPC_GPIOPD 0x5C /**< pull down mask (rev >= 20) */
#define CHIPC_GPIOIN 0x60
#define CHIPC_GPIOOUT 0x64
#define CHIPC_GPIOOUTEN 0x68
-#define CHIPC_GPIOCTRL 0x6c
+#define CHIPC_GPIOCTRL 0x6C
#define CHIPC_GPIOPOL 0x70
-#define CHIPC_GPIOINTM 0x74
-#define CHIPC_WATCHDOG 0x80
+#define CHIPC_GPIOINTM 0x74 /**< gpio interrupt mask */
+
+#define CHIPC_GPIOEVENT 0x78 /**< gpio event (rev >= 11) */
+#define CHIPC_GPIOEVENT_INTM 0x7C /**< gpio event interrupt mask (rev >= 11) */
+
+#define CHIPC_WATCHDOG 0x80 /**< watchdog timer */
+
+#define CHIPC_GPIOEVENT_INTPOLARITY 0x84 /**< gpio even interrupt polarity (rev >= 11) */
+
+#define CHIPC_GPIOTIMERVAL 0x88 /**< gpio-based LED duty cycle (rev >= 16) */
+#define CHIPC_GPIOTIMEROUTMASK 0x8C
+
+/* clock control block */
#define CHIPC_CLKC_N 0x90
-#define CHIPC_CLKC_M0 0x94
-#define CHIPC_CLKC_M1 0x98
-#define CHIPC_CLKC_M2 0x9c
-#define CHIPC_CLKC_M3 0xa0
-#define CHIPC_CLKDIV 0xa4
-#define CHIPC_SYS_CLK_CTL 0xc0
-#define CHIPC_EROMPTR 0xfc /**< 32-bit EROM base address
+#define CHIPC_CLKC_SB 0x94 /* m0 (backplane) */
+#define CHIPC_CLKC_PCI 0x98 /* m1 */
+#define CHIPC_CLKC_M2 0x9C /* mii/uart/mipsref */
+#define CHIPC_CLKC_M3 0xA0 /* cpu */
+#define CHIPC_CLKDIV 0xA4 /* rev >= 3 */
+#define CHIPC_GPIODEBUGSEL 0xA8 /* rev >= 28 */
+#define CHIPC_CAPABILITIES_EXT 0xAC
+
+/* pll delay (registers rev >= 4) */
+#define CHIPC_PLL_ON_DELAY 0xB0
+#define CHIPC_PLL_FREFSEL_DELAY 0xB4
+#define CHIPC_PLL_SLOWCLK_CTL 0xB8 /* revs 6-9 */
+
+/* "instaclock" registers */
+#define CHIPC_SYS_CLK_CTL 0xC0 /* rev >= 10 */
+#define CHIPC_SYS_CLKSTATESTRETCH 0xC4 /* rev >= 10 */
+
+/* indirect backplane access (rev >= 10) */
+#define CHIPC_BP_ADDRLOW 0xD0
+#define CHIPC_BP_ADDRHIGH 0xD4
+#define CHIPC_BP_DATA 0xD8
+#define CHIPC_BP_INDACCESS 0xE0
+
+/* SPI/I2C (rev >= 37) */
+#define CHIPC_GSIO_CTRL 0xE4
+#define CHIPC_GSIO_ADDR 0xE8
+#define CHIPC_GSIO_DATA 0xEC
+
+/* More clock dividers (corerev >= 32) */
+#define CHIPC_CLKDIV2 0xF0
+
+#define CHIPC_EROMPTR 0xFC /**< 32-bit EROM base address
* on BCMA devices */
+
+/* ExtBus control registers (rev >= 3) */
+#define CHIPC_PCMCIA_CFG 0x100
+#define CHIPC_PCMCIA_MEMWAIT 0x104
+#define CHIPC_PCMCIA_ATTRWAIT 0x108
+#define CHIPC_PCMCIA_IOWAIT 0x10C
+#define CHIPC_IDE_CFG 0x110
+#define CHIPC_IDE_MEMWAIT 0x114
+#define CHIPC_IDE_ATTRWAIT 0x118
+#define CHIPC_IDE_IOWAIT 0x11C
+#define CHIPC_PROG_CFG 0x120
+#define CHIPC_PROG_WAITCOUNT 0x124
+#define CHIPC_FLASH_CFG 0x128
+#define CHIPC_FLASH_WAITCOUNT 0x12C
+#define CHIPC_SECI_CFG 0x130
+#define CHIPC_SECI_ST 0x134
+#define CHIPC_SECI_STM 0x138
+#define CHIPC_SECI_RXNBC 0x13C
+
+/* Enhanced Coexistence Interface (ECI) registers (rev 21-34) */
+#define CHIPC_ECI_OUTPUT 0x140
+#define CHIPC_ECI_CTRL 0x144
+#define CHIPC_ECI_INPUTLO 0x148
+#define CHIPC_ECI_INPUTMI 0x14C
+#define CHIPC_ECI_INPUTHI 0x150
+#define CHIPC_ECI_INPUTINTPOLARITYLO 0x154
+#define CHIPC_ECI_INPUTINTPOLARITYMI 0x158
+#define CHIPC_ECI_INPUTINTPOLARITYHI 0x15C
+#define CHIPC_ECI_INTMASKLO 0x160
+#define CHIPC_ECI_INTMASKMI 0x164
+#define CHIPC_ECI_INTMASKHI 0x168
+#define CHIPC_ECI_EVENTLO 0x16C
+#define CHIPC_ECI_EVENTMI 0x170
+#define CHIPC_ECI_EVENTHI 0x174
+#define CHIPC_ECI_EVENTMASKLO 0x178
+#define CHIPC_ECI_EVENTMASKMI 0x17C
+#define CHIPC_ECI_EVENTMASKHI 0x180
+
+#define CHIPC_FLASHSTRCFG 0x18C /**< BCM4706 NAND flash config */
+
#define CHIPC_SPROM_CTRL 0x190 /**< SPROM interface (rev >= 32) */
#define CHIPC_SPROM_ADDR 0x194
#define CHIPC_SPROM_DATA 0x198
-#define CHIPC_CLK_CTL_ST SI_CLK_CTL_ST
-#define CHIPC_PMU_CTL 0x600
+
+/* Clock control and hardware workarounds (corerev >= 20) */
+#define CHIPC_CLK_CTL_ST 0x1E0
+#define CHIPC_SPROM_HWWAR 0x19
+
+#define CHIPC_UART0 0x300
+#define CHIPC_UART1 0x400
+
+/* PMU registers (rev >= 20) */
+#define CHIPC_PMU_BASE 0x600
+#define CHIPC_PMU_CTRL 0x600
#define CHIPC_PMU_CAP 0x604
#define CHIPC_PMU_ST 0x608
#define CHIPC_PMU_RES_STATE 0x60c
+#define CHIPC_PMU_RES_PENDING 0x610
#define CHIPC_PMU_TIMER 0x614
#define CHIPC_PMU_MIN_RES_MASK 0x618
#define CHIPC_PMU_MAX_RES_MASK 0x61c
+#define CHIPC_PMU_RES_TABLE_SEL 0x620
+#define CHIPC_PMU_RES_DEP_MASK 0x624
+#define CHIPC_PMU_RES_UPDN_TIMER 0x628
+#define CHIPC_PMU_RES_TIMER 0x62C
+#define CHIPC_PMU_CLKSTRETCH 0x630
+#define CHIPC_PMU_WATCHDOG 0x634
+#define CHIPC_PMU_GPIOSEL 0x638 /* pmu rev >= 1 ? */
+#define CHIPC_PMU_GPIOEN 0x63C /* pmu rev >= 1 ? */
+#define CHIPC_PMU_RES_REQ_TIMER_SEL 0x640
+#define CHIPC_PMU_RES_REQ_TIMER 0x644
+#define CHIPC_PMU_RES_REQ_MASK 0x648
#define CHIPC_CHIPCTL_ADDR 0x650
#define CHIPC_CHIPCTL_DATA 0x654
#define CHIPC_PMU_REG_CONTROL_ADDR 0x658
#define CHIPC_PMU_REG_CONTROL_DATA 0x65C
#define CHIPC_PMU_PLL_CONTROL_ADDR 0x660
#define CHIPC_PMU_PLL_CONTROL_DATA 0x664
+#define CHIPC_PMU_STRAPOPT 0x668 /* chipc rev >= 28 */
+#define CHIPC_PMU_XTALFREQ 0x66C /* pmu rev >= 10 */
+
#define CHIPC_SPROM_OTP 0x800 /* SPROM/OTP address space */
+#define CHIPC_SPROM_OTP_SIZE 0x400
/** chipid */
-#define CHIPC_ID 0x0 /**< identification register */
#define CHIPC_ID_CHIP_MASK 0x0000FFFF /**< chip id */
#define CHIPC_ID_CHIP_SHIFT 0
#define CHIPC_ID_REV_MASK 0x000F0000 /**< chip revision */
@@ -97,30 +220,49 @@
#define CHIPC_ID_BUS_SHIFT 28
/* capabilities */
-#define CHIPC_CAP_UARTS_MASK 0x00000003 /* Number of UARTs */
+#define CHIPC_CAP_NUM_UART_MASK 0x00000003 /* Number of UARTs (1-3) */
+#define CHIPC_CAP_NUM_UART_SHIFT 0
#define CHIPC_CAP_MIPSEB 0x00000004 /* MIPS is in big-endian mode */
-#define CHIPC_CAP_UCLKSEL 0x00000018 /* UARTs clock select */
-#define CHIPC_CAP_UINTCLK 0x00000008 /* UARTs are driven by internal divided clock */
+#define CHIPC_CAP_UCLKSEL_MASK 0x00000018 /* UARTs clock select */
+#define CHIPC_CAP_UCLKSEL_SHIFT 3
+#define CHIPC_CAP_UCLKSEL_UINTCLK 0x1 /* UARTs are driven by internal divided clock */
#define CHIPC_CAP_UARTGPIO 0x00000020 /* UARTs own GPIOs 15:12 */
#define CHIPC_CAP_EXTBUS_MASK 0x000000c0 /* External bus mask */
-#define CHIPC_CAP_EXTBUS_NONE 0x00000000 /* No ExtBus present */
-#define CHIPC_CAP_EXTBUS_FULL 0x00000040 /* ExtBus: PCMCIA, IDE & Prog */
-#define CHIPC_CAP_EXTBUS_PROG 0x00000080 /* ExtBus: ProgIf only */
+#define CHIPC_CAP_EXTBUS_SHIFT 6
+#define CHIPC_CAP_EXTBUS_NONE 0x0 /* No ExtBus present */
+#define CHIPC_CAP_EXTBUS_FULL 0x1 /* ExtBus: PCMCIA, IDE & Prog */
+#define CHIPC_CAP_EXTBUS_PROG 0x2 /* ExtBus: ProgIf only */
#define CHIPC_CAP_FLASH_MASK 0x00000700 /* Type of flash */
+#define CHIPC_CAP_FLASH_SHIFT 8
+#define CHIPC_CAP_FLASH_NONE 0x000 /* No flash */
+#define CHIPC_CAP_SFLASH_ST 0x100 /* ST serial flash */
+#define CHIPC_CAP_SFLASH_AT 0x200 /* Atmel serial flash */
+#define CHIPC_CAP_NFLASH 0x300 /* NAND flash */
+#define CHIPC_CAP_PFLASH 0x700 /* Parallel flash */
#define CHIPC_CAP_PLL_MASK 0x00038000 /* Type of PLL */
+#define CHIPC_CAP_PLL_SHIFT 15
#define CHIPC_CAP_PWR_CTL 0x00040000 /* Power control */
-#define CHIPC_CAP_OTP_SIZE 0x00380000 /* OTP Size (0 = none) */
+#define CHIPC_CAP_OTP_SIZE_MASK 0x00380000 /* OTP Size (0 = none) */
#define CHIPC_CAP_OTP_SIZE_SHIFT 19 /* OTP Size shift */
#define CHIPC_CAP_OTP_SIZE_BASE 5 /* OTP Size base */
#define CHIPC_CAP_JTAGP 0x00400000 /* JTAG Master Present */
#define CHIPC_CAP_ROM 0x00800000 /* Internal boot rom active */
#define CHIPC_CAP_BKPLN64 0x08000000 /* 64-bit backplane */
#define CHIPC_CAP_PMU 0x10000000 /* PMU Present, rev >= 20 */
+#define CHIPC_CAP_ECI 0x20000000 /* Enhanced Coexistence Interface */
#define CHIPC_CAP_SPROM 0x40000000 /* SPROM Present, rev >= 32 */
-#define CHIPC_CAP_NFLASH 0x80000000 /* Nand flash present, rev >= 35 */
+#define CHIPC_CAP_4706_NFLASH 0x80000000 /* NAND flash present, BCM4706 or chipc rev38 (BCM5357)? */
#define CHIPC_CAP2_SECI 0x00000001 /* SECI Present, rev >= 36 */
#define CHIPC_CAP2_GSIO 0x00000002 /* GSIO (spi/i2c) present, rev >= 37 */
+#define CHIPC_CAP2_GCI 0x00000004 /* GCI present (rev >= ??) */
+#define CHIPC_CAP2_AOB 0x00000040 /* Always on Bus present (rev >= 49)
+ *
+ * If set, PMU and GCI registers
+ * are found in dedicated cores.
+ *
+ * This appears to be a lower power
+ * APB bus, bridged via ARM APB IP. */
/*
* ChipStatus (Common)
@@ -215,8 +357,10 @@
#define CHIPC_OTPP_START_BUSY 0x80000000
#define CHIPC_OTPP_READ 0x40000000 /* HND OTP */
-/* otplayout reg corerev >= 36 */
-#define CHIPC_OTP_CISFORMAT_NEW 0x80000000
+/* otplayout */
+#define CHIPC_OTPL_SIZE_MASK 0x0000f000 /* rev >= 49 */
+#define CHIPC_OTPL_SIZE_SHIFT 12
+#define CHIPC_OTPL_CISFORMAT_NEW 0x80000000 /* rev >= 36 */
/* Opcodes for OTPP_OC field */
#define CHIPC_OTPPOC_READ 0
@@ -488,12 +632,6 @@
#define CHIPC_CLKC_5350_N 0x0311
#define CHIPC_CLKC_5350_M 0x04020009
-/* Flash types in the chipcommon capabilities register */
-#define CHIPC_FLASH_NONE 0x000 /* No flash */
-#define CHIPC_SFLASH_ST 0x100 /* ST serial flash */
-#define CHIPC_SFLASH_AT 0x200 /* Atmel serial flash */
-#define CHIPC_PFLASH 0x700 /* Parallel flash */
-
/* Bits in the ExtBus config registers */
#define CHIPC_CFG_EN 0x0001 /* Enable */
#define CHIPC_CFG_EM_MASK 0x000e /* Extif Mode */
@@ -501,11 +639,11 @@
#define CHIPC_CFG_EM_SYNC 0x0002 /* Synchronous */
#define CHIPC_CFG_EM_PCMCIA 0x0004 /* PCMCIA */
#define CHIPC_CFG_EM_IDE 0x0006 /* IDE */
-#define CHIPC_CFG_DS 0x0010 /* Data size, 0=8bit, 1=16bit */
-#define CHIPC_CFG_CD_MASK 0x00e0 /* Sync: Clock divisor, rev >= 20 */
-#define CHIPC_CFG_CE 0x0100 /* Sync: Clock enable, rev >= 20 */
-#define CHIPC_CFG_SB 0x0200 /* Sync: Size/Bytestrobe, rev >= 20 */
-#define CHIPC_CFG_IS 0x0400 /* Extif Sync Clk Select, rev >= 20 */
+#define CHIPC_FLASH_CFG_DS 0x0010 /* Data size, 0=8bit, 1=16bit */
+#define CHIPC_FLASH_CFG_CD_MASK 0x00e0 /* Sync: Clock divisor, rev >= 20 */
+#define CHIPC_FLASH_CFG_CE 0x0100 /* Sync: Clock enable, rev >= 20 */
+#define CHIPC_FLASH_CFG_SB 0x0200 /* Sync: Size/Bytestrobe, rev >= 20 */
+#define CHIPC_FLASH_CFG_IS 0x0400 /* Extif Sync Clk Select, rev >= 20 */
/* ExtBus address space */
#define CHIPC_EB_BASE 0x1a000000 /* Chipc ExtBus base address */
Index: sys/dev/bhnd/cores/chipc/chipcvar.h
===================================================================
--- sys/dev/bhnd/cores/chipc/chipcvar.h
+++ sys/dev/bhnd/cores/chipc/chipcvar.h
@@ -39,8 +39,55 @@
DECLARE_CLASS(bhnd_chipc);
extern devclass_t bhnd_chipc_devclass;
-#define CHIPC_MAX_RES 1
-#define CHIPC_MAX_RSPEC (CHIPC_MAX_RES+1)
+
+/**
+ * Supported ChipCommon flash types.
+ */
+typedef enum {
+ CHIPC_FLASH_NONE = 0, /**< No flash, or a type unrecognized
+ by the ChipCommon driver */
+ CHIPC_PFLASH_CFI = 1, /**< CFI-compatible parallel flash */
+ CHIPC_SFLASH_ST = 2, /**< ST serial flash */
+ CHIPC_SFLASH_AT = 3, /**< Atmel serial flash */
+ CHIPC_QSFLASH_ST = 4, /**< ST quad-SPI flash */
+ CHIPC_QSFLASH_AT = 5, /**< Atmel quad-SPI flash */
+ CHIPC_NFLASH = 6, /**< NAND flash */
+ CHIPC_NFLASH_4706 = 7 /**< BCM4706 NAND flash */
+} chipc_flash;
+
+/**
+ * ChipCommon capability flags;
+ */
+struct chipc_caps {
+ uint8_t num_uarts; /**< Number of attached UARTS (1-3) */
+ bool mipseb; /**< MIPS is big-endian */
+ uint8_t uart_clock; /**< UART clock source (see CHIPC_CAP_UCLKSEL_*) */
+ 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 */
+ 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 */
+ bool jtag_master; /**< JTAG Master present */
+ bool boot_rom; /**< Internal boot ROM is active */
+ uint8_t backplane_64; /**< Backplane supports 64-bit addressing.
+ Note that this does not gaurantee
+ the CPU itself supports 64-bit
+ addressing. */
+ bool pmu; /**< PMU is present. */
+ bool eci; /**< ECI (enhanced coexistence inteface) is present. */
+ bool seci; /**< SECI (serial ECI) is present */
+ bool sprom; /**< SPROM is present */
+ bool gsio; /**< GSIO (SPI/I2C) present */
+ bool aob; /**< AOB (always on bus) present.
+ If set, PMU and GCI registers are
+ not accessible via ChipCommon,
+ and are instead accessible via
+ dedicated cores on the bhnd bus */
+};
/*
* ChipCommon device quirks / features
@@ -56,10 +103,10 @@
CHIPC_QUIRK_SUPPORTS_SPROM = (1<<1),
/**
- * External NAND NVRAM is supported, along with the CHIPC_CAP_NFLASH
- * capability flag.
+ * The BCM4706 NAND flash interface is supported, along with the
+ * CHIPC_CAP_4706_NFLASH capability flag.
*/
- CHIPC_QUIRK_SUPPORTS_NFLASH = (1<<2),
+ CHIPC_QUIRK_4706_NFLASH = (1<<2),
/**
* The SPROM is attached via muxed pins. The pins must be switched
@@ -104,25 +151,69 @@
* device. The muxed pins must be switched to allow reading/writing
* the SPROM.
*/
- CHIPC_QUIRK_4360_FEM_MUX_SPROM = (1<<5) | CHIPC_QUIRK_MUX_SPROM
+ CHIPC_QUIRK_4360_FEM_MUX_SPROM = (1<<5) |
+ CHIPC_QUIRK_MUX_SPROM,
+
+ /** Supports CHIPC_CAPABILITIES_EXT register */
+ CHIPC_QUIRK_SUPPORTS_CAP_EXT = (1<<6),
+
+ /** OTP size is defined via CHIPC_OTPLAYOUT register in later
+ * ChipCommon revisions using the 'IPX' OTP controller. */
+ CHIPC_QUIRK_IPX_OTPLAYOUT_SIZE = (1<<7),
};
+/**
+ * chipc child device info.
+ */
+struct chipc_devinfo {
+ struct resource_list resources; /**< child resources */
+};
+
+/**
+ * chipc SYS_RES_MEMORY region allocation record.
+ */
+struct chipc_region {
+ bhnd_port_type cr_port_type; /**< bhnd port type */
+ u_int cr_port_num; /**< bhnd port number */
+ u_int cr_region_num; /**< bhnd region number */
+
+ bhnd_addr_t cr_addr; /**< region base address */
+ bhnd_addr_t cr_end; /**< region end address */
+ bhnd_size_t cr_count; /**< region count */
+ int cr_rid; /**< rid, or -1 if no rid
+ * is allocated by the bus for
+ * this region */
+
+ struct bhnd_resource *cr_res; /**< bus resource, or NULL */
+ u_int cr_refs; /**< RF_ALLOCATED refcount */
+ u_int cr_act_refs; /**< RF_ACTIVE refcount */
+
+ STAILQ_ENTRY(chipc_region) cr_link;
+};
+
+/**
+ * chipc driver instance state.
+ */
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 chipc_region *core_region; /**< region containing 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 */
- bhnd_nvram_src_t nvram_src; /**< NVRAM source */
-
+ uint32_t quirks; /**< chipc quirk flags */
+ struct chipc_caps caps; /**< chipc capabilities */
+
+ bhnd_nvram_src_t nvram_src; /**< identified NVRAM source */
+
struct mtx mtx; /**< state mutex. */
struct bhnd_sprom sprom; /**< OTP/SPROM shadow, if any */
+ size_t sprom_refcnt; /**< SPROM hardware refcount */
+
+ struct rman mem_rman; /**< port memory manager */
+
+ STAILQ_HEAD(, chipc_region) mem_regions;/**< memory allocation records */
};
#define CHIPC_LOCK_INIT(sc) \
@@ -133,4 +224,4 @@
#define CHIPC_LOCK_ASSERT(sc, what) mtx_assert(&(sc)->mtx, what)
#define CHIPC_LOCK_DESTROY(sc) mtx_destroy(&(sc)->mtx)
-#endif /* _BHND_CORES_CHIPC_CHIPCVAR_H_ */
\ No newline at end of file
+#endif /* _BHND_CORES_CHIPC_CHIPCVAR_H_ */
Index: sys/dev/bhnd/nvram/bhnd_nvram.h
===================================================================
--- sys/dev/bhnd/nvram/bhnd_nvram.h
+++ sys/dev/bhnd/nvram/bhnd_nvram.h
@@ -40,11 +40,7 @@
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_FLASH, /**< External flash */
BHND_NVRAM_SRC_SPROM, /**< External serial EEPROM. */
BHND_NVRAM_SRC_UNKNOWN /**< No NVRAM source is directly
@@ -71,12 +67,4 @@
*/
} bhnd_nvram_src_t;
-/**
- * Evaluates to true if the given NVRAM data source is accessible via
- * ChipCommon.
- */
-#define BHND_NVRAM_SRC_CC(_src) \
- ((_src) == BHND_NVRAM_SRC_OTP || (_src) == BHND_NVRAM_SRC_SPROM)
-
-
-#endif /* _BHND_NVRAM_BHND_NVRAM_H_ */
\ No newline at end of file
+#endif /* _BHND_NVRAM_BHND_NVRAM_H_ */
Index: sys/dev/bhnd/nvram/bhnd_sprom.c
===================================================================
--- sys/dev/bhnd/nvram/bhnd_sprom.c
+++ sys/dev/bhnd/nvram/bhnd_sprom.c
@@ -1,5 +1,5 @@
/*-
- * Copyright (c) 2015 Landon Fuller <landon@landonf.org>
+ * Copyright (c) 2015-2016 Landon Fuller <landon@landonf.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -30,539 +30,180 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+/*
+ * BHND SPROM driver.
+ *
+ * Abstract driver for memory-mapped SPROM devices.
+ */
+
#include <sys/param.h>
+#include <sys/kernel.h>
#include <sys/bus.h>
-#include <sys/endian.h>
-#include <sys/rman.h>
+#include <sys/limits.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
#include <sys/systm.h>
#include <machine/bus.h>
+#include <sys/rman.h>
#include <machine/resource.h>
-#include <dev/bhnd/bhndvar.h>
+#include <dev/bhnd/bhnd.h>
-#include "nvramvar.h"
+#include "bhnd_nvram_if.h"
-#include "bhnd_spromreg.h"
#include "bhnd_spromvar.h"
-/*
- * BHND SPROM Parsing
- *
- * Provides identification and parsing of BHND SPROM data.
- */
-
-static int sprom_direct_read(struct bhnd_sprom *sc, size_t offset,
- void *buf, size_t nbytes, uint8_t *crc);
-static int sprom_extend_shadow(struct bhnd_sprom *sc, size_t image_size,
- uint8_t *crc);
-static int sprom_populate_shadow(struct bhnd_sprom *sc);
-
-static int sprom_var_defn(struct bhnd_sprom *sc, const char *name,
- const struct bhnd_nvram_var **var,
- const struct bhnd_sprom_var **sprom, size_t *size);
-
-/* SPROM revision is always located at the second-to-last byte */
-#define SPROM_REV(_sc) SPROM_READ_1((_sc), (_sc)->sp_size - 2)
-
-/* SPROM CRC is always located at the last byte */
-#define SPROM_CRC_OFF(_sc) SPROM_CRC_LEN(_sc)
-
-/* SPROM CRC covers all but the final CRC byte */
-#define SPROM_CRC_LEN(_sc) ((_sc)->sp_size - 1)
-
-/* SPROM shadow I/O (with byte-order translation) */
-#define SPROM_READ_1(_sc, _off) SPROM_READ_ENC_1(_sc, _off)
-#define SPROM_READ_2(_sc, _off) le16toh(SPROM_READ_ENC_2(_sc, _off))
-#define SPROM_READ_4(_sc, _off) le32toh(SPROM_READ_ENC_4(_sc, _off))
-
-#define SPROM_WRITE_1(_sc, _off, _v) SPROM_WRITE_ENC_1(_sc, _off, (_v))
-#define SPROM_WRITE_2(_sc, _off, _v) SPROM_WRITE_ENC_2(_sc, _off, \
- htole16(_v))
-#define SPROM_WRITE_4(_sc, _off, _v) SPROM_WRITE_ENC_4(_sc, _off, \
- htole32(_v))
-
-/* SPROM shadow I/O (without byte-order translation) */
-#define SPROM_READ_ENC_1(_sc, _off) (*(uint8_t *)((_sc)->sp_shadow + _off))
-#define SPROM_READ_ENC_2(_sc, _off) (*(uint16_t *)((_sc)->sp_shadow + _off))
-#define SPROM_READ_ENC_4(_sc, _off) (*(uint32_t *)((_sc)->sp_shadow + _off))
-
-#define SPROM_WRITE_ENC_1(_sc, _off, _v) \
- *((uint8_t *)((_sc)->sp_shadow + _off)) = (_v)
-#define SPROM_WRITE_ENC_2(_sc, _off, _v) \
- *((uint16_t *)((_sc)->sp_shadow + _off)) = (_v)
-#define SPROM_WRITE_ENC_4(_sc, _off, _v) \
- *((uint32_t *)((_sc)->sp_shadow + _off)) = (_v)
-
-/* Call @p _next macro with the C type, widened (signed or unsigned) C
- * type, and width associated with @p _dtype */
-#define SPROM_SWITCH_TYPE(_dtype, _next, ...) \
-do { \
- switch (_dtype) { \
- case BHND_NVRAM_DT_UINT8: \
- _next (uint8_t, uint32_t, 1, \
- ## __VA_ARGS__); \
- break; \
- case BHND_NVRAM_DT_UINT16: \
- _next (uint16_t, uint32_t, 2, \
- ## __VA_ARGS__); \
- break; \
- case BHND_NVRAM_DT_UINT32: \
- _next (uint32_t, uint32_t, 4, \
- ## __VA_ARGS__); \
- break; \
- case BHND_NVRAM_DT_INT8: \
- _next (int8_t, int32_t, 1, \
- ## __VA_ARGS__); \
- break; \
- case BHND_NVRAM_DT_INT16: \
- _next (int16_t, int32_t, 2, \
- ## __VA_ARGS__); \
- break; \
- case BHND_NVRAM_DT_INT32: \
- _next (int32_t, int32_t, 4, \
- ## __VA_ARGS__); \
- break; \
- case BHND_NVRAM_DT_CHAR: \
- _next (uint8_t, uint32_t, 1, \
- ## __VA_ARGS__); \
- break; \
- } \
-} while (0)
-
-/*
- * Table of supported SPROM image formats, sorted by image size, ascending.
- */
-#define SPROM_FMT(_sz, _revmin, _revmax, _sig) \
- { SPROM_SZ_ ## _sz, _revmin, _revmax, \
- SPROM_SIG_ ## _sig ## _OFF, \
- SPROM_SIG_ ## _sig }
-
-static const struct sprom_fmt {
- size_t size;
- uint8_t rev_min;
- uint8_t rev_max;
- size_t sig_offset;
- uint16_t sig_req;
-} sprom_fmts[] = {
- SPROM_FMT(R1_3, 1, 3, NONE),
- SPROM_FMT(R4_8_9, 4, 4, R4),
- SPROM_FMT(R4_8_9, 8, 9, R8_9),
- SPROM_FMT(R10, 10, 10, R10),
- SPROM_FMT(R11, 11, 11, R11)
-};
+#define SPROM_LOCK_INIT(sc) \
+ mtx_init(&(sc)->mtx, device_get_nameunit((sc)->dev), \
+ "BHND SPROM lock", MTX_DEF)
+#define SPROM_LOCK(sc) mtx_lock(&(sc)->mtx)
+#define SPROM_UNLOCK(sc) mtx_unlock(&(sc)->mtx)
+#define SPROM_LOCK_ASSERT(sc, what) mtx_assert(&(sc)->mtx, what)
+#define SPROM_LOCK_DESTROY(sc) mtx_destroy(&(sc)->mtx)
/**
- * Identify the SPROM format at @p offset within @p r, verify the CRC,
- * and allocate a local shadow copy of the SPROM data.
- *
- * After successful initialization, @p r will not be accessed; any pin
- * configuration required for SPROM access may be reset.
- *
- * @param[out] sprom On success, will be initialized with shadow of the SPROM
- * data.
- * @param r An active resource mapping the SPROM data.
- * @param offset Offset of the SPROM data within @p resource.
+ * Default bhnd sprom driver implementation of DEVICE_PROBE().
*/
int
-bhnd_sprom_init(struct bhnd_sprom *sprom, struct bhnd_resource *r,
- bus_size_t offset)
+bhnd_sprom_probe(device_t dev)
{
- bus_size_t res_size;
- int error;
-
- sprom->dev = rman_get_device(r->res);
- sprom->sp_res = r;
- sprom->sp_res_off = offset;
-
- /* Determine maximum possible SPROM image size */
- res_size = rman_get_size(r->res);
- if (offset >= res_size)
- return (EINVAL);
+ /* Quiet by default */
+ if (!bootverbose)
+ device_quiet(dev);
+ device_set_desc(dev, "Broadcom SPROM/OTP");
- sprom->sp_size_max = MIN(res_size - offset, SPROM_SZ_MAX);
-
- /* Allocate and populate SPROM shadow */
- sprom->sp_size = 0;
- sprom->sp_capacity = sprom->sp_size_max;
- sprom->sp_shadow = malloc(sprom->sp_capacity, M_BHND, M_NOWAIT);
- if (sprom->sp_shadow == NULL)
- return (ENOMEM);
-
- /* Read and identify SPROM image */
- if ((error = sprom_populate_shadow(sprom)))
- return (error);
-
- return (0);
+ /* Refuse wildcard attachments */
+ return (BUS_PROBE_NOWILDCARD);
}
/**
- * Release all resources held by @p sprom.
+ * Default bhnd sprom driver implementation of DEVICE_ATTACH().
*
- * @param sprom A SPROM instance previously initialized via bhnd_sprom_init().
- */
-void
-bhnd_sprom_fini(struct bhnd_sprom *sprom)
-{
- free(sprom->sp_shadow, M_BHND);
-}
-
-/* Perform a read using a SPROM offset descriptor, safely widening the
- * result to its 32-bit representation before assigning it to @p _dest. */
-#define SPROM_GETVAR_READ(_type, _widen, _width, _sc, _off, _dest) \
-do { \
- _type _v = (_type)SPROM_READ_ ## _width(_sc, _off->offset); \
- if (_off->shift > 0) { \
- _v >>= _off->shift; \
- } else if (off->shift < 0) { \
- _v <<= -_off->shift; \
- } \
- _dest = ((uint32_t) (_widen) _v) & _off->mask; \
-} while(0)
-
-/* Emit a value read using a SPROM offset descriptor, narrowing the
- * result output representation and, if necessary, OR'ing it with the
- * previously read value from @p _buf. */
-#define SPROM_GETVAR_WRITE(_type, _widen, _width, _off, _src, _buf) \
-do { \
- _type _v = (_type) (_widen) _src; \
- if (_off->cont) \
- _v |= *((_type *)_buf); \
- *((_type *)_buf) = _v; \
-} while(0)
-
-/**
- * Read a SPROM variable, performing conversion to host byte order.
- *
- * @param sc The SPROM parser state.
- * @param name The SPROM 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] len 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 len 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.
+ * Assumes sprom is mapped via YS_RES_MEMORY resource with RID 0.
*/
int
-bhnd_sprom_getvar(struct bhnd_sprom *sc, const char *name, void *buf,
- size_t *len)
+bhnd_sprom_attach(device_t dev)
{
- const struct bhnd_nvram_var *nv;
- const struct bhnd_sprom_var *sv;
- size_t all1_offs;
- size_t req_size;
+ struct bhnd_sprom_softc *sc;
int error;
-
- if ((error = sprom_var_defn(sc, name, &nv, &sv, &req_size)))
- return (error);
-
- /* Provide required size */
- if (buf == NULL) {
- *len = req_size;
- return (0);
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+
+ /* Allocate SPROM resource */
+ sc->sprom_rid = 0;
+ sc->sprom_res = bhnd_alloc_resource_any(dev, SYS_RES_MEMORY,
+ &sc->sprom_rid, RF_ACTIVE);
+ if (sc->sprom_res == NULL) {
+ device_printf(dev, "failed to allocate resources\n");
+ return (ENXIO);
}
- /* Check (and update) target buffer len */
- if (*len < req_size)
- return (ENOMEM);
- else
- *len = req_size;
-
- /* Read data */
- all1_offs = 0;
- for (size_t i = 0; i < sv->num_offsets; i++) {
- const struct bhnd_sprom_offset *off;
- uint32_t val;
-
- off = &sv->offsets[i];
- KASSERT(!off->cont || i > 0, ("cont marked on first offset"));
-
- /* If not a continuation, advance the output buffer */
- if (i > 0 && !off->cont) {
- buf = ((uint8_t *)buf) +
- bhnd_nvram_type_width(sv->offsets[i-1].type);
- }
-
- /* Read the value, widening to a common uint32
- * representation */
- SPROM_SWITCH_TYPE(off->type, SPROM_GETVAR_READ, sc, off, val);
-
- /* If IGNALL1, record whether value has all bits set. */
- if (nv->flags & BHND_NVRAM_VF_IGNALL1) {
- uint32_t all1;
-
- all1 = off->mask;
- if (off->shift > 0)
- all1 >>= off->shift;
- else if (off->shift < 0)
- all1 <<= -off->shift;
-
- if ((val & all1) == all1)
- all1_offs++;
- }
-
- /* Write the value, narrowing to the appropriate output
- * width. */
- SPROM_SWITCH_TYPE(nv->type, SPROM_GETVAR_WRITE, off, val, buf);
+ /* Initialize SPROM shadow */
+ if ((error = bhnd_sprom_init(&sc->shadow, sc->sprom_res, 0))) {
+ device_printf(dev, "unrecognized SPROM format\n");
+ goto failed;
}
- /* Should value should be treated as uninitialized? */
- if (nv->flags & BHND_NVRAM_VF_IGNALL1 && all1_offs == sv->num_offsets)
- return (ENOENT);
+ /* Initialize mutex */
+ SPROM_LOCK_INIT(sc);
return (0);
+
+failed:
+ bhnd_release_resource(dev, SYS_RES_MEMORY, sc->sprom_rid,
+ sc->sprom_res);
+ return (error);
}
-/* Perform a read of a variable offset from _src, safely widening the result
- * to its 32-bit representation before assigning it to @p
- * _dest. */
-#define SPROM_SETVAR_READ(_type, _widen, _width, _off, _src, _dest) \
-do { \
- _type _v = *(const _type *)_src; \
- if (_off->shift > 0) { \
- _v <<= _off->shift; \
- } else if (off->shift < 0) { \
- _v >>= -_off->shift; \
- } \
- _dest = ((uint32_t) (_widen) _v) & _off->mask; \
-} while(0)
-
-
-/* Emit a value read using a SPROM offset descriptor, narrowing the
- * result output representation and, if necessary, OR'ing it with the
- * previously read value from @p _buf. */
-#define SPROM_SETVAR_WRITE(_type, _widen, _width, _sc, _off, _src) \
-do { \
- _type _v = (_type) (_widen) _src; \
- if (_off->cont) \
- _v |= SPROM_READ_ ## _width(_sc, _off->offset); \
- SPROM_WRITE_ ## _width(_sc, _off->offset, _v); \
-} while(0)
-
/**
- * Set a local value for a SPROM variable, performing conversion to SPROM byte
- * order.
- *
- * The new value will be written to the backing SPROM shadow.
- *
- * @param sc The SPROM parser state.
- * @param name The SPROM variable name.
- * @param[out] buf The new value.
- * @param[in,out] len The size of @p buf.
- *
- * @retval 0 success
- * @retval ENOENT The requested variable was not found.
- * @retval EINVAL If @p len does not match the expected variable size.
+ * Default bhnd sprom driver implementation of DEVICE_DETACH().
*/
int
-bhnd_sprom_setvar(struct bhnd_sprom *sc, const char *name, const void *buf,
- size_t len)
+bhnd_sprom_resume(device_t dev)
{
- const struct bhnd_nvram_var *nv;
- const struct bhnd_sprom_var *sv;
- size_t req_size;
- int error;
- uint8_t crc;
-
- if ((error = sprom_var_defn(sc, name, &nv, &sv, &req_size)))
- return (error);
-
- /* Provide required size */
- if (len != req_size)
- return (EINVAL);
-
- /* Write data */
- for (size_t i = 0; i < sv->num_offsets; i++) {
- const struct bhnd_sprom_offset *off;
- uint32_t val;
-
- off = &sv->offsets[i];
- KASSERT(!off->cont || i > 0, ("cont marked on first offset"));
-
- /* If not a continuation, advance the input pointer */
- if (i > 0 && !off->cont) {
- buf = ((const uint8_t *)buf) +
- bhnd_nvram_type_width(sv->offsets[i-1].type);
- }
-
- /* Read the value, widening to a common uint32
- * representation */
- SPROM_SWITCH_TYPE(nv->type, SPROM_SETVAR_READ, off, buf, val);
-
- /* Write the value, narrowing to the appropriate output
- * width. */
- SPROM_SWITCH_TYPE(off->type, SPROM_SETVAR_WRITE, sc, off, val);
- }
-
- /* Update CRC */
- crc = ~bhnd_nvram_crc8(sc->sp_shadow, SPROM_CRC_LEN(sc),
- BHND_NVRAM_CRC8_INITIAL);
- SPROM_WRITE_1(sc, SPROM_CRC_OFF(sc), crc);
-
return (0);
}
-/* Read and identify the SPROM image by incrementally performing
- * read + CRC of all supported image formats */
-static int
-sprom_populate_shadow(struct bhnd_sprom *sc)
+/**
+ * Default bhnd sprom driver implementation of DEVICE_DETACH().
+ */
+int
+bhnd_sprom_suspend(device_t dev)
{
- const struct sprom_fmt *fmt;
- int error;
- uint16_t sig;
- uint8_t srom_rev;
- uint8_t crc;
-
- crc = BHND_NVRAM_CRC8_INITIAL;
-
- /* Identify the SPROM revision (and populate the SPROM shadow) */
- for (size_t i = 0; i < nitems(sprom_fmts); i++) {
- fmt = &sprom_fmts[i];
-
- /* Read image data and check CRC */
- if ((error = sprom_extend_shadow(sc, fmt->size, &crc)))
- return (error);
-
- /* Skip on invalid CRC */
- if (crc != BHND_NVRAM_CRC8_VALID)
- continue;
-
- /* Fetch SROM revision */
- srom_rev = SPROM_REV(sc);
-
- /* Early sromrev 1 devices (specifically some BCM440x enet
- * cards) are reported to have been incorrectly programmed
- * with a revision of 0x10. */
- if (fmt->size == SPROM_SZ_R1_3 && srom_rev == 0x10)
- srom_rev = 0x1;
-
- /* Verify revision range */
- if (srom_rev < fmt->rev_min || srom_rev > fmt->rev_max)
- continue;
-
- /* Verify signature (if any) */
- sig = SPROM_SIG_NONE;
- if (fmt->sig_offset != SPROM_SIG_NONE_OFF)
- sig = SPROM_READ_2(sc, fmt->sig_offset);
-
- if (sig != fmt->sig_req) {
- device_printf(sc->dev,
- "invalid sprom %hhu signature: 0x%hx "
- "(expected 0x%hx)\n",
- srom_rev, sig, fmt->sig_req);
- return (EINVAL);
- }
-
- /* Identified */
- sc->sp_rev = srom_rev;
- return (0);
- }
-
- /* identification failed */
- device_printf(sc->dev, "unrecognized sprom format\n");
- return (EINVAL);
+ return (0);
}
-/*
- * Extend the shadowed SPROM buffer to image_size, reading any required
- * data from the backing SPROM resource and updating the CRC.
+/**
+ * Default bhnd sprom driver implementation of DEVICE_DETACH().
*/
-static int
-sprom_extend_shadow(struct bhnd_sprom *sc, size_t image_size,
- uint8_t *crc)
+int
+bhnd_sprom_detach(device_t dev)
{
- int error;
-
- KASSERT(image_size >= sc->sp_size, (("shadow truncation unsupported")));
-
- /* Verify the request fits within our shadow buffer */
- if (image_size > sc->sp_capacity)
- return (ENOSPC);
-
- /* Skip no-op requests */
- if (sc->sp_size == image_size)
- return (0);
+ struct bhnd_sprom_softc *sc;
+
+ sc = device_get_softc(dev);
- /* Populate the extended range */
- error = sprom_direct_read(sc, sc->sp_size, sc->sp_shadow + sc->sp_size,
- image_size - sc->sp_size, crc);
- if (error)
- return (error);
+ bhnd_release_resource(dev, SYS_RES_MEMORY, sc->sprom_rid,
+ sc->sprom_res);
+ bhnd_sprom_fini(&sc->shadow);
+ SPROM_LOCK_DESTROY(sc);
- sc->sp_size = image_size;
return (0);
}
/**
- * Read nbytes at the given offset from the backing SPROM resource, and
- * update the CRC.
+ * Default bhnd sprom driver implementation of BHND_NVRAM_GETVAR().
*/
static int
-sprom_direct_read(struct bhnd_sprom *sc, size_t offset, void *buf,
- size_t nbytes, uint8_t *crc)
+bhnd_sprom_getvar_meth(device_t dev, const char *name, void *buf, size_t *len)
{
- bus_size_t res_offset;
- uint16_t *p;
-
- KASSERT(nbytes % sizeof(uint16_t) == 0, ("unaligned sprom size"));
- KASSERT(offset % sizeof(uint16_t) == 0, ("unaligned sprom offset"));
-
- /* Check for read overrun */
- if (offset >= sc->sp_size_max || sc->sp_size_max - offset < nbytes) {
- device_printf(sc->dev, "requested SPROM read would overrun\n");
- return (EINVAL);
- }
+ struct bhnd_sprom_softc *sc;
+ int error;
- /* Perform read and update CRC */
- p = (uint16_t *)buf;
- res_offset = sc->sp_res_off + offset;
+ sc = device_get_softc(dev);
- bhnd_bus_read_region_stream_2(sc->sp_res, res_offset, p, nbytes);
- *crc = bhnd_nvram_crc8(p, nbytes, *crc);
+ SPROM_LOCK(sc);
+ error = bhnd_sprom_getvar(&sc->shadow, name, buf, len);
+ SPROM_UNLOCK(sc);
- return (0);
+ return (error);
}
-
/**
- * Locate the variable and SPROM revision-specific definitions
- * for variable with @p name.
+ * Default bhnd sprom driver implementation of BHND_NVRAM_SETVAR().
*/
static int
-sprom_var_defn(struct bhnd_sprom *sc, const char *name,
- const struct bhnd_nvram_var **var,
- const struct bhnd_sprom_var **sprom,
- size_t *size)
+bhnd_sprom_setvar_meth(device_t dev, const char *name, const void *buf,
+ size_t len)
{
- /* Find variable definition */
- *var = bhnd_nvram_var_defn(name);
- if (*var == NULL)
- return (ENOENT);
-
- /* Find revision-specific SPROM definition */
- for (size_t i = 0; i < (*var)->num_sp_descs; i++) {
- const struct bhnd_sprom_var *sp = &(*var)->sprom_descs[i];
-
- if (sc->sp_rev < sp->compat.first)
- continue;
-
- if (sc->sp_rev > sp->compat.last)
- continue;
-
- /* Found */
- *sprom = sp;
-
- /* Calculate size in bytes */
- *size = bhnd_nvram_type_width((*var)->type) * sp->num_offsets;
- return (0);
- }
+ struct bhnd_sprom_softc *sc;
+ int error;
+
+ sc = device_get_softc(dev);
- /* Not supported by this SPROM revision */
- return (ENOENT);
+ SPROM_LOCK(sc);
+ error = bhnd_sprom_setvar(&sc->shadow, name, buf, len);
+ SPROM_UNLOCK(sc);
+
+ return (error);
}
+
+static device_method_t bhnd_sprom_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, bhnd_sprom_probe),
+ DEVMETHOD(device_attach, bhnd_sprom_attach),
+ DEVMETHOD(device_resume, bhnd_sprom_resume),
+ DEVMETHOD(device_suspend, bhnd_sprom_suspend),
+ DEVMETHOD(device_detach, bhnd_sprom_detach),
+
+ /* NVRAM interface */
+ DEVMETHOD(bhnd_nvram_getvar, bhnd_sprom_getvar_meth),
+ DEVMETHOD(bhnd_nvram_setvar, bhnd_sprom_setvar_meth),
+
+ DEVMETHOD_END
+};
+
+DEFINE_CLASS_0(bhnd_nvram, bhnd_sprom_driver, bhnd_sprom_methods, sizeof(struct bhnd_sprom_softc));
+MODULE_VERSION(bhnd_sprom, 1);
Index: sys/dev/bhnd/nvram/bhnd_sprom_subr.c
===================================================================
--- sys/dev/bhnd/nvram/bhnd_sprom_subr.c
+++ sys/dev/bhnd/nvram/bhnd_sprom_subr.c
@@ -47,9 +47,9 @@
#include "bhnd_spromvar.h"
/*
- * BHND SPROM Parsing
+ * BHND SPROM Parser
*
- * Provides identification and parsing of BHND SPROM data.
+ * Provides identification, decoding, and encoding of BHND SPROM data.
*/
static int sprom_direct_read(struct bhnd_sprom *sc, size_t offset,
Index: sys/dev/bhnd/nvram/bhnd_spromvar.h
===================================================================
--- sys/dev/bhnd/nvram/bhnd_spromvar.h
+++ sys/dev/bhnd/nvram/bhnd_spromvar.h
@@ -29,9 +29,31 @@
* $FreeBSD$
*/
-#ifndef _BHND_NVRAM_BHND_SPROM_H_
-#define _BHND_NVRAM_BHND_SPROM_H_
+#ifndef _BHND_NVRAM_BHND_SPROMVAR_H_
+#define _BHND_NVRAM_BHND_SPROMVAR_H_
+#include <dev/bhnd/bhnd.h>
+
+DECLARE_CLASS(bhnd_sprom_driver);
+struct bhnd_sprom;
+
+int bhnd_sprom_probe(device_t dev);
+int bhnd_sprom_attach(device_t dev);
+int bhnd_sprom_resume(device_t dev);
+int bhnd_sprom_suspend(device_t dev);
+int bhnd_sprom_detach(device_t dev);
+
+int bhnd_sprom_init(struct bhnd_sprom *sprom, struct bhnd_resource *r,
+ bus_size_t offset);
+void bhnd_sprom_fini(struct bhnd_sprom *sprom);
+int bhnd_sprom_getvar(struct bhnd_sprom *sc, const char *name, void *buf,
+ size_t *len);
+int bhnd_sprom_setvar(struct bhnd_sprom *sc, const char *name,
+ const void *buf, size_t len);
+
+/**
+ * bhnd sprom parser instance state.
+ */
struct bhnd_sprom {
device_t dev; /**< sprom parent device */
@@ -46,13 +68,17 @@
size_t sp_capacity; /**< shadow buffer capacity */
};
-int bhnd_sprom_init(struct bhnd_sprom *sprom, struct bhnd_resource *r,
- bus_size_t offset);
-void bhnd_sprom_fini(struct bhnd_sprom *sprom);
-int bhnd_sprom_getvar(struct bhnd_sprom *sc, const char *name, void *buf,
- size_t *len);
-int bhnd_sprom_setvar(struct bhnd_sprom *sc, const char *name,
- const void *buf, size_t len);
+/**
+ * bhnd_sprom driver instance state. Must be first member of all subclass
+ * softc structures.
+ */
+struct bhnd_sprom_softc {
+ device_t dev;
+ struct bhnd_resource *sprom_res; /**< SPROM resource */
+ int sprom_rid; /**< SPROM RID */
+ struct bhnd_sprom shadow; /**< SPROM shadow */
+ struct mtx mtx; /**< SPROM shadow mutex */
+};
-#endif /* _BHND_NVRAM_BHND_SPROM_H_ */
+#endif /* _BHND_NVRAM_BHND_SPROMVAR_H_ */
Index: sys/dev/bhnd/siba/siba.c
===================================================================
--- sys/dev/bhnd/siba/siba.c
+++ sys/dev/bhnd/siba/siba.c
@@ -409,7 +409,7 @@
continue;
*addr = addrspace->sa_base;
- *size = addrspace->sa_size;
+ *size = addrspace->sa_size - addrspace->sa_bus_reserved;
return (0);
}
Index: sys/dev/bhnd/siba/siba_subr.c
===================================================================
--- sys/dev/bhnd/siba/siba_subr.c
+++ sys/dev/bhnd/siba/siba_subr.c
@@ -243,11 +243,16 @@
{
struct siba_addrspace *sa;
struct siba_port *port;
+ rman_res_t r_size;
/* Verify that base + size will not overflow */
if (UINT32_MAX - size < base)
return (ERANGE);
+ /* Verify that size - bus_reserved will not underflow */
+ if (size < bus_reserved)
+ return (ERANGE);
+
/* Must not be 0-length */
if (size == 0)
return (EINVAL);
@@ -266,11 +271,12 @@
sa->sa_size = size;
sa->sa_sid = sid;
sa->sa_region_num = region_num;
-
+ sa->sa_bus_reserved = bus_reserved;
+
/* Populate the resource list */
- size -= bus_reserved;
+ r_size = size - bus_reserved;
sa->sa_rid = resource_list_add_next(&dinfo->resources, SYS_RES_MEMORY,
- base, base + size - 1, size);
+ base, base + r_size - 1, r_size);
/* Append to target port */
STAILQ_INSERT_TAIL(&port->sp_addrs, sa, sa_link);
Index: sys/dev/bhnd/siba/sibavar.h
===================================================================
--- sys/dev/bhnd/siba/sibavar.h
+++ sys/dev/bhnd/siba/sibavar.h
@@ -97,6 +97,8 @@
u_int sa_region_num; /**< bhnd region id */
uint8_t sa_sid; /**< siba-assigned address space ID */
int sa_rid; /**< bus resource id */
+ uint32_t sa_bus_reserved;/**< number of bytes at high end of
+ * address space reserved for the bus */
STAILQ_ENTRY(siba_addrspace) sa_link;
};
Index: sys/modules/bhnd/Makefile
===================================================================
--- sys/modules/bhnd/Makefile
+++ sys/modules/bhnd/Makefile
@@ -5,7 +5,8 @@
KMOD= bhnd
SRCS= bhnd.c bhnd_subr.c \
- bhnd_sprom.c nvram_subr.c \
+ bhnd_sprom.c bhnd_sprom_subr.c \
+ nvram_subr.c \
bhnd_nvram_map.h bhnd_nvram_map_data.h
SRCS+= bhnd_bus_if.c bhnd_bus_if.h \
Index: sys/modules/bhnd/cores/bhnd_chipc/Makefile
===================================================================
--- sys/modules/bhnd/cores/bhnd_chipc/Makefile
+++ sys/modules/bhnd/cores/bhnd_chipc/Makefile
@@ -3,7 +3,8 @@
.PATH: ${.CURDIR}/../../../../dev/bhnd/cores/chipc
KMOD= bhnd_chipc
-SRCS= chipc.c
+SRCS= chipc.c \
+ bhnd_sprom_chipc.c
SRCS+= device_if.h bus_if.h bhnd_bus_if.h \
bhnd_chipc_if.h bhnd_nvram_if.h
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Apr 10, 1:07 PM (5 h, 41 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28316028
Default Alt Text
D6471.1775826454.diff (95 KB)
Attached To
Mode
D6471: Implement pass-through resource management for ChipCommon
Attached
Detach File
Event Timeline
Log In to Comment