source: rtems/bsps/arm/atsam/console/console.c @ ba619b7f

Last change on this file since ba619b7f was ba619b7f, checked in by Joel Sherrill <joel@…>, on 03/01/22 at 21:38:20

bsps/arm/: Scripted embedded brains header file clean up

Updates #4625.

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