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