Page MenuHomeFreeBSD

D6471.1775826454.diff
No OneTemporary

Size
95 KB
Referenced Files
None
Subscribers
None

D6471.1775826454.diff

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

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)

Event Timeline