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