File indexing completed on 2025-05-11 08:24:05
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 #include <dev/serial/zynq-uart.h>
0029 #include <dev/serial/zynq-uart-regs.h>
0030 #include <bsp/irq.h>
0031 #include <rtems/termiostypes.h>
0032
0033 #include <bspopts.h>
0034
0035 #ifdef ZYNQ_CONSOLE_USE_INTERRUPTS
0036 static void zynq_uart_interrupt(void *arg)
0037 {
0038 rtems_termios_tty *tty = arg;
0039 zynq_uart_context *ctx = rtems_termios_get_device_context(tty);
0040 volatile zynq_uart *regs = ctx->regs;
0041
0042 if ((regs->irq_sts & ZYNQ_UART_RTRIG) != 0) {
0043 char buf[32];
0044 int c = 0;
0045 regs->irq_sts = ZYNQ_UART_RTRIG;
0046 while (c < sizeof(buf) &&
0047 (regs->channel_sts & ZYNQ_UART_CHANNEL_STS_REMPTY) == 0) {
0048 buf[c++] = (char) ZYNQ_UART_TX_RX_FIFO_FIFO_GET(regs->tx_rx_fifo);
0049 }
0050 rtems_termios_enqueue_raw_characters(tty, buf, c);
0051 }
0052
0053 if (ctx->transmitting) {
0054 int sent = ctx->tx_queued;
0055 regs->irq_dis = ZYNQ_UART_TEMPTY;
0056 ctx->transmitting = false;
0057 ctx->tx_queued = 0;
0058 rtems_termios_dequeue_characters(tty, sent);
0059 }
0060 }
0061 #endif
0062
0063 static bool zynq_uart_first_open(
0064 rtems_termios_tty *tty,
0065 rtems_termios_device_context *base,
0066 struct termios *term,
0067 rtems_libio_open_close_args_t *args
0068 )
0069 {
0070 zynq_uart_context *ctx = (zynq_uart_context *) base;
0071 volatile zynq_uart *regs = ctx->regs;
0072 #ifdef ZYNQ_CONSOLE_USE_INTERRUPTS
0073 rtems_status_code sc;
0074 #endif
0075
0076 rtems_termios_set_initial_baud(tty, ZYNQ_UART_DEFAULT_BAUD);
0077 zynq_uart_initialize(regs);
0078
0079 #ifdef ZYNQ_CONSOLE_USE_INTERRUPTS
0080 regs->rx_fifo_trg_lvl = 1;
0081 regs->irq_dis = 0xffffffff;
0082 regs->irq_sts = 0xffffffff;
0083 regs->irq_en = ZYNQ_UART_RTRIG;
0084 sc = rtems_interrupt_handler_install(
0085 ctx->irq,
0086 "UART",
0087 RTEMS_INTERRUPT_SHARED,
0088 zynq_uart_interrupt,
0089 tty
0090 );
0091 if (sc != RTEMS_SUCCESSFUL) {
0092 return false;
0093 }
0094 #endif
0095
0096 return true;
0097 }
0098
0099 #ifdef ZYNQ_CONSOLE_USE_INTERRUPTS
0100 static void zynq_uart_last_close(
0101 rtems_termios_tty *tty,
0102 rtems_termios_device_context *base,
0103 rtems_libio_open_close_args_t *args
0104 )
0105 {
0106 zynq_uart_context *ctx = (zynq_uart_context *) base;
0107
0108 rtems_interrupt_handler_remove(ctx->irq, zynq_uart_interrupt, tty);
0109 }
0110 #endif
0111
0112 #ifndef ZYNQ_CONSOLE_USE_INTERRUPTS
0113 static int zynq_uart_read_polled(rtems_termios_device_context *base)
0114 {
0115 zynq_uart_context *ctx = (zynq_uart_context *) base;
0116 return zynq_uart_read_char_polled(ctx->regs);
0117 }
0118 #endif
0119
0120 static void zynq_uart_write_support(
0121 rtems_termios_device_context *base,
0122 const char *buf,
0123 size_t len
0124 )
0125 {
0126 zynq_uart_context *ctx = (zynq_uart_context *) base;
0127 volatile zynq_uart *regs = ctx->regs;
0128 #ifdef ZYNQ_CONSOLE_USE_INTERRUPTS
0129
0130 regs->irq_dis = ZYNQ_UART_TEMPTY;
0131
0132 if (len > 0) {
0133 const char *p = &buf[0];
0134 regs->irq_sts = ZYNQ_UART_TEMPTY;
0135 while (((regs->channel_sts & ZYNQ_UART_CHANNEL_STS_TNFUL) == 0) &&
0136 len > 0) {
0137 regs->tx_rx_fifo = ZYNQ_UART_TX_RX_FIFO_FIFO(*p);
0138 ++p;
0139 ++ctx->tx_queued;
0140 --len;
0141 }
0142 ctx->transmitting = true;
0143 regs->irq_en = ZYNQ_UART_TEMPTY;
0144 }
0145 #else
0146 size_t i;
0147 for (i = 0; i < len; ++i) {
0148 zynq_uart_write_char_polled(regs, buf[i]);
0149 }
0150 #endif
0151 }
0152
0153 static bool zynq_uart_set_attributes(
0154 rtems_termios_device_context *context,
0155 const struct termios *term
0156 )
0157 {
0158 zynq_uart_context *ctx = (zynq_uart_context *) context;
0159 volatile zynq_uart *regs = ctx->regs;
0160 uint32_t desired_baud;
0161 uint32_t cd;
0162 uint32_t bdiv;
0163 uint32_t mode;
0164
0165
0166
0167
0168 desired_baud = rtems_termios_baud_to_number(term->c_ospeed);
0169 mode = regs->mode & ZYNQ_UART_MODE_CLKS;
0170
0171 if (desired_baud > 0) {
0172 uint32_t error = zynq_uart_calculate_baud(desired_baud, mode, &cd, &bdiv);
0173 uint32_t margin;
0174
0175 if ( desired_baud >= 100 ) {
0176 margin = 3 * (desired_baud / 100);
0177 } else {
0178 margin = 1;
0179 }
0180
0181 if (error > margin) {
0182 return false;
0183 }
0184 }
0185
0186
0187
0188
0189 mode |= ZYNQ_UART_MODE_CHMODE(ZYNQ_UART_MODE_CHMODE_NORMAL);
0190
0191
0192
0193
0194 mode |= ZYNQ_UART_MODE_PAR(ZYNQ_UART_MODE_PAR_NONE);
0195 if (term->c_cflag & PARENB) {
0196 if (!(term->c_cflag & PARODD)) {
0197 mode |= ZYNQ_UART_MODE_PAR(ZYNQ_UART_MODE_PAR_ODD);
0198 } else {
0199 mode |= ZYNQ_UART_MODE_PAR(ZYNQ_UART_MODE_PAR_EVEN);
0200 }
0201 }
0202
0203
0204
0205
0206 switch (term->c_cflag & CSIZE)
0207 {
0208 case CS5:
0209 return false;
0210 case CS6:
0211 mode |= ZYNQ_UART_MODE_CHRL(ZYNQ_UART_MODE_CHRL_6);
0212 break;
0213 case CS7:
0214 mode |= ZYNQ_UART_MODE_CHRL(ZYNQ_UART_MODE_CHRL_7);
0215 break;
0216 case CS8:
0217 default:
0218 mode |= ZYNQ_UART_MODE_CHRL(ZYNQ_UART_MODE_CHRL_8);
0219 break;
0220 }
0221
0222
0223
0224
0225 if (term->c_cflag & CSTOPB) {
0226
0227 mode |= ZYNQ_UART_MODE_NBSTOP(ZYNQ_UART_MODE_NBSTOP_STOP_2);
0228 } else {
0229
0230 mode |= ZYNQ_UART_MODE_NBSTOP(ZYNQ_UART_MODE_NBSTOP_STOP_1);
0231 }
0232
0233
0234
0235
0236
0237 while ((regs->channel_sts & ZYNQ_UART_CHANNEL_STS_TEMPTY) == 0 ||
0238 (regs->channel_sts & ZYNQ_UART_CHANNEL_STS_TACTIVE) != 0) {
0239
0240 }
0241
0242 regs->control = ZYNQ_UART_CONTROL_RXDIS | ZYNQ_UART_CONTROL_TXDIS;
0243
0244 if (desired_baud > 0) {
0245 regs->baud_rate_gen = ZYNQ_UART_BAUD_RATE_GEN_CD(cd);
0246 regs->baud_rate_div = ZYNQ_UART_BAUD_RATE_DIV_BDIV(bdiv);
0247 }
0248 regs->control = ZYNQ_UART_CONTROL_RXRES | ZYNQ_UART_CONTROL_TXRES;
0249 regs->mode = mode;
0250 regs->irq_sts = 0xffffffff;
0251 regs->control = ZYNQ_UART_CONTROL_RXEN | ZYNQ_UART_CONTROL_TXEN;
0252
0253 return true;
0254 }
0255
0256 const rtems_termios_device_handler zynq_uart_handler = {
0257 .first_open = zynq_uart_first_open,
0258 .set_attributes = zynq_uart_set_attributes,
0259 .write = zynq_uart_write_support,
0260 #ifdef ZYNQ_CONSOLE_USE_INTERRUPTS
0261 .last_close = zynq_uart_last_close,
0262 .mode = TERMIOS_IRQ_DRIVEN
0263 #else
0264 .poll_read = zynq_uart_read_polled,
0265 .mode = TERMIOS_POLLED
0266 #endif
0267 };