1 /* $Id: at91spi.c,v 1.8 2025/09/10 01:55:06 thorpej Exp $ */ 2 /* $NetBSD: at91spi.c,v 1.8 2025/09/10 01:55:06 thorpej Exp $ */ 3 4 /*- 5 * Copyright (c) 2007 Embedtronics Oy. All rights reserved. 6 * 7 * Based on arch/mips/alchemy/dev/auspi.c, 8 * Copyright (c) 2006 Urbana-Champaign Independent Media Center. 9 * Copyright (c) 2006 Garrett D'Amore. 10 * All rights reserved. 11 * 12 * Portions of this code were written by Garrett D'Amore for the 13 * Champaign-Urbana Community Wireless Network Project. 14 * 15 * Redistribution and use in source and binary forms, with or 16 * without modification, are permitted provided that the following 17 * conditions are met: 18 * 1. Redistributions of source code must retain the above copyright 19 * notice, this list of conditions and the following disclaimer. 20 * 2. Redistributions in binary form must reproduce the above 21 * copyright notice, this list of conditions and the following 22 * disclaimer in the documentation and/or other materials provided 23 * with the distribution. 24 * 3. All advertising materials mentioning features or use of this 25 * software must display the following acknowledgements: 26 * This product includes software developed by the Urbana-Champaign 27 * Independent Media Center. 28 * This product includes software developed by Garrett D'Amore. 29 * 4. Urbana-Champaign Independent Media Center's name and Garrett 30 * D'Amore's name may not be used to endorse or promote products 31 * derived from this software without specific prior written permission. 32 * 33 * THIS SOFTWARE IS PROVIDED BY THE URBANA-CHAMPAIGN INDEPENDENT 34 * MEDIA CENTER AND GARRETT D'AMORE ``AS IS'' AND ANY EXPRESS OR 35 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 36 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 37 * ARE DISCLAIMED. IN NO EVENT SHALL THE URBANA-CHAMPAIGN INDEPENDENT 38 * MEDIA CENTER OR GARRETT D'AMORE BE LIABLE FOR ANY DIRECT, INDIRECT, 39 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 40 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 41 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 42 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 43 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 44 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 45 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 46 */ 47 48 #include <sys/cdefs.h> 49 __KERNEL_RCSID(0, "$NetBSD: at91spi.c,v 1.8 2025/09/10 01:55:06 thorpej Exp $"); 50 51 #include "locators.h" 52 53 #include <sys/param.h> 54 #include <sys/systm.h> 55 #include <sys/kernel.h> 56 #include <sys/device.h> 57 #include <sys/errno.h> 58 #include <sys/proc.h> 59 60 #include <sys/bus.h> 61 #include <machine/cpu.h> 62 #include <machine/vmparam.h> 63 #include <sys/inttypes.h> 64 65 #include <arm/at91/at91var.h> 66 #include <arm/at91/at91reg.h> 67 #include <arm/at91/at91spivar.h> 68 #include <arm/at91/at91spireg.h> 69 70 #define at91spi_select(sc, slave) \ 71 (sc)->sc_md->select_slave((sc), (slave)) 72 73 #define STATIC 74 75 //#define AT91SPI_DEBUG 4 76 77 #ifdef AT91SPI_DEBUG 78 int at91spi_debug = AT91SPI_DEBUG; 79 #define DPRINTFN(n,x) if (at91spi_debug>(n)) printf x; 80 #else 81 #define DPRINTFN(n,x) 82 #endif 83 84 STATIC int at91spi_intr(void *); 85 86 /* SPI service routines */ 87 STATIC int at91spi_configure(void *, int, int, int); 88 STATIC int at91spi_transfer(void *, struct spi_transfer *); 89 STATIC void at91spi_xfer(struct at91spi_softc *sc, int start); 90 91 /* internal stuff */ 92 STATIC void at91spi_done(struct at91spi_softc *, int); 93 STATIC void at91spi_send(struct at91spi_softc *); 94 STATIC void at91spi_recv(struct at91spi_softc *); 95 STATIC void at91spi_sched(struct at91spi_softc *); 96 97 #define GETREG(sc, x) \ 98 bus_space_read_4(sc->sc_iot, sc->sc_ioh, x) 99 #define PUTREG(sc, x, v) \ 100 bus_space_write_4(sc->sc_iot, sc->sc_ioh, x, v) 101 102 void 103 at91spi_attach_common(device_t parent, device_t self, void *aux, 104 at91spi_machdep_tag_t md) 105 { 106 struct at91spi_softc *sc = device_private(self); 107 struct at91bus_attach_args *sa = aux; 108 bus_dma_segment_t segs; 109 int rsegs, err; 110 111 aprint_normal(": AT91 SPI Controller\n"); 112 113 sc->sc_dev = self; 114 sc->sc_iot = sa->sa_iot; 115 sc->sc_pid = sa->sa_pid; 116 sc->sc_dmat = sa->sa_dmat; 117 sc->sc_md = md; 118 119 if (bus_space_map(sa->sa_iot, sa->sa_addr, sa->sa_size, 0, &sc->sc_ioh)) 120 panic("%s: Cannot map registers", device_xname(self)); 121 122 /* we want to use dma, so allocate dma memory: */ 123 err = bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE, 0, PAGE_SIZE, 124 &segs, 1, &rsegs, BUS_DMA_WAITOK); 125 if (err == 0) { 126 err = bus_dmamem_map(sc->sc_dmat, &segs, 1, PAGE_SIZE, 127 &sc->sc_dmapage, 128 BUS_DMA_WAITOK); 129 } 130 if (err == 0) { 131 err = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, 132 PAGE_SIZE, 0, BUS_DMA_WAITOK, 133 &sc->sc_dmamap); 134 } 135 if (err == 0) { 136 err = bus_dmamap_load(sc->sc_dmat, sc->sc_dmamap, 137 sc->sc_dmapage, PAGE_SIZE, NULL, 138 BUS_DMA_WAITOK); 139 } 140 if (err != 0) { 141 panic("%s: Cannot get DMA memory", device_xname(sc->sc_dev)); 142 } 143 sc->sc_dmaaddr = sc->sc_dmamap->dm_segs[0].ds_addr; 144 145 /* 146 * Initialize SPI controller 147 */ 148 sc->sc_spi.sct_cookie = sc; 149 sc->sc_spi.sct_configure = at91spi_configure; 150 sc->sc_spi.sct_transfer = at91spi_transfer; 151 152 //sc->sc_spi.sct_nslaves must have been initialized by machdep code 153 if (!sc->sc_spi.sct_nslaves) { 154 aprint_error("%s: no slaves!\n", device_xname(sc->sc_dev)); 155 } 156 157 /* initialize the queue */ 158 SIMPLEQ_INIT(&sc->sc_q); 159 160 /* reset the SPI */ 161 at91_peripheral_clock(sc->sc_pid, 1); 162 PUTREG(sc, SPI_CR, SPI_CR_SWRST); 163 delay(100); 164 165 /* be paranoid and make sure the PDC is dead */ 166 PUTREG(sc, SPI_PDC_BASE + PDC_PTCR, PDC_PTCR_TXTDIS | PDC_PTCR_RXTDIS); 167 PUTREG(sc, SPI_PDC_BASE + PDC_RNCR, 0); 168 PUTREG(sc, SPI_PDC_BASE + PDC_RCR, 0); 169 PUTREG(sc, SPI_PDC_BASE + PDC_TNCR, 0); 170 PUTREG(sc, SPI_PDC_BASE + PDC_TCR, 0); 171 172 // configure SPI: 173 PUTREG(sc, SPI_IDR, -1); 174 PUTREG(sc, SPI_CSR(0), SPI_CSR_SCBR | SPI_CSR_BITS_8); 175 PUTREG(sc, SPI_CSR(1), SPI_CSR_SCBR | SPI_CSR_BITS_8); 176 PUTREG(sc, SPI_CSR(2), SPI_CSR_SCBR | SPI_CSR_BITS_8); 177 PUTREG(sc, SPI_CSR(3), SPI_CSR_SCBR | SPI_CSR_BITS_8); 178 PUTREG(sc, SPI_MR, SPI_MR_MODFDIS/* <- machdep? */ | SPI_MR_MSTR); 179 180 /* enable device interrupts */ 181 sc->sc_ih = at91_intr_establish(sc->sc_pid, IPL_BIO, INTR_HIGH_LEVEL, 182 at91spi_intr, sc); 183 184 /* enable SPI */ 185 PUTREG(sc, SPI_CR, SPI_CR_SPIEN); 186 if (GETREG(sc, SPI_SR) & SPI_SR_RDRF) 187 (void)GETREG(sc, SPI_RDR); 188 189 PUTREG(sc, SPI_PDC_BASE + PDC_PTCR, PDC_PTCR_TXTEN | PDC_PTCR_RXTEN); 190 191 /* attach slave devices */ 192 spibus_attach(self, &sc->sc_spi); 193 } 194 195 int 196 at91spi_configure(void *arg, int slave, int mode, int speed) 197 { 198 struct at91spi_softc *sc = arg; 199 uint scbr; 200 uint32_t csr; 201 202 /* setup interrupt registers */ 203 PUTREG(sc, SPI_IDR, -1); /* disable interrupts for now */ 204 205 csr = GETREG(sc, SPI_CSR(0)); /* read register */ 206 csr &= SPI_CSR_RESERVED; /* keep reserved bits */ 207 csr |= SPI_CSR_BITS_8; /* assume 8 bit transfers */ 208 209 /* 210 * Calculate clock divider 211 */ 212 scbr = speed ? ((AT91_MSTCLK + speed - 1) / speed + 1) & ~1 : -1; 213 if (scbr > 0xFF) { 214 aprint_error("%s: speed %d not supported\n", 215 device_xname(sc->sc_dev), speed); 216 return EINVAL; 217 } 218 csr |= scbr << SPI_CSR_SCBR_SHIFT; 219 220 /* 221 * I'm not entirely confident that these values are correct. 222 * But at least mode 0 appears to work properly with the 223 * devices I have tested. The documentation seems to suggest 224 * that I have the meaning of the clock delay bit inverted. 225 */ 226 switch (mode) { 227 case SPI_MODE_0: 228 csr |= SPI_CSR_NCPHA; /* CPHA = 0, CPOL = 0 */ 229 break; 230 case SPI_MODE_1: 231 csr |= 0; /* CPHA = 1, CPOL = 0 */ 232 break; 233 case SPI_MODE_2: 234 csr |= SPI_CSR_NCPHA /* CPHA = 0, CPOL = 1 */ 235 | SPI_CSR_CPOL; 236 break; 237 case SPI_MODE_3: 238 csr |= SPI_CSR_CPOL; /* CPHA = 1, CPOL = 1 */ 239 break; 240 default: 241 return EINVAL; 242 } 243 244 PUTREG(sc, SPI_CSR(0), csr); 245 246 DPRINTFN(3, ("%s: slave %d mode %d speed %d, csr=0x%08"PRIX32"\n", 247 __FUNCTION__, slave, mode, speed, csr)); 248 249 #if 0 250 // wait until ready!? 251 for (i = 1000000; i; i -= 10) { 252 if (GETREG(sc, AUPSC_SPISTAT) & SPISTAT_DR) { 253 return 0; 254 } 255 } 256 257 return ETIMEDOUT; 258 #else 259 return 0; 260 #endif 261 } 262 263 #define HALF_BUF_SIZE (PAGE_SIZE / 2) 264 265 void 266 at91spi_xfer(struct at91spi_softc *sc, int start) 267 { 268 struct spi_chunk *chunk; 269 int len; 270 uint32_t sr; 271 272 DPRINTFN(3, ("%s: sc=%p start=%d\n", __FUNCTION__, sc, start)); 273 274 /* so ready to transmit more / anything received? */ 275 if (((sr = GETREG(sc, SPI_SR)) & (SPI_SR_ENDTX | SPI_SR_ENDRX)) != (SPI_SR_ENDTX | SPI_SR_ENDRX)) { 276 /* not ready, get out */ 277 DPRINTFN(3, ("%s: sc=%p start=%d sr=%"PRIX32"\n", __FUNCTION__, sc, start, sr)); 278 return; 279 } 280 281 DPRINTFN(3, ("%s: sr=%"PRIX32"\n", __FUNCTION__, sr)); 282 283 if (!start) { 284 // ok, something has been transferred, synchronize.. 285 int offs = sc->sc_dmaoffs ^ HALF_BUF_SIZE; 286 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, offs, HALF_BUF_SIZE, 287 BUS_DMASYNC_POSTWRITE | BUS_DMASYNC_POSTREAD); 288 289 if ((chunk = sc->sc_rchunk) != NULL) { 290 if ((len = chunk->chunk_rresid) > HALF_BUF_SIZE) 291 len = HALF_BUF_SIZE; 292 if (chunk->chunk_rptr && len > 0) { 293 memcpy(chunk->chunk_rptr, (const uint8_t *)sc->sc_dmapage + offs, len); 294 chunk->chunk_rptr += len; 295 } 296 if ((chunk->chunk_rresid -= len) <= 0) { 297 // done with this chunk, get next 298 sc->sc_rchunk = chunk->chunk_next; 299 } 300 } 301 } 302 303 /* start transmitting next chunk: */ 304 if ((chunk = sc->sc_wchunk) != NULL) { 305 306 /* make sure we transmit just half buffer at a time */ 307 len = MIN(chunk->chunk_wresid, HALF_BUF_SIZE); 308 309 // setup outgoing data 310 if (chunk->chunk_wptr && len > 0) { 311 memcpy((uint8_t *)sc->sc_dmapage + sc->sc_dmaoffs, chunk->chunk_wptr, len); 312 chunk->chunk_wptr += len; 313 } else { 314 memset((uint8_t *)sc->sc_dmapage + sc->sc_dmaoffs, 0, len); 315 } 316 317 /* advance to next transfer if it's time to */ 318 if ((chunk->chunk_wresid -= len) <= 0) { 319 sc->sc_wchunk = sc->sc_wchunk->chunk_next; 320 } 321 322 /* determine which interrupt to get */ 323 if (sc->sc_wchunk) { 324 /* just wait for next buffer to free */ 325 PUTREG(sc, SPI_IER, SPI_SR_ENDRX); 326 } else { 327 /* must wait until transfer has completed */ 328 PUTREG(sc, SPI_IDR, SPI_SR_ENDRX); 329 PUTREG(sc, SPI_IER, SPI_SR_RXBUFF); 330 } 331 332 DPRINTFN(3, ("%s: dmaoffs=%d len=%d wchunk=%p (%p:%d) rchunk=%p (%p:%d) mr=%"PRIX32" sr=%"PRIX32" imr=%"PRIX32" csr0=%"PRIX32"\n", 333 __FUNCTION__, sc->sc_dmaoffs, len, sc->sc_wchunk, 334 sc->sc_wchunk ? sc->sc_wchunk->chunk_wptr : NULL, 335 sc->sc_wchunk ? sc->sc_wchunk->chunk_wresid : -1, 336 sc->sc_rchunk, 337 sc->sc_rchunk ? sc->sc_rchunk->chunk_rptr : NULL, 338 sc->sc_rchunk ? sc->sc_rchunk->chunk_rresid : -1, 339 GETREG(sc, SPI_MR), GETREG(sc, SPI_SR), 340 GETREG(sc, SPI_IMR), GETREG(sc, SPI_CSR(0)))); 341 342 // prepare DMA 343 bus_dmamap_sync(sc->sc_dmat, sc->sc_dmamap, sc->sc_dmaoffs, len, 344 BUS_DMASYNC_PREWRITE | BUS_DMASYNC_PREREAD); 345 346 // and start transmitting / receiving 347 PUTREG(sc, SPI_PDC_BASE + PDC_RNPR, sc->sc_dmaaddr + sc->sc_dmaoffs); 348 PUTREG(sc, SPI_PDC_BASE + PDC_RNCR, len); 349 PUTREG(sc, SPI_PDC_BASE + PDC_TNPR, sc->sc_dmaaddr + sc->sc_dmaoffs); 350 PUTREG(sc, SPI_PDC_BASE + PDC_TNCR, len); 351 352 // swap buffer 353 sc->sc_dmaoffs ^= HALF_BUF_SIZE; 354 355 // get out 356 return; 357 } else { 358 DPRINTFN(3, ("%s: nothing to write anymore\n", __FUNCTION__)); 359 return; 360 } 361 } 362 363 void 364 at91spi_sched(struct at91spi_softc *sc) 365 { 366 struct spi_transfer *st; 367 int err; 368 369 while ((st = spi_transq_first(&sc->sc_q)) != NULL) { 370 371 DPRINTFN(2, ("%s: st=%p\n", __FUNCTION__, st)); 372 373 /* remove the item */ 374 spi_transq_dequeue(&sc->sc_q); 375 376 /* note that we are working on it */ 377 sc->sc_transfer = st; 378 379 if ((err = at91spi_select(sc, st->st_slave)) != 0) { 380 spi_done(st, err); 381 continue; 382 } 383 384 /* setup chunks */ 385 sc->sc_rchunk = sc->sc_wchunk = st->st_chunks; 386 387 /* now kick the master start to get the chip running */ 388 at91spi_xfer(sc, TRUE); 389 390 /* enable error interrupts too: */ 391 PUTREG(sc, SPI_IER, SPI_SR_MODF | SPI_SR_OVRES); 392 393 sc->sc_running = TRUE; 394 return; 395 } 396 DPRINTFN(2, ("%s: nothing to do anymore\n", __FUNCTION__)); 397 PUTREG(sc, SPI_IDR, -1); /* disable interrupts */ 398 at91spi_select(sc, -1); 399 sc->sc_running = FALSE; 400 } 401 402 void 403 at91spi_done(struct at91spi_softc *sc, int err) 404 { 405 struct spi_transfer *st; 406 407 /* called from interrupt handler */ 408 if ((st = sc->sc_transfer) != NULL) { 409 sc->sc_transfer = NULL; 410 DPRINTFN(2, ("%s: st %p finished with error code %d\n", __FUNCTION__, st, err)); 411 spi_done(st, err); 412 } 413 /* make sure we clear these bits out */ 414 sc->sc_wchunk = sc->sc_rchunk = NULL; 415 at91spi_sched(sc); 416 } 417 418 int 419 at91spi_intr(void *arg) 420 { 421 struct at91spi_softc *sc = arg; 422 uint32_t imr, sr; 423 int err = 0; 424 425 if ((imr = GETREG(sc, SPI_IMR)) == 0) { 426 /* interrupts are not enabled, get out */ 427 DPRINTFN(4, ("%s: interrupts are not enabled\n", __FUNCTION__)); 428 return 0; 429 } 430 431 sr = GETREG(sc, SPI_SR); 432 if (!(sr & imr)) { 433 /* interrupt did not happen, get out */ 434 DPRINTFN(3, ("%s: interrupts are not enabled, sr=%08"PRIX32" imr=%08"PRIX32"\n", 435 __FUNCTION__, sr, imr)); 436 return 0; 437 } 438 439 DPRINTFN(3, ("%s: sr=%08"PRIX32" imr=%08"PRIX32"\n", 440 __FUNCTION__, sr, imr)); 441 442 if (sr & imr & SPI_SR_MODF) { 443 printf("%s: mode fault!\n", device_xname(sc->sc_dev)); 444 err = EIO; 445 } 446 447 if (sr & imr & SPI_SR_OVRES) { 448 printf("%s: overrun error!\n", device_xname(sc->sc_dev)); 449 err = EIO; 450 } 451 if (err) { 452 /* clear errors */ 453 /* complete transfer */ 454 at91spi_done(sc, err); 455 } else { 456 /* do all data exchanges */ 457 at91spi_xfer(sc, FALSE); 458 459 /* 460 * if the master done bit is set, make sure we do the 461 * right processing. 462 */ 463 if (sr & imr & SPI_SR_RXBUFF) { 464 if ((sc->sc_wchunk != NULL) || 465 (sc->sc_rchunk != NULL)) { 466 printf("%s: partial transfer?\n", 467 device_xname(sc->sc_dev)); 468 err = EIO; 469 } 470 at91spi_done(sc, err); 471 } 472 473 } 474 475 return 1; 476 } 477 478 int 479 at91spi_transfer(void *arg, struct spi_transfer *st) 480 { 481 struct at91spi_softc *sc = arg; 482 int s; 483 484 /* make sure we select the right chip */ 485 s = splbio(); 486 spi_transq_enqueue(&sc->sc_q, st); 487 if (sc->sc_running == 0) { 488 at91spi_sched(sc); 489 } 490 splx(s); 491 return 0; 492 } 493 494