svn commit: r300548 - in head/sys: conf dev/bhnd dev/bhnd/bhndb dev/bhnd/cores/chipc dev/bhnd/nvram dev/bhnd/siba modules/bhnd modules/bhnd/cores/bhnd_chipc
Adrian Chadd
adrian at FreeBSD.org
Tue May 24 01:12:21 UTC 2016
Author: adrian
Date: Tue May 24 01:12:19 2016
New Revision: 300548
URL: https://svnweb.freebsd.org/changeset/base/300548
Log:
[bhnd] Implement pass-through resource management for ChipCommon.
This patchset adds support to bhnd_chipc for sharing SYS_RES_MEMORY
resources with its children, allowing us to hang devices off of
bhnd_chipc that rely on access to a subset of the device register space
that bhnd_chipc itself must also allocate.
We could avoid most of this heavy lifting if RF_SHAREABLE+SYS_RES_MEMORY
wasn't limited to use with allocations at the same size/offset.
As a work-around, I implemented something similar to vga_pci.c, which
implements similar reference counting of of PCI BAR resources for its
children.
With these changes, chipc will use reference counting of SYS_RES_MEMORY
allocation/activation requests, to decide when to allocate/activate/
deactivate/release resources from the parent bhnd(4) bus.
The requesting child device is allocated a new resource from chipc's
rman, pointing to (possibly a subregion of) the refcounted bhnd resources
allocated by chipc.
Other resource types are just passed directly to the parent bhnd bus;
RF_SHAREABLE works just fine with IRQs.
I also lifted the SPROM device code out into a common driver, since this
now allows me to hang simple subclasses off of a common driver off of both
bhndb_pci and bhnd_chipc.
Tested:
* (landonf) Tested against BCM4331 and BCM4312, confirmed that SPROM still
attaches and can be queried.
Submitted by: Landon Fuller <landonf at landonf.org>
Reviewed by: mizkha at gmail.com
Differential Revision: https://reviews.freebsd.org/D6471
Added:
head/sys/dev/bhnd/cores/chipc/bhnd_sprom_chipc.c (contents, props changed)
head/sys/dev/bhnd/cores/chipc/chipc_private.h (contents, props changed)
head/sys/dev/bhnd/cores/chipc/chipc_subr.c (contents, props changed)
head/sys/dev/bhnd/nvram/bhnd_sprom_subr.c
- copied, changed from r300546, head/sys/dev/bhnd/nvram/bhnd_sprom.c
Modified:
head/sys/conf/files
head/sys/dev/bhnd/bhnd_subr.c
head/sys/dev/bhnd/bhndb/bhndb_pci_sprom.c
head/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m
head/sys/dev/bhnd/cores/chipc/chipc.c
head/sys/dev/bhnd/cores/chipc/chipc.h
head/sys/dev/bhnd/cores/chipc/chipcreg.h
head/sys/dev/bhnd/cores/chipc/chipcvar.h
head/sys/dev/bhnd/nvram/bhnd_nvram.h
head/sys/dev/bhnd/nvram/bhnd_sprom.c
head/sys/dev/bhnd/nvram/bhnd_spromvar.h
head/sys/dev/bhnd/siba/siba.c
head/sys/dev/bhnd/siba/siba_subr.c
head/sys/dev/bhnd/siba/sibavar.h
head/sys/modules/bhnd/Makefile
head/sys/modules/bhnd/cores/bhnd_chipc/Makefile
Modified: head/sys/conf/files
==============================================================================
--- head/sys/conf/files Tue May 24 00:57:11 2016 (r300547)
+++ head/sys/conf/files Tue May 24 01:12:19 2016 (r300548)
@@ -1139,7 +1139,9 @@ dev/bhnd/bcma/bcma_bhndb.c optional bhn
dev/bhnd/bcma/bcma_erom.c optional bhndbus | bcma
dev/bhnd/bcma/bcma_subr.c optional bhndbus | bcma
dev/bhnd/cores/chipc/chipc.c optional bhndbus | bhnd
+dev/bhnd/cores/chipc/chipc_subr.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
@@ -1148,6 +1150,7 @@ dev/bhnd/cores/pcie2/bhnd_pcie2_hostb.c
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
Modified: head/sys/dev/bhnd/bhnd_subr.c
==============================================================================
--- head/sys/dev/bhnd/bhnd_subr.c Tue May 24 00:57:11 2016 (r300547)
+++ head/sys/dev/bhnd/bhnd_subr.c Tue May 24 01:12:19 2016 (r300548)
@@ -797,11 +797,11 @@ bhnd_parse_chipid(uint32_t idreg, bhnd_a
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 @@ find_nvram_child(device_t dev)
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 */
Modified: head/sys/dev/bhnd/bhndb/bhndb_pci_sprom.c
==============================================================================
--- head/sys/dev/bhnd/bhndb/bhndb_pci_sprom.c Tue May 24 00:57:11 2016 (r300547)
+++ head/sys/dev/bhnd/bhndb/bhndb_pci_sprom.c Tue May 24 01:12:19 2016 (r300548)
@@ -53,29 +53,15 @@ __FBSDID("$FreeBSD$");
#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 @@ bhndb_pci_sprom_probe(device_t dev)
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);
Modified: head/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m
==============================================================================
--- head/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m Tue May 24 00:57:11 2016 (r300547)
+++ head/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m Tue May 24 01:12:19 2016 (r300548)
@@ -36,6 +36,11 @@ INTERFACE bhnd_chipc;
# bhnd(4) ChipCommon interface.
#
+HEADER {
+ /* forward declarations */
+ struct chipc_caps;
+}
+
/**
* Return the preferred NVRAM data source.
*
@@ -63,3 +68,35 @@ METHOD void write_chipctrl {
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;
+}
Added: head/sys/dev/bhnd/cores/chipc/bhnd_sprom_chipc.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ head/sys/dev/bhnd/cores/chipc/bhnd_sprom_chipc.c Tue May 24 01:12:19 2016 (r300548)
@@ -0,0 +1,101 @@
+/*-
+ * Copyright (c) 2015-2016 Landon Fuller <landon at 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);
Modified: head/sys/dev/bhnd/cores/chipc/chipc.c
==============================================================================
--- head/sys/dev/bhnd/cores/chipc/chipc.c Tue May 24 00:57:11 2016 (r300547)
+++ head/sys/dev/bhnd/cores/chipc/chipc.c Tue May 24 01:12:19 2016 (r300548)
@@ -1,5 +1,6 @@
/*-
- * Copyright (c) 2015 Landon Fuller <landon at landonf.org>
+ * Copyright (c) 2015-2016 Landon Fuller <landon at landonf.org>
+ * Copyright (c) 2016 Michael Zhilin <mizhka at gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -42,8 +43,11 @@ __FBSDID("$FreeBSD$");
#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,14 @@ __FBSDID("$FreeBSD$");
#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"
+#include "chipc_private.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 +76,10 @@ static const struct bhnd_device chipc_de
/* 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 +113,37 @@ static struct bhnd_chip_quirk chipc_chip
{{ 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_try_activate_resource(
+ struct chipc_softc *sc, device_t child,
+ int type, int rid, struct resource *r,
+ bool req_direct);
+
+static int chipc_read_caps(struct chipc_softc *sc,
+ struct chipc_caps *caps);
+
+static int chipc_nvram_attach(struct chipc_softc *sc);
+static bhnd_nvram_src_t chipc_nvram_identify(struct chipc_softc *sc);
+static bool chipc_should_enable_sprom(
+ struct chipc_softc *sc);
+
+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);
+
/* 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 +151,6 @@ static struct bhnd_chip_quirk chipc_chip
#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)
{
@@ -159,19 +177,36 @@ chipc_attach(device_t dev)
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 +220,36 @@ chipc_attach(device_t dev)
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 +258,15 @@ static int
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);
@@ -241,58 +274,131 @@ chipc_detach(device_t dev)
return (0);
}
+/* Read and parse chipc capabilities */
static int
-chipc_suspend(device_t dev)
+chipc_read_caps(struct chipc_softc *sc, struct chipc_caps *caps)
{
- return (0);
-}
+ 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;
+ }
-static int
-chipc_resume(device_t dev)
-{
return (0);
}
/**
- * Initialize local SPROM shadow, if required.
- *
- * @param sc chipc driver state.
+ * If supported, add an appropriate NVRAM child device.
*/
static int
-chipc_sprom_init(struct chipc_softc *sc)
+chipc_nvram_attach(struct chipc_softc *sc)
{
- int error;
+ device_t nvram_dev;
+ rman_res_t start;
+ int error;
- KASSERT(sc->nvram_src == BHND_NVRAM_SRC_SPROM,
- ("non-SPROM source (%u)\n", sc->nvram_src));
+ switch (sc->nvram_src) {
+ case BHND_NVRAM_SRC_OTP:
+ // TODO OTP support
+ device_printf(sc->dev, "OTP nvram source unsupported\n");
+ return (0);
- /* Enable access to the SPROM */
- CHIPC_LOCK(sc);
- if ((error = chipc_enable_sprom_pins(sc)))
- goto failed;
+ 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);
- /* 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);
+ case BHND_NVRAM_SRC_FLASH:
+ // TODO flash support
+ device_printf(sc->dev, "flash nvram source unsupported\n");
+ return (0);
- chipc_disable_sprom_pins(sc);
- goto failed;
- }
+ case BHND_NVRAM_SRC_UNKNOWN:
+ /* Handled externally */
+ return (0);
- /* Drop access to the SPROM lines */
- if ((error = chipc_disable_sprom_pins(sc))) {
- bhnd_sprom_fini(&sc->sprom);
- goto failed;
+ default:
+ device_printf(sc->dev, "invalid nvram source: %u\n",
+ sc->nvram_src);
+ return (ENXIO);
}
- CHIPC_UNLOCK(sc);
-
- return (0);
-
-failed:
- CHIPC_UNLOCK(sc);
- return (error);
}
/**
@@ -317,27 +423,645 @@ chipc_nvram_identify(struct chipc_softc
* 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);
}
+static int
+chipc_suspend(device_t dev)
+{
+ 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++) {
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-all
mailing list