sam3: generalize AB(CD)SR register definition for sam3x, add
[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                 PIO_PERIPH_SEL(PIOA_BASE, BV(RXD0) | BV(TXD0), PIO_PERIPH_A); \
95         } while (0)
96 #endif
97
98 #ifndef SER_UART0_BUS_TXBEGIN
99         /**
100          * Invoked before starting a transmission
101          */
102         #define SER_UART0_BUS_TXBEGIN
103 #endif
104
105 #ifndef SER_UART0_BUS_TXCHAR
106         /**
107          * Invoked to send one character.
108          */
109         #define SER_UART0_BUS_TXCHAR(c) do { \
110                 US0_THR = (c); \
111         } while (0)
112 #endif
113
114 #ifndef SER_UART0_BUS_TXEND
115         /**
116          * Invoked as soon as the txfifo becomes empty
117          */
118         #define SER_UART0_BUS_TXEND
119 #endif
120
121 /* End USART0 macros */
122
123 #if USART_PORTS > 1
124
125         #ifndef SER_UART1_BUS_TXINIT
126                 /**
127                  * Default TXINIT macro - invoked in uart1_init()
128                  *
129                  * - Disable GPIO on USART1 tx/rx pins
130                  */
131                 #if CPU_ARM_AT91 && !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                         PIO_PERIPH_SEL(PIOA_BASE, BV(RXD1) | BV(TXD1), PIO_PERIPH_A); \
137                 } while (0)
138         #endif
139
140         #ifndef SER_UART1_BUS_TXBEGIN
141                 /**
142                  * Invoked before starting a transmission
143                  */
144                 #define SER_UART1_BUS_TXBEGIN
145         #endif
146
147         #ifndef SER_UART1_BUS_TXCHAR
148                 /**
149                  * Invoked to send one character.
150                  */
151                 #define SER_UART1_BUS_TXCHAR(c) do { \
152                         US1_THR = (c); \
153                 } while (0)
154         #endif
155
156         #ifndef SER_UART1_BUS_TXEND
157                 /**
158                  * Invoked as soon as the txfifo becomes empty
159                  */
160                 #define SER_UART1_BUS_TXEND
161         #endif
162
163 #endif
164
165 /**
166 * \name Overridable SPI hooks
167 *
168 * These can be redefined in hw.h to implement
169 * special bus policies such as slave select pin handling, etc.
170 *
171 * \{
172 */
173
174 #ifndef SER_SPI0_BUS_TXINIT
175         /**
176         * Default TXINIT macro - invoked in spi_init()
177         * The default is no action.
178         */
179         #if CPU_CM3_SAM3
180                 #define SER_SPI0_BUS_TXINIT do { \
181                         /* Disable PIO on SPI pins */ \
182                         PIOA_PDR = BV(SPI0_SPCK) | BV(SPI0_MOSI) | BV(SPI0_MISO); \
183                         /* SPI is peripheral A on SAM3X,A,N,S,U */ \
184                         PIO_PERIPH_SEL(PIOA_BASE, BV(SPI0_SPCK) | BV(SPI0_MOSI) | BV(SPI0_MISO), PIO_PERIPH_A); \
185                 } while (0)
186         #else
187                 #define SER_SPI0_BUS_TXINIT do { \
188                         /* Disable PIO on SPI pins */ \
189                         PIOA_PDR = BV(SPI0_SPCK) | BV(SPI0_MOSI) | BV(SPI0_MISO); \
190                 } while (0)
191         #endif
192 #endif
193
194 #ifndef SER_SPI0_BUS_TXCLOSE
195         /**
196         * Invoked after the last character has been transmitted.
197         * The default is no action.
198         */
199         #define SER_SPI0_BUS_TXCLOSE do { \
200                 /* Enable PIO on SPI pins */ \
201                 PIOA_PER = BV(SPI0_SPCK) | BV(SPI0_MOSI) | BV(SPI0_MISO); \
202         } while (0)
203 #endif
204
205 #if CPU_ARM_SAM7X
206
207         #ifndef SER_SPI1_BUS_TXINIT
208                 /**
209                 * Default TXINIT macro - invoked in spi_init()
210                 * The default is no action.
211                 */
212                 #define SER_SPI1_BUS_TXINIT do { \
213                         /* Disable PIO on SPI pins */ \
214                         PIOA_PDR = BV(SPI1_SPCK) | BV(SPI1_MOSI) | BV(SPI1_MISO); \
215                         /* SPI1 pins are on B peripheral function! */ \
216                         PIOA_BSR = BV(SPI1_SPCK) | BV(SPI1_MOSI) | BV(SPI1_MISO); \
217                 } while (0)
218         #endif
219
220         #ifndef SER_SPI1_BUS_TXCLOSE
221                 /**
222                 * Invoked after the last character has been transmitted.
223                 * The default is no action.
224                 */
225                 #define SER_SPI1_BUS_TXCLOSE do { \
226                         /* Enable PIO on SPI pins */ \
227                         PIOA_PER = BV(SPI1_SPCK) | BV(SPI1_MOSI) | BV(SPI1_MISO); \
228                 } while (0)
229         #endif
230 #endif
231 /*\}*/
232
233
234 /**
235  * \name Core dependent interrupt handling macros
236  *
237  * Atmel serial hardware is used on different CPU cores,
238  * i.e. SAM3 and SAM7.  The user interface of the serial
239  * subsystem is identical but core interrupt controllers
240  * are different.
241  *
242  * \{
243  */
244 #if CPU_ARM_AT91
245
246 INLINE void sysirq_setHandler(sysirq_t irq, sysirq_handler_t handler)
247 {
248         /* Set the vector. */
249         AIC_SVR(irq) = uart0_irq_dispatcher;
250
251         /* Initialize to level/edge sensitive with defined priority. */
252 #if CPU_ARM_SAM7X
253         if (irq == SPI0_ID || irq == SPI1_ID)
254 #else
255         if (irq == SPI0_ID)
256 #endif
257                 AIC_SMR(irq) = (AIC_SMR(irq) & ~AIC_SRCTYPE_MASK) | AIC_SRCTYPE_INT_EDGE_TRIGGERED;
258         else // USART/UART
259                 AIC_SMR(irq) = (AIC_SMR(irq) & ~AIC_SRCTYPE_MASK) | AIC_SRCTYPE_INT_LEVEL_SENSITIVE;
260
261         /* Enable IRQ */
262         AIC_IECR = BV(irq);
263 }
264
265 INLINE void sysirq_setPriority(sysirq_t irq, int prio)
266 {
267         AIC_SMR(irq) = (AIC_SMR(irq) & ~AIC_PRIOR_MASK) | SERIRQ_PRIORITY;
268 }
269
270 /** Inform hw that we have served the IRQ */
271 #define SER_INT_ACK do { \
272         AIC_EOICR = 0; \
273 } while (0)
274
275 #elif CPU_CM3_SAM3
276
277 /** Inform hw that we have served the IRQ */
278 #define SER_INT_ACK do { /* nop */ } while (0)
279
280 #else
281         #error No interrupt handling macros defined for current architecture
282 #endif
283
284 /*\}*/
285
286 /* From the high-level serial driver */
287 extern struct Serial *ser_handles[SER_CNT];
288
289 /* TX and RX buffers */
290 static unsigned char uart0_txbuffer[CONFIG_UART0_TXBUFSIZE];
291 static unsigned char uart0_rxbuffer[CONFIG_UART0_RXBUFSIZE];
292 #if USART_PORTS > 1
293 static unsigned char uart1_txbuffer[CONFIG_UART1_TXBUFSIZE];
294 static unsigned char uart1_rxbuffer[CONFIG_UART1_RXBUFSIZE];
295 #endif
296 static unsigned char spi0_txbuffer[CONFIG_SPI0_TXBUFSIZE];
297 static unsigned char spi0_rxbuffer[CONFIG_SPI0_RXBUFSIZE];
298 #if CPU_ARM_SAM7X
299 static unsigned char spi1_txbuffer[CONFIG_SPI1_TXBUFSIZE];
300 static unsigned char spi1_rxbuffer[CONFIG_SPI1_RXBUFSIZE];
301 #endif
302
303 /**
304  * Internal hardware state structure
305  *
306  * The \a sending variable is true while the transmission
307  * interrupt is retriggering itself.
308  *
309  * For the USARTs the \a sending flag is useful for taking specific
310  * actions before sending a burst of data, at the start of a trasmission
311  * but not before every char sent.
312  *
313  * For the SPI, this flag is necessary because the SPI sends and receives
314  * bytes at the same time and the SPI IRQ is unique for send/receive.
315  * The only way to start transmission is to write data in SPDR (this
316  * is done by spi_starttx()). We do this *only* if a transfer is
317  * not already started.
318  */
319 struct ArmSerial
320 {
321         struct SerialHardware hw;
322         volatile bool sending;
323 };
324
325 static ISR_PROTO(uart0_irq_dispatcher);
326 #if USART_PORTS > 1
327 static ISR_PROTO(uart1_irq_dispatcher);
328 #endif
329 static ISR_PROTO(spi0_irq_handler);
330 #if CPU_ARM_SAM7X
331 static ISR_PROTO(spi1_irq_handler);
332 #endif
333 /*
334  * Callbacks for USART0
335  */
336 static void uart0_init(
337         UNUSED_ARG(struct SerialHardware *, _hw),
338         UNUSED_ARG(struct Serial *, ser))
339 {
340         US0_IDR = 0xFFFFFFFF;
341         PMC_PCER = BV(US0_ID);
342
343         /*
344          * - Reset USART0
345          * - Set serial param: mode Normal, 8bit data, 1bit stop, parity none
346          * - Enable both the receiver and the transmitter
347          * - Enable only the RX complete interrupt
348          */
349         US0_CR = BV(US_RSTRX) | BV(US_RSTTX);
350         US0_MR = US_CHMODE_NORMAL | US_CHRL_8 | US_NBSTOP_1 | US_PAR_NO;
351         US0_CR = BV(US_RXEN) | BV(US_TXEN);
352         US0_IER = BV(US_RXRDY);
353
354         SER_UART0_BUS_TXINIT;
355
356         sysirq_setPriority(INT_US0, SERIRQ_PRIORITY);
357         sysirq_setHandler(INT_US0, uart0_irq_dispatcher);
358
359         SER_STROBE_INIT;
360 }
361
362 static void uart0_cleanup(UNUSED_ARG(struct SerialHardware *, _hw))
363 {
364         US0_CR = BV(US_RSTRX) | BV(US_RSTTX) | BV(US_RXDIS) | BV(US_TXDIS) | BV(US_RSTSTA);
365 }
366
367 static void uart0_enabletxirq(struct SerialHardware *_hw)
368 {
369         struct ArmSerial *hw = (struct ArmSerial *)_hw;
370
371         /*
372          * WARNING: racy code here!  The tx interrupt sets hw->sending to false
373          * when it runs with an empty fifo.  The order of statements in the
374          * if-block matters.
375          */
376         if (!hw->sending)
377         {
378                 hw->sending = true;
379                 /*
380                  * - Enable the transmitter
381                  * - Enable TX empty interrupt
382                  */
383                 SER_UART0_BUS_TXBEGIN;
384                 US0_IER = BV(US_TXEMPTY);
385         }
386 }
387
388 static void uart0_setbaudrate(UNUSED_ARG(struct SerialHardware *, _hw), unsigned long rate)
389 {
390         /* Compute baud-rate period */
391         US0_BRGR = CPU_FREQ / (16 * rate);
392         //DB(kprintf("uart0_setbaudrate(rate=%lu): period=%d\n", rate, period);)
393 }
394
395 static void uart0_setparity(UNUSED_ARG(struct SerialHardware *, _hw), int parity)
396 {
397         US0_MR &= ~US_PAR_MASK;
398         /* Set UART parity */
399         switch(parity)
400         {
401                 case SER_PARITY_NONE:
402                 {
403                         /* Parity none. */
404                         US0_MR |= US_PAR_NO;
405                         break;
406                 }
407                 case SER_PARITY_EVEN:
408                 {
409                         /* Even parity. */
410                         US0_MR |= US_PAR_EVEN;
411                         break;
412                 }
413                 case SER_PARITY_ODD:
414                 {
415                         /* Odd parity. */
416                         US0_MR |= US_PAR_ODD;
417                         break;
418                 }
419                 default:
420                         ASSERT(0);
421         }
422 }
423
424 #if USART_PORTS > 1
425
426 /*
427  * Callbacks for USART1
428  */
429 static void uart1_init(
430         UNUSED_ARG(struct SerialHardware *, _hw),
431         UNUSED_ARG(struct Serial *, ser))
432 {
433         US1_IDR = 0xFFFFFFFF;
434         PMC_PCER = BV(US1_ID);
435
436         /*
437          * - Reset USART1
438          * - Set serial param: mode Normal, 8bit data, 1bit stop, parity none
439          * - Enable both the receiver and the transmitter
440          * - Enable only the RX complete interrupt
441          */
442         US1_CR = BV(US_RSTRX) | BV(US_RSTTX);
443         US1_MR = US_CHMODE_NORMAL | US_CHRL_8 | US_NBSTOP_1 | US_PAR_NO;
444         US1_CR = BV(US_RXEN) | BV(US_TXEN);
445         US1_IER = BV(US_RXRDY);
446
447         SER_UART1_BUS_TXINIT;
448
449         sysirq_setPriority(INT_US1, SERIRQ_PRIORITY);
450         sysirq_setHandler(INT_US1, uart1_irq_dispatcher);
451
452         SER_STROBE_INIT;
453 }
454
455 static void uart1_cleanup(UNUSED_ARG(struct SerialHardware *, _hw))
456 {
457         US1_CR = BV(US_RSTRX) | BV(US_RSTTX) | BV(US_RXDIS) | BV(US_TXDIS) | BV(US_RSTSTA);
458 }
459
460 static void uart1_enabletxirq(struct SerialHardware *_hw)
461 {
462         struct ArmSerial *hw = (struct ArmSerial *)_hw;
463
464         /*
465          * WARNING: racy code here!  The tx interrupt sets hw->sending to false
466          * when it runs with an empty fifo.  The order of statements in the
467          * if-block matters.
468          */
469         if (!hw->sending)
470         {
471                 hw->sending = true;
472                 /*
473                  * - Enable the transmitter
474                  * - Enable TX empty interrupt
475                  */
476                 SER_UART1_BUS_TXBEGIN;
477                 US1_IER = BV(US_TXEMPTY);
478         }
479 }
480
481 static void uart1_setbaudrate(UNUSED_ARG(struct SerialHardware *, _hw), unsigned long rate)
482 {
483         /* Compute baud-rate period */
484         US1_BRGR = CPU_FREQ / (16 * rate);
485         //DB(kprintf("uart0_setbaudrate(rate=%lu): period=%d\n", rate, period);)
486 }
487
488 static void uart1_setparity(UNUSED_ARG(struct SerialHardware *, _hw), int parity)
489 {
490         US1_MR &= ~US_PAR_MASK;
491         /* Set UART parity */
492         switch(parity)
493         {
494                 case SER_PARITY_NONE:
495                 {
496                         /* Parity none. */
497                         US1_MR |= US_PAR_NO;
498                         break;
499                 }
500                 case SER_PARITY_EVEN:
501                 {
502                         /* Even parity. */
503                         US1_MR |= US_PAR_EVEN;
504                         break;
505                 }
506                 case SER_PARITY_ODD:
507                 {
508                         /* Odd parity. */
509                         US1_MR |= US_PAR_ODD;
510                         break;
511                 }
512                 default:
513                         ASSERT(0);
514         }
515 }
516
517 #endif /* USART_PORTS > 1 */
518
519 /* SPI driver */
520 static void spi0_init(UNUSED_ARG(struct SerialHardware *, _hw), UNUSED_ARG(struct Serial *, ser))
521 {
522         SER_SPI0_BUS_TXINIT;
523
524         /* Reset device */
525         SPI0_CR = BV(SPI_SWRST);
526
527         /*
528          * Set SPI to master mode, fixed peripheral select, chip select directly connected to a peripheral device,
529          * SPI clock set to MCK, mode fault detection disabled, loopback disable, NPCS0 active, Delay between CS = 0
530          */
531         SPI0_MR = BV(SPI_MSTR) | BV(SPI_MODFDIS);
532
533         /*
534          * Set SPI mode.
535          * At reset clock division factor is set to 0, that is
536          * *forbidden*. Set SPI clock to minimum to keep it valid.
537          * Set all possible chip select registers in case user manually
538          * change CPS field in SPI_MR.
539          */
540         SPI0_CSR0 = BV(SPI_NCPHA) | (255 << SPI_SCBR_SHIFT);
541         SPI0_CSR1 = BV(SPI_NCPHA) | (255 << SPI_SCBR_SHIFT);
542         SPI0_CSR2 = BV(SPI_NCPHA) | (255 << SPI_SCBR_SHIFT);
543         SPI0_CSR3 = 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          * Set all possible chip select registers in case user manually
616          * change chip select.
617          */
618         SPI1_CSR0 = BV(SPI_NCPHA) | (255 << SPI_SCBR_SHIFT);
619         SPI1_CSR1 = BV(SPI_NCPHA) | (255 << SPI_SCBR_SHIFT);
620         SPI1_CSR2 = BV(SPI_NCPHA) | (255 << SPI_SCBR_SHIFT);
621         SPI1_CSR3 = BV(SPI_NCPHA) | (255 << SPI_SCBR_SHIFT);
622
623         /* Disable all SPI irqs */
624         SPI1_IDR = 0xFFFFFFFF;
625
626         sysirq_setPriority(INT_SPI1, SERIRQ_PRIORITY);
627         sysirq_setHandler(INT_SPI1, spi1_irq_dispatcher);
628         PMC_PCER = BV(SPI1_ID);
629
630         /* Enable SPI */
631         SPI1_CR = BV(SPI_SPIEN);
632
633         SER_STROBE_INIT;
634 }
635
636 static void spi1_cleanup(UNUSED_ARG(struct SerialHardware *, _hw))
637 {
638         /* Disable SPI */
639         SPI1_CR = BV(SPI_SPIDIS);
640
641         /* Disable all irqs */
642         SPI1_IDR = 0xFFFFFFFF;
643
644         SER_SPI1_BUS_TXCLOSE;
645 }
646
647 static void spi1_starttx(struct SerialHardware *_hw)
648 {
649         struct ArmSerial *hw = (struct ArmSerial *)_hw;
650
651         cpu_flags_t flags;
652         IRQ_SAVE_DISABLE(flags);
653
654         /* Send data only if the SPI is not already transmitting */
655         if (!hw->sending && !fifo_isempty(&ser_handles[SER_SPI1]->txfifo))
656         {
657                 hw->sending = true;
658                 SPI1_TDR = fifo_pop(&ser_handles[SER_SPI1]->txfifo);
659                 /* Enable interrupt on tx buffer empty */
660                 SPI1_IER = BV(SPI_TXEMPTY);
661         }
662
663         IRQ_RESTORE(flags);
664 }
665
666 static void spi1_setbaudrate(UNUSED_ARG(struct SerialHardware *, _hw), unsigned long rate)
667 {
668         SPI1_CSR0 &= ~SPI_SCBR;
669
670         ASSERT((uint8_t)DIV_ROUND(CPU_FREQ, rate));
671         SPI1_CSR0 |= DIV_ROUND(CPU_FREQ, rate) << SPI_SCBR_SHIFT;
672 }
673 #endif
674
675 static void spi_setparity(UNUSED_ARG(struct SerialHardware *, _hw), UNUSED_ARG(int, parity))
676 {
677         // nop
678 }
679
680
681 static bool tx_sending(struct SerialHardware* _hw)
682 {
683         struct ArmSerial *hw = (struct ArmSerial *)_hw;
684         return hw->sending;
685 }
686
687 // FIXME: move into compiler.h?  Ditch?
688 #if COMPILER_C99
689         #define C99INIT(name,val) .name = val
690 #elif defined(__GNUC__)
691         #define C99INIT(name,val) name: val
692 #else
693         #warning No designated initializers, double check your code
694         #define C99INIT(name,val) (val)
695 #endif
696
697 /*
698  * High-level interface data structures
699  */
700 static const struct SerialHardwareVT UART0_VT =
701 {
702         C99INIT(init, uart0_init),
703         C99INIT(cleanup, uart0_cleanup),
704         C99INIT(setBaudrate, uart0_setbaudrate),
705         C99INIT(setParity, uart0_setparity),
706         C99INIT(txStart, uart0_enabletxirq),
707         C99INIT(txSending, tx_sending),
708 };
709
710 #if USART_PORTS > 1
711
712 static const struct SerialHardwareVT UART1_VT =
713 {
714         C99INIT(init, uart1_init),
715         C99INIT(cleanup, uart1_cleanup),
716         C99INIT(setBaudrate, uart1_setbaudrate),
717         C99INIT(setParity, uart1_setparity),
718         C99INIT(txStart, uart1_enabletxirq),
719         C99INIT(txSending, tx_sending),
720 };
721
722 #endif /* USART_PORTS > 1 */
723
724 static const struct SerialHardwareVT SPI0_VT =
725 {
726         C99INIT(init, spi0_init),
727         C99INIT(cleanup, spi0_cleanup),
728         C99INIT(setBaudrate, spi0_setbaudrate),
729         C99INIT(setParity, spi_setparity),
730         C99INIT(txStart, spi0_starttx),
731         C99INIT(txSending, tx_sending),
732 };
733 #if CPU_ARM_SAM7X
734 static const struct SerialHardwareVT SPI1_VT =
735 {
736         C99INIT(init, spi1_init),
737         C99INIT(cleanup, spi1_cleanup),
738         C99INIT(setBaudrate, spi1_setbaudrate),
739         C99INIT(setParity, spi_setparity),
740         C99INIT(txStart, spi1_starttx),
741         C99INIT(txSending, tx_sending),
742 };
743 #endif
744
745 static struct ArmSerial UARTDescs[SER_CNT] =
746 {
747         {
748                 C99INIT(hw, /**/) {
749                         C99INIT(table, &UART0_VT),
750                         C99INIT(txbuffer, uart0_txbuffer),
751                         C99INIT(rxbuffer, uart0_rxbuffer),
752                         C99INIT(txbuffer_size, sizeof(uart0_txbuffer)),
753                         C99INIT(rxbuffer_size, sizeof(uart0_rxbuffer)),
754                 },
755                 C99INIT(sending, false),
756         },
757 #if USART_PORTS > 1
758         {
759                 C99INIT(hw, /**/) {
760                         C99INIT(table, &UART1_VT),
761                         C99INIT(txbuffer, uart1_txbuffer),
762                         C99INIT(rxbuffer, uart1_rxbuffer),
763                         C99INIT(txbuffer_size, sizeof(uart1_txbuffer)),
764                         C99INIT(rxbuffer_size, sizeof(uart1_rxbuffer)),
765                 },
766                 C99INIT(sending, false),
767         },
768 #endif
769
770         {
771                 C99INIT(hw, /**/) {
772                         C99INIT(table, &SPI0_VT),
773                         C99INIT(txbuffer, spi0_txbuffer),
774                         C99INIT(rxbuffer, spi0_rxbuffer),
775                         C99INIT(txbuffer_size, sizeof(spi0_txbuffer)),
776                         C99INIT(rxbuffer_size, sizeof(spi0_rxbuffer)),
777                 },
778                 C99INIT(sending, false),
779         },
780         #if CPU_ARM_SAM7X
781         {
782                 C99INIT(hw, /**/) {
783                         C99INIT(table, &SPI1_VT),
784                         C99INIT(txbuffer, spi1_txbuffer),
785                         C99INIT(rxbuffer, spi1_rxbuffer),
786                         C99INIT(txbuffer_size, sizeof(spi1_txbuffer)),
787                         C99INIT(rxbuffer_size, sizeof(spi1_rxbuffer)),
788                 },
789                 C99INIT(sending, false),
790         }
791
792         #endif
793 };
794
795 struct SerialHardware *ser_hw_getdesc(int unit)
796 {
797         ASSERT(unit < SER_CNT);
798         return &UARTDescs[unit].hw;
799 }
800
801 /**
802  * Serial 0 TX interrupt handler
803  */
804 INLINE void uart0_irq_tx(void)
805 {
806         SER_STROBE_ON;
807
808         struct FIFOBuffer * const txfifo = &ser_handles[SER_UART0]->txfifo;
809
810         if (fifo_isempty(txfifo))
811         {
812                 /*
813                  * - Disable the TX empty interrupts
814                  */
815                 US0_IDR = BV(US_TXEMPTY);
816                 SER_UART0_BUS_TXEND;
817                 UARTDescs[SER_UART0].sending = false;
818         }
819         else
820         {
821                 char c = fifo_pop(txfifo);
822                 SER_UART0_BUS_TXCHAR(c);
823         }
824
825         SER_STROBE_OFF;
826 }
827
828 /**
829  * Serial 0 RX complete interrupt handler.
830  */
831 INLINE void uart0_irq_rx(void)
832 {
833         SER_STROBE_ON;
834
835         /* Should be read before US_CRS */
836         ser_handles[SER_UART0]->status |= US0_CSR & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
837         US0_CR = BV(US_RSTSTA);
838
839         char c = US0_RHR;
840         struct FIFOBuffer * const rxfifo = &ser_handles[SER_UART0]->rxfifo;
841
842         if (fifo_isfull(rxfifo))
843                 ser_handles[SER_UART0]->status |= SERRF_RXFIFOOVERRUN;
844         else
845                 fifo_push(rxfifo, c);
846
847         SER_STROBE_OFF;
848 }
849
850 /**
851  * Serial IRQ dispatcher for USART0.
852  */
853 static DECLARE_ISR(uart0_irq_dispatcher)
854 {
855         if (US0_CSR & BV(US_RXRDY))
856                 uart0_irq_rx();
857
858         if (US0_CSR & BV(US_TXEMPTY))
859                 uart0_irq_tx();
860
861         SER_INT_ACK;
862 }
863
864 #if USART_PORTS > 1
865
866 /**
867  * Serial 1 TX interrupt handler
868  */
869 INLINE void uart1_irq_tx(void)
870 {
871         SER_STROBE_ON;
872
873         struct FIFOBuffer * const txfifo = &ser_handles[SER_UART1]->txfifo;
874
875         if (fifo_isempty(txfifo))
876         {
877                 /*
878                  * - Disable the TX empty interrupts
879                  */
880                 US1_IDR = BV(US_TXEMPTY);
881                 SER_UART1_BUS_TXEND;
882                 UARTDescs[SER_UART1].sending = false;
883         }
884         else
885         {
886                 char c = fifo_pop(txfifo);
887                 SER_UART1_BUS_TXCHAR(c);
888         }
889
890         SER_STROBE_OFF;
891 }
892
893 /**
894  * Serial 1 RX complete interrupt handler.
895  */
896 INLINE void uart1_irq_rx(void)
897 {
898         SER_STROBE_ON;
899
900         /* Should be read before US_CRS */
901         ser_handles[SER_UART1]->status |= US1_CSR & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
902         US1_CR = BV(US_RSTSTA);
903
904         char c = US1_RHR;
905         struct FIFOBuffer * const rxfifo = &ser_handles[SER_UART1]->rxfifo;
906
907         if (fifo_isfull(rxfifo))
908                 ser_handles[SER_UART1]->status |= SERRF_RXFIFOOVERRUN;
909         else
910                 fifo_push(rxfifo, c);
911
912         SER_STROBE_OFF;
913 }
914
915 /**
916  * Serial IRQ dispatcher for USART1.
917  */
918 static DECLARE_ISR(uart1_irq_dispatcher)
919 {
920         if (US1_CSR & BV(US_RXRDY))
921                 uart1_irq_rx();
922
923         if (US1_CSR & BV(US_TXEMPTY))
924                 uart1_irq_tx();
925
926         SER_INT_ACK;
927 }
928
929 #endif /* USART_PORTS > 1 */
930
931 /**
932  * SPI0 interrupt handler
933  */
934 static DECLARE_ISR(spi0_irq_handler)
935 {
936         SER_STROBE_ON;
937
938         char c = SPI0_RDR;
939         /* Read incoming byte. */
940         if (!fifo_isfull(&ser_handles[SER_SPI0]->rxfifo))
941                 fifo_push(&ser_handles[SER_SPI0]->rxfifo, c);
942         /*
943          * FIXME
944         else
945                 ser_handles[SER_SPI0]->status |= SERRF_RXFIFOOVERRUN;
946         */
947
948         /* Send */
949         if (!fifo_isempty(&ser_handles[SER_SPI0]->txfifo))
950                 SPI0_TDR = fifo_pop(&ser_handles[SER_SPI0]->txfifo);
951         else
952         {
953                 UARTDescs[SER_SPI0].sending = false;
954                 /* Disable interrupt on tx buffer empty */
955                 SPI0_IDR = BV(SPI_TXEMPTY);
956         }
957
958         SER_INT_ACK;
959
960         SER_STROBE_OFF;
961 }
962
963
964 #if CPU_ARM_SAM7X
965 /**
966  * SPI1 interrupt handler
967  */
968 static DECLARE_ISR(spi1_irq_handler)
969 {
970         SER_STROBE_ON;
971
972         char c = SPI1_RDR;
973         /* Read incoming byte. */
974         if (!fifo_isfull(&ser_handles[SER_SPI1]->rxfifo))
975                 fifo_push(&ser_handles[SER_SPI1]->rxfifo, c);
976         /*
977          * FIXME
978         else
979                 ser_handles[SER_SPI1]->status |= SERRF_RXFIFOOVERRUN;
980         */
981
982         /* Send */
983         if (!fifo_isempty(&ser_handles[SER_SPI1]->txfifo))
984                 SPI1_TDR = fifo_pop(&ser_handles[SER_SPI1]->txfifo);
985         else
986         {
987                 UARTDescs[SER_SPI1].sending = false;
988                 /* Disable interrupt on tx buffer empty */
989                 SPI1_IDR = BV(SPI_TXEMPTY);
990         }
991
992         SER_INT_ACK;
993
994         SER_STROBE_OFF;
995 }
996 #endif