Index: sys/dev/bhnd/cores/chipc/chipc.h =================================================================== --- sys/dev/bhnd/cores/chipc/chipc.h +++ sys/dev/bhnd/cores/chipc/chipc.h @@ -34,8 +34,10 @@ #include #include +#include #include "bhnd_chipc_if.h" +#include "chipcvar.h" /** * Query a ChipCommon device and return the preferred NVRAM data source. @@ -48,4 +50,11 @@ return (BHND_CHIPC_NVRAM_SRC(dev)); } -#endif /* _BHND_CORES_CHIPC_CHIPC_H_ */ \ No newline at end of file +int chipc_init_pflash(device_t dev, uint32_t flash_config); +int chipc_init_sflash(device_t dev, char* flash_name); +int chipc_init_uarts(struct chipc_softc* sc, uint8_t num_uarts); +int chipc_init_bus(device_t dev); +void chipc_parse_capabilities(struct chipc_capabilities* capabilities, + u_int32_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 @@ -52,6 +52,7 @@ #include +#include "chipc.h" #include "chipcreg.h" #include "chipcvar.h" @@ -114,6 +115,7 @@ uint32_t ccid_reg; uint8_t chip_type; int error; + uint8_t uart_cnt; sc = device_get_softc(dev); sc->dev = dev; @@ -152,6 +154,8 @@ sc->caps = bhnd_bus_read_4(sc->core, CHIPC_CAPABILITIES); sc->cst = bhnd_bus_read_4(sc->core, CHIPC_CHIPST); + chipc_parse_capabilities(&sc->capabilities, sc->caps); + // TODO switch (bhnd_chipc_nvram_src(dev)) { case BHND_NVRAM_SRC_CIS: @@ -171,6 +175,48 @@ break; } + error = chipc_init_bus(dev); + if (error != 0) { + device_printf(dev,"init_bus with: %d\n", error); + goto cleanup; + } + + switch(sc->capabilities.flash_type){ + case CHIPC_PFLASH: + /* Parallel flash */ + sc->flash_cfg = bhnd_bus_read_4(sc->core, CHIPC_FLASH_CFG); + error = chipc_init_pflash(sc->bus, sc->flash_cfg); + break; + case CHIPC_SFLASH_AT: + /* Serial flash at45d */ + error = chipc_init_sflash(sc->bus, "at45d"); //not tested yet + break; + case CHIPC_SFLASH_ST: + /* Serial flash mx25l */ + error = chipc_init_sflash(sc->bus, "mx25l"); + break; + default: + if (bootverbose) + device_printf(dev, "no flash found\n"); + } + + if (error != 0) { + device_printf(dev,"init_flash_failed with: %d\n", error); + goto cleanup; + } + + uart_cnt = sc->capabilities.num_uarts; + if (uart_cnt > 0 && (error = chipc_init_uarts(sc, uart_cnt)) > 0){ + device_printf(dev,"init_uarts 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: @@ -297,7 +343,17 @@ DEVMETHOD(device_detach, chipc_detach), DEVMETHOD(device_suspend, chipc_suspend), DEVMETHOD(device_resume, chipc_resume), - + + /* Bus interface */ + 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), + /* ChipCommon interface */ DEVMETHOD(bhnd_chipc_nvram_src, chipc_nvram_src), Index: sys/dev/bhnd/cores/chipc/chipc_cfi.c =================================================================== --- /dev/null +++ sys/dev/bhnd/cores/chipc/chipc_cfi.c @@ -0,0 +1,88 @@ +/*- + * 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 "chipc_slicer.h" + +static int +chipc_cfi_probe(device_t dev) +{ + int error; + struct cfi_softc *sc; + + sc = device_get_softc(dev); + sc->sc_width = 2; + error = cfi_probe(dev); + if (!error) + 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_flash); + return (0); +} + +static device_method_t chipc_cfi_methods[] = { + /* device interface */ + 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_chipcbus, 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,38 @@ +/*- + * 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 + +int chipc_slicer_flash(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,159 @@ +/*- + * 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 + +#include "chipc_spi.h" +#include "flash_if.h" + +#define TRX_MAGIC 0x30524448 +#define CFE_MAGIC 0x43464531 +#define NVRAM_MAGIC 0x48534C46 + + +static int chipc_slicer_walk(struct resource* res, int flash_size, + struct flash_slice *slices, int *nslices); +int chipc_slicer_flash(device_t dev, struct flash_slice *slices, + int *nslices); + +/* + * 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) + */ +int +chipc_slicer_flash(device_t dev, struct flash_slice *slices, int *nslices) +{ + struct resource *res; + int flash_size; + const char *devclazz; + + devclazz = device_get_name(dev); + BHND_INFO_DEV(dev, "start flash slicer for class %s", devclazz); + if (strcmp(devclazz, "mx25l") == 0) { //SPI + /* flash(mx25l) <- spibus <- chipc_spi */ + device_t spibus; + device_t chipc_spi; + struct chipc_spi_softc *sc; + + spibus = device_get_parent(dev); + chipc_spi = device_get_parent(spibus); + sc = device_get_softc(chipc_spi); + + flash_size = FLASH_GET_SIZE(dev); + res = sc->sc_res; + } else if(strcmp(devclazz, "cfi") == 0) { + /* cfi */ + struct cfi_softc *sc = device_get_softc(dev); + flash_size = sc->sc_size; + res = sc->sc_res; + }else { + /* Unsupported case */ + BHND_ERROR_DEV(dev, "ChipCommon Flash slicer: " + "unsupported flash device class: %s", devclazz); + return (0); + } + + /* + * Main processing part + */ + return (chipc_slicer_walk(res,flash_size,slices,nslices)); +} + +static int +chipc_slicer_walk(struct resource* res, int flash_size, + struct flash_slice *slices, int *nslices) +{ + uint32_t fw_len; + uint32_t fs_ofs; + uint32_t val; + + *nslices = 0; + BHND_TRACE("slicer: scanning memory for headers..."); + + /* + * Find FW header in flash memory with step = 0x1000 + * (or 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_DEBUG("TRX found: %x", ofs); + /* read last offset of TRX header */ + fs_ofs = bus_read_4(res, ofs + 24); + BHND_DEBUG("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 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_DEBUG("CFE found: %x", ofs); + break; + case NVRAM_MAGIC: + BHND_DEBUG("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,100 @@ +/*- + * 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_MAXRES 2 +#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; + struct bhnd_resource *bhnd_res[CHIPC_SPI_MAXRES]; + + /* SPI registers */ + int sc_mem_rid; + struct resource *sc_mem_res; + + /* MMIO flash */ + struct resource *sc_res; + bus_space_handle_t sc_handle; + bus_space_tag_t sc_tag; + int sc_rid; +}; + +/* 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,214 @@ +/*- + * 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 "flash_if.h" + +#include "chipcreg.h" +#include "chipcvar.h" +#include "chipc_spi.h" + +/* + * Flash slicer + */ +#include "chipc_slicer.h" + +/* + * **************************** PROTOTYPES **************************** + */ + +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 int +chipc_spi_probe(device_t dev) +{ + device_set_desc(dev, "ChipCommon SPI"); + return (BUS_PROBE_DEFAULT); +} + +static int +chipc_spi_attach(device_t dev) +{ + struct chipc_spi_softc* sc; + + sc = device_get_softc(dev); + sc->sc_rid = 0; + sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rid, + RF_ACTIVE); + if (sc->sc_res == NULL) + return (ENXIO); + + sc->sc_mem_rid = 1; + sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_mem_rid, + RF_ACTIVE); + if (sc->sc_mem_res == NULL) + return (ENXIO); + + sc->sc_tag = rman_get_bustag(sc->sc_res); + sc->sc_handle = rman_get_bushandle(sc->sc_res); + + flash_register_slicer(chipc_slicer_flash); + 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_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_chipcbus, 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,271 @@ +/*- + * 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" +#include "chipcbus.h" + +static void chipc_print_capabilities(struct chipc_capabilities* capabilities); + +int +chipc_init_bus(device_t dev) +{ + int err; + int ret; + struct chipcbus_ivar *ivar; + struct chipcbus_reg *reg; + struct chipc_softc *sc; + bhnd_addr_t rg_start; + bhnd_size_t rg_size; + device_t bus; + + bus = device_add_child(dev,"bhnd_chipcbus",-1); + if (bus == NULL) { + BHND_ERROR_DEV(dev, "error occurred during adding " + "ChipCommon bus"); + return (ENXIO); + } + + ivar = malloc(sizeof(struct chipcbus_ivar), M_BHND, M_NOWAIT); + if (ivar == NULL) { + BHND_ERROR_DEV(dev, "can't allocate memory for chipcbus_ivar"); + return (ENOMEM); + } + + device_set_ivars(bus, ivar); + + sc = device_get_softc(dev); + sc->bus = bus; + + SLIST_INIT(&ivar->mems); + SLIST_INIT(&ivar->irqs); + + /* Iterate over device ports & regions and fill instance variable */ + for(int i = 0; i < bhnd_get_port_count(dev, BHND_PORT_DEVICE); i++){ + int 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++){ + ret = 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, ret); + if (ret == 0) { + reg = malloc(sizeof(struct chipcbus_reg), + M_BHND, M_NOWAIT); + if (reg == NULL) { + return (ENOMEM); + } + reg->start = rg_start; + reg->end = rg_start + rg_size - 1; + reg->port = i; + reg->reg = j; + SLIST_INSERT_HEAD(&ivar->mems, reg, entries); + } + } + } + + err = device_probe_and_attach(bus); + if (err) + BHND_ERROR_DEV(bus, "ChipCommon bus probing and attaching " + " failed with error: %d", err); + + return (err); +} + +int +chipc_init_pflash(device_t dev, uint32_t flash_config) +{ + //TODO: pass parameters to CFI + int width; + int enabled; + int byteswap; + int err; + device_t flashdev; + + width = (flash_config & CHIPC_CF_DS) ? 2 : 1; + enabled = (flash_config & CHIPC_CF_EN); + byteswap = (flash_config & CHIPC_CF_BS); + + BHND_DEBUG_DEV(dev, "trying attach flash " + "width=%d enabled=%d swapbytes=%d", + width, enabled, byteswap); + flashdev = device_add_child(dev, "cfi", -1); + if (flashdev == NULL) { + BHND_ERROR_DEV(dev, "can't add Parallel Flash to " + "ChipCommon bus"); + return (ENXIO); + } + + err = device_probe_and_attach(flashdev); + if (err) + BHND_ERROR_DEV(dev, "failed attach parallel flash: %d", err); + + return (err); +} + +int +chipc_init_sflash(device_t dev, char* flash_name) +{ + device_t chipc_spi; + device_t *children; + device_t flash; + int cnt_children; + int err; + + chipc_spi = device_add_child(dev, "spi", -1); + if (chipc_spi == NULL) { + BHND_ERROR_DEV(dev, "can't add chipc_spi to ChipCommon"); + return (ENXIO); + } + + err = device_probe_and_attach(chipc_spi); + if (err) { + BHND_ERROR_DEV(dev, "failed attach chipc_spi: %d", err); + return (err); + } + + err = device_get_children(chipc_spi, &children, &cnt_children); + if (err) { + BHND_ERROR_DEV(chipc_spi, "can't get list of children: %d", + err); + return (err); + } + + if (cnt_children == 0) { + BHND_ERROR_DEV(chipc_spi, "no found children"); + return (ENXIO); + } + + flash = BUS_ADD_CHILD(children[0], 0, flash_name, -1); + if (children) + free(children, M_TEMP); + + if (flash == NULL) { + BHND_ERROR_DEV(chipc_spi, "can't add %s to spibus", flash_name); + return (ENXIO); + } + + err = device_probe_and_attach(flash); + if (err) + BHND_ERROR_DEV(dev, "failed attach flash %s: %d", + flash_name, err); + + return (err); +} + +int +chipc_init_uarts(struct chipc_softc* sc, uint8_t num_uarts) +{ + device_t child; + int err; + + if (num_uarts < 0) + return (EINVAL); + else if (num_uarts == 0) + return (0); + + child = device_add_child(sc->bus, "uart", 0); + if (child == NULL) { + BHND_ERROR_DEV(sc->bus, "can'd add UART to bus"); + return (ENXIO); + } + + err = device_probe_and_attach(child); + if (err) + BHND_ERROR_DEV(child, "error occurred on probe_and_attach: %d", + err); + + return (err); +} + +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); +} + +void +chipc_parse_capabilities(struct chipc_capabilities* capabilities, + u_int32_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); + + if(bootverbose) + chipc_print_capabilities(capabilities); +} Index: sys/dev/bhnd/cores/chipc/chipcbus.h =================================================================== --- /dev/null +++ sys/dev/bhnd/cores/chipc/chipcbus.h @@ -0,0 +1,65 @@ +/*- + * 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_CHIPCBUS_H_ +#define _BHND_CORES_CHIPC_CHIPCBUS_H_ + +#include +#define NUM_IRQS 6 + +struct chipcbus_spec { + char *name; + int type, rid; + int port, reg; + rman_res_t start; + rman_res_t size; +}; + +struct chipcbus_softc { + device_t dev; + struct rman chipc_mem; + struct rman chipc_irq; +}; + +struct chipcbus_reg{ + SLIST_ENTRY(chipcbus_reg) entries; + rman_res_t start, end; + int port, reg; +}; + +struct chipcbus_ivar { + SLIST_HEAD(mem_list, chipcbus_reg) mems; + SLIST_HEAD(irq_list, chipcbus_reg) irqs; +}; + +struct chipcbus_devinfo { + struct resource_list resources; +}; + +#endif /* _BHND_CORES_CHIPC_CHIPCBUS_H_ */ Index: sys/dev/bhnd/cores/chipc/chipcbus.c =================================================================== --- /dev/null +++ sys/dev/bhnd/cores/chipc/chipcbus.c @@ -0,0 +1,431 @@ +/*- + * 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$"); + +/* + * The purpose of ChipCommon BUS is resource management for ChipCommon drivers + * like UART, PMU, flash. ChipCommon core was a lot of resource: + * - several memory regions, + * - one or more IRQ lines. + * To manage / split these resources into resources of drivers this bus + * is introduced. The bus has 2 resource managers. Driver gets information + * about BHND ports/regions and map it into resources for drivers. + * + * 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 +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include "chipcbus.h" +#include "chipcreg.h" + +static struct chipcbus_reg* chipcbus_get_region(device_t bus, + int port, + int regid); +static struct resource_list* chipcbus_get_resource_list(device_t dev, + device_t child); +static struct resource* chipcbus_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 int chipcbus_probe(device_t dev); +static int chipcbus_attach(device_t dev); +static int chipcbus_detach(device_t dev); +static void chipcbus_probe_nomatch(device_t dev, device_t child); +static void chipcbus_set_resources(device_t bus, device_t dev, + struct resource_list* rl); +static int chipcbus_release_resource(device_t bus, device_t child, + int type, int rid, struct resource *r); +void chipcbus_cleanup(device_t dev); + +/* + * There are 2 flash resources: + * - resource ID (rid) = 0. This is memory-mapped flash memory + * - resource ID (rid) = 1. This is memory-mapped flash registers (i.e for SPI) + */ +struct chipcbus_spec 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} +}; + +/* + * 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 + */ +struct chipcbus_reg static_irq = { {NULL}, 2, 2, 0, 0 }; + +static struct chipcbus_reg* +chipcbus_get_region(device_t bus, int port, int regid) +{ + struct chipcbus_ivar *ivar; + struct chipcbus_reg *reg; + + ivar = device_get_ivars(bus); + SLIST_FOREACH(reg, &ivar->mems, entries){ + if (reg->port == port && reg->reg == regid) + return (reg); + } + return (NULL); +} + +static void +chipcbus_set_resources(device_t bus, device_t dev, struct resource_list* rl) +{ + const char *devname; + struct chipcbus_spec *spec; + struct chipcbus_reg *reg; + + int rid; + int type; + rman_res_t offset; + rman_res_t start; + rman_res_t end; + rman_res_t count; + + BHND_DEBUG_DEV(dev, "first time to init resources..."); + + devname = device_get_name(dev); + spec = mem_specs; + for (;spec->name != NULL; spec++) { + if (strcmp(spec->name, devname) != 0) + continue; + + /* name is matched */ + reg = NULL; + type = spec->type; + rid = spec->rid; + + switch (type){ + case SYS_RES_MEMORY: + reg = chipcbus_get_region(bus, spec->port, spec->reg); + break; + case SYS_RES_IRQ: + reg = &static_irq; + break; + default: + break; + } + + if (reg == NULL) { + BHND_WARN_DEV(dev, "region is not found " + "[type %d, rid %d, port.region %d.%d]", + spec->type, spec->rid, spec->port, spec->reg); + continue; + } + + offset = reg->start; + start = MIN(offset + spec->start, reg->end); + end = MIN(offset + spec->start + + MIN(spec->size, reg->end - reg->start + 1) - 1, + reg->end); + count = end - start + 1; + resource_list_add(rl,type, rid, start, end, count); + } +} + +void +chipcbus_cleanup(device_t dev) +{ + struct chipcbus_softc *sc; + sc = device_get_softc(dev); + rman_fini(&sc->chipc_irq); + rman_fini(&sc->chipc_mem); +} + +static int +chipcbus_probe(device_t dev) +{ + device_set_desc(dev, "ChipCommon BUS"); + return (BUS_PROBE_GENERIC); +} + +static int +chipcbus_attach(device_t dev) +{ + int err; + struct chipcbus_softc *sc; + struct chipcbus_ivar *ivar; + struct chipcbus_reg *reg; + + BHND_DEBUG_DEV(dev, "start attaching"); + + 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; + } + + ivar = device_get_ivars(dev); + if (ivar == NULL) { + BHND_INFO_DEV(dev, "no instance variables for chipcommon bus"); + goto out; + } + + SLIST_FOREACH(reg, &ivar->mems, entries) { + err = rman_manage_region(&sc->chipc_mem, reg->start, reg->end); + if (err) { + BHND_ERROR_DEV(dev, "error occurred during " + "rman_manage_region of MEMORY rman with " + "params: 0x%jx - 0x%jx : err = %d" + ,reg->start, reg->end, 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 during " + "rman_manage_region of IRQ rman with " + "params: 0x%d - 0x%d : err = %d" + , 0, NUM_IRQS, err); + goto error; + } + +out: + BHND_DEBUG_DEV(dev, "attached successfully"); + return (0); +error: + BHND_DEBUG_DEV(dev, "attaching finished with error: %d", err); + chipcbus_cleanup(dev); + return (err); +} + +static int +chipcbus_detach(device_t dev) +{ + chipcbus_cleanup(dev); + return (0); +} + +static struct resource_list * +chipcbus_get_resource_list(device_t dev, device_t child) +{ + struct chipcbus_devinfo *dinfo; + + dinfo = device_get_ivars(child); + + /* + * Lazy way of resource assignment + */ + if(dinfo == NULL){ + dinfo = malloc(sizeof(struct chipcbus_devinfo*), M_BHND, + M_NOWAIT); + + if (dinfo == NULL) { + BHND_ERROR_DEV(dev, "can't allocate memory for " + "chipcbus_devinfo of %s", + device_get_nameunit(child)); + return (NULL); + } + + resource_list_init(&(dinfo->resources)); + chipcbus_set_resources(dev, child, &(dinfo->resources)); + device_set_ivars(child, dinfo); + } + + return (&dinfo->resources); +} + +static struct resource * +chipcbus_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 chipcbus_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 = chipcbus_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 +chipcbus_release_resource(device_t bus, 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 void +chipcbus_probe_nomatch(device_t dev, device_t child) +{ + device_printf(dev, "no found driver for %s\n", device_get_name(child)); +} + +static device_method_t chipcbus_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, chipcbus_probe), + DEVMETHOD(device_attach, chipcbus_attach), + DEVMETHOD(device_detach, chipcbus_detach), + + /* Bus interface */ + DEVMETHOD(bus_get_resource_list, chipcbus_get_resource_list), + DEVMETHOD(bus_alloc_resource, chipcbus_alloc_resource), + DEVMETHOD(bus_release_resource, chipcbus_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, chipcbus_probe_nomatch), + + /* + * TODO: Add + * - bus_print_child, + * - bus_{get,set,delete}_resource, + * - bus_hinted_child + */ + DEVMETHOD_END +}; + +devclass_t bhnd_chipcbus_devclass; /* bhnd(4) chipcommon bus device class */ + +DEFINE_CLASS_0(bhnd_chipcbus, chipcbus_driver, chipcbus_methods, + sizeof(struct chipcbus_softc)); + +DRIVER_MODULE(bhnd_chipcbus, bhnd_chipc, chipcbus_driver, + bhnd_chipcbus_devclass, 0, 0); +MODULE_DEPEND(bhnd_chipcbus, bhnd_chipc, 1, 1, 1); +MODULE_VERSION(bhnd_chipcbus, 1); 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. */ @@ -60,6 +62,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 @@ -76,10 +80,14 @@ #define CHIPC_CLKC_M3 0xa0 #define CHIPC_CLKDIV 0xa4 #define CHIPC_SYS_CLK_CTL 0xc0 +#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 @@ -96,27 +104,43 @@ #define CHIPC_SPROM_OTP 0x800 /* SPROM/OTP address space */ /* 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 */ @@ -488,10 +512,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,7 +32,10 @@ #ifndef _BHND_CORES_CHIPC_CHIPCVAR_H_ #define _BHND_CORES_CHIPC_CHIPCVAR_H_ -#include "chipc.h" +#include +#include +#include +#include DECLARE_CLASS(bhnd_chipc); extern devclass_t bhnd_chipc_devclass; @@ -78,8 +81,27 @@ CHIPC_QUIRK_SUPPORTS_NFLASH = (1<<6), }; +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; +}; + struct chipc_softc { device_t dev; + device_t bus; struct resource_spec rspec[CHIPC_MAX_RSPEC]; struct bhnd_resource *res[CHIPC_MAX_RES]; @@ -89,6 +111,8 @@ uint32_t quirks; /**< CHIPC_QUIRK_* quirk flags */ uint32_t caps; /**< CHIPC_CAP_* capability register flags */ uint32_t cst; /**< CHIPC_CST* status register flags */ + uint32_t flash_cfg; /**< CHIPC_FLASH_CFG register data */ + struct chipc_capabilities capabilities; }; -#endif /* _BHND_CORES_CHIPC_CHIPCVAR_H_ */ \ No newline at end of file +#endif /* _BHND_CORES_CHIPC_CHIPCVAR_H_ */