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