aacb99b6895e9625c78e812989ae2c5b5a1981c8
[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         /* SPI1 pins are on B peripheral function! */
534         PIOA_BSR = BV(SPI1_SPCK) | BV(SPI1_MOSI) | BV(SPI1_MISO);
535
536         /* Reset device */
537         SPI1_CR = BV(SPI_SWRST);
538
539         /*
540          * Set SPI to master mode, fixed peripheral select, chip select directly connected to a peripheral device,
541          * SPI clock set to MCK, mode fault detection disabled, loopback disable, NPCS0 active, Delay between CS = 0
542          */
543         SPI1_MR = BV(SPI_MSTR) | BV(SPI_MODFDIS);
544
545         /*
546          * Set SPI mode.
547          * At reset clock division factor is set to 0, that is
548          * *forbidden*. Set SPI clock to minimum to keep it valid.
549          */
550         SPI1_CSR0 = BV(SPI_NCPHA) | (255 << SPI_SCBR_SHIFT);
551
552         /* Disable all irqs */
553         SPI1_IDR = 0xFFFFFFFF;
554         /* Set the vector. */
555         AIC_SVR(SPI1_ID) = spi1_irq_handler;
556         /* Initialize to edge triggered with defined priority. */
557         AIC_SMR(SPI1_ID) = AIC_SRCTYPE_INT_EDGE_TRIGGERED | SERIRQ_PRIORITY;
558         /* Enable the USART IRQ */
559         AIC_IECR = BV(SPI1_ID);
560         PMC_PCER = BV(SPI1_ID);
561
562         /* Enable interrupt on tx buffer empty */
563         SPI1_IER = BV(SPI_TXEMPTY);
564
565         /* Enable SPI */
566         SPI1_CR = BV(SPI_SPIEN);
567
568
569         SER_SPI1_BUS_TXINIT;
570
571         SER_STROBE_INIT;
572 }
573
574 static void spi1_cleanup(UNUSED_ARG(struct SerialHardware *, _hw))
575 {
576         /* Disable SPI */
577         SPI1_CR = BV(SPI_SPIDIS);
578
579         /* Disable all irqs */
580         SPI1_IDR = 0xFFFFFFFF;
581
582         SER_SPI1_BUS_TXCLOSE;
583
584         /* Enable PIO on SPI pins */
585         PIOA_PER = BV(SPI1_SPCK) | BV(SPI1_MOSI) | BV(SPI1_MISO);
586 }
587
588 static void spi1_starttx(struct SerialHardware *_hw)
589 {
590         struct ArmSerial *hw = (struct ArmSerial *)_hw;
591
592         cpu_flags_t flags;
593         IRQ_SAVE_DISABLE(flags);
594
595         /* Send data only if the SPI is not already transmitting */
596         if (!hw->sending && !fifo_isempty(&ser_handles[SER_SPI1]->txfifo))
597         {
598                 hw->sending = true;
599                 SPI1_TDR = fifo_pop(&ser_handles[SER_SPI1]->txfifo);
600         }
601
602         IRQ_RESTORE(flags);
603 }
604
605 static void spi1_setbaudrate(UNUSED_ARG(struct SerialHardware *, _hw), unsigned long rate)
606 {
607         SPI1_CSR0 &= ~SPI_SCBR;
608
609         ASSERT((uint8_t)DIV_ROUND(CPU_FREQ, rate));
610         SPI1_CSR0 |= DIV_ROUND(CPU_FREQ, rate) << SPI_SCBR_SHIFT;
611 }
612 #endif
613
614 static void spi_setparity(UNUSED_ARG(struct SerialHardware *, _hw), UNUSED_ARG(int, parity))
615 {
616         // nop
617 }
618
619
620 static bool tx_sending(struct SerialHardware* _hw)
621 {
622         struct ArmSerial *hw = (struct ArmSerial *)_hw;
623         return hw->sending;
624 }
625
626 // FIXME: move into compiler.h?  Ditch?
627 #if COMPILER_C99
628         #define C99INIT(name,val) .name = val
629 #elif defined(__GNUC__)
630         #define C99INIT(name,val) name: val
631 #else
632         #warning No designated initializers, double check your code
633         #define C99INIT(name,val) (val)
634 #endif
635
636 /*
637  * High-level interface data structures
638  */
639 static const struct SerialHardwareVT UART0_VT =
640 {
641         C99INIT(init, uart0_init),
642         C99INIT(cleanup, uart0_cleanup),
643         C99INIT(setBaudrate, uart0_setbaudrate),
644         C99INIT(setParity, uart0_setparity),
645         C99INIT(txStart, uart0_enabletxirq),
646         C99INIT(txSending, tx_sending),
647 };
648
649 static const struct SerialHardwareVT UART1_VT =
650 {
651         C99INIT(init, uart1_init),
652         C99INIT(cleanup, uart1_cleanup),
653         C99INIT(setBaudrate, uart1_setbaudrate),
654         C99INIT(setParity, uart1_setparity),
655         C99INIT(txStart, uart1_enabletxirq),
656         C99INIT(txSending, tx_sending),
657 };
658
659 static const struct SerialHardwareVT SPI0_VT =
660 {
661         C99INIT(init, spi0_init),
662         C99INIT(cleanup, spi0_cleanup),
663         C99INIT(setBaudrate, spi0_setbaudrate),
664         C99INIT(setParity, spi_setparity),
665         C99INIT(txStart, spi0_starttx),
666         C99INIT(txSending, tx_sending),
667 };
668 #if CPU_ARM_SAM7X
669 static const struct SerialHardwareVT SPI1_VT =
670 {
671         C99INIT(init, spi1_init),
672         C99INIT(cleanup, spi1_cleanup),
673         C99INIT(setBaudrate, spi1_setbaudrate),
674         C99INIT(setParity, spi_setparity),
675         C99INIT(txStart, spi1_starttx),
676         C99INIT(txSending, tx_sending),
677 };
678 #endif
679
680 static struct ArmSerial UARTDescs[SER_CNT] =
681 {
682         {
683                 C99INIT(hw, /**/) {
684                         C99INIT(table, &UART0_VT),
685                         C99INIT(txbuffer, uart0_txbuffer),
686                         C99INIT(rxbuffer, uart0_rxbuffer),
687                         C99INIT(txbuffer_size, sizeof(uart0_txbuffer)),
688                         C99INIT(rxbuffer_size, sizeof(uart0_rxbuffer)),
689                 },
690                 C99INIT(sending, false),
691         },
692         {
693                 C99INIT(hw, /**/) {
694                         C99INIT(table, &UART1_VT),
695                         C99INIT(txbuffer, uart1_txbuffer),
696                         C99INIT(rxbuffer, uart1_rxbuffer),
697                         C99INIT(txbuffer_size, sizeof(uart1_txbuffer)),
698                         C99INIT(rxbuffer_size, sizeof(uart1_rxbuffer)),
699                 },
700                 C99INIT(sending, false),
701         },
702
703         {
704                 C99INIT(hw, /**/) {
705                         C99INIT(table, &SPI0_VT),
706                         C99INIT(txbuffer, spi0_txbuffer),
707                         C99INIT(rxbuffer, spi0_rxbuffer),
708                         C99INIT(txbuffer_size, sizeof(spi0_txbuffer)),
709                         C99INIT(rxbuffer_size, sizeof(spi0_rxbuffer)),
710                 },
711                 C99INIT(sending, false),
712         },
713         #if CPU_ARM_SAM7X
714         {
715                 C99INIT(hw, /**/) {
716                         C99INIT(table, &SPI1_VT),
717                         C99INIT(txbuffer, spi1_txbuffer),
718                         C99INIT(rxbuffer, spi1_rxbuffer),
719                         C99INIT(txbuffer_size, sizeof(spi1_txbuffer)),
720                         C99INIT(rxbuffer_size, sizeof(spi1_rxbuffer)),
721                 },
722                 C99INIT(sending, false),
723         }
724
725         #endif
726 };
727
728 struct SerialHardware *ser_hw_getdesc(int unit)
729 {
730         ASSERT(unit < SER_CNT);
731         return &UARTDescs[unit].hw;
732 }
733
734 /**
735  * Serial 0 TX interrupt handler
736  */
737 static void uart0_irq_tx(void)
738 {
739         SER_STROBE_ON;
740
741         struct FIFOBuffer * const txfifo = &ser_handles[SER_UART0]->txfifo;
742
743         if (fifo_isempty(txfifo))
744         {
745                 /*
746                  * - Disable the TX empty interrupts
747                  */
748                 US0_IDR = BV(US_TXEMPTY);
749                 SER_UART0_BUS_TXEND;
750                 UARTDescs[SER_UART0].sending = false;
751         }
752         else
753         {
754                 char c = fifo_pop(txfifo);
755                 SER_UART0_BUS_TXCHAR(c);
756         }
757
758         SER_STROBE_OFF;
759 }
760
761 /**
762  * Serial 0 RX complete interrupt handler.
763  */
764 static void uart0_irq_rx(void)
765 {
766         SER_STROBE_ON;
767
768         /* Should be read before US_CRS */
769         ser_handles[SER_UART0]->status |= US0_CSR & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
770         US0_CR = BV(US_RSTSTA);
771
772         char c = US0_RHR;
773         struct FIFOBuffer * const rxfifo = &ser_handles[SER_UART0]->rxfifo;
774
775         if (fifo_isfull(rxfifo))
776                 ser_handles[SER_UART0]->status |= SERRF_RXFIFOOVERRUN;
777         else
778                 fifo_push(rxfifo, c);
779
780         SER_STROBE_OFF;
781 }
782
783 /**
784  * Serial IRQ dispatcher for USART0.
785  */
786 static void uart0_irq_dispatcher(void) __attribute__ ((interrupt));
787 static void uart0_irq_dispatcher(void)
788 {
789         if (US0_CSR & BV(US_RXRDY))
790                 uart0_irq_rx();
791
792         if (US0_CSR & BV(US_TXEMPTY))
793                 uart0_irq_tx();
794
795         /* Inform hw that we have served the IRQ */
796         AIC_EOICR = 0;
797 }
798
799 /**
800  * Serial 1 TX interrupt handler
801  */
802 static void uart1_irq_tx(void)
803 {
804         SER_STROBE_ON;
805
806         struct FIFOBuffer * const txfifo = &ser_handles[SER_UART1]->txfifo;
807
808         if (fifo_isempty(txfifo))
809         {
810                 /*
811                  * - Disable the TX empty interrupts
812                  */
813                 US1_IDR = BV(US_TXEMPTY);
814                 SER_UART1_BUS_TXEND;
815                 UARTDescs[SER_UART1].sending = false;
816         }
817         else
818         {
819                 char c = fifo_pop(txfifo);
820                 SER_UART1_BUS_TXCHAR(c);
821         }
822
823         SER_STROBE_OFF;
824 }
825
826 /**
827  * Serial 1 RX complete interrupt handler.
828  */
829 static void uart1_irq_rx(void)
830 {
831         SER_STROBE_ON;
832
833         /* Should be read before US_CRS */
834         ser_handles[SER_UART1]->status |= US1_CSR & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
835         US1_CR = BV(US_RSTSTA);
836
837         char c = US1_RHR;
838         struct FIFOBuffer * const rxfifo = &ser_handles[SER_UART1]->rxfifo;
839
840         if (fifo_isfull(rxfifo))
841                 ser_handles[SER_UART1]->status |= SERRF_RXFIFOOVERRUN;
842         else
843                 fifo_push(rxfifo, c);
844
845         SER_STROBE_OFF;
846 }
847
848 /**
849  * Serial IRQ dispatcher for USART1.
850  */
851 static void uart1_irq_dispatcher(void) __attribute__ ((interrupt));
852 static void uart1_irq_dispatcher(void)
853 {
854         if (US1_CSR & BV(US_RXRDY))
855                 uart1_irq_rx();
856
857         if (US1_CSR & BV(US_TXEMPTY))
858                 uart1_irq_tx();
859
860         /* Inform hw that we have served the IRQ */
861         AIC_EOICR = 0;
862 }
863
864 /**
865  * SPI0 interrupt handler
866  */
867 static void spi0_irq_handler(void) __attribute__ ((interrupt));
868 static void spi0_irq_handler(void)
869 {
870         SER_STROBE_ON;
871
872         char c = SPI0_RDR;
873         /* Read incoming byte. */
874         if (!fifo_isfull(&ser_handles[SER_SPI0]->rxfifo))
875                 fifo_push(&ser_handles[SER_SPI0]->rxfifo, c);
876         /*
877          * FIXME
878         else
879                 ser_handles[SER_SPI0]->status |= SERRF_RXFIFOOVERRUN;
880         */
881
882         /* Send */
883         if (!fifo_isempty(&ser_handles[SER_SPI0]->txfifo))
884                 SPI0_TDR = fifo_pop(&ser_handles[SER_SPI0]->txfifo);
885         else
886                 UARTDescs[SER_SPI0].sending = false;
887
888         /* Inform hw that we have served the IRQ */
889         AIC_EOICR = 0;
890         SER_STROBE_OFF;
891 }
892
893
894 #if CPU_ARM_SAM7X
895 /**
896  * SPI1 interrupt handler
897  */
898 static void spi1_irq_handler(void) __attribute__ ((interrupt));
899 static void spi1_irq_handler(void)
900 {
901         SER_STROBE_ON;
902
903         char c = SPI1_RDR;
904         /* Read incoming byte. */
905         if (!fifo_isfull(&ser_handles[SER_SPI1]->rxfifo))
906                 fifo_push(&ser_handles[SER_SPI1]->rxfifo, c);
907         /*
908          * FIXME
909         else
910                 ser_handles[SER_SPI1]->status |= SERRF_RXFIFOOVERRUN;
911         */
912
913         /* Send */
914         if (!fifo_isempty(&ser_handles[SER_SPI1]->txfifo))
915                 SPI1_TDR = fifo_pop(&ser_handles[SER_SPI1]->txfifo);
916         else
917                 UARTDescs[SER_SPI1].sending = false;
918
919         /* Inform hw that we have served the IRQ */
920         AIC_EOICR = 0;
921         SER_STROBE_OFF;
922 }
923 #endif