15b46dd12830cba90cfaba8ffc806cba666ce42d
[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);
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          * Set all possible chip select registers in case user manually
543          * change chip select.
544          */
545         SPI0_CSR0 = BV(SPI_NCPHA) | (255 << SPI_SCBR_SHIFT);
546         SPI0_CSR1 = BV(SPI_NCPHA) | (255 << SPI_SCBR_SHIFT);
547         SPI0_CSR2 = BV(SPI_NCPHA) | (255 << SPI_SCBR_SHIFT);
548         SPI0_CSR3 = BV(SPI_NCPHA) | (255 << SPI_SCBR_SHIFT);
549
550         /* Disable all irqs */
551         SPI0_IDR = 0xFFFFFFFF;
552
553         //sysirq_setPriority(INT_SPI0, SERIRQ_PRIORITY);
554         sysirq_setHandler(INT_SPI0, spi0_irq_handler);
555         PMC_PCER = BV(SPI0_ID);
556
557         /* Enable SPI */
558         SPI0_CR = BV(SPI_SPIEN);
559
560         SER_STROBE_INIT;
561 }
562
563 static void spi0_cleanup(UNUSED_ARG(struct SerialHardware *, _hw))
564 {
565         /* Disable SPI */
566         SPI0_CR = BV(SPI_SPIDIS);
567
568         /* Disable all irqs */
569         SPI0_IDR = 0xFFFFFFFF;
570
571         SER_SPI0_BUS_TXCLOSE;
572 }
573
574 static void spi0_starttx(struct SerialHardware *_hw)
575 {
576         struct ArmSerial *hw = (struct ArmSerial *)_hw;
577
578         cpu_flags_t flags;
579         IRQ_SAVE_DISABLE(flags);
580
581         /* Send data only if the SPI is not already transmitting */
582         if (!hw->sending && !fifo_isempty(&ser_handles[SER_SPI0]->txfifo))
583         {
584                 hw->sending = true;
585                 SPI0_TDR = fifo_pop(&ser_handles[SER_SPI0]->txfifo);
586                 /* Enable interrupt on tx buffer empty */
587                 SPI0_IER = BV(SPI_TDRE);
588         }
589
590         IRQ_RESTORE(flags);
591 }
592
593 static void spi0_setbaudrate(UNUSED_ARG(struct SerialHardware *, _hw), unsigned long rate)
594 {
595         SPI0_CSR0 &= ~SPI_SCBR;
596
597         ASSERT((uint8_t)DIV_ROUND(CPU_FREQ, rate));
598         SPI0_CSR0 |= DIV_ROUND(CPU_FREQ, rate) << SPI_SCBR_SHIFT;
599 }
600
601 #if CPU_ARM_SAM7X
602 /* SPI driver */
603 static void spi1_init(UNUSED_ARG(struct SerialHardware *, _hw), UNUSED_ARG(struct Serial *, ser))
604 {
605         SER_SPI1_BUS_TXINIT;
606
607         /* Reset device */
608         SPI1_CR = BV(SPI_SWRST);
609
610         /*
611          * Set SPI to master mode, fixed peripheral select, chip select directly connected to a peripheral device,
612          * SPI clock set to MCK, mode fault detection disabled, loopback disable, NPCS0 active, Delay between CS = 0
613          */
614         SPI1_MR = BV(SPI_MSTR) | BV(SPI_MODFDIS);
615
616         /*
617          * Set SPI mode.
618          * At reset clock division factor is set to 0, that is
619          * *forbidden*. Set SPI clock to minimum to keep it valid.
620          * Set all possible chip select registers in case user manually
621          * change chip select.
622          */
623         SPI1_CSR0 = BV(SPI_NCPHA) | (255 << SPI_SCBR_SHIFT);
624         SPI1_CSR1 = BV(SPI_NCPHA) | (255 << SPI_SCBR_SHIFT);
625         SPI1_CSR2 = BV(SPI_NCPHA) | (255 << SPI_SCBR_SHIFT);
626         SPI1_CSR3 = BV(SPI_NCPHA) | (255 << SPI_SCBR_SHIFT);
627
628         /* Disable all SPI irqs */
629         SPI1_IDR = 0xFFFFFFFF;
630
631         sysirq_setPriority(INT_SPI1, SERIRQ_PRIORITY);
632         sysirq_setHandler(INT_SPI1, spi1_irq_dispatcher);
633         PMC_PCER = BV(SPI1_ID);
634
635         /* Enable SPI */
636         SPI1_CR = BV(SPI_SPIEN);
637
638         SER_STROBE_INIT;
639 }
640
641 static void spi1_cleanup(UNUSED_ARG(struct SerialHardware *, _hw))
642 {
643         /* Disable SPI */
644         SPI1_CR = BV(SPI_SPIDIS);
645
646         /* Disable all irqs */
647         SPI1_IDR = 0xFFFFFFFF;
648
649         SER_SPI1_BUS_TXCLOSE;
650 }
651
652 static void spi1_starttx(struct SerialHardware *_hw)
653 {
654         struct ArmSerial *hw = (struct ArmSerial *)_hw;
655
656         cpu_flags_t flags;
657         IRQ_SAVE_DISABLE(flags);
658
659         /* Send data only if the SPI is not already transmitting */
660         if (!hw->sending && !fifo_isempty(&ser_handles[SER_SPI1]->txfifo))
661         {
662                 hw->sending = true;
663                 SPI1_TDR = fifo_pop(&ser_handles[SER_SPI1]->txfifo);
664                 /* Enable interrupt on tx buffer empty */
665                 SPI1_IER = BV(SPI_TDRE);
666         }
667
668         IRQ_RESTORE(flags);
669 }
670
671 static void spi1_setbaudrate(UNUSED_ARG(struct SerialHardware *, _hw), unsigned long rate)
672 {
673         SPI1_CSR0 &= ~SPI_SCBR;
674
675         ASSERT((uint8_t)DIV_ROUND(CPU_FREQ, rate));
676         SPI1_CSR0 |= DIV_ROUND(CPU_FREQ, rate) << SPI_SCBR_SHIFT;
677 }
678 #endif
679
680 static void spi_setparity(UNUSED_ARG(struct SerialHardware *, _hw), UNUSED_ARG(int, parity))
681 {
682         // nop
683 }
684
685
686 static bool tx_sending(struct SerialHardware* _hw)
687 {
688         struct ArmSerial *hw = (struct ArmSerial *)_hw;
689         return hw->sending;
690 }
691
692 // FIXME: move into compiler.h?  Ditch?
693 #if COMPILER_C99
694         #define C99INIT(name,val) .name = val
695 #elif defined(__GNUC__)
696         #define C99INIT(name,val) name: val
697 #else
698         #warning No designated initializers, double check your code
699         #define C99INIT(name,val) (val)
700 #endif
701
702 /*
703  * High-level interface data structures
704  */
705 static const struct SerialHardwareVT UART0_VT =
706 {
707         C99INIT(init, uart0_init),
708         C99INIT(cleanup, uart0_cleanup),
709         C99INIT(setBaudrate, uart0_setbaudrate),
710         C99INIT(setParity, uart0_setparity),
711         C99INIT(txStart, uart0_enabletxirq),
712         C99INIT(txSending, tx_sending),
713 };
714
715 static const struct SerialHardwareVT UART1_VT =
716 {
717         C99INIT(init, uart1_init),
718         C99INIT(cleanup, uart1_cleanup),
719         C99INIT(setBaudrate, uart1_setbaudrate),
720         C99INIT(setParity, uart1_setparity),
721         C99INIT(txStart, uart1_enabletxirq),
722         C99INIT(txSending, tx_sending),
723 };
724
725 static const struct SerialHardwareVT SPI0_VT =
726 {
727         C99INIT(init, spi0_init),
728         C99INIT(cleanup, spi0_cleanup),
729         C99INIT(setBaudrate, spi0_setbaudrate),
730         C99INIT(setParity, spi_setparity),
731         C99INIT(txStart, spi0_starttx),
732         C99INIT(txSending, tx_sending),
733 };
734 #if CPU_ARM_SAM7X
735 static const struct SerialHardwareVT SPI1_VT =
736 {
737         C99INIT(init, spi1_init),
738         C99INIT(cleanup, spi1_cleanup),
739         C99INIT(setBaudrate, spi1_setbaudrate),
740         C99INIT(setParity, spi_setparity),
741         C99INIT(txStart, spi1_starttx),
742         C99INIT(txSending, tx_sending),
743 };
744 #endif
745
746 static struct ArmSerial UARTDescs[SER_CNT] =
747 {
748         {
749                 C99INIT(hw, /**/) {
750                         C99INIT(table, &UART0_VT),
751                         C99INIT(txbuffer, uart0_txbuffer),
752                         C99INIT(rxbuffer, uart0_rxbuffer),
753                         C99INIT(txbuffer_size, sizeof(uart0_txbuffer)),
754                         C99INIT(rxbuffer_size, sizeof(uart0_rxbuffer)),
755                 },
756                 C99INIT(sending, false),
757         },
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
769         {
770                 C99INIT(hw, /**/) {
771                         C99INIT(table, &SPI0_VT),
772                         C99INIT(txbuffer, spi0_txbuffer),
773                         C99INIT(rxbuffer, spi0_rxbuffer),
774                         C99INIT(txbuffer_size, sizeof(spi0_txbuffer)),
775                         C99INIT(rxbuffer_size, sizeof(spi0_rxbuffer)),
776                 },
777                 C99INIT(sending, false),
778         },
779         #if CPU_ARM_SAM7X
780         {
781                 C99INIT(hw, /**/) {
782                         C99INIT(table, &SPI1_VT),
783                         C99INIT(txbuffer, spi1_txbuffer),
784                         C99INIT(rxbuffer, spi1_rxbuffer),
785                         C99INIT(txbuffer_size, sizeof(spi1_txbuffer)),
786                         C99INIT(rxbuffer_size, sizeof(spi1_rxbuffer)),
787                 },
788                 C99INIT(sending, false),
789         }
790
791         #endif
792 };
793
794 struct SerialHardware *ser_hw_getdesc(int unit)
795 {
796         ASSERT(unit < SER_CNT);
797         return &UARTDescs[unit].hw;
798 }
799
800 /**
801  * Serial 0 TX interrupt handler
802  */
803 INLINE void uart0_irq_tx(void)
804 {
805         SER_STROBE_ON;
806
807         struct FIFOBuffer * const txfifo = &ser_handles[SER_UART0]->txfifo;
808
809         if (fifo_isempty(txfifo))
810         {
811                 /*
812                  * - Disable the TX empty interrupts
813                  */
814                 US0_IDR = BV(US_TXEMPTY);
815                 SER_UART0_BUS_TXEND;
816                 UARTDescs[SER_UART0].sending = false;
817         }
818         else
819         {
820                 char c = fifo_pop(txfifo);
821                 SER_UART0_BUS_TXCHAR(c);
822         }
823
824         SER_STROBE_OFF;
825 }
826
827 /**
828  * Serial 0 RX complete interrupt handler.
829  */
830 INLINE void uart0_irq_rx(void)
831 {
832         SER_STROBE_ON;
833
834         /* Should be read before US_CRS */
835         ser_handles[SER_UART0]->status |= US0_CSR & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
836         US0_CR = BV(US_RSTSTA);
837
838         char c = US0_RHR;
839         struct FIFOBuffer * const rxfifo = &ser_handles[SER_UART0]->rxfifo;
840
841         if (fifo_isfull(rxfifo))
842                 ser_handles[SER_UART0]->status |= SERRF_RXFIFOOVERRUN;
843         else
844                 fifo_push(rxfifo, c);
845
846         SER_STROBE_OFF;
847 }
848
849 /**
850  * Serial IRQ dispatcher for USART0.
851  */
852 static DECLARE_ISR(uart0_irq_dispatcher)
853 {
854         if (US0_CSR & BV(US_RXRDY))
855                 uart0_irq_rx();
856
857         if (US0_CSR & BV(US_TXEMPTY))
858                 uart0_irq_tx();
859
860         SER_INT_ACK;
861 }
862
863 /**
864  * Serial 1 TX interrupt handler
865  */
866 INLINE void uart1_irq_tx(void)
867 {
868         SER_STROBE_ON;
869
870         struct FIFOBuffer * const txfifo = &ser_handles[SER_UART1]->txfifo;
871
872         if (fifo_isempty(txfifo))
873         {
874                 /*
875                  * - Disable the TX empty interrupts
876                  */
877                 US1_IDR = BV(US_TXEMPTY);
878                 SER_UART1_BUS_TXEND;
879                 UARTDescs[SER_UART1].sending = false;
880         }
881         else
882         {
883                 char c = fifo_pop(txfifo);
884                 SER_UART1_BUS_TXCHAR(c);
885         }
886
887         SER_STROBE_OFF;
888 }
889
890 /**
891  * Serial 1 RX complete interrupt handler.
892  */
893 INLINE void uart1_irq_rx(void)
894 {
895         SER_STROBE_ON;
896
897         /* Should be read before US_CRS */
898         ser_handles[SER_UART1]->status |= US1_CSR & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
899         US1_CR = BV(US_RSTSTA);
900
901         char c = US1_RHR;
902         struct FIFOBuffer * const rxfifo = &ser_handles[SER_UART1]->rxfifo;
903
904         if (fifo_isfull(rxfifo))
905                 ser_handles[SER_UART1]->status |= SERRF_RXFIFOOVERRUN;
906         else
907                 fifo_push(rxfifo, c);
908
909         SER_STROBE_OFF;
910 }
911
912 /**
913  * Serial IRQ dispatcher for USART1.
914  */
915 static DECLARE_ISR(uart1_irq_dispatcher)
916 {
917         if (US1_CSR & BV(US_RXRDY))
918                 uart1_irq_rx();
919
920         if (US1_CSR & BV(US_TXEMPTY))
921                 uart1_irq_tx();
922
923         SER_INT_ACK;
924 }
925
926 /**
927  * SPI0 interrupt handler
928  */
929 static DECLARE_ISR(spi0_irq_handler)
930 {
931         SER_STROBE_ON;
932
933         char c = SPI0_RDR;
934         /* Read incoming byte. */
935         if (!fifo_isfull(&ser_handles[SER_SPI0]->rxfifo))
936                 fifo_push(&ser_handles[SER_SPI0]->rxfifo, c);
937         /*
938          * FIXME
939         else
940                 ser_handles[SER_SPI0]->status |= SERRF_RXFIFOOVERRUN;
941         */
942
943         /* Send */
944         if (!fifo_isempty(&ser_handles[SER_SPI0]->txfifo))
945                 SPI0_TDR = fifo_pop(&ser_handles[SER_SPI0]->txfifo);
946         else
947         {
948                 UARTDescs[SER_SPI0].sending = false;
949                 /* Disable interrupt on tx buffer empty */
950                 SPI0_IDR = BV(SPI_TDRE);
951         }
952
953         SER_INT_ACK;
954
955         SER_STROBE_OFF;
956 }
957
958
959 #if CPU_ARM_SAM7X
960 /**
961  * SPI1 interrupt handler
962  */
963 static DECLARE_ISR(spi1_irq_handler)
964 {
965         SER_STROBE_ON;
966
967         char c = SPI1_RDR;
968         /* Read incoming byte. */
969         if (!fifo_isfull(&ser_handles[SER_SPI1]->rxfifo))
970                 fifo_push(&ser_handles[SER_SPI1]->rxfifo, c);
971         /*
972          * FIXME
973         else
974                 ser_handles[SER_SPI1]->status |= SERRF_RXFIFOOVERRUN;
975         */
976
977         /* Send */
978         if (!fifo_isempty(&ser_handles[SER_SPI1]->txfifo))
979                 SPI1_TDR = fifo_pop(&ser_handles[SER_SPI1]->txfifo);
980         else
981         {
982                 UARTDescs[SER_SPI1].sending = false;
983                 /* Disable interrupt on tx buffer empty */
984                 SPI1_IDR = BV(SPI_TDRE);
985         }
986
987         SER_INT_ACK;
988
989         SER_STROBE_OFF;
990 }
991 #endif