Page MenuHomeFreeBSD

D6250.id16411.diff
No OneTemporary

D6250.id16411.diff

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
@@ -28,7 +28,14 @@
#include <sys/bus.h>
#include <dev/bhnd/bhnd.h>
-#include <dev/bhnd/nvram/bhnd_nvram.h>
+
+#
+# Header includes used struct declarations
+#
+HEADER {
+ #include <dev/bhnd/nvram/bhnd_nvram.h>
+ #include <dev/bhnd/cores/chipc/chipcvar.h>
+}
INTERFACE bhnd_chipc;
@@ -43,4 +50,22 @@
*/
METHOD bhnd_nvram_src_t nvram_src {
device_t dev;
+}
+
+/**
+ * Return the flash configuration register value
+ *
+ * @param dev A bhnd(4) ChipCommon device
+ */
+METHOD uint32_t get_flash_cfg {
+ device_t dev;
+}
+
+/**
+ * Return the ChipCommon capabilities
+ *
+ * @param dev A bhnd(4) ChipCommon device
+ */
+METHOD struct chipc_capabilities* get_capabilities {
+ device_t dev;
}
\ No newline at end of file
Index: sys/dev/bhnd/cores/chipc/chipc.h
===================================================================
--- sys/dev/bhnd/cores/chipc/chipc.h
+++ sys/dev/bhnd/cores/chipc/chipc.h
@@ -36,6 +36,7 @@
#include <dev/bhnd/nvram/bhnd_nvram.h>
#include "bhnd_chipc_if.h"
+#include "chipcvar.h"
/**
* Query a ChipCommon device and return the preferred NVRAM data source.
@@ -48,4 +49,7 @@
return (BHND_CHIPC_NVRAM_SRC(dev));
}
-#endif /* _BHND_CORES_CHIPC_CHIPC_H_ */
\ No newline at end of file
+void chipc_parse_capabilities(struct chipc_capabilities* capabilities,
+ uint32_t caps);
+
+#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
@@ -38,6 +38,25 @@
* and bcma(4) interconnects, providing a common interface to chipset
* identification, bus enumeration, UARTs, clocks, watchdog interrupts, GPIO,
* flash, etc.
+ *
+ * The purpose of this driver is resource management for ChipCommon drivers
+ * like UART, PMU, flash. ChipCommon core has several resources:
+ * - several memory regions,
+ * - one or more IRQ lines.
+ *
+ * ChipCommon driver has 2 resource managers: for memory and for IRQ. Driver
+ * gets information about BHND core ports/regions and map them
+ * into drivers' resources.
+ *
+ * Here is overview of mapping:
+ *
+ * ------------------------------------------------------
+ * | Port.Region| Purpose |
+ * ------------------------------------------------------
+ * | 0.0 | main registers: SPI(0x40), UART(0x300)|
+ * | 1.0 | ? |
+ * | 1.1 | MMIO flash (SPI & CFI) |
+ * ------------------------------------------------------
*/
#include <sys/param.h>
@@ -45,15 +64,18 @@
#include <sys/bus.h>
#include <sys/module.h>
#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/rman.h>
#include <machine/bus.h>
-#include <sys/rman.h>
#include <machine/resource.h>
#include <dev/bhnd/bhnd.h>
+#include <dev/bhnd/bhndvar.h>
#include "bhnd_nvram_if.h"
+#include "chipc.h"
#include "chipcreg.h"
#include "chipcvar.h"
@@ -117,20 +139,53 @@
#define CHIPC_QUIRK(_sc, _name) \
((_sc)->quirks & CHIPC_QUIRK_ ## _name)
-#define CHIPC_CAP(_sc, _name) \
- ((_sc)->caps & CHIPC_ ## _name)
-
#define CHIPC_ASSERT_QUIRK(_sc, name) \
KASSERT(CHIPC_QUIRK((_sc), name), ("quirk " __STRING(_name) " not set"))
-#define CHIPC_ASSERT_CAP(_sc, name) \
- KASSERT(CHIPC_CAP((_sc), name), ("capability " __STRING(_name) " not set"))
+/*
+ * Here is resource configuration for child devices
+ *
+ * [Flash] There are 2 flash resources:
+ * - resource ID (rid) = 0: memory-mapped flash memory
+ * - resource ID (rid) = 1: memory-mapped flash registers (i.e for SPI)
+ *
+ * [UART] Uses IRQ and memory resources:
+ * - resource ID (rid) = 0: memory-mapped registers
+ * - IRQ resource ID (rid) = 0: shared IRQ line for Tx/Rx.
+ */
+struct chipc_spec chipc_children_mem_specs[] = {
+ {"uart", SYS_RES_MEMORY, 0, 0, 0, CHIPC_UART_BASE, CHIPC_UART_SIZE},
+ {"uart", SYS_RES_IRQ, 0,-1,-1, 0, 1 },
+ {"spi", SYS_RES_MEMORY, 0, 1, 1, 0, ~0},
+ {"spi", SYS_RES_MEMORY, 1, 0, 0, CHIPC_FLASHBASE, CHIPC_FLASHREGSZ},
+ {"cfi", SYS_RES_MEMORY, 0, 1, 1, 0, ~0},
+ {"cfi", SYS_RES_MEMORY, 1, 0, 0, CHIPC_FLASHBASE, CHIPC_FLASHREGSZ},
+ {NULL, 0, 0, 0, 0, 0, 0}
+};
+
+static struct resource_list* chipc_get_resource_list(device_t dev,
+ device_t child);
+static struct resource* chipc_alloc_resource(device_t bus,
+ device_t child,
+ int type,
+ int *rid,
+ rman_res_t start,
+ rman_res_t end,
+ rman_res_t count,
+ u_int flags);
+
+static void chipc_probe_nomatch(device_t dev, device_t child);
+static void chipc_set_resources(device_t bus, device_t dev,
+ struct resource_list* rl);
+static int chipc_release_resource(device_t bus, device_t child,
+ int type, int rid, struct resource *r);
+void chipc_cleanup(device_t dev);
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_init_rman(device_t dev);
static int
chipc_probe(device_t dev)
@@ -151,6 +206,7 @@
struct chipc_softc *sc;
bhnd_addr_t enum_addr;
uint32_t ccid_reg;
+ uint32_t caps;
uint8_t chip_type;
int error;
@@ -191,7 +247,8 @@
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);
+ caps = bhnd_bus_read_4(sc->core, CHIPC_CAPABILITIES);
+ chipc_parse_capabilities(&sc->capabilities, caps);
sc->cst = bhnd_bus_read_4(sc->core, CHIPC_CHIPST);
/* Identify NVRAM source */
@@ -219,6 +276,19 @@
break;
}
+ error = chipc_init_rman(dev);
+
+ if (error != 0) {
+ device_printf(dev,"init_rman failed with: %d\n", error);
+ goto cleanup;
+ }
+
+ error = bus_generic_attach(dev);
+ if (error != 0) {
+ device_printf(dev, "bus_generic_attach failed: %d\n", error);
+ goto cleanup;
+ }
+
return (0);
cleanup:
@@ -235,6 +305,7 @@
sc = device_get_softc(dev);
bhnd_release_resources(dev, sc->rspec, sc->res);
bhnd_sprom_fini(&sc->sprom);
+ chipc_cleanup(dev);
CHIPC_LOCK_DESTROY(sc);
@@ -253,6 +324,13 @@
return (0);
}
+
+static void
+chipc_probe_nomatch(device_t dev, device_t child)
+{
+ device_printf(dev, "no found driver for %s\n", device_get_name(child));
+}
+
/**
* Initialize local SPROM shadow, if required.
*
@@ -317,21 +395,21 @@
* 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 (sc->capabilities.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 (sc->capabilities.otp_size)
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))
+ if (CHIPC_QUIRK(sc, SUPPORTS_NFLASH) && sc->capabilities.nflash)
return (BHND_NVRAM_SRC_NFLASH);
/* No NVRAM hardware capability declared */
@@ -489,6 +567,281 @@
return (ENODEV);
}
+static struct chipc_capabilities*
+chipc_get_caps(device_t dev)
+{
+ struct chipc_softc *sc;
+
+ sc = device_get_softc(dev);
+ return (&sc->capabilities);
+}
+
+static uint32_t
+chipc_get_flash_cfg(device_t dev)
+{
+ struct chipc_softc *sc;
+
+ sc = device_get_softc(dev);
+ return (bhnd_bus_read_4(sc->core, CHIPC_FLASH_CFG));
+}
+
+void
+chipc_cleanup(device_t dev)
+{
+ struct chipc_softc *sc;
+ sc = device_get_softc(dev);
+ rman_fini(&sc->chipc_irq);
+ rman_fini(&sc->chipc_mem);
+}
+
+static int
+chipc_init_rman(device_t dev)
+{
+ int err;
+ struct chipc_softc *sc;
+ bhnd_addr_t rg_start;
+ bhnd_size_t rg_size;
+ int rgcnt;
+
+ BHND_DEBUG_DEV(dev, "init rman");
+
+ sc = device_get_softc(dev);
+ sc->chipc_irq.rm_start = 0;
+ sc->chipc_irq.rm_end = NUM_IRQS - 1;
+ sc->chipc_irq.rm_type = RMAN_ARRAY;
+ sc->chipc_irq.rm_descr = "ChipCommon IRQs";
+ err = rman_init(&sc->chipc_irq);
+ if (err) {
+ BHND_ERROR_DEV(dev, "error occurred during rman_init of "
+ "IRQ rman: %d", err);
+ goto error;
+ }
+ sc->chipc_mem.rm_start = 0;
+ sc->chipc_mem.rm_end = BUS_SPACE_MAXADDR;
+ sc->chipc_mem.rm_type = RMAN_ARRAY;
+ sc->chipc_mem.rm_descr = "ChipCommon Memory";
+ err = rman_init(&sc->chipc_mem);
+ if (err) {
+ BHND_ERROR_DEV(dev, "error occurred during init of "
+ "MEMORY rman: %d", err);
+ goto error;
+ }
+
+ /* Iterate over device ports & regions and fill instance variable */
+ for(int i = 0; i < bhnd_get_port_count(dev, BHND_PORT_DEVICE); i++) {
+ rgcnt = bhnd_get_region_count(dev, BHND_PORT_DEVICE, i);
+ BHND_DEBUG_DEV(dev, "[%d] region count = %d", i, rgcnt);
+ for (int j = 0; j < rgcnt; j++) {
+ err = bhnd_get_region_addr(dev, BHND_PORT_DEVICE, i, j,
+ &rg_start, &rg_size);
+ BHND_DEBUG_DEV(dev, "[%d.%d] region addr = 0x%jx (%d)",
+ i, j, rg_start, err);
+ if (err != 0)
+ continue;
+
+ err = rman_manage_region(&sc->chipc_mem, rg_start,
+ rg_start + rg_size - 1);
+ if (err != 0) {
+ BHND_ERROR_DEV(dev, "error occurred during "
+ "rman_manage_region of MEMORY rman with "
+ "params: 0x%jx - 0x%jx : err = %d"
+ ,rg_start, rg_start + rg_size - 1, err);
+ goto error;
+ }
+ }
+ }
+
+/*
+ * We're creating resource manager for all MIPS IRQs, but it's MIPS-ifed code
+ * and it's better to get IRQ number from core info.
+ * TODO: fetch IRQ number from core info to demipsify code
+ */
+ err = rman_manage_region(&sc->chipc_irq, 0, NUM_IRQS - 1);
+ if (err) {
+ BHND_ERROR_DEV(dev, "error occurred (code = %d) during "
+ "rman_manage_region of IRQ rman with params: 0x%d - 0x%d",
+ err, 0, NUM_IRQS);
+ goto error;
+ }
+
+ BHND_DEBUG_DEV(dev, "rmans are initialized successfully");
+ return (0);
+error:
+ BHND_ERROR_DEV(dev, "init_rman finished with error: %d", err);
+ chipc_cleanup(dev);
+ return (err);
+}
+
+static struct resource_list *
+chipc_get_resource_list(device_t dev, device_t child)
+{
+ struct chipc_devinfo *dinfo;
+
+ dinfo = device_get_ivars(child);
+
+ if (dinfo == NULL) {
+ /*
+ * Lazy way of resource assignment
+ */
+ dinfo = malloc(sizeof(struct chipc_devinfo*), M_BHND, M_NOWAIT);
+
+ if (dinfo == NULL) {
+ BHND_ERROR_DEV(dev, "can't allocate memory for "
+ "chipc_devinfo of %s",
+ device_get_nameunit(child));
+ return (NULL);
+ }
+
+ resource_list_init(&(dinfo->resources));
+ chipc_set_resources(dev, child, &(dinfo->resources));
+ device_set_ivars(child, dinfo);
+ }
+
+ return (&dinfo->resources);
+}
+
+static void
+chipc_set_resources(device_t bus, device_t dev, struct resource_list* rl)
+{
+ const char *devname;
+ struct chipc_spec *spec;
+ rman_res_t start;
+ rman_res_t end;
+ bhnd_addr_t region_start;
+ bhnd_addr_t region_end;
+ bhnd_size_t region_size;
+ rman_res_t count;
+ int err;
+
+ BHND_DEBUG_DEV(dev, "init resource list...");
+
+ devname = device_get_name(dev);
+ spec = chipc_children_mem_specs;
+ for (;spec->name != NULL; spec++) {
+ if (strcmp(spec->name, devname) != 0)
+ continue;
+
+ /* device name is matched */
+ switch (spec->type){
+ case SYS_RES_MEMORY:
+ err = bhnd_get_region_addr(bus, BHND_PORT_DEVICE,
+ spec->port, spec->reg, &region_start, &region_size);
+ if (err != 0) {
+ BHND_WARN_DEV(bus, "region is not found "
+ "[type %d, rid %d, port.region %d.%d]",
+ spec->type, spec->rid, spec->port, spec->reg);
+ continue;
+ }
+
+ region_end = region_start + region_size - 1;
+
+ break;
+ /*
+ * We're creating resource manager for all MIPS IRQs,
+ * but it's MIPS-ifed code and it's better to get IRQ number
+ * from core info.
+ *
+ * TODO: fetch IRQ number from core info to demipsify code
+ */
+ case SYS_RES_IRQ:
+ region_start = 2;
+ region_end = 2;
+ region_size = 1;
+ break;
+ default:
+ continue;
+ }
+
+ start = MIN(region_start + spec->start, region_end);
+ end = MIN(region_start + spec->start +
+ MIN(spec->size, region_size) - 1,
+ region_end);
+ count = end - start + 1;
+ resource_list_add(rl, spec->type, spec->rid, start, end, count);
+ }
+}
+
+static struct resource *
+chipc_alloc_resource(device_t bus, 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 rman *rm;
+ struct resource *r;
+ struct resource_list *rl;
+ struct resource_list_entry *rle;
+
+ BHND_DEBUG_DEV(child, "looking for allocation resource [%d]: %d, "
+ "0x%jx, 0x%jx, 0x%jx", type, *rid, start, end, count);
+ if (RMAN_IS_DEFAULT_RANGE(start, end) && count == 1) {
+ rl = chipc_get_resource_list(bus, child);
+ if (rl == NULL) {
+ BHND_ERROR_DEV(bus, "there is no resource list for: %s",
+ device_get_nameunit(child));
+ return (NULL);
+ }
+ rle = resource_list_find(rl, type, *rid);
+ if (rle == NULL) {
+ BHND_DEBUG_DEV(child, "there is no resource in "
+ "resource list: type %d rid %d",
+ type, *rid);
+ return (NULL);
+ }
+ start = rle->start;
+ end = rle->end;
+ count = rle->count;
+ }
+
+ sc = device_get_softc(bus);
+ switch (type) {
+ case SYS_RES_IRQ:
+ rm = &sc->chipc_irq;
+ break;
+ case SYS_RES_MEMORY:
+ rm = &sc->chipc_mem;
+ break;
+ default:
+ BHND_ERROR_DEV(child, "unknown resource type %d", type);
+ return (NULL);
+ }
+
+ BHND_DEBUG_DEV(child, "ready for rman_reserve [%d]: %d, "
+ "0x%jx, 0x%jx, 0x%jx", type, *rid, start, end, count);
+ r = rman_reserve_resource(rm, start, end, count, flags, child);
+ if (r == NULL) {
+ BHND_ERROR_DEV(child, "could not reserve resource %d: "
+ "0x%jx-0x%jx", *rid, start, end);
+ return (NULL);
+ }
+
+ rman_set_rid(r, *rid);
+
+ if (flags & RF_ACTIVE)
+ if (bus_activate_resource(child, type, *rid, r)) {
+ BHND_ERROR_DEV(child, "could not activate resource %d:"
+ " 0x%jx-0x%jx", *rid, start, end);
+ rman_release_resource(r);
+ return (NULL);
+ }
+
+ return (r);
+}
+
+static int
+chipc_release_resource(device_t dev, device_t child, int type, int rid,
+ struct resource *r)
+{
+ int error;
+
+ if (rman_get_flags(r) & RF_ACTIVE) {
+ error = bus_deactivate_resource(child, type, rid, r);
+ if (error)
+ return (error);
+ }
+
+ return (rman_release_resource(r));
+}
+
static device_method_t chipc_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, chipc_probe),
@@ -496,18 +849,44 @@
DEVMETHOD(device_detach, chipc_detach),
DEVMETHOD(device_suspend, chipc_suspend),
DEVMETHOD(device_resume, chipc_resume),
-
+
+ /* Bus interface */
+ DEVMETHOD(bus_add_child, bus_generic_add_child),
+ DEVMETHOD(bus_get_resource_list, chipc_get_resource_list),
+ DEVMETHOD(bus_alloc_resource, chipc_alloc_resource),
+ DEVMETHOD(bus_release_resource, chipc_release_resource),
+ DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
+ DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
+
+ 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),
+
+ DEVMETHOD(bus_probe_nomatch, chipc_probe_nomatch),
+
/* ChipCommon interface */
- DEVMETHOD(bhnd_chipc_nvram_src, chipc_nvram_src),
+ DEVMETHOD(bhnd_chipc_nvram_src, chipc_nvram_src),
+ DEVMETHOD(bhnd_chipc_get_capabilities, chipc_get_caps),
+ DEVMETHOD(bhnd_chipc_get_flash_cfg, chipc_get_flash_cfg),
/* NVRAM interface */
DEVMETHOD(bhnd_nvram_getvar, chipc_nvram_getvar),
DEVMETHOD(bhnd_nvram_setvar, chipc_nvram_setvar),
+ /*
+ * TODO: Add
+ * - bus_print_child,
+ * - bus_{get,set,delete}_resource,
+ * - bus_hinted_child
+ */
+
DEVMETHOD_END
};
DEFINE_CLASS_0(bhnd_chipc, chipc_driver, chipc_methods, sizeof(struct chipc_softc));
-DRIVER_MODULE(bhnd_chipc, bhnd, chipc_driver, bhnd_chipc_devclass, 0, 0);
+EARLY_DRIVER_MODULE(bhnd_chipc, bhnd, chipc_driver, bhnd_chipc_devclass, 0, 0,
+ BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE);
MODULE_DEPEND(bhnd_chipc, bhnd, 1, 1, 1);
MODULE_VERSION(bhnd_chipc, 1);
Index: sys/dev/bhnd/cores/chipc/chipc_cfi.c
===================================================================
--- /dev/null
+++ sys/dev/bhnd/cores/chipc/chipc_cfi.c
@@ -0,0 +1,143 @@
+/*-
+ * Copyright (c) 2016 Michael Zhilin <mizhka@gmail.com>
+ * 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$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+
+#include <machine/bus.h>
+
+#include <dev/bhnd/bhnd_debug.h>
+#include <dev/cfi/cfi_var.h>
+
+#include "bhnd_chipc_if.h"
+#include "chipc_slicer.h"
+#include "chipcreg.h"
+#include "chipcvar.h"
+
+/*
+ * **************************** PROTOTYPES ****************************
+ */
+
+static void chipc_cfi_identify(driver_t *driver, device_t parent);
+static int chipc_cfi_probe(device_t dev);
+static int chipc_cfi_attach(device_t dev);
+
+/*
+ * **************************** IMPLEMENTATION ************************
+ */
+
+static void
+chipc_cfi_identify(driver_t *driver, device_t parent)
+{
+ struct chipc_capabilities *caps;
+
+ caps = BHND_CHIPC_GET_CAPABILITIES(parent);
+ if (caps == NULL)
+ return;
+
+ if (caps->flash_type != CHIPC_PFLASH)
+ return;
+
+ BUS_ADD_CHILD(parent, 0, cfi_driver_name, -1);
+ return;
+}
+
+static int
+chipc_cfi_probe(device_t dev)
+{
+ int error;
+ int width;
+ int enabled;
+ int byteswap;
+ uint32_t flash_config;
+ struct cfi_softc *sc;
+
+ sc = device_get_softc(dev);
+
+ flash_config = BHND_CHIPC_GET_FLASH_CFG(device_get_parent(dev));
+
+ width = (flash_config & CHIPC_CF_DS) ? 2 : 1;
+ enabled = (flash_config & CHIPC_CF_EN);
+ byteswap = (flash_config & CHIPC_CF_BS);
+
+ if (enabled == 0)
+ device_disable(dev);
+
+ BHND_DEBUG_DEV(dev, "trying attach flash "
+ "width=%d enabled=%d swapbytes=%d",
+ width, enabled, byteswap);
+
+ /*
+ * TODO: remove hack coded "2" and use width (now it doesn't work)
+ */
+ sc->sc_width = 2;
+ error = cfi_probe(dev);
+ if (error == 0)
+ device_set_desc(dev, "ChipCommon CFI");
+ return (error);
+}
+
+static int
+chipc_cfi_attach(device_t dev)
+{
+ int error;
+
+ error = cfi_attach(dev);
+ if (error)
+ return (error);
+
+ flash_register_slicer(chipc_slicer_cfi);
+ return (0);
+}
+
+static device_method_t chipc_cfi_methods[] = {
+ /* device interface */
+ DEVMETHOD(device_identify, chipc_cfi_identify),
+ DEVMETHOD(device_probe, chipc_cfi_probe),
+ DEVMETHOD(device_attach, chipc_cfi_attach),
+ DEVMETHOD(device_detach, cfi_detach),
+
+ {0, 0}
+};
+
+static driver_t chipc_cfi_driver = {
+ cfi_driver_name,
+ chipc_cfi_methods,
+ sizeof(struct cfi_softc),
+};
+
+DRIVER_MODULE(cfi, bhnd_chipc, chipc_cfi_driver, cfi_devclass, 0, 0);
+
Index: sys/dev/bhnd/cores/chipc/chipc_slicer.h
===================================================================
--- /dev/null
+++ sys/dev/bhnd/cores/chipc/chipc_slicer.h
@@ -0,0 +1,44 @@
+/*-
+ * Copyright (c) 2016 Michael Zhilin <mizhka@gmail.com>
+ * 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.
+ */
+
+#ifndef _BHND_CORES_CHIPC_CHIPC_SLICER_H_
+#define _BHND_CORES_CHIPC_CHIPC_SLICER_H_
+
+#include <sys/slicer.h>
+
+#define TRX_MAGIC 0x30524448
+#define CFE_MAGIC 0x43464531
+#define NVRAM_MAGIC 0x48534C46
+
+int chipc_slicer_spi(device_t dev, struct flash_slice *slices,
+ int *nslices);
+int chipc_slicer_cfi(device_t dev, struct flash_slice *slices,
+ int *nslices);
+
+#endif /* _BHND_CORES_CHIPC_CHIPC_SLICER_H_ */
Index: sys/dev/bhnd/cores/chipc/chipc_slicer.c
===================================================================
--- /dev/null
+++ sys/dev/bhnd/cores/chipc/chipc_slicer.c
@@ -0,0 +1,173 @@
+/*-
+ * Copyright (c) 2016 Michael Zhilin <mizhka@gmail.com>
+ * 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$");
+
+/*
+ * Slicer is required to split firmware images into pieces.
+ * The first supported FW is TRX-based used by Asus routers
+ * TODO: add NetGear FW (CHK)
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/errno.h>
+#include <sys/rman.h>
+#include <sys/bus.h>
+#include <sys/systm.h>
+#include <sys/slicer.h>
+
+#include <machine/bus.h>
+
+#include <geom/geom_disk.h>
+
+#include <dev/bhnd/bhnd_debug.h>
+
+#include "chipc_slicer.h"
+
+#include <dev/cfi/cfi_var.h>
+#include "chipc_spi.h"
+
+static int chipc_slicer_walk(device_t dev, struct resource* res,
+ struct flash_slice *slices, int *nslices);
+
+int
+chipc_slicer_cfi(device_t dev, struct flash_slice *slices, int *nslices)
+{
+ struct cfi_softc *sc;
+
+ if (strcmp("cfi", device_get_name(dev)) != 0)
+ return (0);
+
+ sc = device_get_softc(dev);
+
+ return (chipc_slicer_walk(dev, sc->sc_res, slices, nslices));
+}
+
+int
+chipc_slicer_spi(device_t dev, struct flash_slice *slices, int *nslices)
+{
+ /* flash(mx25l) <- spibus <- chipc_spi */
+ device_t spibus;
+ device_t chipc_spi;
+ struct chipc_spi_softc *sc;
+
+ BHND_DEBUG_DEV(dev, "initting SPI slicer: %s", device_get_name(dev));
+
+ if (strcmp("mx25l", device_get_name(dev)) != 0)
+ return (EINVAL);
+
+ spibus = device_get_parent(dev);
+ if (spibus == NULL) {
+ BHND_ERROR_DEV(dev, "no found ChipCommon SPI BUS device");
+ return (EINVAL);
+ }
+
+ chipc_spi = device_get_parent(spibus);
+ if (chipc_spi == NULL) {
+ BHND_ERROR_DEV(spibus, "no found ChipCommon SPI device");
+ return (EINVAL);
+ }
+
+ sc = device_get_softc(chipc_spi);
+
+ return (chipc_slicer_walk(dev, sc->sc_res, slices, nslices));
+}
+
+/*
+ * Main processing part
+ */
+static int
+chipc_slicer_walk(device_t dev, struct resource* res,
+ struct flash_slice *slices, int *nslices)
+{
+ uint32_t fw_len;
+ uint32_t fs_ofs;
+ uint32_t val;
+ int flash_size;
+ struct disk *disk;
+
+ *nslices = 0;
+
+ disk = disk_fetch_by_driver(device_get_softc(dev));
+ if (disk == NULL) {
+ BHND_ERROR_DEV(dev, "no found geom_disk by device softc");
+ return (EINVAL);
+ }
+
+ flash_size = disk->d_mediasize;
+ BHND_TRACE_DEV(dev, "slicer: scanning memory [%x bytes] for headers...",
+ flash_size);
+
+ /*
+ * Find FW header in flash memory with step = 0x1000 (block size 128Kb)
+ */
+ for(uint32_t ofs = 0; ofs < flash_size; ofs+= 0x1000){
+ val = bus_read_4(res, ofs);
+ switch (val) {
+ case TRX_MAGIC:
+ BHND_TRACE("TRX found: %x", ofs);
+ /* read last offset of TRX header */
+ fs_ofs = bus_read_4(res, ofs + 24);
+ BHND_TRACE("FS offset: %x", fs_ofs);
+
+ /*
+ * GEOM IO will panic if offset is not aligned
+ * on sector size, i.e. 512 bytes
+ */
+ if (fs_ofs % 0x200 != 0) {
+ BHND_WARN("WARNING! filesystem offset should be"
+ " aligned on sector size (%d bytes)", 0x200);
+ BHND_WARN("ignoring TRX firmware image");
+ break;
+ }
+
+ slices[*nslices].base = ofs + fs_ofs;
+ //XXX: fully sized? any other partition?
+ fw_len = bus_read_4(res, ofs + 4);
+ slices[*nslices].size = fw_len - fs_ofs;
+ slices[*nslices].label = "rootfs";
+ *nslices += 1;
+ break;
+ case CFE_MAGIC:
+ BHND_TRACE("CFE found: %x", ofs);
+ break;
+ case NVRAM_MAGIC:
+ BHND_TRACE("NVRAM found: %x", ofs);
+ break;
+ default:
+ break;
+ }
+ }
+
+ BHND_TRACE("slicer: done");
+ return (0);
+}
Index: sys/dev/bhnd/cores/chipc/chipc_spi.h
===================================================================
--- /dev/null
+++ sys/dev/bhnd/cores/chipc/chipc_spi.h
@@ -0,0 +1,94 @@
+/*-
+ * Copyright (c) 2016 Michael Zhilin <mizhka@gmail.com>
+ * 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.
+ */
+
+/*
+ * $FreeBSD$
+ */
+
+#ifndef _BHND_CORES_CHIPC_CHIPC_SPI_H_
+#define _BHND_CORES_CHIPC_CHIPC_SPI_H_
+
+#define CHIPC_SPI_MAXTRIES 1000
+
+#define CHIPC_SPI_ACTION_INPUT 1
+#define CHIPC_SPI_ACTION_OUTPUT 2
+
+#define CHIPC_SPI_FLASHCTL 0x00
+#define CHIPC_SPI_FLASHCTL_OPCODE 0x000000ff
+#define CHIPC_SPI_FLASHCTL_ACTION 0x00000700 //
+/*
+ * We don't use action at all. Experimentaly found, that
+ * action 0 - read current MISO byte to data register (interactive mode)
+ * action 1 = read 2nd byte to data register
+ * action 2 = read 4th byte to data register (surprise! see action 6)
+ * action 3 = read 5th byte to data register
+ * action 4 = read bytes 5-8 to data register in swapped order
+ * action 5 = read bytes 9-12 to data register in swapped order
+ * action 6 = read 3rd byte to data register
+ * action 7 = read bytes 6-9 to data register in swapped order
+ * It may be wrong if CS bit is 1.
+ * If CS bit is 1, you should write cmd / data to opcode byte-to-byte.
+ */
+#define CHIPC_SPI_FLASHCTL_CSACTIVE 0x00001000
+#define CHIPC_SPI_FLASHCTL_START 0x80000000 //same as BUSY
+#define CHIPC_SPI_FLASHCTL_BUSY 0x80000000 //same as BUSY
+#define CHIPC_SPI_FLASHADDR 0x04
+#define CHIPC_SPI_FLASHDATA 0x08
+
+struct chipc_spi_softc {
+ device_t dev;
+
+ /* SPI registers */
+ struct resource *sc_mem_res;
+
+ /* MMIO flash */
+ struct resource *sc_res;
+};
+
+/* register space access macros */
+#define SPI_BARRIER_WRITE(sc) bus_barrier((sc)->sc_mem_res, 0, 0, \
+ BUS_SPACE_BARRIER_WRITE)
+#define SPI_BARRIER_READ(sc) bus_barrier((sc)->sc_mem_res, 0, 0, \
+ BUS_SPACE_BARRIER_READ)
+#define SPI_BARRIER_RW(sc) bus_barrier((sc)->sc_mem_res, 0, 0, \
+ BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE)
+
+#define SPI_WRITE(sc, reg, val) do { \
+ bus_write_4(sc->sc_mem_res, (reg), (val)); \
+ } while (0)
+
+#define SPI_READ(sc, reg) bus_read_4(sc->sc_mem_res, (reg))
+
+#define SPI_SET_BITS(sc, reg, bits) \
+ SPI_WRITE(sc, reg, SPI_READ(sc, (reg)) | (bits))
+
+#define SPI_CLEAR_BITS(sc, reg, bits) \
+ SPI_WRITE(sc, reg, SPI_READ(sc, (reg)) & ~(bits))
+
+#endif /* _BHND_CORES_CHIPC_CHIPC_SPI_H_ */
Index: sys/dev/bhnd/cores/chipc/chipc_spi.c
===================================================================
--- /dev/null
+++ sys/dev/bhnd/cores/chipc/chipc_spi.c
@@ -0,0 +1,285 @@
+/*-
+ * Copyright (c) 2016 Michael Zhilin <mizhka@gmail.com>
+ * 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$");
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/errno.h>
+#include <sys/rman.h>
+#include <sys/bus.h>
+#include <sys/systm.h>
+
+#include <machine/bus.h>
+
+#include <dev/bhnd/bhndvar.h>
+/*
+ * SPI BUS interface
+ */
+#include <dev/spibus/spi.h>
+
+#include "spibus_if.h"
+
+#include "chipcreg.h"
+#include "chipcvar.h"
+#include "chipc_spi.h"
+#include "bhnd_chipc_if.h"
+
+/*
+ * Flash slicer
+ */
+#include "chipc_slicer.h"
+
+/*
+ * **************************** PROTOTYPES ****************************
+ */
+
+static void chipc_spi_identify(driver_t *driver, device_t parent);
+static int chipc_spi_probe(device_t dev);
+static int chipc_spi_attach(device_t dev);
+static int chipc_spi_transfer(device_t dev, device_t child,
+ struct spi_command *cmd);
+static int chipc_spi_txrx(struct chipc_spi_softc *sc, uint8_t in,
+ uint8_t* out);
+static int chipc_spi_wait(struct chipc_spi_softc *sc);
+
+/*
+ * **************************** IMPLEMENTATION ************************
+ */
+
+static void
+chipc_spi_identify(driver_t *driver, device_t parent)
+{
+ device_t flashdev;
+ device_t *children;
+ device_t flash;
+ int cnt_children;
+ int err;
+ char* flash_name;
+ struct chipc_capabilities *caps;
+
+ flash_name = NULL;
+
+ caps = BHND_CHIPC_GET_CAPABILITIES(parent);
+ if (caps == NULL)
+ return;
+
+ switch (caps->flash_type) {
+ case CHIPC_SFLASH_AT:
+ flash_name = "at45d";
+ break;
+ case CHIPC_SFLASH_ST:
+ flash_name = "mx25l";
+ break;
+ default:
+ return;
+ }
+
+ flashdev = BUS_ADD_CHILD(parent, 0, "spi", -1);
+ if (flashdev == NULL) {
+ BHND_ERROR_DEV(parent, "can't add chipc_spi to ChipCommon");
+ return;
+ }
+
+ err = device_probe_and_attach(flashdev);
+ if (err) {
+ BHND_ERROR_DEV(flashdev, "failed attach chipc_spi: %d", err);
+ return;
+ }
+
+ err = device_get_children(flashdev, &children, &cnt_children);
+ if (err) {
+ BHND_ERROR_DEV(flashdev, "can't get list of children: %d",
+ err);
+ return;
+ }
+
+ if (cnt_children == 0) {
+ BHND_ERROR_DEV(flashdev, "no found children");
+ return;
+ }
+
+ flash = BUS_ADD_CHILD(children[0], 0, flash_name, -1);
+ if (children)
+ free(children, M_TEMP);
+
+ if (flash == NULL) {
+ BHND_ERROR_DEV(children[0], "can't add %s to spibus", flash_name);
+ return;
+ }
+
+ err = device_probe_and_attach(flash);
+ if (err)
+ BHND_ERROR_DEV(flash, "failed attach flash %s: %d",
+ flash_name, err);
+
+ return;
+}
+
+static int
+chipc_spi_probe(device_t dev)
+{
+ device_set_desc(dev, "ChipCommon SPI");
+ return (BUS_PROBE_DEFAULT);
+}
+
+struct resource_spec spec_mem[] = {
+ {SYS_RES_MEMORY, 0, RF_ACTIVE},
+ {SYS_RES_MEMORY, 1, RF_ACTIVE},
+ { -1, -1, 0 }
+ };
+
+static int
+chipc_spi_attach(device_t dev)
+{
+ int err;
+ struct chipc_spi_softc *sc;
+ struct resource *mem[2];
+
+ sc = device_get_softc(dev);
+ err = bus_alloc_resources(dev, spec_mem, mem);
+ if (err != 0)
+ return (ENXIO);
+
+ sc->sc_res = mem[0];
+ sc->sc_mem_res = mem[1];
+
+ flash_register_slicer(chipc_slicer_spi);
+ device_add_child(dev, "spibus", 0);
+ return (bus_generic_attach(dev));
+}
+
+static int
+chipc_spi_wait(struct chipc_spi_softc *sc)
+{
+ int i;
+
+ for (i = CHIPC_SPI_MAXTRIES; i > 0; i--)
+ if (!(SPI_READ(sc, CHIPC_SPI_FLASHCTL) & CHIPC_SPI_FLASHCTL_START))
+ break;
+
+ if (i > 0)
+ return (0);
+
+ BHND_DEBUG_DEV(sc->dev, "busy");
+ return (-1);
+}
+
+static int
+chipc_spi_txrx(struct chipc_spi_softc *sc, uint8_t out, uint8_t* in)
+{
+ uint32_t ctl;
+
+ ctl = CHIPC_SPI_FLASHCTL_START | CHIPC_SPI_FLASHCTL_CSACTIVE | out;
+ SPI_BARRIER_WRITE(sc);
+ SPI_WRITE(sc, CHIPC_SPI_FLASHCTL, ctl);
+ SPI_BARRIER_WRITE(sc);
+
+ if (chipc_spi_wait(sc))
+ return (-1);
+
+ *in = SPI_READ(sc, CHIPC_SPI_FLASHDATA) & 0xff;
+ return (0);
+}
+
+static int
+chipc_spi_transfer(device_t dev, device_t child, struct spi_command *cmd)
+{
+ struct chipc_spi_softc *sc;
+ uint8_t *buf_in;
+ uint8_t *buf_out;
+ int i;
+
+ sc = device_get_softc(dev);
+ KASSERT(cmd->tx_cmd_sz == cmd->rx_cmd_sz,
+ ("TX/RX command sizes should be equal"));
+ KASSERT(cmd->tx_data_sz == cmd->rx_data_sz,
+ ("TX/RX data sizes should be equal"));
+
+ if (cmd->tx_cmd_sz == 0) {
+ BHND_DEBUG_DEV(child, "size of command is ZERO");
+ return (EIO);
+ }
+
+ SPI_BARRIER_WRITE(sc);
+ SPI_WRITE(sc, CHIPC_SPI_FLASHADDR, 0);
+ SPI_BARRIER_WRITE(sc);
+
+ /*
+ * Transfer command
+ */
+ buf_out = (uint8_t *)cmd->tx_cmd;
+ buf_in = (uint8_t *)cmd->rx_cmd;
+ for (i = 0; i < cmd->tx_cmd_sz; i++)
+ if (chipc_spi_txrx(sc, buf_out[i], &(buf_in[i])))
+ return (EIO);
+
+ /*
+ * Receive/transmit data
+ */
+ buf_out = (uint8_t *)cmd->tx_data;
+ buf_in = (uint8_t *)cmd->rx_data;
+ for (i = 0; i < cmd->tx_data_sz; i++)
+ if (chipc_spi_txrx(sc, buf_out[i], &(buf_in[i])))
+ return (EIO);
+
+ /*
+ * Clear CS bit and whole control register
+ */
+ SPI_BARRIER_WRITE(sc);
+ SPI_WRITE(sc, CHIPC_SPI_FLASHCTL, 0);
+ SPI_BARRIER_WRITE(sc);
+
+ return (0);
+}
+
+/*
+ * **************************** METADATA ************************
+ */
+static device_method_t chipc_spi_methods[] = {
+ DEVMETHOD(device_identify, chipc_spi_identify),
+ DEVMETHOD(device_probe, chipc_spi_probe),
+ DEVMETHOD(device_attach, chipc_spi_attach),
+ /* SPI */
+ DEVMETHOD(spibus_transfer, chipc_spi_transfer),
+ DEVMETHOD_END
+};
+
+static driver_t chipc_spi_driver = {
+ "spi",
+ chipc_spi_methods,
+ sizeof(struct chipc_spi_softc),
+};
+
+static devclass_t chipc_spi_devclass;
+
+DRIVER_MODULE(chipc_spi, bhnd_chipc, chipc_spi_driver, chipc_spi_devclass,
+ 0, 0);
Index: sys/dev/bhnd/cores/chipc/chipc_subr.c
===================================================================
--- /dev/null
+++ sys/dev/bhnd/cores/chipc/chipc_subr.c
@@ -0,0 +1,101 @@
+/*-
+ * Copyright (c) 2016 Michael Zhilin <mizhka@gmail.com>
+ * 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$");
+
+#include <sys/param.h>
+#include <sys/errno.h>
+#include <sys/bus.h>
+#include <sys/malloc.h>
+#include <sys/rman.h>
+#include <sys/queue.h>
+
+#include <machine/resource.h>
+#include <dev/bhnd/bhndvar.h>
+#include <dev/bhnd/bhnd_debug.h>
+
+#include "bus_if.h"
+#include "chipc.h"
+#include "chipcvar.h"
+#include "chipcreg.h"
+
+static void chipc_print_capabilities(struct chipc_capabilities* capabilities);
+
+static void
+chipc_print_capabilities(struct chipc_capabilities* capabilities)
+{
+
+ BHND_DEBUG("UARTs: 0x%01x", capabilities->num_uarts);
+ BHND_DEBUG("BigEngian: 0x%01x", capabilities->is_bigend);
+ BHND_DEBUG("UART-GPIO: 0x%01x", capabilities->uart_gpio);
+ BHND_DEBUG("UART Clock: 0x%01x", capabilities->uart_clock);
+ BHND_DEBUG("Flash type: 0x%x", capabilities->flash_type);
+
+ BHND_DEBUG("External buses: 0x%x", capabilities->external_buses);
+ BHND_DEBUG("Power control: 0x%01x", capabilities->power_control);
+ BHND_DEBUG("JTAG master: 0x%01x", capabilities->jtag_master);
+
+ BHND_DEBUG("PLL Type: 0x%x", capabilities->pll_type);
+ BHND_DEBUG("OTP size: 0x%01x", capabilities->otp_size);
+ BHND_DEBUG("Is 64bit? 0x%01x", capabilities->is_64bit);
+ BHND_DEBUG("Boot ROM: 0x%01x", capabilities->boot_rom);
+ BHND_DEBUG("PMU: 0x%01x", capabilities->pmu);
+ BHND_DEBUG("ECI: 0x%01x", capabilities->eci);
+ BHND_DEBUG("SPROM: 0x%01x", capabilities->sprom);
+ BHND_DEBUG("NFLASH: 0x%01x", capabilities->nflash);
+}
+
+void
+chipc_parse_capabilities(struct chipc_capabilities* capabilities,
+ uint32_t caps)
+{
+
+ capabilities->num_uarts = GET_BITS(caps, CHIPC_CAP_UARTS);
+ capabilities->is_bigend = GET_BITS(caps, CHIPC_CAP_MIPSEB);
+ capabilities->uart_gpio = GET_BITS(caps, CHIPC_CAP_UARTGPIO);
+ capabilities->uart_clock= GET_BITS(caps, CHIPC_CAP_UCLKSEL);
+ capabilities->flash_type= GET_BITS(caps, CHIPC_CAP_FLASH);
+
+ capabilities->external_buses = GET_BITS(caps, CHIPC_CAP_EXTBUS);
+ capabilities->power_control = GET_BITS(caps, CHIPC_CAP_PWR_CTL);
+ capabilities->jtag_master = GET_BITS(caps, CHIPC_CAP_JTAGP);
+
+ capabilities->pll_type = GET_BITS(caps, CHIPC_CAP_PLL);
+ capabilities->otp_size = GET_BITS(caps, CHIPC_CAP_OTP_SIZE);
+ capabilities->is_64bit = GET_BITS(caps, CHIPC_CAP_BKPLN64);
+ capabilities->boot_rom = GET_BITS(caps, CHIPC_CAP_ROM);
+ capabilities->pmu = GET_BITS(caps, CHIPC_CAP_PMU);
+ capabilities->eci = GET_BITS(caps, CHIPC_CAP_ECI);
+ capabilities->sprom = GET_BITS(caps, CHIPC_CAP_SPROM);
+ capabilities->nflash = GET_BITS(caps, CHIPC_CAP_NFLASH);
+
+ if(bootverbose)
+ chipc_print_capabilities(capabilities);
+}
Index: sys/dev/bhnd/cores/chipc/chipcreg.h
===================================================================
--- sys/dev/bhnd/cores/chipc/chipcreg.h
+++ sys/dev/bhnd/cores/chipc/chipcreg.h
@@ -25,6 +25,8 @@
#ifndef _BHND_CORES_CHIPC_CHIPCREG_H_
#define _BHND_CORES_CHIPC_CHIPCREG_H_
+#define GET_BITS(value,field) (value & field) >> field##_SHIFT;
+
#define CHIPC_CHIPID_SIZE 0x100 /**< size of the register block
containing the chip
identification registers. */
@@ -46,6 +48,8 @@
#define CHIPC_JTAGIR 0x34
#define CHIPC_JTAGDR 0x38
#define CHIPC_JTAGCTRL 0x3c
+#define CHIPC_FLASHBASE 0x40
+#define CHIPC_FLASHREGSZ 12
#define CHIPC_GPIOPU 0x58
#define CHIPC_GPIOPD 0x5c
#define CHIPC_GPIOIN 0x60
@@ -64,10 +68,14 @@
#define CHIPC_SYS_CLK_CTL 0xc0
#define CHIPC_EROMPTR 0xfc /**< 32-bit EROM base address
* on BCMA devices */
+#define CHIPC_FLASH_CFG 0x128
+#define CHIPC_FLASH_WAIT_CNT 0x12C
#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_UART_BASE 0x300
+#define CHIPC_UART_SIZE 0x100
#define CHIPC_PMU_CTL 0x600
#define CHIPC_PMU_CAP 0x604
#define CHIPC_PMU_ST 0x608
@@ -97,27 +105,43 @@
#define CHIPC_ID_BUS_SHIFT 28
/* capabilities */
-#define CHIPC_CAP_UARTS_MASK 0x00000003 /* Number of UARTs */
-#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_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_FLASH_MASK 0x00000700 /* Type of flash */
-#define CHIPC_CAP_PLL_MASK 0x00038000 /* Type of PLL */
-#define CHIPC_CAP_PWR_CTL 0x00040000 /* Power control */
-#define CHIPC_CAP_OTP_SIZE 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_SPROM 0x40000000 /* SPROM Present, rev >= 32 */
-#define CHIPC_CAP_NFLASH 0x80000000 /* Nand flash present, rev >= 35 */
+#define CHIPC_CAP_UARTS 0x00000003 /* Number of UARTs */
+#define CHIPC_CAP_UARTS_SHIFT 0
+#define CHIPC_CAP_MIPSEB 0x00000004 /* MIPS is in big-endian mode */
+#define CHIPC_CAP_MIPSEB_SHIFT 2
+#define CHIPC_CAP_UCLKSEL 0x00000018 /* UARTs clock select */
+#define CHIPC_CAP_UCLKSEL_SHIFT 3
+#define CHIPC_CAP_UCLKSEL_UINTCLK 0x00000001 /* UARTs are driven by internal divided clock */
+#define CHIPC_CAP_UARTGPIO 0x00000020 /* UARTs own GPIOs 15:12 */
+#define CHIPC_CAP_UARTGPIO_SHIFT 5
+#define CHIPC_CAP_EXTBUS 0x000000c0 /* External bus mask */
+#define CHIPC_CAP_EXTBUS_SHIFT 6
+#define CHIPC_CAP_EXTBUS_NONE 0x00000000 /* No ExtBus present */
+#define CHIPC_CAP_EXTBUS_FULL 0x00000001 /* ExtBus: PCMCIA, IDE & Prog */
+#define CHIPC_CAP_EXTBUS_PROG 0x00000002 /* ExtBus: ProgIf only */
+#define CHIPC_CAP_FLASH 0x00000700 /* Type of flash */
+#define CHIPC_CAP_FLASH_SHIFT 8
+#define CHIPC_CAP_PLL 0x00038000 /* Type of PLL */
+#define CHIPC_CAP_PLL_SHIFT 15
+#define CHIPC_CAP_PWR_CTL 0x00040000 /* Power control */
+#define CHIPC_CAP_PWR_CTL_SHIFT 18
+#define CHIPC_CAP_OTP_SIZE 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_JTAGP_SHIFT 22
+#define CHIPC_CAP_ROM 0x00800000 /* Internal boot rom active */
+#define CHIPC_CAP_ROM_SHIFT 23
+#define CHIPC_CAP_BKPLN64 0x08000000 /* 64-bit backplane */
+#define CHIPC_CAP_BKPLN64_SHIFT 27
+#define CHIPC_CAP_PMU 0x10000000 /* PMU Present, rev >= 20 */
+#define CHIPC_CAP_PMU_SHIFT 28
+#define CHIPC_CAP_ECI 0x20000000 /*Enhanced Coexistence Interface */
+#define CHIPC_CAP_ECI_SHIFT 29
+#define CHIPC_CAP_SPROM 0x40000000 /* SPROM Present, rev >= 32 */
+#define CHIPC_CAP_SPROM_SHIFT 30
+#define CHIPC_CAP_NFLASH 0x80000000 /* Nand flash present, rev >= 35 */
+#define CHIPC_CAP_NFLASH_SHIFT 31
#define CHIPC_CAP2_SECI 0x00000001 /* SECI Present, rev >= 36 */
#define CHIPC_CAP2_GSIO 0x00000002 /* GSIO (spi/i2c) present, rev >= 37 */
@@ -489,10 +513,10 @@
#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 */
+#define CHIPC_FLASH_NONE 0x0 /* No flash */
+#define CHIPC_SFLASH_ST 0x1 /* ST serial flash */
+#define CHIPC_SFLASH_AT 0x2 /* Atmel serial flash */
+#define CHIPC_PFLASH 0x7 /* Parallel flash */
/* Bits in the ExtBus config registers */
#define CHIPC_CFG_EN 0x0001 /* Enable */
Index: sys/dev/bhnd/cores/chipc/chipcvar.h
===================================================================
--- sys/dev/bhnd/cores/chipc/chipcvar.h
+++ sys/dev/bhnd/cores/chipc/chipcvar.h
@@ -32,16 +32,21 @@
#ifndef _BHND_CORES_CHIPC_CHIPCVAR_H_
#define _BHND_CORES_CHIPC_CHIPCVAR_H_
+#include <sys/types.h>
+#include <sys/rman.h>
+#include <dev/bhnd/bhnd.h>
+#include <dev/bhnd/nvram/bhnd_nvram.h>
#include <dev/bhnd/nvram/bhnd_spromvar.h>
-#include "chipc.h"
-
DECLARE_CLASS(bhnd_chipc);
extern devclass_t bhnd_chipc_devclass;
#define CHIPC_MAX_RES 1
#define CHIPC_MAX_RSPEC (CHIPC_MAX_RES+1)
+/* FIXME: MIPS-specific */
+#define NUM_IRQS 6
+
/*
* ChipCommon device quirks / features
*/
@@ -107,6 +112,25 @@
CHIPC_QUIRK_4360_FEM_MUX_SPROM = (1<<5) | CHIPC_QUIRK_MUX_SPROM
};
+struct chipc_capabilities {
+ uint8_t num_uarts;
+ uint8_t is_bigend;
+ uint8_t uart_clock;
+ uint8_t uart_gpio;
+ uint8_t external_buses;
+ uint8_t flash_type;
+ uint8_t pll_type;
+ uint8_t power_control;
+ uint8_t otp_size;
+ uint8_t jtag_master;
+ uint8_t boot_rom;
+ uint8_t is_64bit;
+ uint8_t pmu;
+ uint8_t eci;
+ uint8_t sprom;
+ uint8_t nflash;
+};
+
struct chipc_softc {
device_t dev;
@@ -116,13 +140,34 @@
struct bhnd_resource *core; /**< 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 */
struct mtx mtx; /**< state mutex. */
struct bhnd_sprom sprom; /**< OTP/SPROM shadow, if any */
+ struct chipc_capabilities capabilities;
+
+ struct rman chipc_mem;
+ struct rman chipc_irq;
+};
+
+/*
+ * This is specificaiton of resource assignment for subdevices
+ */
+struct chipc_spec {
+ char *name;
+ int type, rid;
+ int port, reg;
+ rman_res_t start;
+ rman_res_t size;
+};
+
+/*
+ * ChipCommon devinfo is used by subdevices for correct resource assignment
+ */
+struct chipc_devinfo {
+ struct resource_list resources;
};
#define CHIPC_LOCK_INIT(sc) \
@@ -133,4 +178,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_ */

File Metadata

Mime Type
text/plain
Expires
Sat, Feb 21, 2:41 AM (5 h, 20 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28906235
Default Alt Text
D6250.id16411.diff (50 KB)

Event Timeline