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