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