sam3n spi: revert to "end of transmit" interrupt instead of "tx buffer empty",
[bertos.git] / bertos / cpu / cortex-m3 / drv / ser_sam3.c
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
6  * Bertos is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * As a special exception, you may use this file as part of a free software
21  * library without restriction.  Specifically, if other files instantiate
22  * templates or use macros or inline functions from this file, or you compile
23  * this file and link it with other files to produce an executable, this
24  * file does not by itself cause the resulting executable to be covered by
25  * the GNU General Public License.  This exception does not however
26  * invalidate any other reasons why the executable file might be covered by
27  * the GNU General Public License.
28  *
29  * Copyright 2003, 2004 Develer S.r.l. (http://www.develer.com/)
30  * Copyright 2000 Bernie Innocenti <bernie@codewiz.org>
31  *
32  * -->
33  *
34  * \brief ARM UART and SPI I/O driver
35  *
36  *
37  * \author Daniele Basile <asterix@develer.com>
38  * \author Stefano Fedrigo <aleph@develer.com>
39  */
40
41 #include "hw/hw_ser.h"  /* Required for bus macros overrides */
42 #include <hw/hw_cpufreq.h>  /* CPU_FREQ */
43
44 #include "cfg/cfg_ser.h"
45 #include <cfg/debug.h>
46
47
48 //#include <io/arm.h>
49 #include <io/cm3.h>
50 #include <drv/irq_cm3.h>
51
52 #include <cpu/attr.h>
53
54 #include <drv/ser.h>
55 #include <drv/ser_p.h>
56
57 #include <struct/fifobuf.h>
58
59
60 #define SERIRQ_PRIORITY 4 ///< default priority for serial irqs.
61
62 /**
63  * \name Overridable serial bus hooks
64  *
65  * These can be redefined in hw.h to implement
66  * special bus policies such as half-duplex, 485, etc.
67  *
68  *
69  * \code
70  *  TXBEGIN      TXCHAR      TXEND  TXOFF
71  *    |   __________|__________ |     |
72  *    |   |   |   |   |   |   | |     |
73  *    v   v   v   v   v   v   v v     v
74  * ______  __  __  __  __  __  __  ________________
75  *       \/  \/  \/  \/  \/  \/  \/
76  * ______/\__/\__/\__/\__/\__/\__/
77  *
78  * \endcode
79  *
80  * \{
81  */
82
83 #ifndef SER_UART0_BUS_TXINIT
84         /**
85          * Default TXINIT macro - invoked in uart0_init()
86          *
87          * - Disable GPIO on USART0 tx/rx pins
88          */
89         #if CPU_ARM_AT91 && !CPU_ARM_SAM7S_LARGE && !CPU_ARM_SAM7X
90                 #warning Check USART0 pins!
91         #endif
92         #define SER_UART0_BUS_TXINIT do { \
93                 PIOA_PDR = BV(RXD0) | BV(TXD0); \
94         } while (0)
95 #endif
96
97 #ifndef SER_UART0_BUS_TXBEGIN
98         /**
99          * Invoked before starting a transmission
100          */
101         #define SER_UART0_BUS_TXBEGIN
102 #endif
103
104 #ifndef SER_UART0_BUS_TXCHAR
105         /**
106          * Invoked to send one character.
107          */
108         #define SER_UART0_BUS_TXCHAR(c) do { \
109                 US0_THR = (c); \
110         } while (0)
111 #endif
112
113 #ifndef SER_UART0_BUS_TXEND
114         /**
115          * Invoked as soon as the txfifo becomes empty
116          */
117         #define SER_UART0_BUS_TXEND
118 #endif
119
120 /* End USART0 macros */
121
122 #if !CPU_CM3_AT91SAM3U
123
124         #ifndef SER_UART1_BUS_TXINIT
125                 /**
126                  * Default TXINIT macro - invoked in uart1_init()
127                  *
128                  * - Disable GPIO on USART1 tx/rx pins
129                  */
130                 #if CPU_ARM_AT91
131                         #if !CPU_ARM_SAM7S_LARGE && !CPU_ARM_SAM7X
132                                 #warning Check USART1 pins!
133                         #endif
134                         #define SER_UART1_BUS_TXINIT do { \
135                                 PIOA_PDR = BV(RXD1) | BV(TXD1); \
136                         } while (0)
137                 #elif CPU_CM3_AT91SAM3
138                         #define SER_UART1_BUS_TXINIT do { \
139                                 PIOB_PDR = BV(RXD1) | BV(TXD1); \
140                         } while (0)
141                 #else
142                         #error Unknown CPU
143                 #endif
144         #endif
145
146         #ifndef SER_UART1_BUS_TXBEGIN
147                 /**
148                  * Invoked before starting a transmission
149                  */
150                 #define SER_UART1_BUS_TXBEGIN
151         #endif
152
153         #ifndef SER_UART1_BUS_TXCHAR
154                 /**
155                  * Invoked to send one character.
156                  */
157                 #define SER_UART1_BUS_TXCHAR(c) do { \
158                         US1_THR = (c); \
159                 } while (0)
160         #endif
161
162         #ifndef SER_UART1_BUS_TXEND
163                 /**
164                  * Invoked as soon as the txfifo becomes empty
165                  */
166                 #define SER_UART1_BUS_TXEND
167         #endif
168
169 #endif
170
171 /**
172 * \name Overridable SPI hooks
173 *
174 * These can be redefined in hw.h to implement
175 * special bus policies such as slave select pin handling, etc.
176 *
177 * \{
178 */
179
180 #ifndef SER_SPI0_BUS_TXINIT
181         /**
182         * Default TXINIT macro - invoked in spi_init()
183         * The default is no action.
184         */
185         #if CPU_CM3_AT91SAM3
186                 #define SER_SPI0_BUS_TXINIT do { \
187                         /* Disable PIO on SPI pins */ \
188                         PIOA_PDR = BV(SPI0_SPCK) | BV(SPI0_MOSI) | BV(SPI0_MISO); \
189                         /* PIO is peripheral A */ \
190                         PIOA_ABCDSR1 &= ~(BV(SPI0_SPCK) | BV(SPI0_MOSI) | BV(SPI0_MISO)); \
191                         PIOA_ABCDSR2 &= ~(BV(SPI0_SPCK) | BV(SPI0_MOSI) | BV(SPI0_MISO)); \
192                 } while (0)
193         #else
194                 #define SER_SPI0_BUS_TXINIT do { \
195                         /* Disable PIO on SPI pins */ \
196                         PIOA_PDR = BV(SPI0_SPCK) | BV(SPI0_MOSI) | BV(SPI0_MISO); \
197                 } while (0)
198         #endif
199 #endif
200
201 #ifndef SER_SPI0_BUS_TXCLOSE
202         /**
203         * Invoked after the last character has been transmitted.
204         * The default is no action.
205         */
206         #define SER_SPI0_BUS_TXCLOSE do { \
207                 /* Enable PIO on SPI pins */ \
208                 PIOA_PER = BV(SPI0_SPCK) | BV(SPI0_MOSI) | BV(SPI0_MISO); \
209         } while (0)
210 #endif
211
212 #if CPU_ARM_SAM7X
213
214         #ifndef SER_SPI1_BUS_TXINIT
215                 /**
216                 * Default TXINIT macro - invoked in spi_init()
217                 * The default is no action.
218                 */
219                 #define SER_SPI1_BUS_TXINIT do { \
220                         /* Disable PIO on SPI pins */ \
221                         PIOA_PDR = BV(SPI1_SPCK) | BV(SPI1_MOSI) | BV(SPI1_MISO); \
222                         /* SPI1 pins are on B peripheral function! */ \
223                         PIOA_BSR = BV(SPI1_SPCK) | BV(SPI1_MOSI) | BV(SPI1_MISO); \
224                 } while (0)
225         #endif
226
227         #ifndef SER_SPI1_BUS_TXCLOSE
228                 /**
229                 * Invoked after the last character has been transmitted.
230                 * The default is no action.
231                 */
232                 #define SER_SPI1_BUS_TXCLOSE do { \
233                         /* Enable PIO on SPI pins */ \
234                         PIOA_PER = BV(SPI1_SPCK) | BV(SPI1_MOSI) | BV(SPI1_MISO); \
235                 } while (0)
236         #endif
237 #endif
238 /*\}*/
239
240
241 /**
242  * \name Core dependent interrupt handling macros
243  *
244  * Atmel serial hardware is used on different CPU cores,
245  * i.e. SAM3 and SAM7.  The user interface of the serial
246  * subsystem is identical but core interrupt controllers
247  * are different.
248  *
249  * \{
250  */
251 #if CPU_ARM_AT91
252
253 INLINE void sysirq_setHandler(sysirq_t irq, sysirq_handler_t handler)
254 {
255         /* Set the vector. */
256         AIC_SVR(irq) = uart0_irq_dispatcher;
257
258         /* Initialize to level/edge sensitive with defined priority. */
259 #if CPU_ARM_SAM7X
260         if (irq == SPI0_ID || irq == SPI1_ID)
261 #else
262         if (irq == SPI0_ID)
263 #endif
264                 AIC_SMR(irq) = (AIC_SMR(irq) & ~AIC_SRCTYPE_MASK) | AIC_SRCTYPE_INT_EDGE_TRIGGERED;
265         else // USART/UART
266                 AIC_SMR(irq) = (AIC_SMR(irq) & ~AIC_SRCTYPE_MASK) | AIC_SRCTYPE_INT_LEVEL_SENSITIVE;
267
268         /* Enable IRQ */
269         AIC_IECR = BV(irq);
270 }
271
272 INLINE void sysirq_setPriority(sysirq_t irq, int prio)
273 {
274         AIC_SMR(irq) = (AIC_SMR(irq) & ~AIC_PRIOR_MASK) | SERIRQ_PRIORITY;
275 }
276
277 /** Inform hw that we have served the IRQ */
278 #define SER_INT_ACK do { \
279         AIC_EOICR = 0; \
280 } while (0)
281
282 #elif CPU_CM3_AT91SAM3
283
284 /** Inform hw that we have served the IRQ */
285 #define SER_INT_ACK do { /* nop */ } while (0)
286
287 #else
288         #error No interrupt handling macros defined for current architecture
289 #endif
290
291 /*\}*/
292
293 /* From the high-level serial driver */
294 extern struct Serial *ser_handles[SER_CNT];
295
296 /* TX and RX buffers */
297 static unsigned char uart0_txbuffer[CONFIG_UART0_TXBUFSIZE];
298 static unsigned char uart0_rxbuffer[CONFIG_UART0_RXBUFSIZE];
299 #if !CPU_CM3_AT91SAM3U
300 static unsigned char uart1_txbuffer[CONFIG_UART1_TXBUFSIZE];
301 static unsigned char uart1_rxbuffer[CONFIG_UART1_RXBUFSIZE];
302 #endif
303 static unsigned char spi0_txbuffer[CONFIG_SPI0_TXBUFSIZE];
304 static unsigned char spi0_rxbuffer[CONFIG_SPI0_RXBUFSIZE];
305 #if CPU_ARM_SAM7X
306 static unsigned char spi1_txbuffer[CONFIG_SPI1_TXBUFSIZE];
307 static unsigned char spi1_rxbuffer[CONFIG_SPI1_RXBUFSIZE];
308 #endif
309
310 /**
311  * Internal hardware state structure
312  *
313  * The \a sending variable is true while the transmission
314  * interrupt is retriggering itself.
315  *
316  * For the USARTs the \a sending flag is useful for taking specific
317  * actions before sending a burst of data, at the start of a trasmission
318  * but not before every char sent.
319  *
320  * For the SPI, this flag is necessary because the SPI sends and receives
321  * bytes at the same time and the SPI IRQ is unique for send/receive.
322  * The only way to start transmission is to write data in SPDR (this
323  * is done by spi_starttx()). We do this *only* if a transfer is
324  * not already started.
325  */
326 struct ArmSerial
327 {
328         struct SerialHardware hw;
329         volatile bool sending;
330 };
331
332 static ISR_PROTO(uart0_irq_dispatcher);
333 #if !CPU_CM3_AT91SAM3U
334 static ISR_PROTO(uart1_irq_dispatcher);
335 #endif
336 static ISR_PROTO(spi0_irq_handler);
337 #if CPU_ARM_SAM7X
338 static ISR_PROTO(spi1_irq_handler);
339 #endif
340 /*
341  * Callbacks for USART0
342  */
343 static void uart0_init(
344         UNUSED_ARG(struct SerialHardware *, _hw),
345         UNUSED_ARG(struct Serial *, ser))
346 {
347         US0_IDR = 0xFFFFFFFF;
348         PMC_PCER = BV(US0_ID);
349
350         /*
351          * - Reset USART0
352          * - Set serial param: mode Normal, 8bit data, 1bit stop, parity none
353          * - Enable both the receiver and the transmitter
354          * - Enable only the RX complete interrupt
355          */
356         US0_CR = BV(US_RSTRX) | BV(US_RSTTX);
357         US0_MR = US_CHMODE_NORMAL | US_CHRL_8 | US_NBSTOP_1 | US_PAR_NO;
358         US0_CR = BV(US_RXEN) | BV(US_TXEN);
359         US0_IER = BV(US_RXRDY);
360
361         SER_UART0_BUS_TXINIT;
362
363         sysirq_setPriority(INT_US0, SERIRQ_PRIORITY);
364         sysirq_setHandler(INT_US0, uart0_irq_dispatcher);
365
366         SER_STROBE_INIT;
367 }
368
369 static void uart0_cleanup(UNUSED_ARG(struct SerialHardware *, _hw))
370 {
371         US0_CR = BV(US_RSTRX) | BV(US_RSTTX) | BV(US_RXDIS) | BV(US_TXDIS) | BV(US_RSTSTA);
372 }
373
374 static void uart0_enabletxirq(struct SerialHardware *_hw)
375 {
376         struct ArmSerial *hw = (struct ArmSerial *)_hw;
377
378         /*
379          * WARNING: racy code here!  The tx interrupt sets hw->sending to false
380          * when it runs with an empty fifo.  The order of statements in the
381          * if-block matters.
382          */
383         if (!hw->sending)
384         {
385                 hw->sending = true;
386                 /*
387                  * - Enable the transmitter
388                  * - Enable TX empty interrupt
389                  */
390                 SER_UART0_BUS_TXBEGIN;
391                 US0_IER = BV(US_TXEMPTY);
392         }
393 }
394
395 static void uart0_setbaudrate(UNUSED_ARG(struct SerialHardware *, _hw), unsigned long rate)
396 {
397         /* Compute baud-rate period */
398         US0_BRGR = CPU_FREQ / (16 * rate);
399         //DB(kprintf("uart0_setbaudrate(rate=%lu): period=%d\n", rate, period);)
400 }
401
402 static void uart0_setparity(UNUSED_ARG(struct SerialHardware *, _hw), int parity)
403 {
404         US0_MR &= ~US_PAR_MASK;
405         /* Set UART parity */
406         switch(parity)
407         {
408                 case SER_PARITY_NONE:
409                 {
410                         /* Parity none. */
411                         US0_MR |= US_PAR_NO;
412                         break;
413                 }
414                 case SER_PARITY_EVEN:
415                 {
416                         /* Even parity. */
417                         US0_MR |= US_PAR_EVEN;
418                         break;
419                 }
420                 case SER_PARITY_ODD:
421                 {
422                         /* Odd parity. */
423                         US0_MR |= US_PAR_ODD;
424                         break;
425                 }
426                 default:
427                         ASSERT(0);
428         }
429 }
430 /*
431  * Callbacks for USART1
432  */
433 static void uart1_init(
434         UNUSED_ARG(struct SerialHardware *, _hw),
435         UNUSED_ARG(struct Serial *, ser))
436 {
437         US1_IDR = 0xFFFFFFFF;
438         PMC_PCER = BV(US1_ID);
439
440         /*
441          * - Reset USART1
442          * - Set serial param: mode Normal, 8bit data, 1bit stop, parity none
443          * - Enable both the receiver and the transmitter
444          * - Enable only the RX complete interrupt
445          */
446         US1_CR = BV(US_RSTRX) | BV(US_RSTTX);
447         US1_MR = US_CHMODE_NORMAL | US_CHRL_8 | US_NBSTOP_1 | US_PAR_NO;
448         US1_CR = BV(US_RXEN) | BV(US_TXEN);
449         US1_IER = BV(US_RXRDY);
450
451         SER_UART1_BUS_TXINIT;
452
453         sysirq_setPriority(INT_US1, SERIRQ_PRIORITY);
454         sysirq_setHandler(INT_US1, uart1_irq_dispatcher);
455
456         SER_STROBE_INIT;
457 }
458
459 static void uart1_cleanup(UNUSED_ARG(struct SerialHardware *, _hw))
460 {
461         US1_CR = BV(US_RSTRX) | BV(US_RSTTX) | BV(US_RXDIS) | BV(US_TXDIS) | BV(US_RSTSTA);
462 }
463
464 static void uart1_enabletxirq(struct SerialHardware *_hw)
465 {
466         struct ArmSerial *hw = (struct ArmSerial *)_hw;
467
468         /*
469          * WARNING: racy code here!  The tx interrupt sets hw->sending to false
470          * when it runs with an empty fifo.  The order of statements in the
471          * if-block matters.
472          */
473         if (!hw->sending)
474         {
475                 hw->sending = true;
476                 /*
477                  * - Enable the transmitter
478                  * - Enable TX empty interrupt
479                  */
480                 SER_UART1_BUS_TXBEGIN;
481                 US1_IER = BV(US_TXEMPTY);
482         }
483 }
484
485 static void uart1_setbaudrate(UNUSED_ARG(struct SerialHardware *, _hw), unsigned long rate)
486 {
487         /* Compute baud-rate period */
488         US1_BRGR = CPU_FREQ / (16 * rate);
489         //DB(kprintf("uart0_setbaudrate(rate=%lu): period=%d\n", rate, period);)
490 }
491
492 static void uart1_setparity(UNUSED_ARG(struct SerialHardware *, _hw), int parity)
493 {
494         US1_MR &= ~US_PAR_MASK;
495         /* Set UART parity */
496         switch(parity)
497         {
498                 case SER_PARITY_NONE:
499                 {
500                         /* Parity none. */
501                         US1_MR |= US_PAR_NO;
502                         break;
503                 }
504                 case SER_PARITY_EVEN:
505                 {
506                         /* Even parity. */
507                         US1_MR |= US_PAR_EVEN;
508                         break;
509                 }
510                 case SER_PARITY_ODD:
511                 {
512                         /* Odd parity. */
513                         US1_MR |= US_PAR_ODD;
514                         break;
515                 }
516                 default:
517                         ASSERT(0);
518         }
519 }
520
521 /* SPI driver */
522 static void spi0_init(UNUSED_ARG(struct SerialHardware *, _hw), UNUSED_ARG(struct Serial *, ser))
523 {
524         SER_SPI0_BUS_TXINIT;
525
526         /* Reset device */
527         SPI0_CR = BV(SPI_SWRST);
528
529         /*
530          * Set SPI to master mode, fixed peripheral select, chip select directly connected to a peripheral device,
531          * SPI clock set to MCK, mode fault detection disabled, loopback disable, NPCS0 active, Delay between CS = 0
532          */
533         SPI0_MR = BV(SPI_MSTR) | BV(SPI_MODFDIS);
534
535         /*
536          * Set SPI mode.
537          * At reset clock division factor is set to 0, that is
538          * *forbidden*. Set SPI clock to minimum to keep it valid.
539          * Set all possible chip select registers in case user manually
540          * change CPS field in SPI_MR.
541          */
542         SPI0_CSR0 = BV(SPI_NCPHA) | (255 << SPI_SCBR_SHIFT);
543         SPI0_CSR1 = BV(SPI_NCPHA) | (255 << SPI_SCBR_SHIFT);
544         SPI0_CSR2 = BV(SPI_NCPHA) | (255 << SPI_SCBR_SHIFT);
545         SPI0_CSR3 = BV(SPI_NCPHA) | (255 << SPI_SCBR_SHIFT);
546
547         /* Disable all irqs */
548         SPI0_IDR = 0xFFFFFFFF;
549
550         //sysirq_setPriority(INT_SPI0, SERIRQ_PRIORITY);
551         sysirq_setHandler(INT_SPI0, spi0_irq_handler);
552         PMC_PCER = BV(SPI0_ID);
553
554         /* Enable SPI */
555         SPI0_CR = BV(SPI_SPIEN);
556
557         SER_STROBE_INIT;
558 }
559
560 static void spi0_cleanup(UNUSED_ARG(struct SerialHardware *, _hw))
561 {
562         /* Disable SPI */
563         SPI0_CR = BV(SPI_SPIDIS);
564
565         /* Disable all irqs */
566         SPI0_IDR = 0xFFFFFFFF;
567
568         SER_SPI0_BUS_TXCLOSE;
569 }
570
571 static void spi0_starttx(struct SerialHardware *_hw)
572 {
573         struct ArmSerial *hw = (struct ArmSerial *)_hw;
574
575         cpu_flags_t flags;
576         IRQ_SAVE_DISABLE(flags);
577
578         /* Send data only if the SPI is not already transmitting */
579         if (!hw->sending && !fifo_isempty(&ser_handles[SER_SPI0]->txfifo))
580         {
581                 hw->sending = true;
582                 SPI0_TDR = fifo_pop(&ser_handles[SER_SPI0]->txfifo);
583                 /* Enable interrupt on tx buffer empty */
584                 SPI0_IER = BV(SPI_TXEMPTY);
585         }
586
587         IRQ_RESTORE(flags);
588 }
589
590 static void spi0_setbaudrate(UNUSED_ARG(struct SerialHardware *, _hw), unsigned long rate)
591 {
592         SPI0_CSR0 &= ~SPI_SCBR;
593
594         ASSERT((uint8_t)DIV_ROUND(CPU_FREQ, rate));
595         SPI0_CSR0 |= DIV_ROUND(CPU_FREQ, rate) << SPI_SCBR_SHIFT;
596 }
597
598 #if CPU_ARM_SAM7X
599 /* SPI driver */
600 static void spi1_init(UNUSED_ARG(struct SerialHardware *, _hw), UNUSED_ARG(struct Serial *, ser))
601 {
602         SER_SPI1_BUS_TXINIT;
603
604         /* Reset device */
605         SPI1_CR = BV(SPI_SWRST);
606
607         /*
608          * Set SPI to master mode, fixed peripheral select, chip select directly connected to a peripheral device,
609          * SPI clock set to MCK, mode fault detection disabled, loopback disable, NPCS0 active, Delay between CS = 0
610          */
611         SPI1_MR = BV(SPI_MSTR) | BV(SPI_MODFDIS);
612
613         /*
614          * Set SPI mode.
615          * At reset clock division factor is set to 0, that is
616          * *forbidden*. Set SPI clock to minimum to keep it valid.
617          * Set all possible chip select registers in case user manually
618          * change chip select.
619          */
620         SPI1_CSR0 = BV(SPI_NCPHA) | (255 << SPI_SCBR_SHIFT);
621         SPI1_CSR1 = BV(SPI_NCPHA) | (255 << SPI_SCBR_SHIFT);
622         SPI1_CSR2 = BV(SPI_NCPHA) | (255 << SPI_SCBR_SHIFT);
623         SPI1_CSR3 = BV(SPI_NCPHA) | (255 << SPI_SCBR_SHIFT);
624
625         /* Disable all SPI irqs */
626         SPI1_IDR = 0xFFFFFFFF;
627
628         sysirq_setPriority(INT_SPI1, SERIRQ_PRIORITY);
629         sysirq_setHandler(INT_SPI1, spi1_irq_dispatcher);
630         PMC_PCER = BV(SPI1_ID);
631
632         /* Enable SPI */
633         SPI1_CR = BV(SPI_SPIEN);
634
635         SER_STROBE_INIT;
636 }
637
638 static void spi1_cleanup(UNUSED_ARG(struct SerialHardware *, _hw))
639 {
640         /* Disable SPI */
641         SPI1_CR = BV(SPI_SPIDIS);
642
643         /* Disable all irqs */
644         SPI1_IDR = 0xFFFFFFFF;
645
646         SER_SPI1_BUS_TXCLOSE;
647 }
648
649 static void spi1_starttx(struct SerialHardware *_hw)
650 {
651         struct ArmSerial *hw = (struct ArmSerial *)_hw;
652
653         cpu_flags_t flags;
654         IRQ_SAVE_DISABLE(flags);
655
656         /* Send data only if the SPI is not already transmitting */
657         if (!hw->sending && !fifo_isempty(&ser_handles[SER_SPI1]->txfifo))
658         {
659                 hw->sending = true;
660                 SPI1_TDR = fifo_pop(&ser_handles[SER_SPI1]->txfifo);
661                 /* Enable interrupt on tx buffer empty */
662                 SPI1_IER = BV(SPI_TXEMPTY);
663         }
664
665         IRQ_RESTORE(flags);
666 }
667
668 static void spi1_setbaudrate(UNUSED_ARG(struct SerialHardware *, _hw), unsigned long rate)
669 {
670         SPI1_CSR0 &= ~SPI_SCBR;
671
672         ASSERT((uint8_t)DIV_ROUND(CPU_FREQ, rate));
673         SPI1_CSR0 |= DIV_ROUND(CPU_FREQ, rate) << SPI_SCBR_SHIFT;
674 }
675 #endif
676
677 static void spi_setparity(UNUSED_ARG(struct SerialHardware *, _hw), UNUSED_ARG(int, parity))
678 {
679         // nop
680 }
681
682
683 static bool tx_sending(struct SerialHardware* _hw)
684 {
685         struct ArmSerial *hw = (struct ArmSerial *)_hw;
686         return hw->sending;
687 }
688
689 // FIXME: move into compiler.h?  Ditch?
690 #if COMPILER_C99
691         #define C99INIT(name,val) .name = val
692 #elif defined(__GNUC__)
693         #define C99INIT(name,val) name: val
694 #else
695         #warning No designated initializers, double check your code
696         #define C99INIT(name,val) (val)
697 #endif
698
699 /*
700  * High-level interface data structures
701  */
702 static const struct SerialHardwareVT UART0_VT =
703 {
704         C99INIT(init, uart0_init),
705         C99INIT(cleanup, uart0_cleanup),
706         C99INIT(setBaudrate, uart0_setbaudrate),
707         C99INIT(setParity, uart0_setparity),
708         C99INIT(txStart, uart0_enabletxirq),
709         C99INIT(txSending, tx_sending),
710 };
711
712 static const struct SerialHardwareVT UART1_VT =
713 {
714         C99INIT(init, uart1_init),
715         C99INIT(cleanup, uart1_cleanup),
716         C99INIT(setBaudrate, uart1_setbaudrate),
717         C99INIT(setParity, uart1_setparity),
718         C99INIT(txStart, uart1_enabletxirq),
719         C99INIT(txSending, tx_sending),
720 };
721
722 static const struct SerialHardwareVT SPI0_VT =
723 {
724         C99INIT(init, spi0_init),
725         C99INIT(cleanup, spi0_cleanup),
726         C99INIT(setBaudrate, spi0_setbaudrate),
727         C99INIT(setParity, spi_setparity),
728         C99INIT(txStart, spi0_starttx),
729         C99INIT(txSending, tx_sending),
730 };
731 #if CPU_ARM_SAM7X
732 static const struct SerialHardwareVT SPI1_VT =
733 {
734         C99INIT(init, spi1_init),
735         C99INIT(cleanup, spi1_cleanup),
736         C99INIT(setBaudrate, spi1_setbaudrate),
737         C99INIT(setParity, spi_setparity),
738         C99INIT(txStart, spi1_starttx),
739         C99INIT(txSending, tx_sending),
740 };
741 #endif
742
743 static struct ArmSerial UARTDescs[SER_CNT] =
744 {
745         {
746                 C99INIT(hw, /**/) {
747                         C99INIT(table, &UART0_VT),
748                         C99INIT(txbuffer, uart0_txbuffer),
749                         C99INIT(rxbuffer, uart0_rxbuffer),
750                         C99INIT(txbuffer_size, sizeof(uart0_txbuffer)),
751                         C99INIT(rxbuffer_size, sizeof(uart0_rxbuffer)),
752                 },
753                 C99INIT(sending, false),
754         },
755         {
756                 C99INIT(hw, /**/) {
757                         C99INIT(table, &UART1_VT),
758                         C99INIT(txbuffer, uart1_txbuffer),
759                         C99INIT(rxbuffer, uart1_rxbuffer),
760                         C99INIT(txbuffer_size, sizeof(uart1_txbuffer)),
761                         C99INIT(rxbuffer_size, sizeof(uart1_rxbuffer)),
762                 },
763                 C99INIT(sending, false),
764         },
765
766         {
767                 C99INIT(hw, /**/) {
768                         C99INIT(table, &SPI0_VT),
769                         C99INIT(txbuffer, spi0_txbuffer),
770                         C99INIT(rxbuffer, spi0_rxbuffer),
771                         C99INIT(txbuffer_size, sizeof(spi0_txbuffer)),
772                         C99INIT(rxbuffer_size, sizeof(spi0_rxbuffer)),
773                 },
774                 C99INIT(sending, false),
775         },
776         #if CPU_ARM_SAM7X
777         {
778                 C99INIT(hw, /**/) {
779                         C99INIT(table, &SPI1_VT),
780                         C99INIT(txbuffer, spi1_txbuffer),
781                         C99INIT(rxbuffer, spi1_rxbuffer),
782                         C99INIT(txbuffer_size, sizeof(spi1_txbuffer)),
783                         C99INIT(rxbuffer_size, sizeof(spi1_rxbuffer)),
784                 },
785                 C99INIT(sending, false),
786         }
787
788         #endif
789 };
790
791 struct SerialHardware *ser_hw_getdesc(int unit)
792 {
793         ASSERT(unit < SER_CNT);
794         return &UARTDescs[unit].hw;
795 }
796
797 /**
798  * Serial 0 TX interrupt handler
799  */
800 INLINE void uart0_irq_tx(void)
801 {
802         SER_STROBE_ON;
803
804         struct FIFOBuffer * const txfifo = &ser_handles[SER_UART0]->txfifo;
805
806         if (fifo_isempty(txfifo))
807         {
808                 /*
809                  * - Disable the TX empty interrupts
810                  */
811                 US0_IDR = BV(US_TXEMPTY);
812                 SER_UART0_BUS_TXEND;
813                 UARTDescs[SER_UART0].sending = false;
814         }
815         else
816         {
817                 char c = fifo_pop(txfifo);
818                 SER_UART0_BUS_TXCHAR(c);
819         }
820
821         SER_STROBE_OFF;
822 }
823
824 /**
825  * Serial 0 RX complete interrupt handler.
826  */
827 INLINE void uart0_irq_rx(void)
828 {
829         SER_STROBE_ON;
830
831         /* Should be read before US_CRS */
832         ser_handles[SER_UART0]->status |= US0_CSR & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
833         US0_CR = BV(US_RSTSTA);
834
835         char c = US0_RHR;
836         struct FIFOBuffer * const rxfifo = &ser_handles[SER_UART0]->rxfifo;
837
838         if (fifo_isfull(rxfifo))
839                 ser_handles[SER_UART0]->status |= SERRF_RXFIFOOVERRUN;
840         else
841                 fifo_push(rxfifo, c);
842
843         SER_STROBE_OFF;
844 }
845
846 /**
847  * Serial IRQ dispatcher for USART0.
848  */
849 static DECLARE_ISR(uart0_irq_dispatcher)
850 {
851         if (US0_CSR & BV(US_RXRDY))
852                 uart0_irq_rx();
853
854         if (US0_CSR & BV(US_TXEMPTY))
855                 uart0_irq_tx();
856
857         SER_INT_ACK;
858 }
859
860 /**
861  * Serial 1 TX interrupt handler
862  */
863 INLINE void uart1_irq_tx(void)
864 {
865         SER_STROBE_ON;
866
867         struct FIFOBuffer * const txfifo = &ser_handles[SER_UART1]->txfifo;
868
869         if (fifo_isempty(txfifo))
870         {
871                 /*
872                  * - Disable the TX empty interrupts
873                  */
874                 US1_IDR = BV(US_TXEMPTY);
875                 SER_UART1_BUS_TXEND;
876                 UARTDescs[SER_UART1].sending = false;
877         }
878         else
879         {
880                 char c = fifo_pop(txfifo);
881                 SER_UART1_BUS_TXCHAR(c);
882         }
883
884         SER_STROBE_OFF;
885 }
886
887 /**
888  * Serial 1 RX complete interrupt handler.
889  */
890 INLINE void uart1_irq_rx(void)
891 {
892         SER_STROBE_ON;
893
894         /* Should be read before US_CRS */
895         ser_handles[SER_UART1]->status |= US1_CSR & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
896         US1_CR = BV(US_RSTSTA);
897
898         char c = US1_RHR;
899         struct FIFOBuffer * const rxfifo = &ser_handles[SER_UART1]->rxfifo;
900
901         if (fifo_isfull(rxfifo))
902                 ser_handles[SER_UART1]->status |= SERRF_RXFIFOOVERRUN;
903         else
904                 fifo_push(rxfifo, c);
905
906         SER_STROBE_OFF;
907 }
908
909 /**
910  * Serial IRQ dispatcher for USART1.
911  */
912 static DECLARE_ISR(uart1_irq_dispatcher)
913 {
914         if (US1_CSR & BV(US_RXRDY))
915                 uart1_irq_rx();
916
917         if (US1_CSR & BV(US_TXEMPTY))
918                 uart1_irq_tx();
919
920         SER_INT_ACK;
921 }
922
923 /**
924  * SPI0 interrupt handler
925  */
926 static DECLARE_ISR(spi0_irq_handler)
927 {
928         SER_STROBE_ON;
929
930         char c = SPI0_RDR;
931         /* Read incoming byte. */
932         if (!fifo_isfull(&ser_handles[SER_SPI0]->rxfifo))
933                 fifo_push(&ser_handles[SER_SPI0]->rxfifo, c);
934         /*
935          * FIXME
936         else
937                 ser_handles[SER_SPI0]->status |= SERRF_RXFIFOOVERRUN;
938         */
939
940         /* Send */
941         if (!fifo_isempty(&ser_handles[SER_SPI0]->txfifo))
942                 SPI0_TDR = fifo_pop(&ser_handles[SER_SPI0]->txfifo);
943         else
944         {
945                 UARTDescs[SER_SPI0].sending = false;
946                 /* Disable interrupt on tx buffer empty */
947                 SPI0_IDR = BV(SPI_TXEMPTY);
948         }
949
950         SER_INT_ACK;
951
952         SER_STROBE_OFF;
953 }
954
955
956 #if CPU_ARM_SAM7X
957 /**
958  * SPI1 interrupt handler
959  */
960 static DECLARE_ISR(spi1_irq_handler)
961 {
962         SER_STROBE_ON;
963
964         char c = SPI1_RDR;
965         /* Read incoming byte. */
966         if (!fifo_isfull(&ser_handles[SER_SPI1]->rxfifo))
967                 fifo_push(&ser_handles[SER_SPI1]->rxfifo, c);
968         /*
969          * FIXME
970         else
971                 ser_handles[SER_SPI1]->status |= SERRF_RXFIFOOVERRUN;
972         */
973
974         /* Send */
975         if (!fifo_isempty(&ser_handles[SER_SPI1]->txfifo))
976                 SPI1_TDR = fifo_pop(&ser_handles[SER_SPI1]->txfifo);
977         else
978         {
979                 UARTDescs[SER_SPI1].sending = false;
980                 /* Disable interrupt on tx buffer empty */
981                 SPI1_IDR = BV(SPI_TXEMPTY);
982         }
983
984         SER_INT_ACK;
985
986         SER_STROBE_OFF;
987 }
988 #endif