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