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