File indexing completed on 2025-05-11 08:24:00
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040 #ifdef HAVE_CONFIG_H
0041 #include "config.h"
0042 #endif
0043
0044 #include <rtems/bspIo.h>
0045 #include <rtems/console.h>
0046 #include <rtems/sysinit.h>
0047 #include <rtems/termiostypes.h>
0048
0049 #include <bsp/fatal.h>
0050 #include <bsp/fdt.h>
0051 #include <bsp/irq.h>
0052 #include <bsp/riscv.h>
0053
0054 #include <libfdt.h>
0055
0056 #include <grlib/apbuart.h>
0057 #include <grlib/apbuart_termios.h>
0058 static struct apbuart_context apbuarts[RISCV_CONSOLE_MAX_APBUART_DEVICES];
0059 static size_t apbuart_devices = 0;
0060
0061 static struct {
0062 rtems_termios_device_context *context;
0063 void (*putchar)(rtems_termios_device_context *base, char c);
0064 int (*getchar)(rtems_termios_device_context *base);
0065 } riscv_console;
0066
0067 static void riscv_output_char(char c)
0068 {
0069 (*riscv_console.putchar)(riscv_console.context, c);
0070 }
0071
0072 static void apbuart_putchar(rtems_termios_device_context *base, char c)
0073 {
0074 struct apbuart_context *ctx = (struct apbuart_context *) base;
0075 apbuart_outbyte_polled(ctx->regs, c);
0076 }
0077
0078 static int apbuart_getchar(rtems_termios_device_context *base)
0079 {
0080 struct apbuart_context *ctx = (struct apbuart_context *) base;
0081 return apbuart_inbyte_nonblocking(ctx->regs);
0082 }
0083
0084 #define RISCV_CONSOLE_IS_COMPATIBLE(actual, actual_len, desired) \
0085 (actual_len == sizeof(desired) \
0086 && memcmp(actual, desired, sizeof(desired) - 1) == 0)
0087
0088 static uint32_t get_core_frequency(void)
0089 {
0090 uint32_t node;
0091 const char *fdt;
0092 int len;
0093 const fdt32_t *val;
0094
0095 fdt = bsp_fdt_get();
0096 node = fdt_node_offset_by_compatible(fdt, -1, "fixed-clock");
0097
0098 val = fdt_getprop(fdt, node, "clock-frequency", &len);
0099 if (val == NULL && len != 4) {
0100 bsp_fatal(RISCV_FATAL_NO_APBUART_CLOCK_FREQUENCY_IN_DEVICE_TREE);
0101 }
0102
0103 return fdt32_to_cpu(*val);
0104 }
0105
0106 static void riscv_console_probe(void)
0107 {
0108 const void *fdt;
0109 int node;
0110
0111 fdt = bsp_fdt_get();
0112
0113 node = fdt_next_node(fdt, -1, NULL);
0114
0115 while (node >= 0) {
0116 const char *compat;
0117 int compat_len;
0118
0119 compat = fdt_getprop(fdt, node, "compatible", &compat_len);
0120 if (compat == NULL) {
0121 compat_len = 0;
0122 }
0123
0124 if (
0125 RISCV_CONSOLE_IS_COMPATIBLE(compat, compat_len, "gaisler,apbuart")
0126 && (apbuart_devices < RISCV_CONSOLE_MAX_APBUART_DEVICES)
0127 ) {
0128 struct apbuart_context *ctx;
0129 fdt32_t *val;
0130 int len;
0131
0132 ctx = &apbuarts[apbuart_devices];
0133
0134 ctx->regs = riscv_fdt_get_address(fdt, node);
0135 if (ctx->regs == NULL) {
0136 bsp_fatal(RISCV_FATAL_NO_APBUART_REG_IN_DEVICE_TREE);
0137 }
0138
0139 ctx->freq_hz = get_core_frequency();
0140
0141 val = (fdt32_t *) fdt_getprop(fdt, node, "interrupts", &len);
0142 if (val == NULL || len != 4) {
0143 bsp_fatal(RISCV_FATAL_NO_APBUART_INTERRUPTS_IN_DEVICE_TREE);
0144 }
0145 ctx->irq = RISCV_INTERRUPT_VECTOR_EXTERNAL(fdt32_to_cpu(val[0]));
0146
0147 if (apbuart_devices == 0) {
0148 riscv_console.context = &ctx->base;
0149 riscv_console.putchar = apbuart_putchar;
0150 riscv_console.getchar = apbuart_getchar;
0151 }
0152
0153 rtems_termios_device_context_initialize(&ctx->base, "APBUART");
0154
0155 apbuart_devices++;
0156 };
0157
0158 node = fdt_next_node(fdt, node, NULL);
0159 }
0160
0161 BSP_output_char = riscv_output_char;
0162 }
0163
0164 static void riscv_output_char_init(char c)
0165 {
0166 riscv_console_probe();
0167 riscv_output_char(c);
0168 }
0169
0170 BSP_output_char_function_type BSP_output_char = riscv_output_char_init;
0171
0172 BSP_polling_getchar_function_type BSP_poll_char = NULL;
0173
0174 rtems_status_code console_initialize(
0175 rtems_device_major_number major,
0176 rtems_device_minor_number minor,
0177 void *arg
0178 )
0179 {
0180 char path[] = "/dev/ttyS?";
0181
0182 rtems_termios_initialize();
0183
0184 const rtems_termios_device_handler *handler = &apbuart_handler_polled;
0185
0186 if (BSP_CONSOLE_USE_INTERRUPTS) {
0187 handler = &apbuart_handler_interrupt;
0188 }
0189 for (size_t i = 0; i < apbuart_devices; ++i) {
0190 struct apbuart_context *ctx;
0191
0192 ctx = &apbuarts[i];
0193 path[sizeof(path) - 2] = (char) ('0' + i);
0194 rtems_termios_device_install(path, handler, NULL, &ctx->base);
0195
0196 if (&ctx->base == riscv_console.context) {
0197 link(path, CONSOLE_DEVICE_NAME);
0198 }
0199 }
0200
0201 return RTEMS_SUCCESSFUL;
0202 }
0203
0204 RTEMS_SYSINIT_ITEM(
0205 riscv_console_probe,
0206 RTEMS_SYSINIT_BSP_START,
0207 RTEMS_SYSINIT_ORDER_LAST_BUT_5
0208 );