1 /* $Id: at91spi.c,v 1.2 2008/07/03 01:15:38 matt Exp $ */
5 * Copyright (c) 2007 Embedtronics Oy. All rights reserved.
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.
12 * Portions of this code were written by Garrett D'Amore for the
13 * Champaign-Urbana Community Wireless Network Project.
15 * Redistribution and use in source and binary forms, with or
16 * without modification, are permitted provided that the following
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.
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.
48 #include <sys/cdefs.h>
49 __KERNEL_RCSID(0, "$NetBSD$");
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>
60 #include <machine/bus.h>
61 #include <machine/cpu.h>
62 #include <machine/vmparam.h>
63 #include <sys/inttypes.h>
65 #include <arm/at91/at91var.h>
66 #include <arm/at91/at91reg.h>
67 #include <arm/at91/at91spivar.h>
68 #include <arm/at91/at91spireg.h>
70 #define at91spi_select(sc, slave) \
71 (sc)->sc_md->select_slave((sc), (slave))
75 //#define AT91SPI_DEBUG 4
78 int at91spi_debug
= AT91SPI_DEBUG
;
79 #define DPRINTFN(n,x) if (at91spi_debug>(n)) printf x;
84 STATIC
int at91spi_intr(void *);
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
);
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
*);
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)
103 at91spi_attach_common(device_t parent
, device_t self
, void *aux
,
104 at91spi_machdep_tag_t md
)
106 struct at91spi_softc
*sc
= device_private(self
);
107 struct at91bus_attach_args
*sa
= aux
;
108 struct spibus_attach_args sba
;
109 bus_dma_segment_t segs
;
112 aprint_normal(": AT91 SPI Controller\n");
115 sc
->sc_iot
= sa
->sa_iot
;
116 sc
->sc_pid
= sa
->sa_pid
;
117 sc
->sc_dmat
= sa
->sa_dmat
;
120 if (bus_space_map(sa
->sa_iot
, sa
->sa_addr
, sa
->sa_size
, 0, &sc
->sc_ioh
))
121 panic("%s: Cannot map registers", device_xname(self
));
123 /* we want to use dma, so allocate dma memory: */
124 err
= bus_dmamem_alloc(sc
->sc_dmat
, PAGE_SIZE
, 0, PAGE_SIZE
,
125 &segs
, 1, &rsegs
, BUS_DMA_WAITOK
);
127 err
= bus_dmamem_map(sc
->sc_dmat
, &segs
, 1, PAGE_SIZE
,
132 err
= bus_dmamap_create(sc
->sc_dmat
, PAGE_SIZE
, 1,
133 PAGE_SIZE
, 0, BUS_DMA_WAITOK
,
137 err
= bus_dmamap_load(sc
->sc_dmat
, sc
->sc_dmamap
,
138 sc
->sc_dmapage
, PAGE_SIZE
, NULL
,
142 panic("%s: Cannot get DMA memory", device_xname(sc
->sc_dev
));
144 sc
->sc_dmaaddr
= sc
->sc_dmamap
->dm_segs
[0].ds_addr
;
147 * Initialize SPI controller
149 sc
->sc_spi
.sct_cookie
= sc
;
150 sc
->sc_spi
.sct_configure
= at91spi_configure
;
151 sc
->sc_spi
.sct_transfer
= at91spi_transfer
;
153 //sc->sc_spi.sct_nslaves must have been initialized by machdep code
154 if (!sc
->sc_spi
.sct_nslaves
) {
155 aprint_error("%s: no slaves!\n", device_xname(sc
->sc_dev
));
158 sba
.sba_controller
= &sc
->sc_spi
;
160 /* initialize the queue */
161 SIMPLEQ_INIT(&sc
->sc_q
);
164 at91_peripheral_clock(sc
->sc_pid
, 1);
165 PUTREG(sc
, SPI_CR
, SPI_CR_SWRST
);
168 /* be paranoid and make sure the PDC is dead */
169 PUTREG(sc
, SPI_PDC_BASE
+ PDC_PTCR
, PDC_PTCR_TXTDIS
| PDC_PTCR_RXTDIS
);
170 PUTREG(sc
, SPI_PDC_BASE
+ PDC_RNCR
, 0);
171 PUTREG(sc
, SPI_PDC_BASE
+ PDC_RCR
, 0);
172 PUTREG(sc
, SPI_PDC_BASE
+ PDC_TNCR
, 0);
173 PUTREG(sc
, SPI_PDC_BASE
+ PDC_TCR
, 0);
176 PUTREG(sc
, SPI_IDR
, -1);
177 PUTREG(sc
, SPI_CSR(0), SPI_CSR_SCBR
| SPI_CSR_BITS_8
);
178 PUTREG(sc
, SPI_CSR(1), SPI_CSR_SCBR
| SPI_CSR_BITS_8
);
179 PUTREG(sc
, SPI_CSR(2), SPI_CSR_SCBR
| SPI_CSR_BITS_8
);
180 PUTREG(sc
, SPI_CSR(3), SPI_CSR_SCBR
| SPI_CSR_BITS_8
);
181 PUTREG(sc
, SPI_MR
, SPI_MR_MODFDIS
/* <- machdep? */ | SPI_MR_MSTR
);
183 /* enable device interrupts */
184 sc
->sc_ih
= at91_intr_establish(sc
->sc_pid
, IPL_BIO
, INTR_HIGH_LEVEL
,
188 PUTREG(sc
, SPI_CR
, SPI_CR_SPIEN
);
189 if (GETREG(sc
, SPI_SR
) & SPI_SR_RDRF
)
190 (void)GETREG(sc
, SPI_RDR
);
192 PUTREG(sc
, SPI_PDC_BASE
+ PDC_PTCR
, PDC_PTCR_TXTEN
| PDC_PTCR_RXTEN
);
194 /* attach slave devices */
195 (void) config_found_ia(sc
->sc_dev
, "spibus", &sba
, spibus_print
);
199 at91spi_configure(void *arg
, int slave
, int mode
, int speed
)
201 struct at91spi_softc
*sc
= arg
;
205 /* setup interrupt registers */
206 PUTREG(sc
, SPI_IDR
, -1); /* disable interrupts for now */
208 csr
= GETREG(sc
, SPI_CSR(0)); /* read register */
209 csr
&= SPI_CSR_RESERVED
; /* keep reserved bits */
210 csr
|= SPI_CSR_BITS_8
; /* assume 8 bit transfers */
213 * Calculate clock divider
215 scbr
= speed
? ((AT91_MSTCLK
+ speed
- 1) / speed
+ 1) & ~1 : -1;
217 aprint_error("%s: speed %d not supported\n",
218 device_xname(sc
->sc_dev
), speed
);
221 csr
|= scbr
<< SPI_CSR_SCBR_SHIFT
;
224 * I'm not entirely confident that these values are correct.
225 * But at least mode 0 appears to work properly with the
226 * devices I have tested. The documentation seems to suggest
227 * that I have the meaning of the clock delay bit inverted.
231 csr
|= SPI_CSR_NCPHA
; /* CPHA = 0, CPOL = 0 */
234 csr
|= 0; /* CPHA = 1, CPOL = 0 */
237 csr
|= SPI_CSR_NCPHA
/* CPHA = 0, CPOL = 1 */
241 csr
|= SPI_CSR_CPOL
; /* CPHA = 1, CPOL = 1 */
247 PUTREG(sc
, SPI_CSR(0), csr
);
249 DPRINTFN(3, ("%s: slave %d mode %d speed %d, csr=0x%08"PRIX32
"\n",
250 __FUNCTION__
, slave
, mode
, speed
, csr
));
253 // wait until ready!?
254 for (i
= 1000000; i
; i
-= 10) {
255 if (GETREG(sc
, AUPSC_SPISTAT
) & SPISTAT_DR
) {
266 #define HALF_BUF_SIZE (PAGE_SIZE / 2)
269 at91spi_xfer(struct at91spi_softc
*sc
, int start
)
271 struct spi_chunk
*chunk
;
275 DPRINTFN(3, ("%s: sc=%p start=%d\n", __FUNCTION__
, sc
, start
));
277 /* so ready to transmit more / anything received? */
278 if (((sr
= GETREG(sc
, SPI_SR
)) & (SPI_SR_ENDTX
| SPI_SR_ENDRX
)) != (SPI_SR_ENDTX
| SPI_SR_ENDRX
)) {
279 /* not ready, get out */
280 DPRINTFN(3, ("%s: sc=%p start=%d sr=%"PRIX32
"\n", __FUNCTION__
, sc
, start
, sr
));
284 DPRINTFN(3, ("%s: sr=%"PRIX32
"\n", __FUNCTION__
, sr
));
287 // ok, something has been transfered, synchronize..
288 int offs
= sc
->sc_dmaoffs
^ HALF_BUF_SIZE
;
289 bus_dmamap_sync(sc
->sc_dmat
, sc
->sc_dmamap
, offs
, HALF_BUF_SIZE
,
290 BUS_DMASYNC_POSTWRITE
| BUS_DMASYNC_POSTREAD
);
292 if ((chunk
= sc
->sc_rchunk
) != NULL
) {
293 if ((len
= chunk
->chunk_rresid
) > HALF_BUF_SIZE
)
295 if (chunk
->chunk_rptr
&& len
> 0) {
296 memcpy(chunk
->chunk_rptr
, (const uint8_t *)sc
->sc_dmapage
+ offs
, len
);
297 chunk
->chunk_rptr
+= len
;
299 if ((chunk
->chunk_rresid
-= len
) <= 0) {
300 // done with this chunk, get next
301 sc
->sc_rchunk
= chunk
->chunk_next
;
306 /* start transmitting next chunk: */
307 if ((chunk
= sc
->sc_wchunk
) != NULL
) {
309 /* make sure we transmit just half buffer at a time */
310 len
= MIN(chunk
->chunk_wresid
, HALF_BUF_SIZE
);
312 // setup outgoing data
313 if (chunk
->chunk_wptr
&& len
> 0) {
314 memcpy((uint8_t *)sc
->sc_dmapage
+ sc
->sc_dmaoffs
, chunk
->chunk_wptr
, len
);
315 chunk
->chunk_wptr
+= len
;
317 memset((uint8_t *)sc
->sc_dmapage
+ sc
->sc_dmaoffs
, 0, len
);
320 /* advance to next transfer if it's time to */
321 if ((chunk
->chunk_wresid
-= len
) <= 0) {
322 sc
->sc_wchunk
= sc
->sc_wchunk
->chunk_next
;
325 /* determine which interrupt to get */
327 /* just wait for next buffer to free */
328 PUTREG(sc
, SPI_IER
, SPI_SR_ENDRX
);
330 /* must wait until transfer has completed */
331 PUTREG(sc
, SPI_IDR
, SPI_SR_ENDRX
);
332 PUTREG(sc
, SPI_IER
, SPI_SR_RXBUFF
);
335 DPRINTFN(3, ("%s: dmaoffs=%d len=%d wchunk=%p (%p:%d) rchunk=%p (%p:%d) mr=%"PRIX32
" sr=%"PRIX32
" imr=%"PRIX32
" csr0=%"PRIX32
"\n",
336 __FUNCTION__
, sc
->sc_dmaoffs
, len
, sc
->sc_wchunk
,
337 sc
->sc_wchunk
? sc
->sc_wchunk
->chunk_wptr
: NULL
,
338 sc
->sc_wchunk
? sc
->sc_wchunk
->chunk_wresid
: -1,
340 sc
->sc_rchunk
? sc
->sc_rchunk
->chunk_rptr
: NULL
,
341 sc
->sc_rchunk
? sc
->sc_rchunk
->chunk_rresid
: -1,
342 GETREG(sc
, SPI_MR
), GETREG(sc
, SPI_SR
),
343 GETREG(sc
, SPI_IMR
), GETREG(sc
, SPI_CSR(0))));
346 bus_dmamap_sync(sc
->sc_dmat
, sc
->sc_dmamap
, sc
->sc_dmaoffs
, len
,
347 BUS_DMASYNC_PREWRITE
| BUS_DMASYNC_PREREAD
);
349 // and start transmitting / receiving
350 PUTREG(sc
, SPI_PDC_BASE
+ PDC_RNPR
, sc
->sc_dmaaddr
+ sc
->sc_dmaoffs
);
351 PUTREG(sc
, SPI_PDC_BASE
+ PDC_RNCR
, len
);
352 PUTREG(sc
, SPI_PDC_BASE
+ PDC_TNPR
, sc
->sc_dmaaddr
+ sc
->sc_dmaoffs
);
353 PUTREG(sc
, SPI_PDC_BASE
+ PDC_TNCR
, len
);
356 sc
->sc_dmaoffs
^= HALF_BUF_SIZE
;
361 DPRINTFN(3, ("%s: nothing to write anymore\n", __FUNCTION__
));
367 at91spi_sched(struct at91spi_softc
*sc
)
369 struct spi_transfer
*st
;
372 while ((st
= spi_transq_first(&sc
->sc_q
)) != NULL
) {
374 DPRINTFN(2, ("%s: st=%p\n", __FUNCTION__
, st
));
376 /* remove the item */
377 spi_transq_dequeue(&sc
->sc_q
);
379 /* note that we are working on it */
380 sc
->sc_transfer
= st
;
382 if ((err
= at91spi_select(sc
, st
->st_slave
)) != 0) {
388 sc
->sc_rchunk
= sc
->sc_wchunk
= st
->st_chunks
;
390 /* now kick the master start to get the chip running */
391 at91spi_xfer(sc
, TRUE
);
393 /* enable error interrupts too: */
394 PUTREG(sc
, SPI_IER
, SPI_SR_MODF
| SPI_SR_OVRES
);
396 sc
->sc_running
= TRUE
;
399 DPRINTFN(2, ("%s: nothing to do anymore\n", __FUNCTION__
));
400 PUTREG(sc
, SPI_IDR
, -1); /* disable interrupts */
401 at91spi_select(sc
, -1);
402 sc
->sc_running
= FALSE
;
406 at91spi_done(struct at91spi_softc
*sc
, int err
)
408 struct spi_transfer
*st
;
410 /* called from interrupt handler */
411 if ((st
= sc
->sc_transfer
) != NULL
) {
412 sc
->sc_transfer
= NULL
;
413 DPRINTFN(2, ("%s: st %p finished with error code %d\n", __FUNCTION__
, st
, err
));
416 /* make sure we clear these bits out */
417 sc
->sc_wchunk
= sc
->sc_rchunk
= NULL
;
422 at91spi_intr(void *arg
)
424 struct at91spi_softc
*sc
= arg
;
428 if ((imr
= GETREG(sc
, SPI_IMR
)) == 0) {
429 /* interrupts are not enabled, get out */
430 DPRINTFN(4, ("%s: interrupts are not enabled\n", __FUNCTION__
));
434 sr
= GETREG(sc
, SPI_SR
);
436 /* interrupt did not happen, get out */
437 DPRINTFN(3, ("%s: interrupts are not enabled, sr=%08"PRIX32
" imr=%08"PRIX32
"\n",
438 __FUNCTION__
, sr
, imr
));
442 DPRINTFN(3, ("%s: sr=%08"PRIX32
" imr=%08"PRIX32
"\n",
443 __FUNCTION__
, sr
, imr
));
445 if (sr
& imr
& SPI_SR_MODF
) {
446 printf("%s: mode fault!\n", device_xname(sc
->sc_dev
));
450 if (sr
& imr
& SPI_SR_OVRES
) {
451 printf("%s: overrun error!\n", device_xname(sc
->sc_dev
));
456 /* complete transfer */
457 at91spi_done(sc
, err
);
459 /* do all data exchanges */
460 at91spi_xfer(sc
, FALSE
);
463 * if the master done bit is set, make sure we do the
466 if (sr
& imr
& SPI_SR_RXBUFF
) {
467 if ((sc
->sc_wchunk
!= NULL
) ||
468 (sc
->sc_rchunk
!= NULL
)) {
469 printf("%s: partial transfer?\n",
470 device_xname(sc
->sc_dev
));
473 at91spi_done(sc
, err
);
482 at91spi_transfer(void *arg
, struct spi_transfer
*st
)
484 struct at91spi_softc
*sc
= arg
;
487 /* make sure we select the right chip */
489 spi_transq_enqueue(&sc
->sc_q
, st
);
490 if (sc
->sc_running
== 0) {