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 #include -#include + +# +# Header includes used struct declarations +# +HEADER { + #include + #include +} 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 #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 @@ -45,15 +64,18 @@ #include #include #include +#include +#include #include -#include #include #include +#include #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 + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#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 + * 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 + +#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 + * 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 +__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 +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + +#include "chipc_slicer.h" + +#include +#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 + * 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 + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +/* + * SPI BUS interface + */ +#include + +#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 + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#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 +#include +#include +#include #include -#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_ */