source: rtems/bsps/arm/imx/console/console-config.c @ 9c7bffb

5
Last change on this file since 9c7bffb was 9c7bffb, checked in by Christian Mauderer <christian.mauderer@…>, on 02/10/20 at 09:35:14

bsp/imx: Use muxed mode for serials.

Update #3869.

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