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  * Copyright (C) 2024 Kevin Kirspel
0005  *
0006  * Redistribution and use in source and binary forms, with or without
0007  * modification, are permitted provided that the following conditions
0008  * are met:
0009  * 1. Redistributions of source code must retain the above copyright
0010  *    notice, this list of conditions and the following disclaimer.
0011  * 2. Redistributions in binary form must reproduce the above copyright
0012  *    notice, this list of conditions and the following disclaimer in the
0013  *    documentation and/or other materials provided with the distribution.
0014  *
0015  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0016  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0017  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0018  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0019  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0020  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0021  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0023  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0024  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0025  * POSSIBILITY OF SUCH DAMAGE.
0026  */
0027 
0028 #ifdef HAVE_CONFIG_H
0029 #include "config.h"
0030 #endif
0031 
0032 #include <rtems/bspIo.h>
0033 #include <rtems/console.h>
0034 #include <rtems/sysinit.h>
0035 #include <rtems/termiostypes.h>
0036 
0037 #include <bsp/fatal.h>
0038 #include <bsp/irq.h>
0039 #include <bsp/niosv.h>
0040 #include <bsp.h>
0041 #include <bsp/console-termios.h>
0042 #include <rtems/libio.h>
0043 
0044 typedef struct {
0045   rtems_termios_device_context base;
0046   rtems_termios_tty *tty;
0047   rtems_vector_number irq;
0048   size_t out_total;
0049   size_t out_remaining;
0050   size_t out_current;
0051   const char *out_buf;
0052 } jtag_uart_context;
0053 
0054 static void jtag_uart_initialize_interrupts(
0055   struct rtems_termios_tty *tty,
0056   jtag_uart_context *ctx, void (*isr)(void *)
0057 );
0058 static bool jtag_uart_console_first_open(
0059   struct rtems_termios_tty *tty,
0060   rtems_termios_device_context *base, struct termios *term,
0061   rtems_libio_open_close_args_t *args
0062 );
0063 static void jtag_uart_close(
0064   struct rtems_termios_tty *tty,
0065   rtems_termios_device_context *base,
0066   rtems_libio_open_close_args_t *args
0067 );
0068 static void jtag_uart_console_write_int(
0069   rtems_termios_device_context *base,
0070   const char *buf, size_t len
0071 );
0072 static size_t jtag_uart_write_to_fifo(const char *buf, size_t len);
0073 static void jtag_uart_clear_and_set_control(
0074   jtag_uart_context *ctx,
0075   uint32_t clear, uint32_t set
0076 );
0077 static void jtag_uart_console_putchar(char c);
0078 
0079 static jtag_uart_context jtag_uart_console_instance;
0080 
0081 static const rtems_termios_device_handler jtag_uart_console_handler = {
0082   .first_open = jtag_uart_console_first_open,
0083   .last_close = jtag_uart_close,
0084   .poll_read = NULL,
0085   .write = jtag_uart_console_write_int,
0086   .set_attributes = NULL,
0087   .mode = TERMIOS_IRQ_DRIVEN
0088 };
0089 
0090 static void jtag_uart_clear_and_set_control(
0091   jtag_uart_context *ctx,
0092   uint32_t clear,
0093   uint32_t set
0094 )
0095 {
0096   volatile altera_avalon_jtag_uart_regs *ajur = JTAG_UART_REGS;
0097   rtems_interrupt_lock_context lock_context;
0098   uint8_t val;
0099 
0100   rtems_termios_device_lock_acquire(&ctx->base, &lock_context);
0101   val = ajur->control;
0102   val &= ~clear;
0103   val |= set;
0104   ajur->control = val;
0105   rtems_termios_device_lock_release(&ctx->base, &lock_context);
0106 }
0107 
0108 static size_t jtag_uart_write_to_fifo(const char *buf, size_t len)
0109 {
0110   volatile altera_avalon_jtag_uart_regs *ajur = JTAG_UART_REGS;
0111   uint32_t space = (
0112     ajur->control & ALTERA_AVALON_JTAG_UART_CONTROL_WSPACE_MSK
0113   ) >> ALTERA_AVALON_JTAG_UART_CONTROL_WSPACE_OFST;
0114   size_t out = len > space ? space : len;
0115   size_t i;
0116 
0117   for (i = 0; i < out; ++i) {
0118     ajur->data = buf[i];
0119   }
0120 
0121   return out;
0122 }
0123 
0124 static void jtag_uart_isr(void *arg)
0125 {
0126   rtems_termios_tty *tty = arg;
0127   jtag_uart_context *ctx = rtems_termios_get_device_context(tty);
0128   volatile altera_avalon_jtag_uart_regs *ajur = JTAG_UART_REGS;
0129   int i = 0;
0130   char buf [JTAG_UART_READ_DEPTH];
0131 
0132   /* Iterate until no more interrupts are pending */
0133   do {
0134     if (ajur->control & ALTERA_AVALON_JTAG_UART_CONTROL_RI_MSK) {
0135       /* Fetch received characters */
0136       for (i = 0; i < JTAG_UART_READ_DEPTH; ++i) {
0137         uint32_t data = ajur->data;
0138         if ((data & ALTERA_AVALON_JTAG_UART_DATA_RVALID_MSK) == 0) {
0139           break;
0140         } else {
0141           buf[i] = (char) data;
0142         }
0143       }
0144 
0145       /* Enqueue fetched characters */
0146       rtems_termios_enqueue_raw_characters(tty, buf, i);
0147     }
0148 
0149     /* Do transmit */
0150     if (ctx->out_total > 0 &&
0151       ajur->control & ALTERA_AVALON_JTAG_UART_CONTROL_WI_MSK
0152     ) {
0153       size_t current = ctx->out_current;
0154 
0155       ctx->out_buf += current;
0156       ctx->out_remaining -= current;
0157 
0158       if(ctx->out_remaining > 0) {
0159         ctx->out_current =
0160           jtag_uart_write_to_fifo(ctx->out_buf, ctx->out_remaining);
0161       } else {
0162         rtems_termios_dequeue_characters(tty, ctx->out_total);
0163       }
0164     }
0165   } while((ajur->control & (ALTERA_AVALON_JTAG_UART_CONTROL_RI_MSK |
0166     ALTERA_AVALON_JTAG_UART_CONTROL_WI_MSK)) != 0);
0167 }
0168 
0169 static void jtag_uart_console_putchar(char c)
0170 {
0171   volatile altera_avalon_jtag_uart_regs *ajur = JTAG_UART_REGS;
0172 
0173   /*
0174    *  Wait for the transmitter to be ready.
0175    *  Check for flow control requests and process.
0176    *  Then output the character.
0177    */
0178   while ((ajur->control & ALTERA_AVALON_JTAG_UART_CONTROL_WSPACE_MSK) == 0);
0179 
0180   ajur->data = c;
0181 }
0182 
0183 static void jtag_uart_console_probe(void)
0184 {
0185   rtems_termios_device_context_initialize(
0186     &jtag_uart_console_instance.base,
0187     "JURT"
0188   );
0189 
0190   jtag_uart_console_instance.irq =
0191     NIOSV_INTERRUPT_VECTOR_EXTERNAL(JTAG_UART_IRQ);
0192 }
0193 
0194 rtems_status_code console_initialize(
0195   rtems_device_major_number major,
0196   rtems_device_minor_number minor,
0197   void *arg
0198 )
0199 {
0200   rtems_termios_device_context *base;
0201   char jtag_uart_path[] = "/dev/ttyJtagUart";
0202 
0203   rtems_termios_initialize();
0204 
0205   base = &jtag_uart_console_instance.base;
0206   rtems_termios_device_install(
0207     jtag_uart_path,
0208     &jtag_uart_console_handler,
0209     NULL,
0210     base
0211   );
0212 
0213   link(jtag_uart_path, CONSOLE_DEVICE_NAME);
0214 
0215   return RTEMS_SUCCESSFUL;
0216 }
0217 
0218 static void jtag_uart_initialize_interrupts(
0219   struct rtems_termios_tty *tty,
0220   jtag_uart_context *ctx,
0221   void (*isr)(void *)
0222 )
0223 {
0224   rtems_status_code sc = RTEMS_SUCCESSFUL;
0225   sc = rtems_interrupt_handler_install(
0226     ctx->irq,
0227     "JTAG_UART",
0228     RTEMS_INTERRUPT_UNIQUE,
0229     isr,
0230     tty
0231   );
0232   if (sc != RTEMS_SUCCESSFUL) {
0233     printk( "%s: Error: Install interrupt handler\n", __func__);
0234     rtems_fatal_error_occurred(0xdeadbeef);
0235   }
0236   /* Enable JUART interrupts */
0237   alt_irq_enable(JTAG_UART_IRQ);
0238 }
0239 
0240 static void jtag_uart_cleanup_interrupts(
0241   struct rtems_termios_tty *tty,
0242   jtag_uart_context *ctx,
0243   void (*isr)(void *)
0244 )
0245 {
0246   rtems_status_code sc = RTEMS_SUCCESSFUL;
0247 
0248   /* Disable JUART interrupts */
0249   alt_irq_disable(JTAG_UART_IRQ);
0250 
0251   sc = rtems_interrupt_handler_remove(
0252     ctx->irq,
0253     isr,
0254     tty
0255   );
0256   if (sc != RTEMS_SUCCESSFUL) {
0257     /* FIXME */
0258     printk("%s: Error: Remove interrupt handler\n", __func__);
0259     rtems_fatal_error_occurred(0xdeadbeef);
0260   }
0261 }
0262 
0263 static bool jtag_uart_console_first_open(
0264   struct rtems_termios_tty *tty,
0265   rtems_termios_device_context *base,
0266   struct termios *term,
0267   rtems_libio_open_close_args_t *args
0268 )
0269 {
0270   jtag_uart_context *ctx = (jtag_uart_context *)base;
0271 
0272   ctx->tty = tty;
0273 
0274   if (tty->handler.mode == TERMIOS_IRQ_DRIVEN) {
0275     jtag_uart_initialize_interrupts(tty, ctx, jtag_uart_isr);
0276     jtag_uart_clear_and_set_control(
0277       ctx,
0278       ALTERA_AVALON_JTAG_UART_CONTROL_WE_MSK,
0279       ALTERA_AVALON_JTAG_UART_CONTROL_RE_MSK
0280     );
0281   }
0282 
0283   return true;
0284 }
0285 
0286 static void jtag_uart_close(
0287   struct rtems_termios_tty *tty,
0288   rtems_termios_device_context *base,
0289   rtems_libio_open_close_args_t *args
0290 )
0291 {
0292   jtag_uart_context *ctx = (jtag_uart_context *) base;
0293 
0294   /* disable interrupts */
0295   jtag_uart_clear_and_set_control(
0296     ctx,
0297     ALTERA_AVALON_JTAG_UART_CONTROL_WE_MSK |
0298     ALTERA_AVALON_JTAG_UART_CONTROL_RE_MSK,
0299     0
0300   );
0301 
0302   if (tty->handler.mode == TERMIOS_IRQ_DRIVEN) {
0303     jtag_uart_cleanup_interrupts(tty, ctx, jtag_uart_isr);
0304   }
0305 }
0306 
0307 static void jtag_uart_console_write_int(
0308   rtems_termios_device_context *base,
0309   const char *buf,
0310   size_t len
0311 )
0312 {
0313   jtag_uart_context *ctx = (jtag_uart_context *) base;
0314 
0315   ctx->out_total = len;
0316 
0317   if (len > 0) {
0318     ctx->out_remaining = len;
0319     ctx->out_buf = buf;
0320     ctx->out_current = jtag_uart_write_to_fifo(buf, len);
0321 
0322     jtag_uart_clear_and_set_control(
0323       ctx,
0324       0,
0325       ALTERA_AVALON_JTAG_UART_CONTROL_WE_MSK
0326     );
0327   } else {
0328     jtag_uart_clear_and_set_control(
0329       ctx,
0330       ALTERA_AVALON_JTAG_UART_CONTROL_WE_MSK,
0331       0
0332     );
0333   }
0334 }
0335 
0336 static void jtag_uart_output_char_init(char c)
0337 {
0338   BSP_output_char = jtag_uart_console_putchar;
0339   jtag_uart_console_putchar(c);
0340 }
0341 
0342 BSP_output_char_function_type BSP_output_char = jtag_uart_output_char_init;
0343 BSP_polling_getchar_function_type BSP_poll_char = NULL;
0344 
0345 RTEMS_SYSINIT_ITEM(
0346   jtag_uart_console_probe,
0347   RTEMS_SYSINIT_BSP_START,
0348   RTEMS_SYSINIT_ORDER_LAST_BUT_5
0349 );