1/*- 2 * Copyright (c) 2016, Hiroki Mori 3 * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice unmodified, this list of conditions, and the following 11 * disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> 30__FBSDID("$FreeBSD$"); 31 32#include <sys/param.h> 33#include <sys/systm.h> 34 35#include <sys/bus.h> 36#include <sys/interrupt.h> 37#include <sys/malloc.h> 38#include <sys/kernel.h> 39#include <sys/module.h> 40#include <sys/rman.h> 41#include <sys/sysctl.h> 42 43#include <vm/vm.h> 44#include <vm/pmap.h> 45#include <vm/vm_extern.h> 46 47#include <machine/bus.h> 48#include <machine/cpu.h> 49#include <machine/pmap.h> 50 51#include <dev/spibus/spi.h> 52#include <dev/spibus/spibusvar.h> 53#include "spibus_if.h" 54 55#include <mips/atheros/ar531x/arspireg.h> 56#include <mips/atheros/ar531x/ar5315reg.h> 57 58#undef AR531X_SPI_DEBUG 59#ifdef AR531X_SPI_DEBUG 60#define dprintf printf 61#else 62#define dprintf(x, arg...) 63#endif 64 65/* 66 * register space access macros 67 */ 68#define SPI_WRITE(sc, reg, val) do { \ 69 bus_write_4(sc->sc_mem_res, (reg), (val)); \ 70 } while (0) 71 72#define SPI_READ(sc, reg) bus_read_4(sc->sc_mem_res, (reg)) 73 74#define SPI_SET_BITS(sc, reg, bits) \ 75 SPI_WRITE(sc, reg, SPI_READ(sc, (reg)) | (bits)) 76 77#define SPI_CLEAR_BITS(sc, reg, bits) \ 78 SPI_WRITE(sc, reg, SPI_READ(sc, (reg)) & ~(bits)) 79 80struct ar5315_spi_softc { 81 device_t sc_dev; 82 struct resource *sc_mem_res; 83 uint32_t sc_reg_ctrl; 84 uint32_t sc_debug; 85}; 86 87static void 88ar5315_spi_attach_sysctl(device_t dev) 89{ 90 struct ar5315_spi_softc *sc; 91 struct sysctl_ctx_list *ctx; 92 struct sysctl_oid *tree; 93 94 sc = device_get_softc(dev); 95 ctx = device_get_sysctl_ctx(dev); 96 tree = device_get_sysctl_tree(dev); 97 98 SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, 99 "debug", CTLFLAG_RW, &sc->sc_debug, 0, 100 "ar5315_spi debugging flags"); 101} 102 103static int 104ar5315_spi_probe(device_t dev) 105{ 106 device_set_desc(dev, "AR5315 SPI"); 107 return (0); 108} 109 110static int 111ar5315_spi_attach(device_t dev) 112{ 113 struct ar5315_spi_softc *sc = device_get_softc(dev); 114 int rid; 115 116 sc->sc_dev = dev; 117 rid = 0; 118 sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 119 RF_ACTIVE); 120 if (!sc->sc_mem_res) { 121 device_printf(dev, "Could not map memory\n"); 122 return (ENXIO); 123 } 124 125 device_add_child(dev, "spibus", -1); 126 ar5315_spi_attach_sysctl(dev); 127 128 return (bus_generic_attach(dev)); 129} 130 131static void 132ar5315_spi_chip_activate(struct ar5315_spi_softc *sc, int cs) 133{ 134} 135 136static void 137ar5315_spi_chip_deactivate(struct ar5315_spi_softc *sc, int cs) 138{ 139} 140 141static int 142ar5315_spi_get_block(off_t offset, caddr_t data, off_t count) 143{ 144 int i; 145 for(i = 0; i < count / 4; ++i) { 146 *((uint32_t *)data + i) = ATH_READ_REG(AR5315_MEM1_BASE + offset + i * 4); 147 } 148// printf("ar5315_spi_get_blockr: %x %x %x\n", 149// (int)offset, (int)count, *(uint32_t *)data); 150 return (0); 151} 152 153static int 154ar5315_spi_transfer(device_t dev, device_t child, struct spi_command *cmd) 155{ 156 struct ar5315_spi_softc *sc; 157 uint8_t *buf_in, *buf_out; 158 int lin, lout; 159 uint32_t ctl, cnt, op, rdat, cs; 160 int i, j; 161 162 sc = device_get_softc(dev); 163 164 if (sc->sc_debug & 0x8000) 165 printf("ar5315_spi_transfer: CMD "); 166 167 spibus_get_cs(child, &cs); 168 169 cs &= ~SPIBUS_CS_HIGH; 170 171 /* Open SPI controller interface */ 172 ar5315_spi_chip_activate(sc, cs); 173 174 do { 175 ctl = SPI_READ(sc, ARSPI_REG_CTL); 176 } while (ctl & ARSPI_CTL_BUSY); 177 178 /* 179 * Transfer command 180 */ 181 buf_out = (uint8_t *)cmd->tx_cmd; 182 op = buf_out[0]; 183 if(op == 0x0b) { 184 int offset = buf_out[1] << 16 | buf_out[2] << 8 | buf_out[3]; 185 ar5315_spi_get_block(offset, cmd->rx_data, cmd->rx_data_sz); 186 return (0); 187 } 188 do { 189 ctl = SPI_READ(sc, ARSPI_REG_CTL); 190 } while (ctl & ARSPI_CTL_BUSY); 191 if (sc->sc_debug & 0x8000) { 192 printf("%08x ", op); 193 printf("tx_cmd_sz=%d rx_cmd_sz=%d ", cmd->tx_cmd_sz, 194 cmd->rx_cmd_sz); 195 if(cmd->tx_cmd_sz != 1) { 196 printf("%08x ", *((uint32_t *)cmd->tx_cmd)); 197 printf("%08x ", *((uint32_t *)cmd->tx_cmd + 1)); 198 } 199 } 200 SPI_WRITE(sc, ARSPI_REG_OPCODE, op); 201 202 /* clear all of the tx and rx bits */ 203 ctl &= ~(ARSPI_CTL_TXCNT_MASK | ARSPI_CTL_RXCNT_MASK); 204 205 /* now set txcnt */ 206 cnt = 1; 207 208 ctl |= (cnt << ARSPI_CTL_TXCNT_SHIFT); 209 210 cnt = 24; 211 /* now set txcnt */ 212 if(cmd->rx_cmd_sz < 24) 213 cnt = cmd->rx_cmd_sz; 214 ctl |= (cnt << ARSPI_CTL_RXCNT_SHIFT); 215 216 ctl |= ARSPI_CTL_START; 217 218 SPI_WRITE(sc, ARSPI_REG_CTL, ctl); 219 220 if(op == 0x0b) 221 SPI_WRITE(sc, ARSPI_REG_DATA, 0); 222 if (sc->sc_debug & 0x8000) 223 printf("\nDATA "); 224 /* 225 * Receive/transmit data (depends on command) 226 */ 227// buf_out = (uint8_t *)cmd->tx_data; 228 buf_in = (uint8_t *)cmd->rx_cmd; 229// lout = cmd->tx_data_sz; 230 lin = cmd->rx_cmd_sz; 231 if (sc->sc_debug & 0x8000) 232 printf("t%d r%d ", lout, lin); 233 for(i = 0; i <= (cnt - 1) / 4; ++i) { 234 do { 235 ctl = SPI_READ(sc, ARSPI_REG_CTL); 236 } while (ctl & ARSPI_CTL_BUSY); 237 238 rdat = SPI_READ(sc, ARSPI_REG_DATA); 239 if (sc->sc_debug & 0x8000) 240 printf("I%08x ", rdat); 241 242 for(j = 0; j < 4; ++j) { 243 buf_in[i * 4 + j + 1] = 0xff & (rdat >> (8 * j)); 244 if(i * 4 + j + 2 == cnt) 245 break; 246 } 247 } 248 249 ar5315_spi_chip_deactivate(sc, cs); 250 /* 251 * Close SPI controller interface, restore flash memory mapped access. 252 */ 253 if (sc->sc_debug & 0x8000) 254 printf("\n"); 255 256 return (0); 257} 258 259static int 260ar5315_spi_detach(device_t dev) 261{ 262 struct ar5315_spi_softc *sc = device_get_softc(dev); 263 264 if (sc->sc_mem_res) 265 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res); 266 267 return (0); 268} 269 270static device_method_t ar5315_spi_methods[] = { 271 /* Device interface */ 272 DEVMETHOD(device_probe, ar5315_spi_probe), 273 DEVMETHOD(device_attach, ar5315_spi_attach), 274 DEVMETHOD(device_detach, ar5315_spi_detach), 275 276 DEVMETHOD(spibus_transfer, ar5315_spi_transfer), 277// DEVMETHOD(spibus_get_block, ar5315_spi_get_block), 278 279 DEVMETHOD_END 280}; 281 282static driver_t ar5315_spi_driver = { 283 "spi", 284 ar5315_spi_methods, 285 sizeof(struct ar5315_spi_softc), 286}; 287 288static devclass_t ar5315_spi_devclass; 289 290DRIVER_MODULE(ar5315_spi, nexus, ar5315_spi_driver, ar5315_spi_devclass, 0, 0); 291