Explicit USART pins name in at91sam7s256.h.
[bertos.git] / cpu / arm / drv / ser_at91.c
1 /**
2  * \file
3  * <!--
4  * This file is part of BeRTOS.
5  *
6  * Bertos is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  * As a special exception, you may use this file as part of a free software
21  * library without restriction.  Specifically, if other files instantiate
22  * templates or use macros or inline functions from this file, or you compile
23  * this file and link it with other files to produce an executable, this
24  * file does not by itself cause the resulting executable to be covered by
25  * the GNU General Public License.  This exception does not however
26  * invalidate any other reasons why the executable file might be covered by
27  * the GNU General Public License.
28  *
29  * Copyright 2003, 2004 Develer S.r.l. (http://www.develer.com/)
30  * Copyright 2000 Bernardo Innocenti <bernie@codewiz.org>
31  *
32  * -->
33  *
34  * \brief ARM UART and SPI I/O driver
35  *
36  *
37  * \version $Id: ser_amr.c 18280 2007-10-11 15:14:20Z asterix $
38  * \author Daniele Basile <asterix@develer.com>
39  */
40
41 #include <io/arm.h>
42
43 #include <cpu/attr.h>
44 #include <drv/ser.h>
45 #include <drv/ser_p.h>
46
47 #include <hw/hw_ser.h>  /* Required for bus macros overrides */
48 #include <hw/hw_cpu.h>  /* CLOCK_FREQ */
49
50 #include <mware/fifobuf.h>
51 #include <cfg/debug.h>
52
53 #include <appconfig.h>
54
55 #define SERIRQ_PRIORITY 4 ///< default priority for serial irqs.
56
57 /**
58  * \name Overridable serial bus hooks
59  *
60  * These can be redefined in hw.h to implement
61  * special bus policies such as half-duplex, 485, etc.
62  *
63  *
64  * \code
65  *  TXBEGIN      TXCHAR      TXEND  TXOFF
66  *    |   __________|__________ |     |
67  *    |   |   |   |   |   |   | |     |
68  *    v   v   v   v   v   v   v v     v
69  * ______  __  __  __  __  __  __  ________________
70  *       \/  \/  \/  \/  \/  \/  \/
71  * ______/\__/\__/\__/\__/\__/\__/
72  *
73  * \endcode
74  *
75  * \{
76  */
77
78 #ifndef SER_UART0_IRQ_INIT
79         /**
80          * Default IRQ INIT macro - invoked in uart0_init()
81          *
82          * - Disable all interrupt
83          * - Register USART0 interrupt
84          * - Enable USART0 clock.
85          */
86         #define SER_UART0_IRQ_INIT do { \
87                 US0_IDR = 0xFFFFFFFF; \
88                 /* Set the vector. */ \
89                 AIC_SVR(US0_ID) = uart0_irq_dispatcher; \
90                 /* Initialize to edge triggered with defined priority. */ \
91                 AIC_SMR(US0_ID) = AIC_SRCTYPE_INT_EDGE_TRIGGERED | SERIRQ_PRIORITY; \
92                 /* Enable the USART IRQ */ \
93                 AIC_IECR = BV(US0_ID); \
94                 PMC_PCER = BV(US0_ID); \
95         } while (0)
96 #endif
97
98 #ifndef SER_UART0_BUS_TXINIT
99         /**
100          * Default TXINIT macro - invoked in uart0_init()
101          *
102          * - Disable GPIO on USART0 tx/rx pins
103          * - Reset USART0
104          * - Set serial param: mode Normal, 8bit data, 1bit stop
105          * - Enable both the receiver and the transmitter
106          * - Enable only the RX complete interrupt
107          */
108         #if !CPU_ARM_AT91SAM7S256
109                 #warning Check USART0 pins!
110         #endif
111         #define SER_UART0_BUS_TXINIT do { \
112                 PIOA_PDR = BV(RXD0) | BV(TXD0); \
113                 US0_CR = BV(US_RSTRX) | BV(US_RSTTX); \
114                 US0_MR = US_CHMODE_NORMAL | US_CHRL_8 | US_NBSTOP_1; \
115                 US0_CR = BV(US_RXEN) | BV(US_TXEN); \
116                 US0_IER = BV(US_RXRDY); \
117         } while (0)
118
119 #endif
120
121 #ifndef SER_UART0_BUS_TXBEGIN
122         /**
123          * Invoked before starting a transmission
124          *
125          * - Enable both the receiver and the transmitter
126          * - Enable both the RX complete and TX empty interrupts
127          */
128         #define SER_UART0_BUS_TXBEGIN do { \
129                 US0_CR = BV(US_RXEN) | BV(US_TXEN); \
130                 US0_IER = BV(US_TXRDY) | BV(US_RXRDY); \
131         } while (0)
132 #endif
133
134 #ifndef SER_UART0_BUS_TXCHAR
135         /**
136          * Invoked to send one character.
137          */
138         #define SER_UART0_BUS_TXCHAR(c) do { \
139                 US0_THR = (c); \
140         } while (0)
141 #endif
142
143 #ifndef SER_UART0_BUS_TXEND
144         /**
145          * Invoked as soon as the txfifo becomes empty
146          *
147          * - Keep both the receiver and the transmitter enabled
148          * - Keep the RX complete interrupt enabled
149          * - Disable the TX empty interrupts
150          */
151         #define SER_UART0_BUS_TXEND do { \
152                 US0_CR = BV(US_RXEN) | BV(US_TXEN); \
153                 US0_IER = BV(US_RXRDY); \
154                 US0_IDR = BV(US_TXRDY); \
155         } while (0)
156 #endif
157
158 /* End USART0 macros */
159
160 #ifndef SER_UART1_IRQ_INIT
161         /** \sa SER_UART0_BUS_TXINIT */
162         #define SER_UART1_IRQ_INIT do { \
163                 US1_IDR = 0xFFFFFFFF; \
164                 /* Set the vector. */ \
165                 AIC_SVR(US1_ID) = uart1_irq_dispatcher; \
166                 /* Initialize to edge triggered with defined priority. */ \
167                 AIC_SMR(US1_ID) = AIC_SRCTYPE_INT_EDGE_TRIGGERED | SERIRQ_PRIORITY; \
168                 /* Enable the USART IRQ */ \
169                 AIC_IECR = BV(US1_ID); \
170                 PMC_PCER = BV(US1_ID); \
171         } while (0)
172 #endif
173
174 #ifndef SER_UART1_BUS_TXINIT
175         /** \sa SER_UART1_BUS_TXINIT */
176         #if !CPU_ARM_AT91SAM7S256
177                 #warning Check USART1 pins!
178         #endif
179         #define SER_UART1_BUS_TXINIT do { \
180                 PIOA_PDR = BV(RXD1) | BV(TXD1); \
181                 US1_CR = BV(US_RSTRX) | BV(US_RSTTX); \
182                 US1_MR = US_CHMODE_NORMAL | US_CHRL_8 | US_NBSTOP_1; \
183                 US1_CR = BV(US_RXEN) | BV(US_TXEN); \
184                 US1_IER = BV(US_RXRDY); \
185         } while (0)
186 #endif
187
188 #ifndef SER_UART1_BUS_TXBEGIN
189         /** \sa SER_UART1_BUS_TXBEGIN */
190         #define SER_UART1_BUS_TXBEGIN do { \
191                 US1_CR = BV(US_RXEN) | BV(US_TXEN); \
192                 US1_IER = BV(US_TXRDY) | BV(US_RXRDY); \
193         } while (0)
194 #endif
195
196 #ifndef SER_UART1_BUS_TXCHAR
197         /** \sa SER_UART1_BUS_TXCHAR */
198         #define SER_UART1_BUS_TXCHAR(c) do { \
199                 US1_THR = (c); \
200         } while (0)
201 #endif
202
203 #ifndef SER_UART1_BUS_TXEND
204         /** \sa SER_UART1_BUS_TXEND */
205         #define SER_UART1_BUS_TXEND do { \
206                 US1_CR = BV(US_RXEN) | BV(US_TXEN); \
207                 US1_IER = BV(US_RXRDY); \
208                 US1_IDR = BV(US_TXRDY); \
209         } while (0)
210 #endif
211
212 /**
213  * \def CONFIG_SER_STROBE
214  *
215  * This is a debug facility that can be used to
216  * monitor SER interrupt activity on an external pin.
217  *
218  * To use strobes, redefine the macros SER_STROBE_ON,
219  * SER_STROBE_OFF and SER_STROBE_INIT and set
220  * CONFIG_SER_STROBE to 1.
221  */
222 #if !defined(CONFIG_SER_STROBE) || !CONFIG_SER_STROBE
223         #define SER_STROBE_ON    do {/*nop*/} while(0)
224         #define SER_STROBE_OFF   do {/*nop*/} while(0)
225         #define SER_STROBE_INIT  do {/*nop*/} while(0)
226 #endif
227
228
229 /* From the high-level serial driver */
230 extern struct Serial ser_handles[SER_CNT];
231
232 /* TX and RX buffers */
233 static unsigned char uart0_txbuffer[CONFIG_UART0_TXBUFSIZE];
234 static unsigned char uart0_rxbuffer[CONFIG_UART0_RXBUFSIZE];
235
236 static unsigned char uart1_txbuffer[CONFIG_UART1_TXBUFSIZE];
237 static unsigned char uart1_rxbuffer[CONFIG_UART1_RXBUFSIZE];
238
239 /**
240  * Internal hardware state structure
241  *
242  * The \a sending variable is true while the transmission
243  * interrupt is retriggering itself.
244  *
245  * For the USARTs the \a sending flag is useful for taking specific
246  * actions before sending a burst of data, at the start of a trasmission
247  * but not before every char sent.
248  *
249  * For the SPI, this flag is necessary because the SPI sends and receives
250  * bytes at the same time and the SPI IRQ is unique for send/receive.
251  * The only way to start transmission is to write data in SPDR (this
252  * is done by spi_starttx()). We do this *only* if a transfer is
253  * not already started.
254  */
255 struct ArmSerial
256 {
257         struct SerialHardware hw;
258         volatile bool sending;
259 };
260
261
262 /*
263  * These are to trick GCC into *not* using absolute addressing mode
264  * when accessing ser_handles, which is very expensive.
265  *
266  * Accessing through these pointers generates much shorter
267  * (and hopefully faster) code.
268  */
269 struct Serial *ser_uart0 = &ser_handles[SER_UART0];
270 struct Serial *ser_uart1 = &ser_handles[SER_UART1];
271
272
273 static void uart0_irq_dispatcher(void);
274 static void uart1_irq_dispatcher(void);
275 /*
276  * Callbacks for USART0
277  */
278 static void uart0_init(
279         UNUSED_ARG(struct SerialHardware *, _hw),
280         UNUSED_ARG(struct Serial *, ser))
281 {
282         SER_UART0_IRQ_INIT;
283         SER_UART0_BUS_TXINIT;
284         SER_STROBE_INIT;
285 }
286
287 static void uart0_cleanup(UNUSED_ARG(struct SerialHardware *, _hw))
288 {
289         US0_CR = BV(US_RSTRX) | BV(US_RSTTX) | BV(US_RXDIS) | BV(US_TXDIS) | BV(US_RSTSTA);
290 }
291
292 static void uart0_enabletxirq(struct SerialHardware *_hw)
293 {
294         struct ArmSerial *hw = (struct ArmSerial *)_hw;
295
296         /*
297          * WARNING: racy code here!  The tx interrupt sets hw->sending to false
298          * when it runs with an empty fifo.  The order of statements in the
299          * if-block matters.
300          */
301         if (!hw->sending)
302         {
303                 hw->sending = true;
304                 SER_UART0_BUS_TXBEGIN;
305         }
306 }
307
308 static void uart0_setbaudrate(UNUSED_ARG(struct SerialHardware *, _hw), unsigned long rate)
309 {
310         /* Compute baud-rate period */
311         US0_BRGR = CLOCK_FREQ / (16 * rate);
312         //DB(kprintf("uart0_setbaudrate(rate=%lu): period=%d\n", rate, period);)
313 }
314
315 static void uart0_setparity(UNUSED_ARG(struct SerialHardware *, _hw), int parity)
316 {
317         US0_MR &= ~US_PAR_MASK;
318         /* Set UART parity */
319         switch(parity)
320         {
321                 case SER_PARITY_NONE:
322                 {
323             /* Parity mode. */
324                         US0_MR |= US_PAR_NO;
325                         break;
326                 }
327                 case SER_PARITY_EVEN:
328                 {
329             /* Even parity.*/
330                         US0_MR |= US_PAR_EVEN;
331                         break;
332                 }
333                 case SER_PARITY_ODD:
334                 {
335             /* Odd parity.*/
336                         US0_MR |= US_PAR_ODD;
337                         break;
338                 }
339                 default:
340                         ASSERT(0);
341         }
342
343 }
344 /*
345  * Callbacks for USART1
346  */
347 static void uart1_init(
348         UNUSED_ARG(struct SerialHardware *, _hw),
349         UNUSED_ARG(struct Serial *, ser))
350 {
351         SER_UART1_IRQ_INIT;
352         SER_UART1_BUS_TXINIT;
353         SER_STROBE_INIT;
354 }
355
356 static void uart1_cleanup(UNUSED_ARG(struct SerialHardware *, _hw))
357 {
358         US1_CR = BV(US_RSTRX) | BV(US_RSTTX) | BV(US_RXDIS) | BV(US_TXDIS) | BV(US_RSTSTA);
359 }
360
361 static void uart1_enabletxirq(struct SerialHardware *_hw)
362 {
363         struct ArmSerial *hw = (struct ArmSerial *)_hw;
364
365         /*
366          * WARNING: racy code here!  The tx interrupt sets hw->sending to false
367          * when it runs with an empty fifo.  The order of statements in the
368          * if-block matters.
369          */
370         if (!hw->sending)
371         {
372                 hw->sending = true;
373                 SER_UART1_BUS_TXBEGIN;
374         }
375 }
376
377 static void uart1_setbaudrate(UNUSED_ARG(struct SerialHardware *, _hw), unsigned long rate)
378 {
379         /* Compute baud-rate period */
380         US1_BRGR = CLOCK_FREQ / (16 * rate);
381         //DB(kprintf("uart0_setbaudrate(rate=%lu): period=%d\n", rate, period);)
382 }
383
384 static void uart1_setparity(UNUSED_ARG(struct SerialHardware *, _hw), int parity)
385 {
386         US1_MR &= ~US_PAR_MASK;
387         /* Set UART parity */
388         switch(parity)
389         {
390                 case SER_PARITY_NONE:
391                 {
392             /* Parity mode. */
393                         US1_MR |= US_PAR_NO;
394                         break;
395                 }
396                 case SER_PARITY_EVEN:
397                 {
398             /* Even parity.*/
399                         US1_MR |= US_PAR_EVEN;
400                         break;
401                 }
402                 case SER_PARITY_ODD:
403                 {
404             /* Odd parity.*/
405                         US1_MR |= US_PAR_ODD;
406                         break;
407                 }
408                 default:
409                         ASSERT(0);
410         }
411
412 }
413
414 static bool tx_sending(struct SerialHardware* _hw)
415 {
416         struct ArmSerial *hw = (struct ArmSerial *)_hw;
417         return hw->sending;
418 }
419
420 // FIXME: move into compiler.h?  Ditch?
421 #if COMPILER_C99
422         #define C99INIT(name,val) .name = val
423 #elif defined(__GNUC__)
424         #define C99INIT(name,val) name: val
425 #else
426         #warning No designated initializers, double check your code
427         #define C99INIT(name,val) (val)
428 #endif
429
430 /*
431  * High-level interface data structures
432  */
433 static const struct SerialHardwareVT UART0_VT =
434 {
435         C99INIT(init, uart0_init),
436         C99INIT(cleanup, uart0_cleanup),
437         C99INIT(setBaudrate, uart0_setbaudrate),
438         C99INIT(setParity, uart0_setparity),
439         C99INIT(txStart, uart0_enabletxirq),
440         C99INIT(txSending, tx_sending),
441 };
442
443 static const struct SerialHardwareVT UART1_VT =
444 {
445         C99INIT(init, uart1_init),
446         C99INIT(cleanup, uart1_cleanup),
447         C99INIT(setBaudrate, uart1_setbaudrate),
448         C99INIT(setParity, uart1_setparity),
449         C99INIT(txStart, uart1_enabletxirq),
450         C99INIT(txSending, tx_sending),
451 };
452
453 static struct ArmSerial UARTDescs[SER_CNT] =
454 {
455         {
456                 C99INIT(hw, /**/) {
457                         C99INIT(table, &UART0_VT),
458                         C99INIT(txbuffer, uart0_txbuffer),
459                         C99INIT(rxbuffer, uart0_rxbuffer),
460                         C99INIT(txbuffer_size, sizeof(uart0_txbuffer)),
461                         C99INIT(rxbuffer_size, sizeof(uart0_rxbuffer)),
462                 },
463                 C99INIT(sending, false),
464         },
465         {
466                 C99INIT(hw, /**/) {
467                         C99INIT(table, &UART1_VT),
468                         C99INIT(txbuffer, uart1_txbuffer),
469                         C99INIT(rxbuffer, uart1_rxbuffer),
470                         C99INIT(txbuffer_size, sizeof(uart1_txbuffer)),
471                         C99INIT(rxbuffer_size, sizeof(uart1_rxbuffer)),
472                 },
473                 C99INIT(sending, false),
474         }
475 };
476
477 struct SerialHardware *ser_hw_getdesc(int unit)
478 {
479         ASSERT(unit < SER_CNT);
480         return &UARTDescs[unit].hw;
481 }
482
483 /**
484  * Serial 0 TX interrupt handler
485  */
486 static void uart0_irq_tx(void)
487 {
488         SER_STROBE_ON;
489
490         struct FIFOBuffer * const txfifo = &ser_uart0->txfifo;
491
492         if (fifo_isempty(txfifo))
493         {
494                 SER_UART0_BUS_TXEND;
495                 UARTDescs[SER_UART0].sending = false;
496         }
497         else
498         {
499                 char c = fifo_pop(txfifo);
500                 SER_UART0_BUS_TXCHAR(c);
501         }
502
503         SER_STROBE_OFF;
504 }
505
506 /**
507  * Serial 0 RX complete interrupt handler.
508  */
509 static void uart0_irq_rx(void)
510 {
511         SER_STROBE_ON;
512
513         /* Should be read before US_CRS */
514         ser_uart0->status |= US0_CSR & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
515
516         char c = US0_RHR;
517         struct FIFOBuffer * const rxfifo = &ser_uart0->rxfifo;
518
519         if (fifo_isfull(rxfifo))
520                 ser_uart0->status |= SERRF_RXFIFOOVERRUN;
521         else
522                 fifo_push(rxfifo, c);
523
524         SER_STROBE_OFF;
525 }
526
527 /**
528  * Serial IRQ dispatcher for USART0.
529  */
530 static void uart0_irq_dispatcher(void) __attribute__ ((naked));
531 static void uart0_irq_dispatcher(void)
532 {
533         IRQ_ENTRY();
534
535         if (US0_IMR & BV(US_RXRDY))
536                 uart0_irq_rx();
537
538         if (US0_IMR & BV(US_TXRDY))
539                 uart0_irq_tx();
540
541         IRQ_EXIT();
542 }
543
544 /**
545  * Serial 1 TX interrupt handler
546  */
547 static void uart1_irq_tx(void)
548 {
549         SER_STROBE_ON;
550
551         struct FIFOBuffer * const txfifo = &ser_uart1->txfifo;
552
553         if (fifo_isempty(txfifo))
554         {
555                 SER_UART1_BUS_TXEND;
556                 UARTDescs[SER_UART1].sending = false;
557         }
558         else
559         {
560                 char c = fifo_pop(txfifo);
561                 SER_UART1_BUS_TXCHAR(c);
562         }
563
564         SER_STROBE_OFF;
565 }
566
567 /**
568  * Serial 1 RX complete interrupt handler.
569  */
570 static void uart1_irq_rx(void)
571 {
572         SER_STROBE_ON;
573
574         /* Should be read before US_CRS */
575         ser_uart1->status |= US1_CSR & (SERRF_RXSROVERRUN | SERRF_FRAMEERROR);
576
577         char c = US1_RHR;
578         struct FIFOBuffer * const rxfifo = &ser_uart1->rxfifo;
579
580         if (fifo_isfull(rxfifo))
581                 ser_uart1->status |= SERRF_RXFIFOOVERRUN;
582         else
583                 fifo_push(rxfifo, c);
584
585         SER_STROBE_OFF;
586 }
587
588 /**
589  * Serial IRQ dispatcher for USART1.
590  */
591 static void uart1_irq_dispatcher(void) __attribute__ ((naked));
592 static void uart1_irq_dispatcher(void)
593 {
594         IRQ_ENTRY();
595
596         if (US1_IMR & BV(US_RXRDY))
597                 uart1_irq_rx();
598
599         if (US1_IMR & BV(US_TXRDY))
600                 uart1_irq_tx();
601
602         IRQ_EXIT();
603 }