[a94d46c8] | 1 | /* |
---|
[f1eedbd] | 2 | * SPDX-License-Identifier: BSD-2-Clause |
---|
[a94d46c8] | 3 | * |
---|
[f1eedbd] | 4 | * Copyright (C) 2013, 2017 embedded brains GmbH |
---|
[a94d46c8] | 5 | * |
---|
[f1eedbd] | 6 | * Redistribution and use in source and binary forms, with or without |
---|
| 7 | * modification, are permitted provided that the following conditions |
---|
| 8 | * are met: |
---|
| 9 | * 1. Redistributions of source code must retain the above copyright |
---|
| 10 | * notice, this list of conditions and the following disclaimer. |
---|
| 11 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
| 12 | * notice, this list of conditions and the following disclaimer in the |
---|
| 13 | * documentation and/or other materials provided with the distribution. |
---|
| 14 | * |
---|
| 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
---|
| 16 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
| 17 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
| 18 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
---|
| 19 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
---|
| 20 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
---|
| 21 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
---|
| 22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
---|
| 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
---|
| 24 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
---|
| 25 | * POSSIBILITY OF SUCH DAMAGE. |
---|
[a94d46c8] | 26 | */ |
---|
| 27 | |
---|
[f085957] | 28 | #include <dev/serial/zynq-uart.h> |
---|
| 29 | #include <dev/serial/zynq-uart-regs.h> |
---|
[11f0d52] | 30 | #include <bsp/irq.h> |
---|
[a94d46c8] | 31 | |
---|
[18bd35bc] | 32 | #include <bspopts.h> |
---|
| 33 | |
---|
[11f0d52] | 34 | #ifdef ZYNQ_CONSOLE_USE_INTERRUPTS |
---|
| 35 | static void zynq_uart_interrupt(void *arg) |
---|
| 36 | { |
---|
| 37 | rtems_termios_tty *tty = arg; |
---|
| 38 | zynq_uart_context *ctx = rtems_termios_get_device_context(tty); |
---|
| 39 | volatile zynq_uart *regs = ctx->regs; |
---|
| 40 | uint32_t channel_sts; |
---|
| 41 | |
---|
| 42 | if ((regs->irq_sts & (ZYNQ_UART_TIMEOUT | ZYNQ_UART_RTRIG)) != 0) { |
---|
| 43 | regs->irq_sts = ZYNQ_UART_TIMEOUT | ZYNQ_UART_RTRIG; |
---|
| 44 | |
---|
| 45 | do { |
---|
| 46 | char c = (char) ZYNQ_UART_TX_RX_FIFO_FIFO_GET(regs->tx_rx_fifo); |
---|
| 47 | |
---|
| 48 | rtems_termios_enqueue_raw_characters(tty, &c, 1); |
---|
| 49 | |
---|
| 50 | channel_sts = regs->channel_sts; |
---|
| 51 | } while ((channel_sts & ZYNQ_UART_CHANNEL_STS_REMPTY) == 0); |
---|
| 52 | } else { |
---|
| 53 | channel_sts = regs->channel_sts; |
---|
| 54 | } |
---|
| 55 | |
---|
| 56 | if (ctx->transmitting && (channel_sts & ZYNQ_UART_CHANNEL_STS_TEMPTY) != 0) { |
---|
| 57 | rtems_termios_dequeue_characters(tty, 1); |
---|
| 58 | } |
---|
| 59 | } |
---|
| 60 | #endif |
---|
| 61 | |
---|
[6b2fcc4] | 62 | static bool zynq_uart_first_open( |
---|
| 63 | rtems_termios_tty *tty, |
---|
| 64 | rtems_termios_device_context *base, |
---|
| 65 | struct termios *term, |
---|
| 66 | rtems_libio_open_close_args_t *args |
---|
| 67 | ) |
---|
[a94d46c8] | 68 | { |
---|
[11f0d52] | 69 | #ifdef ZYNQ_CONSOLE_USE_INTERRUPTS |
---|
| 70 | zynq_uart_context *ctx = (zynq_uart_context *) base; |
---|
| 71 | volatile zynq_uart *regs = ctx->regs; |
---|
| 72 | rtems_status_code sc; |
---|
| 73 | #endif |
---|
| 74 | |
---|
[6b2fcc4] | 75 | rtems_termios_set_initial_baud(tty, ZYNQ_UART_DEFAULT_BAUD); |
---|
| 76 | zynq_uart_initialize(base); |
---|
[a94d46c8] | 77 | |
---|
[11f0d52] | 78 | #ifdef ZYNQ_CONSOLE_USE_INTERRUPTS |
---|
| 79 | regs->rx_timeout = 32; |
---|
| 80 | regs->rx_fifo_trg_lvl = ZYNQ_UART_FIFO_DEPTH / 2; |
---|
| 81 | regs->irq_dis = 0xffffffff; |
---|
| 82 | regs->irq_sts = 0xffffffff; |
---|
| 83 | regs->irq_en = ZYNQ_UART_RTRIG | ZYNQ_UART_TIMEOUT; |
---|
| 84 | sc = rtems_interrupt_handler_install( |
---|
| 85 | ctx->irq, |
---|
| 86 | "UART", |
---|
| 87 | RTEMS_INTERRUPT_SHARED, |
---|
| 88 | zynq_uart_interrupt, |
---|
| 89 | tty |
---|
| 90 | ); |
---|
| 91 | if (sc != RTEMS_SUCCESSFUL) { |
---|
| 92 | return false; |
---|
| 93 | } |
---|
| 94 | #endif |
---|
| 95 | |
---|
[6b2fcc4] | 96 | return true; |
---|
[a94d46c8] | 97 | } |
---|
| 98 | |
---|
[11f0d52] | 99 | #ifdef ZYNQ_CONSOLE_USE_INTERRUPTS |
---|
| 100 | static void zynq_uart_last_close( |
---|
| 101 | rtems_termios_tty *tty, |
---|
| 102 | rtems_termios_device_context *base, |
---|
| 103 | rtems_libio_open_close_args_t *args |
---|
| 104 | ) |
---|
| 105 | { |
---|
| 106 | zynq_uart_context *ctx = (zynq_uart_context *) base; |
---|
| 107 | |
---|
| 108 | rtems_interrupt_handler_remove(ctx->irq, zynq_uart_interrupt, tty); |
---|
| 109 | } |
---|
| 110 | #endif |
---|
| 111 | |
---|
| 112 | static void zynq_uart_write_support( |
---|
[6b2fcc4] | 113 | rtems_termios_device_context *base, |
---|
[11f0d52] | 114 | const char *buf, |
---|
| 115 | size_t len |
---|
[a94d46c8] | 116 | ) |
---|
| 117 | { |
---|
[11f0d52] | 118 | #ifdef ZYNQ_CONSOLE_USE_INTERRUPTS |
---|
| 119 | zynq_uart_context *ctx = (zynq_uart_context *) base; |
---|
| 120 | volatile zynq_uart *regs = ctx->regs; |
---|
| 121 | |
---|
| 122 | if (len > 0) { |
---|
| 123 | ctx->transmitting = true; |
---|
| 124 | regs->irq_sts = ZYNQ_UART_TEMPTY; |
---|
| 125 | regs->irq_en = ZYNQ_UART_TEMPTY; |
---|
| 126 | regs->tx_rx_fifo = ZYNQ_UART_TX_RX_FIFO_FIFO(buf[0]); |
---|
| 127 | } else { |
---|
| 128 | ctx->transmitting = false; |
---|
| 129 | regs->irq_dis = ZYNQ_UART_TEMPTY; |
---|
| 130 | } |
---|
| 131 | #else |
---|
| 132 | ssize_t i; |
---|
[a94d46c8] | 133 | |
---|
[11f0d52] | 134 | for (i = 0; i < len; ++i) { |
---|
| 135 | zynq_uart_write_polled(base, buf[i]); |
---|
[a94d46c8] | 136 | } |
---|
[11f0d52] | 137 | #endif |
---|
[a94d46c8] | 138 | } |
---|
| 139 | |
---|
[6b2fcc4] | 140 | static bool zynq_uart_set_attributes( |
---|
| 141 | rtems_termios_device_context *context, |
---|
| 142 | const struct termios *term |
---|
| 143 | ) |
---|
[a94d46c8] | 144 | { |
---|
[5686b44d] | 145 | zynq_uart_context *ctx = (zynq_uart_context *) context; |
---|
| 146 | volatile zynq_uart *regs = ctx->regs; |
---|
[6e4255d] | 147 | uint32_t brgr = 0; |
---|
| 148 | uint32_t bauddiv = 0; |
---|
[5686b44d] | 149 | uint32_t mode = 0; |
---|
[6e4255d] | 150 | int rc; |
---|
| 151 | |
---|
| 152 | rc = zynq_cal_baud_rate(115200, &brgr, &bauddiv, regs->mode); |
---|
| 153 | if (rc != 0) |
---|
| 154 | return rc; |
---|
| 155 | |
---|
[5686b44d] | 156 | /* |
---|
| 157 | * Configure the mode register |
---|
| 158 | */ |
---|
| 159 | mode |= ZYNQ_UART_MODE_CHMODE(ZYNQ_UART_MODE_CHMODE_NORMAL); |
---|
| 160 | |
---|
| 161 | /* |
---|
| 162 | * Parity |
---|
| 163 | */ |
---|
| 164 | mode |= ZYNQ_UART_MODE_PAR(ZYNQ_UART_MODE_PAR_NONE); |
---|
| 165 | if (term->c_cflag & PARENB) { |
---|
| 166 | if (!(term->c_cflag & PARODD)) { |
---|
| 167 | mode |= ZYNQ_UART_MODE_PAR(ZYNQ_UART_MODE_PAR_ODD); |
---|
| 168 | } else { |
---|
| 169 | mode |= ZYNQ_UART_MODE_PAR(ZYNQ_UART_MODE_PAR_EVEN); |
---|
| 170 | } |
---|
| 171 | } |
---|
| 172 | |
---|
| 173 | /* |
---|
| 174 | * Character Size |
---|
| 175 | */ |
---|
| 176 | switch (term->c_cflag & CSIZE) |
---|
| 177 | { |
---|
| 178 | case CS5: |
---|
| 179 | return false; |
---|
| 180 | case CS6: |
---|
| 181 | mode |= ZYNQ_UART_MODE_CHRL(ZYNQ_UART_MODE_CHRL_6); |
---|
| 182 | break; |
---|
| 183 | case CS7: |
---|
| 184 | mode |= ZYNQ_UART_MODE_CHRL(ZYNQ_UART_MODE_CHRL_7); |
---|
| 185 | break; |
---|
| 186 | case CS8: |
---|
| 187 | default: |
---|
| 188 | mode |= ZYNQ_UART_MODE_CHRL(ZYNQ_UART_MODE_CHRL_8); |
---|
| 189 | break; |
---|
| 190 | } |
---|
| 191 | |
---|
| 192 | /* |
---|
| 193 | * Stop Bits |
---|
| 194 | */ |
---|
| 195 | if (term->c_cflag & CSTOPB) { |
---|
| 196 | /* 2 stop bits */ |
---|
| 197 | mode |= ZYNQ_UART_MODE_NBSTOP(ZYNQ_UART_MODE_NBSTOP_STOP_2); |
---|
| 198 | } else { |
---|
| 199 | /* 1 stop bit */ |
---|
| 200 | mode |= ZYNQ_UART_MODE_NBSTOP(ZYNQ_UART_MODE_NBSTOP_STOP_1); |
---|
| 201 | } |
---|
| 202 | |
---|
[6e4255d] | 203 | regs->control &= ~(ZYNQ_UART_CONTROL_RXEN | ZYNQ_UART_CONTROL_TXEN); |
---|
[5686b44d] | 204 | regs->mode = mode; |
---|
[6e4255d] | 205 | regs->baud_rate_gen = ZYNQ_UART_BAUD_RATE_GEN_CD(brgr); |
---|
| 206 | regs->baud_rate_div = ZYNQ_UART_BAUD_RATE_DIV_BDIV(bauddiv); |
---|
| 207 | regs->control |= ZYNQ_UART_CONTROL_RXEN | ZYNQ_UART_CONTROL_TXEN; |
---|
| 208 | |
---|
[6b2fcc4] | 209 | return true; |
---|
[a94d46c8] | 210 | } |
---|
| 211 | |
---|
[6b2fcc4] | 212 | const rtems_termios_device_handler zynq_uart_handler = { |
---|
| 213 | .first_open = zynq_uart_first_open, |
---|
| 214 | .set_attributes = zynq_uart_set_attributes, |
---|
[11f0d52] | 215 | .write = zynq_uart_write_support, |
---|
| 216 | #ifdef ZYNQ_CONSOLE_USE_INTERRUPTS |
---|
| 217 | .last_close = zynq_uart_last_close, |
---|
| 218 | .mode = TERMIOS_IRQ_DRIVEN |
---|
| 219 | #else |
---|
| 220 | .poll_read = zynq_uart_read_polled, |
---|
[6b2fcc4] | 221 | .mode = TERMIOS_POLLED |
---|
[11f0d52] | 222 | #endif |
---|
[a94d46c8] | 223 | }; |
---|