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