1e72dd8d7SRuslan Bukin /*- 2e72dd8d7SRuslan Bukin * Copyright (c) 2016 Ruslan Bukin <br@bsdpad.com> 3e72dd8d7SRuslan Bukin * All rights reserved. 4e72dd8d7SRuslan Bukin * 5e72dd8d7SRuslan Bukin * Portions of this software were developed by SRI International and the 6e72dd8d7SRuslan Bukin * University of Cambridge Computer Laboratory under DARPA/AFRL contract 7e72dd8d7SRuslan Bukin * FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme. 8e72dd8d7SRuslan Bukin * 9e72dd8d7SRuslan Bukin * Portions of this software were developed by the University of Cambridge 10e72dd8d7SRuslan Bukin * Computer Laboratory as part of the CTSRD Project, with support from the 11e72dd8d7SRuslan Bukin * UK Higher Education Innovation Fund (HEIF). 12e72dd8d7SRuslan Bukin * 13e72dd8d7SRuslan Bukin * Redistribution and use in source and binary forms, with or without 14e72dd8d7SRuslan Bukin * modification, are permitted provided that the following conditions 15e72dd8d7SRuslan Bukin * are met: 16e72dd8d7SRuslan Bukin * 1. Redistributions of source code must retain the above copyright 17e72dd8d7SRuslan Bukin * notice, this list of conditions and the following disclaimer. 18e72dd8d7SRuslan Bukin * 2. Redistributions in binary form must reproduce the above copyright 19e72dd8d7SRuslan Bukin * notice, this list of conditions and the following disclaimer in the 20e72dd8d7SRuslan Bukin * documentation and/or other materials provided with the distribution. 21e72dd8d7SRuslan Bukin * 22e72dd8d7SRuslan Bukin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 23e72dd8d7SRuslan Bukin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24e72dd8d7SRuslan Bukin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25e72dd8d7SRuslan Bukin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 26e72dd8d7SRuslan Bukin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27e72dd8d7SRuslan Bukin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28e72dd8d7SRuslan Bukin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29e72dd8d7SRuslan Bukin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30e72dd8d7SRuslan Bukin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31e72dd8d7SRuslan Bukin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32e72dd8d7SRuslan Bukin * SUCH DAMAGE. 33e72dd8d7SRuslan Bukin */ 34e72dd8d7SRuslan Bukin 35e72dd8d7SRuslan Bukin /* 36e72dd8d7SRuslan Bukin * Xilinx AXI_QUAD_SPI 37e72dd8d7SRuslan Bukin */ 38e72dd8d7SRuslan Bukin 39e72dd8d7SRuslan Bukin #include <sys/param.h> 40e72dd8d7SRuslan Bukin #include <sys/systm.h> 41e72dd8d7SRuslan Bukin #include <sys/bus.h> 42e72dd8d7SRuslan Bukin #include <sys/kernel.h> 43e72dd8d7SRuslan Bukin #include <sys/module.h> 44e72dd8d7SRuslan Bukin #include <sys/malloc.h> 45e72dd8d7SRuslan Bukin #include <sys/rman.h> 46e72dd8d7SRuslan Bukin #include <sys/timeet.h> 47e72dd8d7SRuslan Bukin #include <sys/timetc.h> 48e72dd8d7SRuslan Bukin #include <sys/watchdog.h> 49e72dd8d7SRuslan Bukin 50e72dd8d7SRuslan Bukin #include <dev/spibus/spi.h> 51e72dd8d7SRuslan Bukin #include <dev/spibus/spibusvar.h> 52e72dd8d7SRuslan Bukin 53e72dd8d7SRuslan Bukin #include "spibus_if.h" 54e72dd8d7SRuslan Bukin 55e72dd8d7SRuslan Bukin #include <dev/fdt/fdt_common.h> 56e72dd8d7SRuslan Bukin #include <dev/ofw/openfirm.h> 57e72dd8d7SRuslan Bukin #include <dev/ofw/ofw_bus.h> 58e72dd8d7SRuslan Bukin #include <dev/ofw/ofw_bus_subr.h> 59e72dd8d7SRuslan Bukin 60e72dd8d7SRuslan Bukin #include <machine/bus.h> 61e72dd8d7SRuslan Bukin #include <machine/cpu.h> 62e72dd8d7SRuslan Bukin #include <machine/intr.h> 63e72dd8d7SRuslan Bukin 64e72dd8d7SRuslan Bukin #define READ4(_sc, _reg) \ 65e72dd8d7SRuslan Bukin bus_space_read_4(_sc->bst, _sc->bsh, _reg) 66e72dd8d7SRuslan Bukin #define WRITE4(_sc, _reg, _val) \ 67e72dd8d7SRuslan Bukin bus_space_write_4(_sc->bst, _sc->bsh, _reg, _val) 68e72dd8d7SRuslan Bukin 69e72dd8d7SRuslan Bukin #define SPI_SRR 0x40 /* Software reset register */ 70e72dd8d7SRuslan Bukin #define SRR_RESET 0x0A /* The only reset value */ 71e72dd8d7SRuslan Bukin #define SPI_CR 0x60 /* Control register */ 72e72dd8d7SRuslan Bukin #define CR_LSB_FIRST (1 << 9) /* LSB first */ 73e72dd8d7SRuslan Bukin #define CR_MASTER_TI (1 << 8) /* Master Transaction Inhibit */ 74e72dd8d7SRuslan Bukin #define CR_MSS (1 << 7) /* Manual Slave Select */ 75e72dd8d7SRuslan Bukin #define CR_RST_RX (1 << 6) /* RX FIFO Reset */ 76e72dd8d7SRuslan Bukin #define CR_RST_TX (1 << 5) /* TX FIFO Reset */ 77e72dd8d7SRuslan Bukin #define CR_CPHA (1 << 4) /* Clock phase */ 78e72dd8d7SRuslan Bukin #define CR_CPOL (1 << 3) /* Clock polarity */ 79e72dd8d7SRuslan Bukin #define CR_MASTER (1 << 2) /* Master (SPI master mode) */ 80e72dd8d7SRuslan Bukin #define CR_SPE (1 << 1) /* SPI system enable */ 81e72dd8d7SRuslan Bukin #define CR_LOOP (1 << 0) /* Local loopback mode */ 82e72dd8d7SRuslan Bukin #define SPI_SR 0x64 /* Status register */ 83e72dd8d7SRuslan Bukin #define SR_TX_FULL (1 << 3) /* Transmit full */ 84e72dd8d7SRuslan Bukin #define SR_TX_EMPTY (1 << 2) /* Transmit empty */ 85e72dd8d7SRuslan Bukin #define SR_RX_FULL (1 << 1) /* Receive full */ 86e72dd8d7SRuslan Bukin #define SR_RX_EMPTY (1 << 0) /* Receive empty */ 87e72dd8d7SRuslan Bukin #define SPI_DTR 0x68 /* Data transmit register */ 88e72dd8d7SRuslan Bukin #define SPI_DRR 0x6C /* Data receive register */ 89e72dd8d7SRuslan Bukin #define SPI_SSR 0x70 /* Slave select register */ 90e72dd8d7SRuslan Bukin #define SPI_TFOR 0x74 /* Transmit FIFO Occupancy Register */ 91e72dd8d7SRuslan Bukin #define SPI_RFOR 0x78 /* Receive FIFO Occupancy Register */ 92e72dd8d7SRuslan Bukin #define SPI_DGIER 0x1C /* Device global interrupt enable register */ 93e72dd8d7SRuslan Bukin #define SPI_IPISR 0x20 /* IP interrupt status register */ 94e72dd8d7SRuslan Bukin #define SPI_IPIER 0x28 /* IP interrupt enable register */ 95e72dd8d7SRuslan Bukin 96e72dd8d7SRuslan Bukin struct spi_softc { 97e72dd8d7SRuslan Bukin struct resource *res[1]; 98e72dd8d7SRuslan Bukin bus_space_tag_t bst; 99e72dd8d7SRuslan Bukin bus_space_handle_t bsh; 100e72dd8d7SRuslan Bukin void *ih; 101e72dd8d7SRuslan Bukin }; 102e72dd8d7SRuslan Bukin 103e72dd8d7SRuslan Bukin static struct resource_spec spi_spec[] = { 104e72dd8d7SRuslan Bukin { SYS_RES_MEMORY, 0, RF_ACTIVE }, 105e72dd8d7SRuslan Bukin { -1, 0 } 106e72dd8d7SRuslan Bukin }; 107e72dd8d7SRuslan Bukin 108e72dd8d7SRuslan Bukin static int 109e72dd8d7SRuslan Bukin spi_probe(device_t dev) 110e72dd8d7SRuslan Bukin { 111e72dd8d7SRuslan Bukin 112e72dd8d7SRuslan Bukin if (!ofw_bus_status_okay(dev)) 113e72dd8d7SRuslan Bukin return (ENXIO); 114e72dd8d7SRuslan Bukin 115e72dd8d7SRuslan Bukin if (!ofw_bus_is_compatible(dev, "xlnx,xps-spi-3.2")) 116e72dd8d7SRuslan Bukin return (ENXIO); 117e72dd8d7SRuslan Bukin 118e72dd8d7SRuslan Bukin device_set_desc(dev, "Xilinx Quad SPI"); 119e72dd8d7SRuslan Bukin return (BUS_PROBE_DEFAULT); 120e72dd8d7SRuslan Bukin } 121e72dd8d7SRuslan Bukin 122e72dd8d7SRuslan Bukin static int 123e72dd8d7SRuslan Bukin spi_attach(device_t dev) 124e72dd8d7SRuslan Bukin { 125e72dd8d7SRuslan Bukin struct spi_softc *sc; 126e72dd8d7SRuslan Bukin uint32_t reg; 127e72dd8d7SRuslan Bukin 128e72dd8d7SRuslan Bukin sc = device_get_softc(dev); 129e72dd8d7SRuslan Bukin 130e72dd8d7SRuslan Bukin if (bus_alloc_resources(dev, spi_spec, sc->res)) { 131e72dd8d7SRuslan Bukin device_printf(dev, "could not allocate resources\n"); 132e72dd8d7SRuslan Bukin return (ENXIO); 133e72dd8d7SRuslan Bukin } 134e72dd8d7SRuslan Bukin 135e72dd8d7SRuslan Bukin /* Memory interface */ 136e72dd8d7SRuslan Bukin sc->bst = rman_get_bustag(sc->res[0]); 137e72dd8d7SRuslan Bukin sc->bsh = rman_get_bushandle(sc->res[0]); 138e72dd8d7SRuslan Bukin 139e72dd8d7SRuslan Bukin /* Reset */ 140e72dd8d7SRuslan Bukin WRITE4(sc, SPI_SRR, SRR_RESET); 141e72dd8d7SRuslan Bukin 142e72dd8d7SRuslan Bukin DELAY(1000); 143e72dd8d7SRuslan Bukin 144e72dd8d7SRuslan Bukin reg = (CR_MASTER | CR_MSS | CR_RST_RX | CR_RST_TX); 145e72dd8d7SRuslan Bukin WRITE4(sc, SPI_CR, reg); 146e72dd8d7SRuslan Bukin WRITE4(sc, SPI_DGIER, 0); /* Disable interrupts */ 147e72dd8d7SRuslan Bukin 148e72dd8d7SRuslan Bukin reg = (CR_MASTER | CR_MSS | CR_SPE); 149e72dd8d7SRuslan Bukin WRITE4(sc, SPI_CR, reg); 150e72dd8d7SRuslan Bukin 151e72dd8d7SRuslan Bukin device_add_child(dev, "spibus", 0); 152*18250ec6SJohn Baldwin bus_attach_children(dev); 153*18250ec6SJohn Baldwin return (0); 154e72dd8d7SRuslan Bukin } 155e72dd8d7SRuslan Bukin 156e72dd8d7SRuslan Bukin static int 157e72dd8d7SRuslan Bukin spi_txrx(struct spi_softc *sc, uint8_t *out_buf, 158e72dd8d7SRuslan Bukin uint8_t *in_buf, int bufsz, int cs) 159e72dd8d7SRuslan Bukin { 160e72dd8d7SRuslan Bukin uint32_t data; 161e72dd8d7SRuslan Bukin uint32_t i; 162e72dd8d7SRuslan Bukin 163e72dd8d7SRuslan Bukin for (i = 0; i < bufsz; i++) { 164e72dd8d7SRuslan Bukin WRITE4(sc, SPI_DTR, out_buf[i]); 165e72dd8d7SRuslan Bukin 166e72dd8d7SRuslan Bukin while(!(READ4(sc, SPI_SR) & SR_TX_EMPTY)) 167e72dd8d7SRuslan Bukin continue; 168e72dd8d7SRuslan Bukin 169e72dd8d7SRuslan Bukin data = READ4(sc, SPI_DRR); 170e72dd8d7SRuslan Bukin if (in_buf) 171e72dd8d7SRuslan Bukin in_buf[i] = (data & 0xff); 172e72dd8d7SRuslan Bukin } 173e72dd8d7SRuslan Bukin 174e72dd8d7SRuslan Bukin return (0); 175e72dd8d7SRuslan Bukin } 176e72dd8d7SRuslan Bukin 177e72dd8d7SRuslan Bukin static int 178e72dd8d7SRuslan Bukin spi_transfer(device_t dev, device_t child, struct spi_command *cmd) 179e72dd8d7SRuslan Bukin { 180e72dd8d7SRuslan Bukin struct spi_softc *sc; 181d1bdbe12SRuslan Bukin uint32_t reg; 182e72dd8d7SRuslan Bukin uint32_t cs; 183e72dd8d7SRuslan Bukin 184e72dd8d7SRuslan Bukin sc = device_get_softc(dev); 185e72dd8d7SRuslan Bukin 186e72dd8d7SRuslan Bukin KASSERT(cmd->tx_cmd_sz == cmd->rx_cmd_sz, 187e72dd8d7SRuslan Bukin ("%s: TX/RX command sizes should be equal", __func__)); 188e72dd8d7SRuslan Bukin KASSERT(cmd->tx_data_sz == cmd->rx_data_sz, 189e72dd8d7SRuslan Bukin ("%s: TX/RX data sizes should be equal", __func__)); 190e72dd8d7SRuslan Bukin 191e72dd8d7SRuslan Bukin /* get the proper chip select */ 192e72dd8d7SRuslan Bukin spibus_get_cs(child, &cs); 193e72dd8d7SRuslan Bukin 1947073d12cSEmmanuel Vadot cs &= ~SPIBUS_CS_HIGH; 1957073d12cSEmmanuel Vadot 196d1bdbe12SRuslan Bukin /* Assert CS */ 197d1bdbe12SRuslan Bukin reg = READ4(sc, SPI_SSR); 198d1bdbe12SRuslan Bukin reg &= ~(1 << cs); 199d1bdbe12SRuslan Bukin WRITE4(sc, SPI_SSR, reg); 200d1bdbe12SRuslan Bukin 201e72dd8d7SRuslan Bukin /* Command */ 202e72dd8d7SRuslan Bukin spi_txrx(sc, cmd->tx_cmd, cmd->rx_cmd, cmd->tx_cmd_sz, cs); 203e72dd8d7SRuslan Bukin 204e72dd8d7SRuslan Bukin /* Data */ 205e72dd8d7SRuslan Bukin spi_txrx(sc, cmd->tx_data, cmd->rx_data, cmd->tx_data_sz, cs); 206e72dd8d7SRuslan Bukin 207d1bdbe12SRuslan Bukin /* Deassert CS */ 208d1bdbe12SRuslan Bukin reg = READ4(sc, SPI_SSR); 209d1bdbe12SRuslan Bukin reg |= (1 << cs); 210d1bdbe12SRuslan Bukin WRITE4(sc, SPI_SSR, reg); 211d1bdbe12SRuslan Bukin 212e72dd8d7SRuslan Bukin return (0); 213e72dd8d7SRuslan Bukin } 214e72dd8d7SRuslan Bukin 215e72dd8d7SRuslan Bukin static device_method_t spi_methods[] = { 216e72dd8d7SRuslan Bukin /* Device interface */ 217e72dd8d7SRuslan Bukin DEVMETHOD(device_probe, spi_probe), 218e72dd8d7SRuslan Bukin DEVMETHOD(device_attach, spi_attach), 219e72dd8d7SRuslan Bukin 220e72dd8d7SRuslan Bukin /* SPI interface */ 221e72dd8d7SRuslan Bukin DEVMETHOD(spibus_transfer, spi_transfer), 222e72dd8d7SRuslan Bukin DEVMETHOD_END 223e72dd8d7SRuslan Bukin }; 224e72dd8d7SRuslan Bukin 225e72dd8d7SRuslan Bukin static driver_t spi_driver = { 226e72dd8d7SRuslan Bukin "spi", 227e72dd8d7SRuslan Bukin spi_methods, 228e72dd8d7SRuslan Bukin sizeof(struct spi_softc), 229e72dd8d7SRuslan Bukin }; 230e72dd8d7SRuslan Bukin 23190b8b224SJohn Baldwin DRIVER_MODULE(spi, simplebus, spi_driver, 0, 0); 232