Index: head/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m =================================================================== --- head/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m +++ head/sys/dev/bhnd/cores/chipc/bhnd_chipc_if.m @@ -28,7 +28,6 @@ #include #include -#include INTERFACE bhnd_chipc; @@ -37,6 +36,7 @@ # HEADER { + #include /* forward declarations */ struct chipc_caps; struct chipc_caps *bhnd_chipc_generic_get_caps(device_t dev); @@ -123,3 +123,12 @@ METHOD void disable_sprom { 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; +} Index: head/sys/dev/bhnd/cores/chipc/chipc.c =================================================================== --- head/sys/dev/bhnd/cores/chipc/chipc.c +++ head/sys/dev/bhnd/cores/chipc/chipc.c @@ -39,19 +39,36 @@ * 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 memory resource management for ChipCommon drivers + * like UART, PMU, flash. ChipCommon core has several memory regions. + * + * ChipCommon driver has memory resource manager. Driver + * gets information about BHND core ports/regions and map them + * into drivers' resources. + * + * Here is overview of mapping: + * + * ------------------------------------------------------ + * | Port.Region| Purpose | + * ------------------------------------------------------ + * | 0.0 | PMU, SPI(0x40), UART(0x300) | + * | 1.0 | ? | + * | 1.1 | MMIO flash (SPI & CFI) | + * ------------------------------------------------------ */ #include #include #include #include +#include #include #include #include #include #include -#include #include #include @@ -99,6 +116,18 @@ }; +/* + * Here is resource configuration hints 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. + */ + static const struct chipc_hint { const char *name; int unit; @@ -1288,6 +1317,15 @@ return (&sc->caps); } +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)); +} + static device_method_t chipc_methods[] = { /* Device interface */ DEVMETHOD(device_probe, chipc_probe), @@ -1330,11 +1368,13 @@ DEVMETHOD(bhnd_chipc_enable_sprom, chipc_enable_sprom_pins), DEVMETHOD(bhnd_chipc_disable_sprom, chipc_disable_sprom_pins), DEVMETHOD(bhnd_chipc_get_caps, chipc_get_caps), + DEVMETHOD(bhnd_chipc_get_flash_cfg, chipc_get_flash_cfg), 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: head/sys/dev/bhnd/cores/chipc/chipc_cfi.c =================================================================== --- head/sys/dev/bhnd/cores/chipc/chipc_cfi.c +++ head/sys/dev/bhnd/cores/chipc/chipc_cfi.c @@ -0,0 +1,141 @@ +/*- + * 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 + +#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_caps *caps; + + if (device_find_child(parent, cfi_driver_name, -1) != NULL) + return; + + caps = BHND_CHIPC_GET_CAPS(parent); + if (caps == NULL) + return; + + if (caps->flash_type != CHIPC_PFLASH_CFI) + return; + + BUS_ADD_CHILD(parent, 0, cfi_driver_name, -1); + return; +} + +static int +chipc_cfi_probe(device_t dev) +{ + int error; + 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)); + + 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 enabled=%d swapbytes=%d", + enabled, byteswap); + + sc->sc_width = 0; + 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: head/sys/dev/bhnd/cores/chipc/chipc_slicer.h =================================================================== --- head/sys/dev/bhnd/cores/chipc/chipc_slicer.h +++ head/sys/dev/bhnd/cores/chipc/chipc_slicer.h @@ -0,0 +1,46 @@ +/*- + * 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_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: head/sys/dev/bhnd/cores/chipc/chipc_slicer.c =================================================================== --- head/sys/dev/bhnd/cores/chipc/chipc_slicer.c +++ head/sys/dev/bhnd/cores/chipc/chipc_slicer.c @@ -0,0 +1,172 @@ +/*- + * 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 "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; + uint32_t ofs_trx; + int flash_size; + + *nslices = 0; + + flash_size = rman_get_size(res); + ofs_trx = flash_size; + + BHND_TRACE_DEV(dev, "slicer: scanning memory [%x bytes] for headers...", + flash_size); + + /* Find FW header in flash memory with step=128Kb (0x1000) */ + for(uint32_t ofs = 0; ofs < flash_size; ofs+= 0x1000){ + val = bus_read_4(res, ofs); + switch (val) { + case TRX_MAGIC: + /* check for second TRX */ + if (ofs_trx < ofs) { + BHND_TRACE_DEV(dev, "stop on 2nd TRX: %x", ofs); + break; + } + + BHND_TRACE("TRX found: %x", ofs); + ofs_trx = 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: head/sys/dev/bhnd/cores/chipc/chipc_spi.h =================================================================== --- head/sys/dev/bhnd/cores/chipc/chipc_spi.h +++ head/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: head/sys/dev/bhnd/cores/chipc/chipc_spi.c =================================================================== --- head/sys/dev/bhnd/cores/chipc/chipc_spi.c +++ head/sys/dev/bhnd/cores/chipc/chipc_spi.c @@ -0,0 +1,280 @@ +/*- + * 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) +{ + struct chipc_caps *caps; + device_t spidev; + device_t spibus; + device_t flash; + char* flash_name; + int err; + + flash_name = NULL; + + if (device_find_child(parent, "spi", -1) != NULL) + return; + + caps = BHND_CHIPC_GET_CAPS(parent); + if (caps == NULL) { + BHND_ERROR_DEV(parent, "can't retrieve ChipCommon capabilities"); + return; + } + + switch (caps->flash_type) { + case CHIPC_SFLASH_AT: + flash_name = "at45d"; + break; + case CHIPC_SFLASH_ST: + flash_name = "mx25l"; + break; + default: + return; + } + + spidev = BUS_ADD_CHILD(parent, 0, "spi", -1); + if (spidev == NULL) { + BHND_ERROR_DEV(parent, "can't add chipc_spi to ChipCommon"); + return; + } + + err = device_probe_and_attach(spidev); + if (err) { + BHND_ERROR_DEV(spidev, "failed attach chipc_spi: %d", err); + return; + } + + spibus = device_find_child(spidev, "spibus", -1); + if (spibus == NULL) { + BHND_ERROR_DEV(spidev, "can't find spibus under chipc_spi"); + return; + } + + flash = BUS_ADD_CHILD(spibus, 0, flash_name, -1); + if (flash == NULL) { + BHND_ERROR_DEV(spibus, "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: head/sys/mips/broadcom/uart_bus_chipc.c =================================================================== --- head/sys/mips/broadcom/uart_bus_chipc.c +++ head/sys/mips/broadcom/uart_bus_chipc.c @@ -45,9 +45,12 @@ #include #include +#include + #include "uart_if.h" #include "bhnd_chipc_if.h" + static int uart_chipc_probe(device_t dev); extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs; @@ -55,9 +58,18 @@ static void uart_chipc_identify(driver_t *driver, device_t parent) { - struct chipc_capabilities *caps; + struct chipc_caps *caps; - caps = BHND_CHIPC_GET_CAPABILITIES(parent); + if (device_find_child(parent, "uart", -1) != NULL) + return; + + caps = BHND_CHIPC_GET_CAPS(parent); + + if (caps == NULL) { + device_printf(parent, "error: can't retrieve ChipCommon " + "capabilities\n"); + return; + } if (caps->num_uarts == 0) return; @@ -74,6 +86,7 @@ struct uart_softc *sc; struct resource *res; int rid; + int err; rid = 0; res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); @@ -97,7 +110,11 @@ sc->sc_bas.bst = sc->sc_sysdev->bas.bst; sc->sc_bas.bsh = sc->sc_sysdev->bas.bsh; - bus_release_resource(dev, SYS_RES_MEMORY, rid, res); + err = bus_release_resource(dev, SYS_RES_MEMORY, rid, res); + if (err) { + device_printf(dev, "can't release resource [%d]\n", rid); + return (ENXIO); + } /* We use internal SoC clock generator with non-standart freq MHz */ return (uart_bus_probe(dev, 0, sc->sc_sysdev->bas.rclk, 0, 0));