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

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

bsp/imx: Add UART baud change

Update #3090.

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