source: rtems/bsps/riscv/riscv/console/console-config.c @ 56b0387

5
Last change on this file since 56b0387 was 56b0387, checked in by Sebastian Huber <sebastian.huber@…>, on 08/01/18 at 06:13:39

bsp/riscv: Add NS16750 support to console driver

Update #3433.

  • Property mode set to 100644
File size: 6.2 KB
Line 
1/*
2 * Copyright (c) 2018 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 <rtems/bspIo.h>
16#include <rtems/console.h>
17#include <rtems/sysinit.h>
18#include <rtems/termiostypes.h>
19
20#include <bsp/fatal.h>
21#include <bsp/fdt.h>
22#include <bsp/irq.h>
23#include <bsp/riscv.h>
24
25#include <dev/serial/htif.h>
26#include <libchip/ns16550.h>
27
28#include <libfdt.h>
29#include <string.h>
30
31#if RISCV_ENABLE_HTIF_SUPPORT != 0
32static htif_console_context htif_console_instance;
33#endif
34
35#if RISCV_CONSOLE_MAX_NS16550_DEVICES > 0
36static ns16550_context ns16550_instances[RISCV_CONSOLE_MAX_NS16550_DEVICES];
37#endif
38
39static struct {
40  rtems_termios_device_context *context;
41  void (*putchar)(rtems_termios_device_context *base, char c);
42  int (*getchar)(rtems_termios_device_context *base);
43} riscv_console;
44
45static void riscv_output_char(char c)
46{
47  (*riscv_console.putchar)(riscv_console.context, c);
48}
49
50static int riscv_get_console_node(const void *fdt)
51{
52  const char *stdout_path;
53  int node;
54
55  node = fdt_path_offset(fdt, "/chosen");
56
57  stdout_path = fdt_getprop(fdt, node, "stdout-path", NULL);
58  if (stdout_path == NULL) {
59    stdout_path = "";
60  }
61
62  return fdt_path_offset(fdt, stdout_path);
63}
64
65#if RISCV_CONSOLE_MAX_NS16550_DEVICES > 0
66static uint8_t riscv_console_get_reg_8(uintptr_t addr, uint8_t i)
67{
68  volatile uint8_t *reg;
69
70  reg = (uint8_t *) addr;
71  return reg[i];
72}
73
74static void riscv_console_set_reg_8(uintptr_t addr, uint8_t i, uint8_t val)
75{
76  volatile uint8_t *reg;
77
78  reg = (uint8_t *)addr;
79  reg[i] = val;
80}
81
82static uint8_t riscv_console_get_reg_32(uintptr_t addr, uint8_t i)
83{
84  volatile uint32_t *reg;
85
86  reg = (uint32_t *) addr;
87  return reg[i];
88}
89
90static void riscv_console_set_reg_32(uintptr_t addr, uint8_t i, uint8_t val)
91{
92  volatile uint32_t *reg;
93
94  reg = (uint32_t *)addr;
95  reg[i] = val;
96}
97#endif
98
99#define RISCV_CONSOLE_IS_COMPATIBLE(actual, actual_len, desired) \
100  (actual_len == sizeof(desired) \
101     && memcmp(actual, desired, sizeof(desired) - 1) == 0)
102
103static void riscv_console_probe(void)
104{
105  const void *fdt;
106  int node;
107  int console_node;
108#if RISCV_CONSOLE_MAX_NS16550_DEVICES > 0
109  size_t ns16550_devices;
110#endif
111
112  fdt = bsp_fdt_get();
113  console_node = riscv_get_console_node(fdt);
114#if RISCV_CONSOLE_MAX_NS16550_DEVICES > 0
115  ns16550_devices = 0;
116#endif
117
118  node = fdt_next_node(fdt, -1, NULL);
119
120  while (node >= 0) {
121    const char *compat;
122    int compat_len;
123
124    compat = fdt_getprop(fdt, node, "compatible", &compat_len);
125    if (compat == NULL) {
126      compat_len = 0;
127    }
128
129#if RISCV_ENABLE_HTIF_SUPPORT != 0
130    if (RISCV_CONSOLE_IS_COMPATIBLE(compat, compat_len, "ucb,htif0")) {
131      htif_console_context_init(&htif_console_instance.base, node);
132
133      riscv_console.context = &htif_console_instance.base;
134      riscv_console.putchar = htif_console_putchar;
135      riscv_console.getchar = htif_console_getchar;
136    };
137#endif
138
139#if RISCV_CONSOLE_MAX_NS16550_DEVICES > 0
140    if (
141      (RISCV_CONSOLE_IS_COMPATIBLE(compat, compat_len, "ns16550a")
142          || RISCV_CONSOLE_IS_COMPATIBLE(compat, compat_len, "ns16750"))
143        && ns16550_devices < RISCV_CONSOLE_MAX_NS16550_DEVICES
144    ) {
145      ns16550_context *ctx;
146      fdt32_t *val;
147      int len;
148
149      ctx = &ns16550_instances[ns16550_devices];
150      ctx->initial_baud = BSP_CONSOLE_BAUD;
151
152      if (RISCV_CONSOLE_IS_COMPATIBLE(compat, compat_len, "ns16750")) {
153        ctx->has_precision_clock_synthesizer = true;
154        ctx->get_reg = riscv_console_get_reg_32;
155        ctx->set_reg = riscv_console_set_reg_32;
156      } else {
157        ctx->get_reg = riscv_console_get_reg_8;
158        ctx->set_reg = riscv_console_set_reg_8;
159      }
160
161      ctx->port = (uintptr_t) riscv_fdt_get_address(fdt, node);
162
163      if (ctx->port == 0) {
164        bsp_fatal(RISCV_FATAL_NO_NS16550_REG_IN_DEVICE_TREE);
165      }
166
167      val = (fdt32_t *) fdt_getprop(fdt, node, "clock-frequency", &len);
168
169      if (val == NULL || len != 4) {
170        bsp_fatal(RISCV_FATAL_NO_NS16550_CLOCK_FREQUENCY_IN_DEVICE_TREE);
171      }
172
173      ctx->clock = fdt32_to_cpu(val[0]);
174
175      val = (fdt32_t *) fdt_getprop(fdt, node, "interrupts", &len);
176
177      if (val == NULL || len != 4) {
178        bsp_fatal(RISCV_FATAL_NO_NS16550_INTERRUPTS_IN_DEVICE_TREE);
179      }
180
181      ctx->irq = RISCV_INTERRUPT_VECTOR_EXTERNAL(fdt32_to_cpu(val[0]));
182
183      if (node == console_node) {
184        riscv_console.context = &ctx->base;
185        riscv_console.putchar = ns16550_polled_putchar;
186        riscv_console.getchar = ns16550_polled_getchar;
187      }
188
189      rtems_termios_device_context_initialize(&ctx->base, "NS16550");
190      ns16550_probe(&ctx->base);
191
192      ++ns16550_devices;
193    }
194#endif
195
196    node = fdt_next_node(fdt, node, NULL);
197  }
198
199  BSP_output_char = riscv_output_char;
200}
201
202static void riscv_output_char_init(char c)
203{
204  riscv_console_probe();
205  riscv_output_char(c);
206}
207
208BSP_output_char_function_type BSP_output_char = riscv_output_char_init;
209
210BSP_polling_getchar_function_type BSP_poll_char = NULL;
211
212rtems_status_code console_initialize(
213  rtems_device_major_number major,
214  rtems_device_minor_number minor,
215  void *arg
216)
217{
218#if RISCV_ENABLE_HTIF_SUPPORT != 0
219  rtems_termios_device_context *base;
220  char htif_path[] = "/dev/ttyShtif";
221#endif
222#if RISCV_CONSOLE_MAX_NS16550_DEVICES > 0
223  char path[] = "/dev/ttyS?";
224  size_t i;
225#endif
226
227  rtems_termios_initialize();
228
229#if RISCV_ENABLE_HTIF_SUPPORT != 0
230  base = &htif_console_instance.base;
231  rtems_termios_device_install(htif_path, &htif_console_handler, NULL, base);
232
233  if (base == riscv_console.context) {
234    link(htif_path, CONSOLE_DEVICE_NAME);
235  }
236#endif
237
238#if RISCV_CONSOLE_MAX_NS16550_DEVICES > 0
239  for (i = 0; i < RISCV_CONSOLE_MAX_NS16550_DEVICES; ++i) {
240    ns16550_context *ctx;
241
242    ctx = &ns16550_instances[i];
243    path[sizeof(path) - 2] = (char) ('0' + i);
244
245    rtems_termios_device_install(
246      path,
247      &ns16550_handler_interrupt,
248      NULL,
249      &ctx->base
250    );
251
252    if (&ctx->base == riscv_console.context) {
253      link(path, CONSOLE_DEVICE_NAME);
254    }
255  }
256#endif
257
258  return RTEMS_SUCCESSFUL;
259}
260
261RTEMS_SYSINIT_ITEM(
262  riscv_console_probe,
263  RTEMS_SYSINIT_BSP_START,
264  RTEMS_SYSINIT_ORDER_LAST
265);
Note: See TracBrowser for help on using the repository browser.