1 /*- 2 * Copyright (c) 2017 Justin Hibbits <jhibbits@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 */ 27 28 #include <sys/param.h> 29 #include <sys/systm.h> 30 #include <sys/bus.h> 31 #include <sys/kernel.h> 32 #include <sys/lock.h> 33 #include <sys/malloc.h> 34 #include <sys/module.h> 35 #include <sys/mutex.h> 36 37 #include <machine/bus.h> 38 39 #include <dev/spibus/spi.h> 40 #include <dev/spibus/spibusvar.h> 41 42 #include <dev/ofw/ofw_bus.h> 43 #include <dev/ofw/ofw_bus_subr.h> 44 45 #include <powerpc/mpc85xx/mpc85xx.h> 46 47 #include "spibus_if.h" 48 49 /* TODO: 50 * 51 * Optimize FIFO reads and writes to do word-at-a-time instead of byte-at-a-time 52 */ 53 #define ESPI_SPMODE 0x0 54 #define ESPI_SPMODE_EN 0x80000000 55 #define ESPI_SPMODE_LOOP 0x40000000 56 #define ESPI_SPMODE_HO_ADJ_M 0x00070000 57 #define ESPI_SPMODE_TXTHR_M 0x00003f00 58 #define ESPI_SPMODE_TXTHR_S 8 59 #define ESPI_SPMODE_RXTHR_M 0x0000001f 60 #define ESPI_SPMODE_RXTHR_S 0 61 #define ESPI_SPIE 0x4 62 #define ESPI_SPIE_RXCNT_M 0x3f000000 63 #define ESPI_SPIE_RXCNT_S 24 64 #define ESPI_SPIE_TXCNT_M 0x003f0000 65 #define ESPI_SPIE_TXCNT_S 16 66 #define ESPI_SPIE_TXE 0x00008000 67 #define ESPI_SPIE_DON 0x00004000 68 #define ESPI_SPIE_RXT 0x00002000 69 #define ESPI_SPIE_RXF 0x00001000 70 #define ESPI_SPIE_TXT 0x00000800 71 #define ESPI_SPIE_RNE 0x00000200 72 #define ESPI_SPIE_TNF 0x00000100 73 #define ESPI_SPIM 0x8 74 #define ESPI_SPCOM 0xc 75 #define ESPI_SPCOM_CS_M 0xc0000000 76 #define ESPI_SPCOM_CS_S 30 77 #define ESPI_SPCOM_RXDELAY 0x20000000 78 #define ESPI_SPCOM_DO 0x10000000 79 #define ESPI_SPCOM_TO 0x08000000 80 #define ESPI_SPCOM_HLD 0x04000000 81 #define ESPI_SPCOM_RXSKIP_M 0x00ff0000 82 #define ESPI_SPCOM_TRANLEN_M 0x0000ffff 83 #define ESPI_SPITF 0x10 84 #define ESPI_SPIRF 0x14 85 #define ESPI_SPMODE0 0x20 86 #define ESPI_SPMODE1 0x24 87 #define ESPI_SPMODE2 0x28 88 #define ESPI_SPMODE3 0x2c 89 #define ESPI_CSMODE_CI 0x80000000 90 #define ESPI_CSMODE_CP 0x40000000 91 #define ESPI_CSMODE_REV 0x20000000 92 #define ESPI_CSMODE_DIV16 0x10000000 93 #define ESPI_CSMODE_PM_M 0x0f000000 94 #define ESPI_CSMODE_PM_S 24 95 #define ESPI_CSMODE_ODD 0x00800000 96 #define ESPI_CSMODE_POL 0x00100000 97 #define ESPI_CSMODE_LEN_M 0x000f0000 98 #define ESPI_CSMODE_LEN(x) (x << 16) 99 #define ESPI_CSMODE_CSBEF_M 0x0000f000 100 #define ESPI_CSMODE_CSAFT_M 0x00000f00 101 #define ESPI_CSMODE_CSCG_M 0x000000f8 102 #define ESPI_CSMODE_CSCG(x) (x << 3) 103 #define ESPI_CSMODE(n) (ESPI_SPMODE0 + n * 4) 104 105 #define FSL_ESPI_WRITE(sc,off,val) bus_write_4(sc->sc_mem_res, off, val) 106 #define FSL_ESPI_READ(sc,off) bus_read_4(sc->sc_mem_res, off) 107 #define FSL_ESPI_WRITE_FIFO(sc,off,val) bus_write_1(sc->sc_mem_res, off, val) 108 #define FSL_ESPI_READ_FIFO(sc,off) bus_read_1(sc->sc_mem_res, off) 109 110 #define FSL_ESPI_LOCK(_sc) \ 111 mtx_lock(&(_sc)->sc_mtx) 112 #define FSL_ESPI_UNLOCK(_sc) \ 113 mtx_unlock(&(_sc)->sc_mtx) 114 115 struct fsl_espi_softc 116 { 117 device_t sc_dev; 118 struct resource *sc_mem_res; 119 struct resource *sc_irq_res; 120 struct mtx sc_mtx; 121 int sc_num_cs; 122 struct spi_command *sc_cmd; 123 uint32_t sc_len; 124 uint32_t sc_read; 125 uint32_t sc_flags; 126 #define FSL_ESPI_BUSY 0x00000001 127 uint32_t sc_written; 128 void * sc_intrhand; 129 }; 130 131 static void fsl_espi_intr(void *); 132 133 static int 134 fsl_espi_probe(device_t dev) 135 { 136 137 if (!ofw_bus_status_okay(dev)) 138 return (ENXIO); 139 140 if (!ofw_bus_is_compatible(dev, "fsl,mpc8536-espi")) 141 return (ENXIO); 142 143 device_set_desc(dev, "Freescale eSPI controller"); 144 145 return (BUS_PROBE_DEFAULT); 146 } 147 148 static int 149 fsl_espi_attach(device_t dev) 150 { 151 struct fsl_espi_softc *sc; 152 int rid; 153 phandle_t node; 154 155 sc = device_get_softc(dev); 156 sc->sc_dev = dev; 157 node = ofw_bus_get_node(dev); 158 159 rid = 0; 160 sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 161 RF_ACTIVE); 162 if (!sc->sc_mem_res) { 163 device_printf(dev, "cannot allocate memory resource\n"); 164 return (ENXIO); 165 } 166 167 rid = 0; 168 sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 169 RF_ACTIVE); 170 if (!sc->sc_irq_res) { 171 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res); 172 device_printf(dev, "cannot allocate interrupt\n"); 173 return (ENXIO); 174 } 175 176 /* Hook up our interrupt handler. */ 177 if (bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE, 178 NULL, fsl_espi_intr, sc, &sc->sc_intrhand)) { 179 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res); 180 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res); 181 device_printf(dev, "cannot setup the interrupt handler\n"); 182 return (ENXIO); 183 } 184 if (OF_getencprop(node, "fsl,espi-num-chipselects", 185 &sc->sc_num_cs, sizeof(sc->sc_num_cs)) < 0 ) 186 sc->sc_num_cs = 4; 187 188 mtx_init(&sc->sc_mtx, "fsl_espi", NULL, MTX_DEF); 189 190 /* Enable the SPI controller. */ 191 FSL_ESPI_WRITE(sc, ESPI_SPMODE, ESPI_SPMODE_EN | 192 (16 << ESPI_SPMODE_TXTHR_S) | (15 << ESPI_SPMODE_RXTHR_S)); 193 194 /* Disable all interrupts until we start transfers */ 195 FSL_ESPI_WRITE(sc, ESPI_SPIM, 0); 196 197 device_add_child(dev, "spibus", -1); 198 199 return (bus_generic_attach(dev)); 200 } 201 202 static int 203 fsl_espi_detach(device_t dev) 204 { 205 struct fsl_espi_softc *sc; 206 207 bus_generic_detach(dev); 208 209 sc = device_get_softc(dev); 210 FSL_ESPI_WRITE(sc, ESPI_SPMODE, 0); 211 212 sc = device_get_softc(dev); 213 mtx_destroy(&sc->sc_mtx); 214 if (sc->sc_intrhand) 215 bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intrhand); 216 if (sc->sc_irq_res) 217 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res); 218 if (sc->sc_mem_res) 219 bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res); 220 221 return (0); 222 } 223 224 static void 225 fsl_espi_fill_fifo(struct fsl_espi_softc *sc) 226 { 227 struct spi_command *cmd; 228 uint32_t spier, written; 229 uint8_t *data; 230 231 cmd = sc->sc_cmd; 232 spier = FSL_ESPI_READ(sc, ESPI_SPIE); 233 while (sc->sc_written < sc->sc_len && 234 (spier & ESPI_SPIE_TNF)) { 235 data = (uint8_t *)cmd->tx_cmd; 236 written = sc->sc_written++; 237 if (written >= cmd->tx_cmd_sz) { 238 data = (uint8_t *)cmd->tx_data; 239 written -= cmd->tx_cmd_sz; 240 } 241 FSL_ESPI_WRITE_FIFO(sc, ESPI_SPITF, data[written]); 242 spier = FSL_ESPI_READ(sc, ESPI_SPIE); 243 } 244 } 245 246 static void 247 fsl_espi_drain_fifo(struct fsl_espi_softc *sc) 248 { 249 struct spi_command *cmd; 250 uint32_t spier, read; 251 uint8_t *data; 252 uint8_t r; 253 254 cmd = sc->sc_cmd; 255 spier = FSL_ESPI_READ(sc, ESPI_SPIE); 256 while (sc->sc_read < sc->sc_len && (spier & ESPI_SPIE_RNE)) { 257 data = (uint8_t *)cmd->rx_cmd; 258 read = sc->sc_read++; 259 if (read >= cmd->rx_cmd_sz) { 260 data = (uint8_t *)cmd->rx_data; 261 read -= cmd->rx_cmd_sz; 262 } 263 r = FSL_ESPI_READ_FIFO(sc, ESPI_SPIRF); 264 data[read] = r; 265 spier = FSL_ESPI_READ(sc, ESPI_SPIE); 266 } 267 } 268 269 static void 270 fsl_espi_intr(void *arg) 271 { 272 struct fsl_espi_softc *sc; 273 uint32_t spie; 274 275 sc = (struct fsl_espi_softc *)arg; 276 FSL_ESPI_LOCK(sc); 277 278 /* Filter stray interrupts. */ 279 if ((sc->sc_flags & FSL_ESPI_BUSY) == 0) { 280 FSL_ESPI_UNLOCK(sc); 281 return; 282 } 283 spie = FSL_ESPI_READ(sc, ESPI_SPIE); 284 FSL_ESPI_WRITE(sc, ESPI_SPIE, spie); 285 286 /* TX - Fill up the FIFO. */ 287 fsl_espi_fill_fifo(sc); 288 289 /* RX - Drain the FIFO. */ 290 fsl_espi_drain_fifo(sc); 291 292 /* Check for end of transfer. */ 293 if (spie & ESPI_SPIE_DON) 294 wakeup(sc->sc_dev); 295 296 FSL_ESPI_UNLOCK(sc); 297 } 298 299 static int 300 fsl_espi_transfer(device_t dev, device_t child, struct spi_command *cmd) 301 { 302 struct fsl_espi_softc *sc; 303 u_long plat_clk; 304 uint32_t csmode, spi_clk, spi_mode; 305 int cs, err, pm; 306 307 sc = device_get_softc(dev); 308 309 KASSERT(cmd->tx_cmd_sz == cmd->rx_cmd_sz, 310 ("TX/RX command sizes should be equal")); 311 KASSERT(cmd->tx_data_sz == cmd->rx_data_sz, 312 ("TX/RX data sizes should be equal")); 313 314 /* Restrict transmit length to command max length */ 315 if (cmd->tx_cmd_sz + cmd->tx_data_sz > ESPI_SPCOM_TRANLEN_M + 1) { 316 return (EINVAL); 317 } 318 319 /* Get the proper chip select for this child. */ 320 spibus_get_cs(child, &cs); 321 if (cs < 0 || cs > sc->sc_num_cs) { 322 device_printf(dev, 323 "Invalid chip select %d requested by %s\n", cs, 324 device_get_nameunit(child)); 325 return (EINVAL); 326 } 327 spibus_get_clock(child, &spi_clk); 328 spibus_get_mode(child, &spi_mode); 329 330 FSL_ESPI_LOCK(sc); 331 332 /* If the controller is in use wait until it is available. */ 333 while (sc->sc_flags & FSL_ESPI_BUSY) 334 mtx_sleep(dev, &sc->sc_mtx, 0, "fsl_espi", 0); 335 336 /* Now we have control over SPI controller. */ 337 sc->sc_flags = FSL_ESPI_BUSY; 338 339 /* Save a pointer to the SPI command. */ 340 sc->sc_cmd = cmd; 341 sc->sc_read = 0; 342 sc->sc_written = 0; 343 sc->sc_len = cmd->tx_cmd_sz + cmd->tx_data_sz; 344 345 plat_clk = mpc85xx_get_system_clock(); 346 spi_clk = max(spi_clk, plat_clk / (16 * 16)); 347 if (plat_clk == 0) { 348 device_printf(dev, 349 "unable to get platform clock, giving up.\n"); 350 return (EINVAL); 351 } 352 csmode = 0; 353 if (plat_clk > spi_clk * 16 * 2) { 354 csmode |= ESPI_CSMODE_DIV16; 355 plat_clk /= 16; 356 } 357 pm = howmany(plat_clk, spi_clk * 2) - 1; 358 if (pm < 0) 359 pm = 1; 360 if (pm > 15) 361 pm = 15; 362 363 csmode |= (pm << ESPI_CSMODE_PM_S); 364 csmode |= ESPI_CSMODE_REV; 365 if (spi_mode == SPIBUS_MODE_CPOL || spi_mode == SPIBUS_MODE_CPOL_CPHA) 366 csmode |= ESPI_CSMODE_CI; 367 if (spi_mode == SPIBUS_MODE_CPHA || spi_mode == SPIBUS_MODE_CPOL_CPHA) 368 csmode |= ESPI_CSMODE_CP; 369 if (!(cs & SPIBUS_CS_HIGH)) 370 csmode |= ESPI_CSMODE_POL; 371 csmode |= ESPI_CSMODE_LEN(7);/* Only deal with 8-bit characters. */ 372 csmode |= ESPI_CSMODE_CSCG(1); /* XXX: Make this configurable? */ 373 /* Configure transaction */ 374 FSL_ESPI_WRITE(sc, ESPI_SPCOM, (cs << ESPI_SPCOM_CS_S) | (sc->sc_len - 1)); 375 FSL_ESPI_WRITE(sc, ESPI_CSMODE(cs), csmode); 376 /* Enable interrupts we need. */ 377 FSL_ESPI_WRITE(sc, ESPI_SPIM, 378 ESPI_SPIE_TXE | ESPI_SPIE_DON | ESPI_SPIE_RXF); 379 380 /* Wait for the transaction to complete. */ 381 err = mtx_sleep(dev, &sc->sc_mtx, 0, "fsl_espi", hz * 2); 382 FSL_ESPI_WRITE(sc, ESPI_SPIM, 0); 383 384 /* Release the controller and wakeup the next thread waiting for it. */ 385 sc->sc_flags = 0; 386 wakeup_one(dev); 387 FSL_ESPI_UNLOCK(sc); 388 389 /* 390 * Check for transfer timeout. The SPI controller doesn't 391 * return errors. 392 */ 393 if (err == EWOULDBLOCK) { 394 device_printf(sc->sc_dev, "SPI error\n"); 395 err = EIO; 396 } 397 398 return (err); 399 } 400 401 static phandle_t 402 fsl_espi_get_node(device_t bus, device_t dev) 403 { 404 405 /* We only have one child, the SPI bus, which needs our own node. */ 406 return (ofw_bus_get_node(bus)); 407 } 408 409 static device_method_t fsl_espi_methods[] = { 410 /* Device interface */ 411 DEVMETHOD(device_probe, fsl_espi_probe), 412 DEVMETHOD(device_attach, fsl_espi_attach), 413 DEVMETHOD(device_detach, fsl_espi_detach), 414 415 /* SPI interface */ 416 DEVMETHOD(spibus_transfer, fsl_espi_transfer), 417 418 /* ofw_bus interface */ 419 DEVMETHOD(ofw_bus_get_node, fsl_espi_get_node), 420 421 DEVMETHOD_END 422 }; 423 424 static driver_t fsl_espi_driver = { 425 "spi", 426 fsl_espi_methods, 427 sizeof(struct fsl_espi_softc), 428 }; 429 430 DRIVER_MODULE(fsl_espi, simplebus, fsl_espi_driver, 0, 0); 431