diff options
Diffstat (limited to 'bsps/powerpc/qoriq/console/console-config.c')
-rw-r--r-- | bsps/powerpc/qoriq/console/console-config.c | 330 |
1 files changed, 330 insertions, 0 deletions
diff --git a/bsps/powerpc/qoriq/console/console-config.c b/bsps/powerpc/qoriq/console/console-config.c new file mode 100644 index 0000000000..4c1ca1d3f6 --- /dev/null +++ b/bsps/powerpc/qoriq/console/console-config.c @@ -0,0 +1,330 @@ +/** + * @file + * + * @ingroup QorIQ + * + * @brief Console configuration. + */ + +/* + * Copyright (c) 2010, 2017 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * <rtems@embedded-brains.de> + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#include <string.h> + +#include <libfdt.h> + +#include <rtems/bspIo.h> + +#include <libchip/ns16550.h> + +#include <asm/epapr_hcalls.h> + +#include <bsp.h> +#include <bsp/fdt.h> +#include <bsp/irq.h> +#include <bsp/qoriq.h> +#include <bsp/intercom.h> +#include <bsp/uart-bridge.h> +#include <bsp/console-termios.h> + +static void output_char(char c); + +#ifdef QORIQ_IS_HYPERVISOR_GUEST +typedef struct { + rtems_termios_device_context base; + uint32_t handle; +} qoriq_bc_context; + +static bool qoriq_bc_probe(rtems_termios_device_context *base) +{ + qoriq_bc_context *ctx; + const void *fdt; + int node; + const uint32_t *handle; + int len; + + fdt = bsp_fdt_get(); + + node = fdt_node_offset_by_compatible(fdt, -1, "epapr,hv-byte-channel"); + if (node < 0) { + return false; + } + + handle = fdt_getprop(fdt, node, "hv-handle", &len); + if (handle == NULL || len != 4) { + return false; + } + + ctx = (qoriq_bc_context *) base; + ctx->handle = fdt32_to_cpu(*handle); + + BSP_output_char = output_char; + return true; +} + +static int qoriq_bc_read_polled(rtems_termios_device_context *base) +{ + qoriq_bc_context *ctx; + char buf[EV_BYTE_CHANNEL_MAX_BYTES]; + unsigned int count; + unsigned int status; + + ctx = (qoriq_bc_context *) base; + count = 1; + status = ev_byte_channel_receive(ctx->handle, &count, buf); + + if (status != EV_SUCCESS || count == 0) { + return -1; + } + + return (unsigned char) buf[0]; +} + +static void qoriq_bc_write_polled( + rtems_termios_device_context *base, + const char *buf, + size_t len +) +{ + qoriq_bc_context *ctx; + uint32_t handle; + + ctx = (qoriq_bc_context *) base; + handle = ctx->handle; + + while (len > 0) { + unsigned int count; + unsigned int status; + char buf2[EV_BYTE_CHANNEL_MAX_BYTES]; + const char *out; + + if (len < EV_BYTE_CHANNEL_MAX_BYTES) { + count = len; + out = memcpy(buf2, buf, len); + } else { + count = EV_BYTE_CHANNEL_MAX_BYTES; + out = buf; + } + + status = ev_byte_channel_send(handle, &count, out); + + if (status == EV_SUCCESS) { + len -= count; + buf += count; + } + } +} + +static const rtems_termios_device_handler qoriq_bc_handler_polled = { + .poll_read = qoriq_bc_read_polled, + .write = qoriq_bc_write_polled, + .mode = TERMIOS_POLLED +}; + +static qoriq_bc_context qoriq_bc_context_0 = { + .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("BC 0"), +}; +#endif /* QORIQ_IS_HYPERVISOR_GUEST */ + +#if (QORIQ_UART_0_ENABLE + QORIQ_UART_BRIDGE_0_ENABLE == 2) \ + || (QORIQ_UART_1_ENABLE + QORIQ_UART_BRIDGE_1_ENABLE == 2) + #define BRIDGE_MASTER +#elif QORIQ_UART_BRIDGE_0_ENABLE || QORIQ_UART_BRIDGE_1_ENABLE + #define BRIDGE_SLAVE +#endif + +#ifdef BSP_USE_UART_INTERRUPTS + #define DEVICE_FNS &ns16550_handler_interrupt +#else + #define DEVICE_FNS &ns16550_handler_polled +#endif + +#if QORIQ_UART_0_ENABLE || QORIQ_UART_1_ENABLE + static bool uart_probe(rtems_termios_device_context *base) + { + ns16550_context *ctx = (ns16550_context *) base; + + ctx->clock = BSP_bus_frequency; + + return ns16550_probe(base); + } + + static uint8_t get_register(uintptr_t addr, uint8_t i) + { + volatile uint8_t *reg = (uint8_t *) addr; + + return reg [i]; + } + + static void set_register(uintptr_t addr, uint8_t i, uint8_t val) + { + volatile uint8_t *reg = (uint8_t *) addr; + + reg [i] = val; + } +#endif + +#if QORIQ_UART_0_ENABLE +static ns16550_context qoriq_uart_context_0 = { + .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("UART 0"), + .get_reg = get_register, + .set_reg = set_register, + .port = (uintptr_t) &qoriq.uart_0, + .irq = QORIQ_IRQ_DUART_1, + .initial_baud = BSP_CONSOLE_BAUD +}; +#endif + +#if QORIQ_UART_1_ENABLE +static ns16550_context qoriq_uart_context_1 = { + .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("UART 1"), + .get_reg = get_register, + .set_reg = set_register, + .port = (uintptr_t) &qoriq.uart_1, + .irq = QORIQ_IRQ_DUART_1, + .initial_baud = BSP_CONSOLE_BAUD +}; +#endif + +#ifdef BRIDGE_MASTER + #define BRIDGE_PROBE qoriq_uart_bridge_master_probe + #define BRIDGE_FNS &qoriq_uart_bridge_master + #if QORIQ_UART_BRIDGE_0_ENABLE + static uart_bridge_master_context bridge_0_context = { + .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("UART Bridge 0"), + .device_path = "/dev/ttyS0", + .type = INTERCOM_TYPE_UART_0, + .transmit_fifo = RTEMS_CHAIN_INITIALIZER_EMPTY( + bridge_0_context.transmit_fifo + ) + }; + #define BRIDGE_0_CONTEXT &bridge_0_context.base + #endif + #if QORIQ_UART_BRIDGE_1_ENABLE + static uart_bridge_master_context bridge_1_context = { + .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("UART Bridge 1"), + .device_path = "/dev/ttyS1", + .type = INTERCOM_TYPE_UART_1, + .transmit_fifo = RTEMS_CHAIN_INITIALIZER_EMPTY( + bridge_1_context.transmit_fifo + ) + }; + #define BRIDGE_1_CONTEXT &bridge_1_context.base + #endif +#endif + +#ifdef BRIDGE_SLAVE + #define BRIDGE_PROBE console_device_probe_default + #define BRIDGE_FNS &qoriq_uart_bridge_slave + #if QORIQ_UART_BRIDGE_0_ENABLE + static uart_bridge_slave_context bridge_0_context = { + .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("UART Bridge 0"), + .type = INTERCOM_TYPE_UART_0, + .transmit_fifo = RTEMS_CHAIN_INITIALIZER_EMPTY( + bridge_0_context.transmit_fifo + ) + }; + #define BRIDGE_0_CONTEXT &bridge_0_context.base + #endif + #if QORIQ_UART_BRIDGE_1_ENABLE + static uart_bridge_slave_context bridge_1_context = { + .base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("UART Bridge 1"), + .type = INTERCOM_TYPE_UART_1, + .transmit_fifo = RTEMS_CHAIN_INITIALIZER_EMPTY( + bridge_1_context.transmit_fifo + ) + }; + #define BRIDGE_1_CONTEXT &bridge_1_context.base + #endif +#endif + +const console_device console_device_table[] = { + #ifdef QORIQ_IS_HYPERVISOR_GUEST + { + .device_file = "/dev/ttyBC0", + .probe = qoriq_bc_probe, + .handler = &qoriq_bc_handler_polled, + .context = &qoriq_bc_context_0.base + }, + #endif + #if QORIQ_UART_0_ENABLE + { + .device_file = "/dev/ttyS0", + .probe = uart_probe, + .handler = DEVICE_FNS, + .context = &qoriq_uart_context_0.base + }, + #endif + #if QORIQ_UART_1_ENABLE + { + .device_file = "/dev/ttyS1", + .probe = uart_probe, + .handler = DEVICE_FNS, + .context = &qoriq_uart_context_1.base + }, + #endif + #if QORIQ_UART_BRIDGE_0_ENABLE + { + #if QORIQ_UART_1_ENABLE + .device_file = "/dev/ttyB0", + #else + .device_file = "/dev/ttyS0", + #endif + .probe = BRIDGE_PROBE, + .handler = BRIDGE_FNS, + .context = BRIDGE_0_CONTEXT + }, + #endif + #if QORIQ_UART_BRIDGE_1_ENABLE + { + #if QORIQ_UART_1_ENABLE + .device_file = "/dev/ttyB1", + #else + .device_file = "/dev/ttyS1", + #endif + .probe = BRIDGE_PROBE, + .handler = BRIDGE_FNS, + .context = BRIDGE_1_CONTEXT + } + #endif +}; + +const size_t console_device_count = RTEMS_ARRAY_SIZE(console_device_table); + +static void output_char(char c) +{ + rtems_termios_device_context *base = console_device_table[0].context; + +#ifdef QORIQ_IS_HYPERVISOR_GUEST + qoriq_bc_write_polled(base, &c, 1); +#else + ns16550_polled_putchar(base, c); +#endif +} + +#ifdef QORIQ_IS_HYPERVISOR_GUEST +static void qoriq_bc_output_char_init(char c) +{ + rtems_termios_device_context *base = console_device_table[0].context; + + qoriq_bc_probe(base); + output_char(c); +} + +BSP_output_char_function_type BSP_output_char = qoriq_bc_output_char_init; +#else +BSP_output_char_function_type BSP_output_char = output_char; +#endif + +BSP_polling_getchar_function_type BSP_poll_char = NULL; |