source: rtems/c/src/lib/libbsp/arm/atsam/console/console.c @ f2e0f8e

5
Last change on this file since f2e0f8e was f2e0f8e, checked in by Sebastian Huber <sebastian.huber@…>, on Jan 14, 2016 at 3:03:51 PM

bsp/atsam: New

Close #2529.

  • Property mode set to 100644
File size: 10.7 KB
Line 
1/*
2 * Copyright (c) 2016 embedded brains GmbH.  All rights reserved.
3 *
4 *  embedded brains GmbH
5 *  Dornierstr. 4
6 *  82178 Puchheim
7 *  Germany
8 *  <rtems@embedded-brains.de>
9 *
10 * The license and distribution terms for this file may be
11 * found in the file LICENSE in this distribution or at
12 * http://www.rtems.org/license/LICENSE.
13 */
14
15#include <bsp.h>
16#include <bsp/irq.h>
17#include <bsp/fatal.h>
18
19#include <rtems/termiostypes.h>
20
21#include <chip.h>
22
23typedef struct {
24  rtems_termios_device_context base;
25  Usart *regs;
26  rtems_vector_number irq;
27  uint32_t id;
28  bool console;
29#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
30  bool transmitting;
31#endif
32} atsam_usart_context;
33
34static atsam_usart_context atsam_usart_instances[] = {
35  {
36    .regs = USART0,
37    .irq = USART0_IRQn,
38    .id = ID_USART0
39  }
40#ifdef USART1
41  , {
42    .regs = USART1,
43    .irq = USART1_IRQn,
44    .id = ID_USART1
45  }
46#endif
47#ifdef USART2
48  , {
49    .regs = USART2,
50    .irq = USART2_IRQn,
51    .id = ID_USART2
52  }
53#endif
54};
55
56#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
57static void atsam_usart_interrupt(void *arg)
58{
59  rtems_termios_tty *tty = arg;
60  atsam_usart_context *ctx = rtems_termios_get_device_context(tty);
61  Usart *regs = ctx->regs;
62  uint32_t csr = regs->US_CSR;
63
64  while ((csr & US_CSR_RXRDY) != 0) {
65    char c = (char) regs->US_RHR;
66
67    rtems_termios_enqueue_raw_characters(tty, &c, 1);
68
69    csr = regs->US_CSR;
70  }
71
72  if (ctx->transmitting && (csr & US_CSR_TXEMPTY) != 0) {
73    rtems_termios_dequeue_characters(tty, 1);
74  }
75}
76#endif
77
78static bool atsam_usart_set_attributes(
79  rtems_termios_device_context *base,
80  const struct termios *term
81)
82{
83  atsam_usart_context *ctx = (atsam_usart_context *) base;
84  Usart *regs = ctx->regs;
85  rtems_termios_baud_t baud;
86  uint32_t mr;
87
88  baud = rtems_termios_baud_to_number(term->c_cflag);
89  regs->US_BRGR = (BOARD_MCK / baud) / 16;
90
91  if ((term->c_cflag & CREAD) != 0) {
92    regs->US_CR = US_CR_RXEN | US_CR_TXEN;
93  } else {
94    regs->US_CR = US_CR_TXEN;
95  }
96
97  mr = US_MR_USART_MODE_NORMAL | US_MR_USCLKS_MCK;
98
99  switch (term->c_cflag & CSIZE) {
100    case CS5:
101      mr |= US_MR_CHRL_5_BIT;
102      break;
103    case CS6:
104      mr |= US_MR_CHRL_6_BIT;
105      break;
106    case CS7:
107      mr |= US_MR_CHRL_7_BIT;
108      break;
109    default:
110      mr |= US_MR_CHRL_8_BIT;
111      break;
112  }
113
114  if ((term->c_cflag & PARENB) != 0) {
115    if ((term->c_cflag & PARODD) != 0) {
116      mr |= US_MR_PAR_ODD;
117    } else {
118      mr |= US_MR_PAR_EVEN;
119    }
120  } else {
121    mr |= US_MR_PAR_NO;
122  }
123
124  if ((term->c_cflag & CSTOPB) != 0) {
125    mr |= US_MR_NBSTOP_2_BIT;
126  } else {
127    mr |= US_MR_NBSTOP_1_BIT;
128  }
129
130  regs->US_MR = mr;
131
132  return true;
133}
134
135static bool atsam_usart_first_open(
136  rtems_termios_tty *tty,
137  rtems_termios_device_context *base,
138  struct termios *term,
139  rtems_libio_open_close_args_t *args
140)
141{
142  atsam_usart_context *ctx = (atsam_usart_context *) base;
143  Usart *regs = ctx->regs;
144#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
145  rtems_status_code sc;
146#endif
147
148  regs->US_CR = US_CR_RSTRX | US_CR_RSTTX | US_CR_RSTSTA;
149  regs->US_IDR = 0xffffffff;
150
151  PMC_EnablePeripheral(ctx->id);
152
153  rtems_termios_set_initial_baud(tty, ATSAM_CONSOLE_BAUD);
154  atsam_usart_set_attributes(base, term);
155
156#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
157  regs->US_IER = US_IDR_RXRDY;
158  sc = rtems_interrupt_handler_install(
159    ctx->irq,
160    "USART",
161    RTEMS_INTERRUPT_SHARED,
162    atsam_usart_interrupt,
163    tty
164  );
165  if (sc != RTEMS_SUCCESSFUL) {
166    return false;
167  }
168#endif
169
170  return true;
171}
172
173static void atsam_usart_last_close(
174  rtems_termios_tty *tty,
175  rtems_termios_device_context *base,
176  rtems_libio_open_close_args_t *args
177)
178{
179  atsam_usart_context *ctx = (atsam_usart_context *) base;
180
181#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
182  rtems_interrupt_handler_remove(ctx->irq, atsam_usart_interrupt, tty);
183#endif
184
185  if (!ctx->console) {
186    PMC_DisablePeripheral(ctx->id);
187  }
188}
189
190static void atsam_usart_write(
191  rtems_termios_device_context *base,
192  const char *buf,
193  size_t len
194)
195{
196  atsam_usart_context *ctx = (atsam_usart_context *) base;
197  Usart *regs = ctx->regs;
198
199#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
200  if (len > 0) {
201    ctx->transmitting = true;
202    regs->US_THR = buf[0];
203    regs->US_IER = US_IDR_TXEMPTY;
204  } else {
205    ctx->transmitting = false;
206    regs->US_IDR = US_IDR_TXEMPTY;
207  }
208#else
209  size_t i;
210
211  for (i = 0; i < len; ++i) {
212    while ((regs->US_CSR & US_CSR_TXEMPTY) == 0) {
213      /* Wait */
214    }
215
216    regs->US_THR = buf[i];
217  }
218#endif
219}
220
221#ifndef ATSAM_CONSOLE_USE_INTERRUPTS
222static int atsam_usart_read(rtems_termios_device_context *base)
223{
224  atsam_usart_context *ctx = (atsam_usart_context *) base;
225  Usart *regs = ctx->regs;
226
227  if ((regs->US_CSR & US_CSR_RXRDY) != 0) {
228    return (char) regs->US_RHR;
229  } else {
230    return -1;
231  }
232}
233#endif
234
235static const rtems_termios_device_handler atsam_usart_handler = {
236  .first_open = atsam_usart_first_open,
237  .last_close = atsam_usart_last_close,
238  .write = atsam_usart_write,
239  .set_attributes = atsam_usart_set_attributes,
240#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
241  .mode = TERMIOS_IRQ_DRIVEN
242#else
243  .poll_read = atsam_usart_read,
244  .mode = TERMIOS_POLLED
245#endif
246};
247
248typedef struct {
249  rtems_termios_device_context base;
250  Uart *regs;
251  rtems_vector_number irq;
252  uint32_t id;
253  bool console;
254#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
255  bool transmitting;
256#endif
257} atsam_uart_context;
258
259static atsam_uart_context atsam_uart_instances[] = {
260  {
261    .regs = UART0,
262    .irq = UART0_IRQn,
263    .id = ID_UART0
264  }
265#ifdef UART1
266  , {
267    .regs = UART1,
268    .irq = UART1_IRQn,
269    .id = ID_UART1
270  }
271#endif
272#ifdef UART2
273  , {
274    .regs = UART2,
275    .irq = UART2_IRQn,
276    .id = ID_UART2
277  }
278#endif
279#ifdef UART3
280  , {
281    .regs = UART3,
282    .irq = UART3_IRQn,
283    .id = ID_UART3
284  }
285#endif
286#ifdef UART4
287  , {
288    .regs = UART4,
289    .irq = UART4_IRQn,
290    .id = ID_UART4
291  }
292#endif
293};
294
295#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
296static void atsam_uart_interrupt(void *arg)
297{
298  rtems_termios_tty *tty = arg;
299  atsam_uart_context *ctx = rtems_termios_get_device_context(tty);
300  Uart *regs = ctx->regs;
301  uint32_t sr = regs->UART_SR;
302
303  while ((sr & UART_SR_RXRDY) != 0) {
304    char c = (char) regs->UART_RHR;
305
306    rtems_termios_enqueue_raw_characters(tty, &c, 1);
307
308    sr = regs->UART_SR;
309  }
310
311  if (ctx->transmitting && (sr & UART_SR_TXEMPTY) != 0) {
312    rtems_termios_dequeue_characters(tty, 1);
313  }
314}
315#endif
316
317static bool atsam_uart_set_attributes(
318  rtems_termios_device_context *base,
319  const struct termios *term
320)
321{
322  atsam_uart_context *ctx = (atsam_uart_context *) base;
323  Uart *regs = ctx->regs;
324  rtems_termios_baud_t baud;
325  uint32_t mr;
326
327  baud = rtems_termios_baud_to_number(term->c_cflag);
328  regs->UART_BRGR = (BOARD_MCK / baud) / 16;
329
330  if ((term->c_cflag & CREAD) != 0) {
331    regs->UART_CR = UART_CR_RXEN | UART_CR_TXEN;
332  } else {
333    regs->UART_CR = UART_CR_TXEN;
334  }
335
336  mr = UART_MR_FILTER_DISABLED | UART_MR_BRSRCCK_PERIPH_CLK;
337
338  if ((term->c_cflag & CSIZE) != CS8) {
339    return false;
340  }
341
342  if ((term->c_cflag & PARENB) != 0) {
343    if ((term->c_cflag & PARODD) != 0) {
344      mr |= UART_MR_PAR_ODD;
345    } else {
346      mr |= UART_MR_PAR_EVEN;
347    }
348  } else {
349    mr |= UART_MR_PAR_NO;
350  }
351
352  if ((term->c_cflag & CSTOPB) != 0) {
353    return false;
354  }
355
356  regs->UART_MR = mr;
357
358  return true;
359}
360
361static bool atsam_uart_first_open(
362  rtems_termios_tty *tty,
363  rtems_termios_device_context *base,
364  struct termios *term,
365  rtems_libio_open_close_args_t *args
366)
367{
368  atsam_uart_context *ctx = (atsam_uart_context *) base;
369  Uart *regs = ctx->regs;
370#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
371  rtems_status_code sc;
372#endif
373
374  regs->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX | UART_CR_RSTSTA;
375  regs->UART_IDR = 0xffffffff;
376
377  PMC_EnablePeripheral(ctx->id);
378
379  rtems_termios_set_initial_baud(tty, ATSAM_CONSOLE_BAUD);
380  atsam_uart_set_attributes(base, term);
381
382#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
383  regs->UART_IER = UART_IDR_RXRDY;
384  sc = rtems_interrupt_handler_install(
385    ctx->irq,
386    "UART",
387    RTEMS_INTERRUPT_SHARED,
388    atsam_uart_interrupt,
389    tty
390  );
391  if (sc != RTEMS_SUCCESSFUL) {
392    return false;
393  }
394#endif
395
396  return true;
397}
398
399static void atsam_uart_last_close(
400  rtems_termios_tty *tty,
401  rtems_termios_device_context *base,
402  rtems_libio_open_close_args_t *args
403)
404{
405  atsam_uart_context *ctx = (atsam_uart_context *) base;
406
407#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
408  rtems_interrupt_handler_remove(ctx->irq, atsam_uart_interrupt, tty);
409#endif
410
411  if (!ctx->console) {
412    PMC_DisablePeripheral(ctx->id);
413  }
414}
415
416static void atsam_uart_write(
417  rtems_termios_device_context *base,
418  const char *buf,
419  size_t len
420)
421{
422  atsam_uart_context *ctx = (atsam_uart_context *) base;
423  Uart *regs = ctx->regs;
424
425#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
426  if (len > 0) {
427    ctx->transmitting = true;
428    regs->UART_THR = buf[0];
429    regs->UART_IER = UART_IDR_TXEMPTY;
430  } else {
431    ctx->transmitting = false;
432    regs->UART_IDR = UART_IDR_TXEMPTY;
433  }
434#else
435  size_t i;
436
437  for (i = 0; i < len; ++i) {
438    while ((regs->UART_SR & UART_SR_TXEMPTY) == 0) {
439      /* Wait */
440    }
441
442    regs->UART_THR = buf[i];
443  }
444#endif
445}
446
447#ifndef ATSAM_CONSOLE_USE_INTERRUPTS
448static int atsam_uart_read(rtems_termios_device_context *base)
449{
450  atsam_uart_context *ctx = (atsam_uart_context *) base;
451  Uart *regs = ctx->regs;
452
453  if ((regs->UART_SR & UART_SR_RXRDY) != 0) {
454    return (char) regs->UART_RHR;
455  } else {
456    return -1;
457  }
458}
459#endif
460
461static const rtems_termios_device_handler atsam_uart_handler = {
462  .first_open = atsam_uart_first_open,
463  .last_close = atsam_uart_last_close,
464  .write = atsam_uart_write,
465  .set_attributes = atsam_uart_set_attributes,
466#ifdef ATSAM_CONSOLE_USE_INTERRUPTS
467  .mode = TERMIOS_IRQ_DRIVEN
468#else
469  .poll_read = atsam_uart_read,
470  .mode = TERMIOS_POLLED
471#endif
472};
473
474rtems_status_code console_initialize(
475  rtems_device_major_number major,
476  rtems_device_minor_number minor,
477  void *arg
478)
479{
480  size_t i;
481
482  rtems_termios_initialize();
483
484  for (i = 0; i < RTEMS_ARRAY_SIZE(atsam_usart_instances); ++i) {
485    char usart[] = "/dev/ttyUSARTX";
486
487    usart[sizeof(usart) - 2] = (char) ('0' + i);
488    rtems_termios_device_install(
489      &usart[0],
490      major,
491      minor,
492      &atsam_usart_handler,
493      NULL,
494      &atsam_usart_instances[i].base
495    );
496
497#if ATSAM_CONSOLE_DEVICE_TYPE == 0
498    if (i == ATSAM_CONSOLE_DEVICE_INDEX) {
499      atsam_usart_instances[i].console = true;
500      rtems_io_register_name(CONSOLE_DEVICE_NAME, major, minor);
501    }
502#endif
503
504    ++minor;
505  }
506
507  for (i = 0; i < RTEMS_ARRAY_SIZE(atsam_uart_instances); ++i) {
508    char uart[] = "/dev/ttyUARTX";
509
510    uart[sizeof(uart) - 2] = (char) ('0' + i);
511    rtems_termios_device_install(
512      &uart[0],
513      major,
514      minor,
515      &atsam_uart_handler,
516      NULL,
517      &atsam_uart_instances[i].base
518    );
519
520#if ATSAM_CONSOLE_DEVICE_TYPE == 1
521    if (i == ATSAM_CONSOLE_DEVICE_INDEX) {
522      atsam_uart_instances[i].console = true;
523      rtems_io_register_name(CONSOLE_DEVICE_NAME, major, minor);
524    }
525#endif
526
527    ++minor;
528  }
529
530  return RTEMS_SUCCESSFUL;
531}
Note: See TracBrowser for help on using the repository browser.