source: rtems/c/src/lib/libbsp/arm/imx/console/console-config.c @ 336fe3b

5
Last change on this file since 336fe3b was 336fe3b, checked in by Sebastian Huber <sebastian.huber@…>, on Nov 8, 2017 at 7:19:15 AM

bsp/imx: Better utilize UART transmit FIFO

Update #3090.

  • Property mode set to 100644
File size: 7.4 KB
Line 
1/*
2 * Copyright (c) 2017 embedded brains GmbH.  All rights reserved.
3 *
4 *  embedded brains GmbH
5 *  Dornierstr. 4
6 *  82178 Puchheim
7 *  Germany
8 *  <info@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 <sys/param.h>
16
17#include <rtems/bspIo.h>
18#include <rtems/console.h>
19#include <rtems/sysinit.h>
20#include <rtems/termiostypes.h>
21
22#include <bsp.h>
23#include <bsp/fdt.h>
24#include <bsp/irq.h>
25
26#include <arm/freescale/imx/imx_uartreg.h>
27
28#include <libfdt.h>
29
30#define IMX_UART_TX_FIFO_LEVEL 16
31
32typedef struct {
33  rtems_termios_device_context base;
34  volatile imx_uart *regs;
35#ifdef CONSOLE_USE_INTERRUPTS
36  rtems_vector_number irq;
37  int tx_in_progress;
38#endif
39} imx_uart_context;
40
41static imx_uart_context imx_uart_instances[7];
42
43static imx_uart_context *imx_uart_console = &imx_uart_instances[0];
44
45static volatile imx_uart *imx_uart_get_regs(rtems_termios_device_context *base)
46{
47  imx_uart_context *ctx;
48
49  ctx = (imx_uart_context *) base;
50  return ctx->regs;
51}
52
53static void imx_uart_write_polled(rtems_termios_device_context *base, char c)
54{
55  volatile imx_uart *regs;
56
57  regs = imx_uart_get_regs(base);
58
59  while ((regs->usr1 & IMX_UART_USR1_TRDY) == 0) {
60    /* Wait */
61  }
62
63  regs->utxd = IMX_UART_UTXD_TX_DATA(c);
64}
65
66void imx_uart_console_drain(void)
67{
68  volatile imx_uart *regs;
69
70  regs = imx_uart_get_regs(&imx_uart_console->base);
71
72  if (regs != NULL) {
73    while ((regs->usr2 & IMX_UART_USR2_TXFE) == 0) {
74      /* Wait */
75    }
76  }
77}
78
79static void imx_output_char(char c)
80{
81  imx_uart_write_polled(&imx_uart_console->base, c);
82}
83
84static void imx_uart_init_context(
85  imx_uart_context *ctx,
86  const char *fdt,
87  const char *serial
88)
89{
90  int node;
91
92  rtems_termios_device_context_initialize(&ctx->base, "UART");
93  node = fdt_path_offset(fdt, serial);
94  ctx->regs = imx_get_reg_of_node(fdt, node);
95#ifdef CONSOLE_USE_INTERRUPTS
96  ctx->irq = imx_get_irq_of_node(fdt, node, 0);
97#endif
98}
99
100static void imx_uart_probe(void)
101{
102  const void *fdt;
103  int node;
104  int offset;
105  const char *console;
106  size_t i;
107
108  fdt = bsp_fdt_get();
109  node = fdt_path_offset(fdt, "/chosen");
110
111  console = fdt_getprop(fdt, node, "stdout-path", NULL);
112  if (console == NULL) {
113    console = "";
114  }
115
116  node = fdt_path_offset(fdt, "/aliases");
117  offset = fdt_first_property_offset(fdt, node);
118  i = 0;
119
120  while (offset >= 0 && i < RTEMS_ARRAY_SIZE(imx_uart_instances)) {
121    const struct fdt_property *prop;
122
123    prop = fdt_get_property_by_offset(fdt, offset, NULL);
124
125    if (prop != NULL) {
126      const char *name;
127
128      name = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
129      if (strstr(name, "serial") != NULL) {
130        imx_uart_context *ctx;
131        const char *serial;
132
133        ctx = &imx_uart_instances[i];
134        serial = prop->data;
135
136        if (strcmp(serial, console) == 0) {
137          imx_uart_console = ctx;
138        }
139
140        imx_uart_init_context(ctx, fdt, serial);
141        ++i;
142      }
143    }
144
145    offset = fdt_next_property_offset(fdt, offset);
146  }
147
148  BSP_output_char = imx_output_char;
149}
150
151static void imx_output_char_init(char c)
152{
153  imx_uart_probe();
154  imx_output_char(c);
155}
156
157BSP_output_char_function_type BSP_output_char = imx_output_char_init;
158
159BSP_polling_getchar_function_type BSP_poll_char = NULL;
160
161#ifdef CONSOLE_USE_INTERRUPTS
162static void imx_uart_interrupt(void *arg)
163{
164  rtems_termios_tty *tty;
165  imx_uart_context *ctx;
166  volatile imx_uart *regs;
167  uint32_t usr2;
168
169  tty = arg;
170  ctx = rtems_termios_get_device_context(tty);
171  regs = ctx->regs;
172  usr2 = regs->usr2;
173
174  regs->usr1 = IMX_UART_USR1_AGTIM;
175
176  while ((usr2 & IMX_UART_USR2_RDR) != 0) {
177    char c;
178
179    c = IMX_UART_URXD_RX_DATA_GET(regs->urxd);
180    rtems_termios_enqueue_raw_characters(tty, &c, 1);
181    usr2 = regs->usr2;
182  }
183
184  if (ctx->tx_in_progress > 0 && (regs->usr1 & IMX_UART_USR1_TRDY) != 0) {
185    rtems_termios_dequeue_characters(tty, ctx->tx_in_progress);
186  }
187}
188#endif
189
190static bool imx_uart_set_attributes(
191  rtems_termios_device_context *base,
192  const struct termios *term
193)
194{
195  return true;
196}
197
198static bool imx_uart_first_open(
199  rtems_termios_tty *tty,
200  rtems_termios_device_context *base,
201  struct termios *term,
202  rtems_libio_open_close_args_t *args
203)
204{
205  imx_uart_context *ctx;
206  volatile imx_uart *regs;
207#ifdef CONSOLE_USE_INTERRUPTS
208  rtems_status_code sc;
209  uint32_t ufcr;
210#endif
211
212  ctx = (imx_uart_context *) base;
213  regs = imx_uart_get_regs(&ctx->base);
214
215  regs->ucr1 = IMX_UART_UCR1_UARTEN;
216  regs->ucr2 = IMX_UART_UCR2_IRTS | IMX_UART_UCR2_WS | IMX_UART_UCR2_RXEN
217    | IMX_UART_UCR2_TXEN | IMX_UART_UCR2_SRST;
218
219  rtems_termios_set_initial_baud(tty, 115200);
220  imx_uart_set_attributes(base, term);
221
222#ifdef CONSOLE_USE_INTERRUPTS
223  ufcr = regs->ufcr;
224  ufcr = IMX_UART_UFCR_RXTL_SET(ufcr, 16);
225  ufcr = IMX_UART_UFCR_TXTL_SET(ufcr, IMX_UART_TX_FIFO_LEVEL);
226  regs->ufcr = ufcr;
227  regs->ucr1 |= IMX_UART_UCR1_RRDYEN;
228  regs->ucr2 |= IMX_UART_UCR2_ATEN;
229  sc = rtems_interrupt_handler_install(
230    ctx->irq,
231    "UART",
232    RTEMS_INTERRUPT_SHARED,
233    imx_uart_interrupt,
234    tty
235  );
236  if (sc != RTEMS_SUCCESSFUL) {
237    return false;
238  }
239#endif
240
241  return true;
242}
243
244static void imx_uart_last_close(
245  rtems_termios_tty *tty,
246  rtems_termios_device_context *base,
247  rtems_libio_open_close_args_t *args
248)
249{
250#ifdef CONSOLE_USE_INTERRUPTS
251  imx_uart_context *ctx;
252
253  ctx = (imx_uart_context *) base;
254  rtems_interrupt_handler_remove(ctx->irq, imx_uart_interrupt, tty);
255#endif
256}
257
258static void imx_uart_write(
259  rtems_termios_device_context *base,
260  const char *buf,
261  size_t len
262)
263{
264#ifdef CONSOLE_USE_INTERRUPTS
265  imx_uart_context *ctx;
266  volatile imx_uart *regs;
267  int n;
268  uint32_t ucr1;
269
270  ctx = (imx_uart_context *) base;
271  regs = imx_uart_get_regs(&ctx->base);
272  ucr1 = regs->ucr1;
273
274  if (len > 0) {
275    int i;
276
277    n = (int) MIN(len, IMX_UART_TX_FIFO_LEVEL);
278    ucr1 |= IMX_UART_UCR1_TRDYEN;
279
280    for (i = 0; i < n; ++i) {
281      regs->utxd = IMX_UART_UTXD_TX_DATA(buf[i]);
282    }
283  } else {
284    n = 0;
285    ucr1 &= ~IMX_UART_UCR1_TRDYEN;
286  }
287
288  regs->ucr1 = ucr1;
289  ctx->tx_in_progress = n;
290#else
291  size_t i;
292
293  for (i = 0; i < len; ++i) {
294    imx_uart_write_polled(base, buf[i]);
295  }
296#endif
297}
298
299#ifndef CONSOLE_USE_INTERRUPTS
300static int imx_uart_read(rtems_termios_device_context *base)
301{
302  volatile imx_uart *regs;
303
304  regs = imx_uart_get_regs(base);
305
306  if ((regs->usr2 & IMX_UART_USR2_RDR) != 0) {
307    return IMX_UART_URXD_RX_DATA_GET(regs->urxd);
308  } else {
309    return -1;
310  }
311}
312#endif
313
314static const rtems_termios_device_handler imx_uart_handler = {
315  .first_open = imx_uart_first_open,
316  .last_close = imx_uart_last_close,
317  .write = imx_uart_write,
318  .set_attributes = imx_uart_set_attributes,
319#ifdef CONSOLE_USE_INTERRUPTS
320  .mode = TERMIOS_IRQ_DRIVEN
321#else
322  .poll_read = imx_uart_read,
323  .mode = TERMIOS_POLLED
324#endif
325};
326
327rtems_status_code console_initialize(
328  rtems_device_major_number major,
329  rtems_device_minor_number minor,
330  void *arg
331)
332{
333  char path[] = "/dev/ttyS?";
334  size_t i;
335
336  rtems_termios_initialize();
337
338  for (i = 0; i < RTEMS_ARRAY_SIZE(imx_uart_instances); ++i) {
339    imx_uart_context *ctx;
340
341    ctx = &imx_uart_instances[i];
342    path[sizeof(path) - 2] = (char) ('0' + i);
343
344    rtems_termios_device_install(
345      path,
346      &imx_uart_handler,
347      NULL,
348      &ctx->base
349    );
350
351    if (ctx == imx_uart_console) {
352      link(path, CONSOLE_DEVICE_NAME);
353    }
354  }
355
356  return RTEMS_SUCCESSFUL;
357}
358
359RTEMS_SYSINIT_ITEM(
360  imx_uart_probe,
361  RTEMS_SYSINIT_BSP_START,
362  RTEMS_SYSINIT_ORDER_LAST
363);
Note: See TracBrowser for help on using the repository browser.