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