File indexing completed on 2025-05-11 08:22:42
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/versal-uart.h>
0029 #include <dev/serial/arm-pl011.h>
0030 #include <bsp/irq.h>
0031
0032 #include <bspopts.h>
0033
0034 static uint32_t versal_uart_intr_all(void)
0035 {
0036 return PL011_UARTI_OEI |
0037 PL011_UARTI_BEI |
0038 PL011_UARTI_PEI |
0039 PL011_UARTI_FEI |
0040 PL011_UARTI_RTI |
0041 PL011_UARTI_TXI |
0042 PL011_UARTI_RXI |
0043 PL011_UARTI_DSRMI |
0044 PL011_UARTI_DCDMI |
0045 PL011_UARTI_CTSMI |
0046 PL011_UARTI_RIMI;
0047 }
0048
0049 #ifdef BSP_CONSOLE_USE_INTERRUPTS
0050 static void versal_uart_intr_clear(volatile arm_pl011_uart *regs, uint32_t ints)
0051 {
0052 regs->base.uarticr = ints;
0053 }
0054
0055 static void versal_uart_intr_clearall(volatile arm_pl011_uart *regs)
0056 {
0057 versal_uart_intr_clear(regs, versal_uart_intr_all());
0058 }
0059
0060 static void versal_uart_intr_enable(volatile arm_pl011_uart *regs, uint32_t ints)
0061 {
0062 regs->base.uartimsc |= ints;
0063 }
0064 #endif
0065
0066 static void versal_uart_intr_disable(volatile arm_pl011_uart *regs, uint32_t ints)
0067 {
0068 regs->base.uartimsc &= ~ints;
0069 }
0070
0071 static void versal_uart_intr_disableall(volatile arm_pl011_uart *regs)
0072 {
0073 versal_uart_intr_disable(regs, versal_uart_intr_all());
0074 }
0075
0076 #ifdef BSP_CONSOLE_USE_INTERRUPTS
0077 static bool versal_uart_flags_clear(volatile arm_pl011_uart *regs, uint32_t flags)
0078 {
0079 return (regs->base.uartfr & flags) == 0;
0080 }
0081
0082 static void versal_uart_interrupt(void *arg)
0083 {
0084 rtems_termios_tty *tty = arg;
0085 versal_pl011_context *ctx = rtems_termios_get_device_context(tty);
0086 volatile arm_pl011_uart *regs = (volatile arm_pl011_uart *) ctx->pl011_ctx.regs;
0087 uint32_t uartmis = regs->base.uartmis;
0088
0089 versal_uart_intr_clear(regs, uartmis);
0090
0091 if ((uartmis & (PL011_UARTI_RTI | PL011_UARTI_RXI)) != 0) {
0092 char buf[32];
0093 int c = 0;
0094 while (c < sizeof(buf) &&
0095 versal_uart_flags_clear(regs, PL011_UARTFR_RXFE)) {
0096 buf[c++] = (char) PL011_UARTDR_DATA_GET(regs->base.uartdr);
0097 }
0098 rtems_termios_enqueue_raw_characters(tty, buf, c);
0099 }
0100
0101 if (ctx->transmitting) {
0102 int sent = ctx->pl011_ctx.tx_queued_chars;
0103 ctx->transmitting = false;
0104 ctx->pl011_ctx.tx_queued_chars = 0;
0105 versal_uart_intr_disable(regs, PL011_UARTI_TXI);
0106 rtems_termios_dequeue_characters(tty, sent);
0107 }
0108 }
0109 #endif
0110
0111 void versal_uart_reset_tx_flush(rtems_termios_device_context *base)
0112 {
0113 volatile arm_pl011_uart *regs = (volatile arm_pl011_uart *) arm_pl011_get_regs(base);
0114 int c = 4;
0115
0116 while (c-- > 0) {
0117 arm_pl011_write_polled(base, '\r');
0118 }
0119
0120 while ((regs->base.uartfr & PL011_UARTFR_TXFE) == 0) {
0121
0122 }
0123 while ((regs->base.uartfr & PL011_UARTFR_BUSY) != 0) {
0124
0125 }
0126 }
0127
0128 int versal_uart_initialize(rtems_termios_device_context *base)
0129 {
0130 volatile pl011_base *regs = (volatile pl011_base *)arm_pl011_get_regs(base);
0131 arm_pl011_context *ctx = (arm_pl011_context *) base;
0132 uint32_t maxerr = 3;
0133 uint32_t ibauddiv = 0;
0134 uint32_t fbauddiv = 0;
0135 int rv;
0136
0137 versal_uart_reset_tx_flush(base);
0138
0139 rv = arm_pl011_compute_baudrate_params(
0140 &ibauddiv,
0141 &fbauddiv,
0142 VERSAL_UART_DEFAULT_BAUD,
0143 ctx->clock,
0144 maxerr
0145 );
0146 if (rv != 0) {
0147 return rv;
0148 }
0149
0150
0151 regs->uartlcr_h = PL011_UARTLCR_H_WLEN( PL011_UARTLCR_H_WLEN_8 )
0152 | PL011_UARTLCR_H_FEN;
0153
0154
0155 regs->uartcr = PL011_UARTCR_RXE
0156 | PL011_UARTCR_TXE
0157 | PL011_UARTCR_UARTEN;
0158
0159 regs->uartibrd = ibauddiv;
0160 regs->uartfbrd = fbauddiv;
0161
0162 return 0;
0163 }
0164
0165 static bool versal_uart_first_open(
0166 rtems_termios_tty *tty,
0167 rtems_termios_device_context *base,
0168 struct termios *term,
0169 rtems_libio_open_close_args_t *args
0170 )
0171 {
0172 #ifdef BSP_CONSOLE_USE_INTERRUPTS
0173 versal_pl011_context *ctx = (versal_pl011_context *) base;
0174 volatile arm_pl011_uart *regs = (volatile arm_pl011_uart *) ctx->pl011_ctx.regs;
0175 rtems_status_code sc;
0176
0177 ctx->transmitting = false;
0178 ctx->pl011_ctx.tx_queued_chars = 0;
0179 ctx->pl011_ctx.needs_sw_triggered_tx_irq = true;
0180 #endif
0181
0182 rtems_termios_set_initial_baud(tty, VERSAL_UART_DEFAULT_BAUD);
0183 versal_uart_initialize(base);
0184
0185 #ifdef BSP_CONSOLE_USE_INTERRUPTS
0186 regs->base.uartifls = PL011_UARTIFLS_RXIFLSEL(2) | PL011_UARTIFLS_TXIFLSEL(2);
0187 regs->base.uartlcr_h |= PL011_UARTLCR_H_FEN;
0188 versal_uart_intr_disableall(regs);
0189 sc = rtems_interrupt_handler_install(
0190 ctx->pl011_ctx.irq,
0191 "UART",
0192 RTEMS_INTERRUPT_SHARED,
0193 versal_uart_interrupt,
0194 tty
0195 );
0196 if (sc != RTEMS_SUCCESSFUL) {
0197 return false;
0198 }
0199 versal_uart_intr_clearall(regs);
0200 versal_uart_intr_enable(regs, PL011_UARTI_RTI | PL011_UARTI_RXI);
0201 #endif
0202
0203 return true;
0204 }
0205
0206 #ifdef BSP_CONSOLE_USE_INTERRUPTS
0207 static void versal_uart_last_close(
0208 rtems_termios_tty *tty,
0209 rtems_termios_device_context *base,
0210 rtems_libio_open_close_args_t *args
0211 )
0212 {
0213 versal_pl011_context *ctx = (versal_pl011_context *) base;
0214 rtems_interrupt_handler_remove(ctx->pl011_ctx.irq, versal_uart_interrupt, tty);
0215 }
0216 #endif
0217
0218 static void versal_uart_write_support(
0219 rtems_termios_device_context *base,
0220 const char *buf,
0221 size_t len
0222 )
0223 {
0224 #ifdef BSP_CONSOLE_USE_INTERRUPTS
0225 versal_pl011_context *ctx = (versal_pl011_context *) base;
0226 volatile arm_pl011_uart *regs = (volatile arm_pl011_uart *) ctx->pl011_ctx.regs;
0227
0228 if (len > 0) {
0229 size_t len_remaining = len;
0230 const char *p = &buf[0];
0231 versal_uart_intr_enable(regs, PL011_UARTI_TXI);
0232
0233
0234
0235
0236
0237 if (ctx->pl011_ctx.needs_sw_triggered_tx_irq) {
0238 ctx->pl011_ctx.needs_sw_triggered_tx_irq = false;
0239 for (int i = 0; i < 17; ++i) {
0240 regs->base.uartdr = PL011_UARTDR_DATA('\r');
0241 }
0242 }
0243 while (versal_uart_flags_clear(regs, PL011_UARTFR_TXFF) &&
0244 len_remaining > 0) {
0245 regs->base.uartdr = PL011_UARTDR_DATA(*p++);
0246 --len_remaining;
0247 }
0248 ctx->pl011_ctx.tx_queued_chars = len - len_remaining;
0249 ctx->transmitting = true;
0250 }
0251 #else
0252 ssize_t i;
0253 for (i = 0; i < len; ++i) {
0254 arm_pl011_write_polled(base, buf[i]);
0255 }
0256 #endif
0257 }
0258
0259 static bool versal_uart_set_attributes(
0260 rtems_termios_device_context *context,
0261 const struct termios *term
0262 )
0263 {
0264 versal_pl011_context *ctx = (versal_pl011_context *) context;
0265 volatile arm_pl011_uart *regs = (volatile arm_pl011_uart *) ctx->pl011_ctx.regs;
0266 int32_t baud;
0267 uint32_t ibauddiv = 0;
0268 uint32_t fbauddiv = 0;
0269 uint32_t mode = 0;
0270 int rc;
0271
0272
0273
0274
0275 baud = rtems_termios_baud_to_number(term->c_ospeed);
0276
0277 if (baud > 0) {
0278 uint32_t maxerr = 3;
0279
0280 rc = arm_pl011_compute_baudrate_params(
0281 &ibauddiv,
0282 &fbauddiv,
0283 baud,
0284 ctx->pl011_ctx.clock,
0285 maxerr
0286 );
0287 if (rc != 0) {
0288 return rc;
0289 }
0290 }
0291
0292
0293
0294
0295 mode = regs->base.uartlcr_h & PL011_UARTLCR_H_FEN;
0296
0297
0298
0299
0300 if ((term->c_cflag & PARENB) != 0) {
0301 mode |= PL011_UARTLCR_H_PEN;
0302 if ((term->c_cflag & PARODD) == 0) {
0303 mode |= PL011_UARTLCR_H_EPS;
0304 }
0305 }
0306
0307
0308
0309
0310 switch (term->c_cflag & CSIZE)
0311 {
0312 case CS5:
0313 mode = PL011_UARTLCR_H_WLEN_SET(mode, PL011_UARTLCR_H_WLEN_5);
0314 break;
0315 case CS6:
0316 mode = PL011_UARTLCR_H_WLEN_SET(mode, PL011_UARTLCR_H_WLEN_6);
0317 break;
0318 case CS7:
0319 mode = PL011_UARTLCR_H_WLEN_SET(mode, PL011_UARTLCR_H_WLEN_7);
0320 break;
0321 case CS8:
0322 default:
0323 mode = PL011_UARTLCR_H_WLEN_SET(mode, PL011_UARTLCR_H_WLEN_8);
0324 break;
0325 }
0326
0327
0328
0329
0330 if (term->c_cflag & CSTOPB) {
0331
0332 mode |= PL011_UARTLCR_H_STP2;
0333 }
0334
0335 versal_uart_intr_disableall(regs);
0336
0337
0338
0339
0340
0341 while ((regs->base.uartfr & PL011_UARTFR_TXFE) == 0 ||
0342 (regs->base.uartfr & PL011_UARTFR_BUSY) != 0) {
0343
0344 }
0345
0346 regs->base.uartcr = PL011_UARTCR_UARTEN;
0347
0348 if (baud > 0) {
0349 regs->base.uartibrd = ibauddiv;
0350 regs->base.uartfbrd = fbauddiv;
0351 }
0352 regs->base.uartlcr_h = mode;
0353
0354
0355 regs->base.uartcr = PL011_UARTCR_RXE
0356 | PL011_UARTCR_TXE
0357 | PL011_UARTCR_UARTEN;
0358
0359 #ifdef BSP_CONSOLE_USE_INTERRUPTS
0360 versal_uart_intr_clearall(regs);
0361 versal_uart_intr_enable(regs, PL011_UARTI_RTI | PL011_UARTI_RXI);
0362 #endif
0363
0364 return true;
0365 }
0366
0367 const rtems_termios_device_handler versal_uart_handler = {
0368 .first_open = versal_uart_first_open,
0369 .set_attributes = versal_uart_set_attributes,
0370 .write = versal_uart_write_support,
0371 #ifdef BSP_CONSOLE_USE_INTERRUPTS
0372 .last_close = versal_uart_last_close,
0373 .mode = TERMIOS_IRQ_DRIVEN
0374 #else
0375 .poll_read = arm_pl011_read_polled,
0376 .mode = TERMIOS_POLLED
0377 #endif
0378 };