Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F145451858
D6250.id16411.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
50 KB
Referenced Files
None
Subscribers
None
D6250.id16411.diff
View Options
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, ®ion_start, ®ion_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
Details
Attached
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)
Attached To
Mode
D6250: [BHND] ChipCommon: Resource managers, Serial & Parallel Flash support,
Attached
Detach File
Event Timeline
Log In to Comment