From 1a192398bfff40e7e8f46f3ef872ee289e131fd3 Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Fri, 6 Jul 2018 11:20:31 +0200 Subject: bsp/riscv: Add console support for NS16550 devices Update #3433. --- bsps/riscv/riscv/console/console-config.c | 100 ++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) (limited to 'bsps/riscv') diff --git a/bsps/riscv/riscv/console/console-config.c b/bsps/riscv/riscv/console/console-config.c index 2cbb2091cd..6847deeb66 100644 --- a/bsps/riscv/riscv/console/console-config.c +++ b/bsps/riscv/riscv/console/console-config.c @@ -18,10 +18,12 @@ #include #include +#include #include #include #include +#include #include @@ -29,6 +31,10 @@ static htif_console_context htif_console_instance; #endif +#if RISCV_CONSOLE_MAX_NS16550_DEVICES > 0 +static ns16550_context ns16550_instances[RISCV_CONSOLE_MAX_NS16550_DEVICES]; +#endif + static struct { rtems_termios_device_context *context; void (*putchar)(rtems_termios_device_context *base, char c); @@ -55,14 +61,38 @@ static int riscv_get_console_node(const void *fdt) return fdt_path_offset(fdt, stdout_path); } +#if RISCV_CONSOLE_MAX_NS16550_DEVICES > 0 +static uint8_t get_register(uintptr_t addr, uint8_t i) +{ + volatile uint8_t *reg; + + reg = (uint8_t *) addr; + return reg[i]; +} + +static void set_register(uintptr_t addr, uint8_t i, uint8_t val) +{ + volatile uint8_t *reg; + + reg = (uint8_t *)addr; + reg[i] = val; +} +#endif + static void riscv_console_probe(void) { const void *fdt; int node; int console_node; +#if RISCV_CONSOLE_MAX_NS16550_DEVICES > 0 + size_t ns16550_devices; +#endif fdt = bsp_fdt_get(); console_node = riscv_get_console_node(fdt); +#if RISCV_CONSOLE_MAX_NS16550_DEVICES > 0 + ns16550_devices = 0; +#endif node = fdt_next_node(fdt, -1, NULL); @@ -77,6 +107,52 @@ static void riscv_console_probe(void) }; #endif +#if RISCV_CONSOLE_MAX_NS16550_DEVICES > 0 + if (fdt_node_check_compatible(fdt, node, "ns16550a") == 0) { + if (ns16550_devices < RISCV_CONSOLE_MAX_NS16550_DEVICES) { + ns16550_context *ctx; + fdt32_t *val; + int len; + + ctx = &ns16550_instances[ns16550_devices]; + ctx->get_reg = get_register; + ctx->set_reg = set_register; + ctx->initial_baud = BSP_CONSOLE_BAUD; + + val = (fdt32_t *) fdt_getprop(fdt, node, "reg", &len); + + if (val == NULL || (len != 8 && len != 16)) { + bsp_fatal(RISCV_FATAL_NO_NS16550_REG_IN_DEVICE_TREE); + } + + if (len == 16) { + ctx->port = fdt32_to_cpu(val[1]); + } else { + ctx->port = fdt32_to_cpu(val[0]); + } + + val = (fdt32_t *) fdt_getprop(fdt, node, "clock-frequency", &len); + + if (val == NULL || len != 4) { + bsp_fatal(RISCV_FATAL_NO_NS16550_CLOCK_FREQUENCY_IN_DEVICE_TREE); + } + + ctx->clock = fdt32_to_cpu(val[0]); + + if (node == console_node) { + riscv_console.context = &ctx->base; + riscv_console.putchar = ns16550_polled_putchar; + riscv_console.getchar = ns16550_polled_getchar; + } + + rtems_termios_device_context_initialize(&ctx->base, "NS16550"); + ns16550_probe(&ctx->base); + + ++ns16550_devices; + } + } +#endif + node = fdt_next_node(fdt, node, NULL); } @@ -101,6 +177,10 @@ rtems_status_code console_initialize( { rtems_termios_device_context *base; char htif_path[] = "/dev/ttyShtif"; +#if RISCV_CONSOLE_MAX_NS16550_DEVICES > 0 + char path[] = "/dev/ttyS?"; + size_t i; +#endif rtems_termios_initialize(); @@ -113,6 +193,26 @@ rtems_status_code console_initialize( } #endif +#if RISCV_CONSOLE_MAX_NS16550_DEVICES > 0 + for (i = 0; i < RISCV_CONSOLE_MAX_NS16550_DEVICES; ++i) { + ns16550_context *ctx; + + ctx = &ns16550_instances[i]; + path[sizeof(path) - 2] = (char) ('0' + i); + + rtems_termios_device_install( + path, + &ns16550_handler_polled, + NULL, + &ctx->base + ); + + if (&ctx->base == riscv_console.context) { + link(path, CONSOLE_DEVICE_NAME); + } + } +#endif + return RTEMS_SUCCESSFUL; } -- cgit v1.2.3