mtk_spi_v1.c revision 310158
1/*- 2 * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org> 3 * Copyright (c) 2011, Aleksandr Rybalko <ray@FreeBSD.org> 4 * Copyright (c) 2013, Alexander A. Mityaev <sansan@adm.ua> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice unmodified, this list of conditions, and the following 12 * disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30#include <sys/cdefs.h> 31__FBSDID("$FreeBSD: stable/11/sys/mips/mediatek/mtk_spi_v1.c 310158 2016-12-16 15:45:09Z manu $"); 32 33#include <sys/param.h> 34#include <sys/systm.h> 35#include <sys/bus.h> 36 37#include <sys/kernel.h> 38#include <sys/module.h> 39#include <sys/rman.h> 40#include <sys/lock.h> 41#include <sys/mutex.h> 42 43#include <machine/bus.h> 44#include <machine/cpu.h> 45 46#include <dev/spibus/spi.h> 47#include <dev/spibus/spibusvar.h> 48#include "spibus_if.h" 49 50#include "opt_platform.h" 51 52#include <dev/ofw/openfirm.h> 53#include <dev/ofw/ofw_bus.h> 54#include <dev/ofw/ofw_bus_subr.h> 55 56#include <mips/mediatek/mtk_spi_v1.h> 57#include <dev/flash/mx25lreg.h> 58 59#undef MTK_SPI_DEBUG 60#ifdef MTK_SPI_DEBUG 61#define dprintf printf 62#else 63#define dprintf(x, arg...) 64#endif 65 66/* 67 * register space access macros 68 */ 69#define SPI_WRITE(sc, reg, val) do { \ 70 bus_write_4(sc->sc_mem_res, (reg), (val)); \ 71 } while (0) 72 73#define SPI_READ(sc, reg) bus_read_4(sc->sc_mem_res, (reg)) 74 75#define SPI_SET_BITS(sc, reg, bits) \ 76 SPI_WRITE(sc, reg, SPI_READ(sc, (reg)) | (bits)) 77 78#define SPI_CLEAR_BITS(sc, reg, bits) \ 79 SPI_WRITE(sc, reg, SPI_READ(sc, (reg)) & ~(bits)) 80 81struct mtk_spi_softc { 82 device_t sc_dev; 83 struct resource *sc_mem_res; 84}; 85 86static int mtk_spi_probe(device_t); 87static int mtk_spi_attach(device_t); 88static int mtk_spi_detach(device_t); 89static int mtk_spi_wait(struct mtk_spi_softc *); 90static void mtk_spi_chip_activate(struct mtk_spi_softc *); 91static void mtk_spi_chip_deactivate(struct mtk_spi_softc *); 92static uint8_t mtk_spi_txrx(struct mtk_spi_softc *, uint8_t *, int); 93static int mtk_spi_transfer(device_t, device_t, struct spi_command *); 94static phandle_t mtk_spi_get_node(device_t, device_t); 95 96static struct ofw_compat_data compat_data[] = { 97 { "ralink,rt2880-spi", 1 }, 98 { "ralink,rt3050-spi", 1 }, 99 { "ralink,rt3352-spi", 1 }, 100 { "ralink,rt3883-spi", 1 }, 101 { "ralink,rt5350-spi", 1 }, 102 { "ralink,mt7620a-spi", 1 }, 103 { NULL, 0 } 104}; 105 106static int 107mtk_spi_probe(device_t dev) 108{ 109 110 if (!ofw_bus_status_okay(dev)) 111 return (ENXIO); 112 113 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 114 return(ENXIO); 115 116 device_set_desc(dev, "MTK SPI Controller (v1)"); 117 118 return (0); 119} 120 121static int 122mtk_spi_attach(device_t dev) 123{ 124 struct mtk_spi_softc *sc = device_get_softc(dev); 125 int rid; 126 127 sc->sc_dev = dev; 128 rid = 0; 129 sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 130 RF_ACTIVE); 131 if (!sc->sc_mem_res) { 132 device_printf(dev, "Could not map memory\n"); 133 return (ENXIO); 134 } 135 136 if (mtk_spi_wait(sc)) { 137 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res); 138 return (EBUSY); 139 } 140 141 SPI_WRITE(sc, MTK_SPICFG, MSBFIRST | SPICLKPOL | TX_ON_CLK_FALL | 142 SPI_CLK_DIV8); /* XXX: make it configurable */ 143 /* 144 * W25Q64CV max 104MHz, bus 120-192 MHz, so divide by 2. 145 * Update: divide by 4, DEV2 to fast for flash. 146 */ 147 148 device_add_child(dev, "spibus", 0); 149 return (bus_generic_attach(dev)); 150} 151 152static int 153mtk_spi_detach(device_t dev) 154{ 155 struct mtk_spi_softc *sc = device_get_softc(dev); 156 157 SPI_SET_BITS(sc, MTK_SPICTL, HIZSMOSI | CS_HIGH); 158 159 if (sc->sc_mem_res) 160 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res); 161 162 return (0); 163} 164 165static void 166mtk_spi_chip_activate(struct mtk_spi_softc *sc) 167{ 168 mtk_spi_wait(sc); 169 /* 170 * Put all CSx to low 171 */ 172 SPI_CLEAR_BITS(sc, MTK_SPICTL, CS_HIGH | HIZSMOSI); 173} 174 175static void 176mtk_spi_chip_deactivate(struct mtk_spi_softc *sc) 177{ 178 mtk_spi_wait(sc); 179 /* 180 * Put all CSx to high 181 */ 182 SPI_SET_BITS(sc, MTK_SPICTL, CS_HIGH | HIZSMOSI); 183} 184 185static int 186mtk_spi_wait(struct mtk_spi_softc *sc) 187{ 188 int i = 1000; 189 190 while (i--) { 191 if (!SPI_READ(sc, MTK_SPIBUSY)) 192 break; 193 } 194 if (i == 0) { 195 printf("busy\n"); 196 return (1); 197 } 198 199 return (0); 200} 201 202static uint8_t 203mtk_spi_txrx(struct mtk_spi_softc *sc, uint8_t *data, int write) 204{ 205 206 if (mtk_spi_wait(sc)) 207 return (EBUSY); 208 209 if (write == MTK_SPI_WRITE) { 210 SPI_WRITE(sc, MTK_SPIDATA, *data); 211 SPI_SET_BITS(sc, MTK_SPICTL, START_WRITE); 212 } else {/* MTK_SPI_READ */ 213 SPI_SET_BITS(sc, MTK_SPICTL, START_READ); 214 if (mtk_spi_wait(sc)) 215 return (EBUSY); 216 217 *data = SPI_READ(sc, MTK_SPIDATA) & 0xff; 218 } 219 return (0); 220} 221 222static int 223mtk_spi_transfer(device_t dev, device_t child, struct spi_command *cmd) 224{ 225 struct mtk_spi_softc *sc; 226 uint8_t *buf, byte, *tx_buf; 227 uint32_t cs; 228 int i, sz, error = 0, write = 0; 229 230 sc = device_get_softc(dev); 231 232 spibus_get_cs(child, &cs); 233 234 if (cs != 0) 235 /* Only 1 CS */ 236 return (ENXIO); 237 238 /* There is always a command to transfer. */ 239 tx_buf = (uint8_t *)(cmd->tx_cmd); 240 241 /* Perform some fixup because MTK dont support duplex SPI */ 242 switch(tx_buf[0]) { 243 case CMD_READ_IDENT: 244 cmd->tx_cmd_sz = 1; 245 cmd->rx_cmd_sz = 3; 246 break; 247 case CMD_ENTER_4B_MODE: 248 case CMD_EXIT_4B_MODE: 249 case CMD_WRITE_ENABLE: 250 case CMD_WRITE_DISABLE: 251 cmd->tx_cmd_sz = 1; 252 cmd->rx_cmd_sz = 0; 253 break; 254 case CMD_READ_STATUS: 255 cmd->tx_cmd_sz = 1; 256 cmd->rx_cmd_sz = 1; 257 break; 258 case CMD_READ: 259 case CMD_FAST_READ: 260 cmd->rx_cmd_sz = cmd->tx_data_sz = 0; 261 break; 262 case CMD_SECTOR_ERASE: 263 cmd->rx_cmd_sz = 0; 264 break; 265 case CMD_PAGE_PROGRAM: 266 cmd->rx_cmd_sz = cmd->rx_data_sz = 0; 267 break; 268 } 269 270 mtk_spi_chip_activate(sc); 271 272 if (cmd->tx_cmd_sz + cmd->rx_cmd_sz) { 273 buf = (uint8_t *)(cmd->rx_cmd); 274 tx_buf = (uint8_t *)(cmd->tx_cmd); 275 sz = cmd->tx_cmd_sz + cmd->rx_cmd_sz; 276 277 for (i = 0; i < sz; i++) { 278 if(i < cmd->tx_cmd_sz) { 279 byte = tx_buf[i]; 280 error = mtk_spi_txrx(sc, &byte, 281 MTK_SPI_WRITE); 282 if (error) 283 goto mtk_spi_transfer_fail; 284 continue; 285 } 286 error = mtk_spi_txrx(sc, &byte, 287 MTK_SPI_READ); 288 if (error) 289 goto mtk_spi_transfer_fail; 290 buf[i] = byte; 291 } 292 } 293 294 /* 295 * Transfer/Receive data 296 */ 297 298 if (cmd->tx_data_sz + cmd->rx_data_sz) { 299 write = (cmd->tx_data_sz > 0)?1:0; 300 buf = (uint8_t *)(write ? cmd->tx_data : cmd->rx_data); 301 sz = write ? cmd->tx_data_sz : cmd->rx_data_sz; 302 303 for (i = 0; i < sz; i++) { 304 byte = buf[i]; 305 error = mtk_spi_txrx(sc, &byte, 306 write ? MTK_SPI_WRITE : MTK_SPI_READ); 307 if (error) 308 goto mtk_spi_transfer_fail; 309 buf[i] = byte; 310 } 311 } 312mtk_spi_transfer_fail: 313 mtk_spi_chip_deactivate(sc); 314 315 return (error); 316} 317 318static phandle_t 319mtk_spi_get_node(device_t bus, device_t dev) 320{ 321 322 /* We only have one child, the SPI bus, which needs our own node. */ 323 return (ofw_bus_get_node(bus)); 324} 325 326static device_method_t mtk_spi_methods[] = { 327 /* Device interface */ 328 DEVMETHOD(device_probe, mtk_spi_probe), 329 DEVMETHOD(device_attach, mtk_spi_attach), 330 DEVMETHOD(device_detach, mtk_spi_detach), 331 332 DEVMETHOD(spibus_transfer, mtk_spi_transfer), 333 334 /* ofw_bus interface */ 335 DEVMETHOD(ofw_bus_get_node, mtk_spi_get_node), 336 337 DEVMETHOD_END 338}; 339 340static driver_t mtk_spi_driver = { 341 .name = "spi", 342 .methods = mtk_spi_methods, 343 .size = sizeof(struct mtk_spi_softc), 344}; 345 346static devclass_t mtk_spi_devclass; 347 348DRIVER_MODULE(mtk_spi_v1, simplebus, mtk_spi_driver, mtk_spi_devclass, 0, 0); 349