Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:00

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup RTEMSBSPsRISCVNOEL
0007  *
0008  * @brief This source file contains NOEL-V/APBUART definitions of
0009  *   ::BSP_output_char_function_type and :: BSP_output_char and an
0010  *   implementation of console_initialize().
0011  */
0012 
0013 /*
0014  * Copyright (c) 2021 Cobham Gaisler AB.
0015  *
0016  * Copyright (C) 2018 embedded brains GmbH & Co. KG
0017  *
0018  * Redistribution and use in source and binary forms, with or without
0019  * modification, are permitted provided that the following conditions
0020  * are met:
0021  * 1. Redistributions of source code must retain the above copyright
0022  *    notice, this list of conditions and the following disclaimer.
0023  * 2. Redistributions in binary form must reproduce the above copyright
0024  *    notice, this list of conditions and the following disclaimer in the
0025  *    documentation and/or other materials provided with the distribution.
0026  *
0027  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0028  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0029  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0030  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0031  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0032  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0033  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0034  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0035  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0036  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0037  * POSSIBILITY OF SUCH DAMAGE.
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 );