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 <land...@landonf.org>
  Reviewed by:  miz...@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 <lan...@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 <lan...@landonf.org>
+ * Copyright (c) 2015-2016 Landon Fuller <lan...@landonf.org>
+ * Copyright (c) 2016 Michael Zhilin <miz...@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 ***
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to