1a7d2d98cSAlistair Francis /* 2a7d2d98cSAlistair Francis * QEMU lowRISC Ibex UART device 3a7d2d98cSAlistair Francis * 4a7d2d98cSAlistair Francis * Copyright (c) 2020 Western Digital 5a7d2d98cSAlistair Francis * 6a7d2d98cSAlistair Francis * For details check the documentation here: 7a7d2d98cSAlistair Francis * https://docs.opentitan.org/hw/ip/uart/doc/ 8a7d2d98cSAlistair Francis * 9a7d2d98cSAlistair Francis * Permission is hereby granted, free of charge, to any person obtaining a copy 10a7d2d98cSAlistair Francis * of this software and associated documentation files (the "Software"), to deal 11a7d2d98cSAlistair Francis * in the Software without restriction, including without limitation the rights 12a7d2d98cSAlistair Francis * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13a7d2d98cSAlistair Francis * copies of the Software, and to permit persons to whom the Software is 14a7d2d98cSAlistair Francis * furnished to do so, subject to the following conditions: 15a7d2d98cSAlistair Francis * 16a7d2d98cSAlistair Francis * The above copyright notice and this permission notice shall be included in 17a7d2d98cSAlistair Francis * all copies or substantial portions of the Software. 18a7d2d98cSAlistair Francis * 19a7d2d98cSAlistair Francis * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20a7d2d98cSAlistair Francis * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21a7d2d98cSAlistair Francis * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22a7d2d98cSAlistair Francis * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23a7d2d98cSAlistair Francis * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24a7d2d98cSAlistair Francis * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25a7d2d98cSAlistair Francis * THE SOFTWARE. 26a7d2d98cSAlistair Francis */ 27a7d2d98cSAlistair Francis 28a7d2d98cSAlistair Francis #include "qemu/osdep.h" 29a7d2d98cSAlistair Francis #include "hw/char/ibex_uart.h" 30a7d2d98cSAlistair Francis #include "hw/irq.h" 31940aabb9SAlistair Francis #include "hw/qdev-clock.h" 32a7d2d98cSAlistair Francis #include "hw/qdev-properties.h" 33ce35e229SEduardo Habkost #include "hw/qdev-properties-system.h" 34a7d2d98cSAlistair Francis #include "migration/vmstate.h" 35a7d2d98cSAlistair Francis #include "qemu/log.h" 36a7d2d98cSAlistair Francis #include "qemu/module.h" 37a7d2d98cSAlistair Francis 38bdc36ce6SAlistair Francis REG32(INTR_STATE, 0x00) 39bdc36ce6SAlistair Francis FIELD(INTR_STATE, TX_WATERMARK, 0, 1) 40bdc36ce6SAlistair Francis FIELD(INTR_STATE, RX_WATERMARK, 1, 1) 41bdc36ce6SAlistair Francis FIELD(INTR_STATE, TX_EMPTY, 2, 1) 42bdc36ce6SAlistair Francis FIELD(INTR_STATE, RX_OVERFLOW, 3, 1) 43bdc36ce6SAlistair Francis REG32(INTR_ENABLE, 0x04) 44bdc36ce6SAlistair Francis REG32(INTR_TEST, 0x08) 4524bfb98dSAlistair Francis REG32(ALERT_TEST, 0x0C) 4624bfb98dSAlistair Francis REG32(CTRL, 0x10) 47bdc36ce6SAlistair Francis FIELD(CTRL, TX_ENABLE, 0, 1) 48bdc36ce6SAlistair Francis FIELD(CTRL, RX_ENABLE, 1, 1) 49bdc36ce6SAlistair Francis FIELD(CTRL, NF, 2, 1) 50bdc36ce6SAlistair Francis FIELD(CTRL, SLPBK, 4, 1) 51bdc36ce6SAlistair Francis FIELD(CTRL, LLPBK, 5, 1) 52bdc36ce6SAlistair Francis FIELD(CTRL, PARITY_EN, 6, 1) 53bdc36ce6SAlistair Francis FIELD(CTRL, PARITY_ODD, 7, 1) 54bdc36ce6SAlistair Francis FIELD(CTRL, RXBLVL, 8, 2) 55bdc36ce6SAlistair Francis FIELD(CTRL, NCO, 16, 16) 5624bfb98dSAlistair Francis REG32(STATUS, 0x14) 57bdc36ce6SAlistair Francis FIELD(STATUS, TXFULL, 0, 1) 58bdc36ce6SAlistair Francis FIELD(STATUS, RXFULL, 1, 1) 59bdc36ce6SAlistair Francis FIELD(STATUS, TXEMPTY, 2, 1) 60bdc36ce6SAlistair Francis FIELD(STATUS, RXIDLE, 4, 1) 61bdc36ce6SAlistair Francis FIELD(STATUS, RXEMPTY, 5, 1) 6224bfb98dSAlistair Francis REG32(RDATA, 0x18) 6324bfb98dSAlistair Francis REG32(WDATA, 0x1C) 6424bfb98dSAlistair Francis REG32(FIFO_CTRL, 0x20) 65bdc36ce6SAlistair Francis FIELD(FIFO_CTRL, RXRST, 0, 1) 66bdc36ce6SAlistair Francis FIELD(FIFO_CTRL, TXRST, 1, 1) 67bdc36ce6SAlistair Francis FIELD(FIFO_CTRL, RXILVL, 2, 3) 68bdc36ce6SAlistair Francis FIELD(FIFO_CTRL, TXILVL, 5, 2) 6924bfb98dSAlistair Francis REG32(FIFO_STATUS, 0x24) 70bdc36ce6SAlistair Francis FIELD(FIFO_STATUS, TXLVL, 0, 5) 71bdc36ce6SAlistair Francis FIELD(FIFO_STATUS, RXLVL, 16, 5) 7224bfb98dSAlistair Francis REG32(OVRD, 0x28) 7324bfb98dSAlistair Francis REG32(VAL, 0x2C) 7424bfb98dSAlistair Francis REG32(TIMEOUT_CTRL, 0x30) 75bdc36ce6SAlistair Francis 76a7d2d98cSAlistair Francis static void ibex_uart_update_irqs(IbexUartState *s) 77a7d2d98cSAlistair Francis { 7859093cc4SAlistair Francis if (s->uart_intr_state & s->uart_intr_enable & R_INTR_STATE_TX_WATERMARK_MASK) { 79a7d2d98cSAlistair Francis qemu_set_irq(s->tx_watermark, 1); 80a7d2d98cSAlistair Francis } else { 81a7d2d98cSAlistair Francis qemu_set_irq(s->tx_watermark, 0); 82a7d2d98cSAlistair Francis } 83a7d2d98cSAlistair Francis 8459093cc4SAlistair Francis if (s->uart_intr_state & s->uart_intr_enable & R_INTR_STATE_RX_WATERMARK_MASK) { 85a7d2d98cSAlistair Francis qemu_set_irq(s->rx_watermark, 1); 86a7d2d98cSAlistair Francis } else { 87a7d2d98cSAlistair Francis qemu_set_irq(s->rx_watermark, 0); 88a7d2d98cSAlistair Francis } 89a7d2d98cSAlistair Francis 9059093cc4SAlistair Francis if (s->uart_intr_state & s->uart_intr_enable & R_INTR_STATE_TX_EMPTY_MASK) { 91a7d2d98cSAlistair Francis qemu_set_irq(s->tx_empty, 1); 92a7d2d98cSAlistair Francis } else { 93a7d2d98cSAlistair Francis qemu_set_irq(s->tx_empty, 0); 94a7d2d98cSAlistair Francis } 95a7d2d98cSAlistair Francis 9659093cc4SAlistair Francis if (s->uart_intr_state & s->uart_intr_enable & R_INTR_STATE_RX_OVERFLOW_MASK) { 97a7d2d98cSAlistair Francis qemu_set_irq(s->rx_overflow, 1); 98a7d2d98cSAlistair Francis } else { 99a7d2d98cSAlistair Francis qemu_set_irq(s->rx_overflow, 0); 100a7d2d98cSAlistair Francis } 101a7d2d98cSAlistair Francis } 102a7d2d98cSAlistair Francis 103a7d2d98cSAlistair Francis static int ibex_uart_can_receive(void *opaque) 104a7d2d98cSAlistair Francis { 105a7d2d98cSAlistair Francis IbexUartState *s = opaque; 106a7d2d98cSAlistair Francis 10782a4ed8eSAlexander Wagner if ((s->uart_ctrl & R_CTRL_RX_ENABLE_MASK) 10882a4ed8eSAlexander Wagner && !(s->uart_status & R_STATUS_RXFULL_MASK)) { 109a7d2d98cSAlistair Francis return 1; 110a7d2d98cSAlistair Francis } 111a7d2d98cSAlistair Francis 112a7d2d98cSAlistair Francis return 0; 113a7d2d98cSAlistair Francis } 114a7d2d98cSAlistair Francis 115a7d2d98cSAlistair Francis static void ibex_uart_receive(void *opaque, const uint8_t *buf, int size) 116a7d2d98cSAlistair Francis { 117a7d2d98cSAlistair Francis IbexUartState *s = opaque; 11859093cc4SAlistair Francis uint8_t rx_fifo_level = (s->uart_fifo_ctrl & R_FIFO_CTRL_RXILVL_MASK) 11959093cc4SAlistair Francis >> R_FIFO_CTRL_RXILVL_SHIFT; 120a7d2d98cSAlistair Francis 121a7d2d98cSAlistair Francis s->uart_rdata = *buf; 122a7d2d98cSAlistair Francis 12359093cc4SAlistair Francis s->uart_status &= ~R_STATUS_RXIDLE_MASK; 12459093cc4SAlistair Francis s->uart_status &= ~R_STATUS_RXEMPTY_MASK; 12582a4ed8eSAlexander Wagner /* The RXFULL is set after receiving a single byte 12682a4ed8eSAlexander Wagner * as the FIFO buffers are not yet implemented. 12782a4ed8eSAlexander Wagner */ 12882a4ed8eSAlexander Wagner s->uart_status |= R_STATUS_RXFULL_MASK; 12982a4ed8eSAlexander Wagner s->rx_level += 1; 130a7d2d98cSAlistair Francis 131a7d2d98cSAlistair Francis if (size > rx_fifo_level) { 13259093cc4SAlistair Francis s->uart_intr_state |= R_INTR_STATE_RX_WATERMARK_MASK; 133a7d2d98cSAlistair Francis } 134a7d2d98cSAlistair Francis 135a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 136a7d2d98cSAlistair Francis } 137a7d2d98cSAlistair Francis 138*bf7b1eabSMarc-André Lureau static gboolean ibex_uart_xmit(void *do_not_use, GIOCondition cond, 139a7d2d98cSAlistair Francis void *opaque) 140a7d2d98cSAlistair Francis { 141a7d2d98cSAlistair Francis IbexUartState *s = opaque; 14259093cc4SAlistair Francis uint8_t tx_fifo_level = (s->uart_fifo_ctrl & R_FIFO_CTRL_TXILVL_MASK) 14359093cc4SAlistair Francis >> R_FIFO_CTRL_TXILVL_SHIFT; 144a7d2d98cSAlistair Francis int ret; 145a7d2d98cSAlistair Francis 146a7d2d98cSAlistair Francis /* instant drain the fifo when there's no back-end */ 147a7d2d98cSAlistair Francis if (!qemu_chr_fe_backend_connected(&s->chr)) { 148a7d2d98cSAlistair Francis s->tx_level = 0; 149a7d2d98cSAlistair Francis return FALSE; 150a7d2d98cSAlistair Francis } 151a7d2d98cSAlistair Francis 152a7d2d98cSAlistair Francis if (!s->tx_level) { 15359093cc4SAlistair Francis s->uart_status &= ~R_STATUS_TXFULL_MASK; 15459093cc4SAlistair Francis s->uart_status |= R_STATUS_TXEMPTY_MASK; 15559093cc4SAlistair Francis s->uart_intr_state |= R_INTR_STATE_TX_EMPTY_MASK; 15659093cc4SAlistair Francis s->uart_intr_state &= ~R_INTR_STATE_TX_WATERMARK_MASK; 157a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 158a7d2d98cSAlistair Francis return FALSE; 159a7d2d98cSAlistair Francis } 160a7d2d98cSAlistair Francis 161a7d2d98cSAlistair Francis ret = qemu_chr_fe_write(&s->chr, s->tx_fifo, s->tx_level); 162a7d2d98cSAlistair Francis 163a7d2d98cSAlistair Francis if (ret >= 0) { 164a7d2d98cSAlistair Francis s->tx_level -= ret; 165a7d2d98cSAlistair Francis memmove(s->tx_fifo, s->tx_fifo + ret, s->tx_level); 166a7d2d98cSAlistair Francis } 167a7d2d98cSAlistair Francis 168a7d2d98cSAlistair Francis if (s->tx_level) { 169a7d2d98cSAlistair Francis guint r = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP, 170a7d2d98cSAlistair Francis ibex_uart_xmit, s); 171a7d2d98cSAlistair Francis if (!r) { 172a7d2d98cSAlistair Francis s->tx_level = 0; 173a7d2d98cSAlistair Francis return FALSE; 174a7d2d98cSAlistair Francis } 175a7d2d98cSAlistair Francis } 176a7d2d98cSAlistair Francis 177a7d2d98cSAlistair Francis /* Clear the TX Full bit */ 178a7d2d98cSAlistair Francis if (s->tx_level != IBEX_UART_TX_FIFO_SIZE) { 17959093cc4SAlistair Francis s->uart_status &= ~R_STATUS_TXFULL_MASK; 180a7d2d98cSAlistair Francis } 181a7d2d98cSAlistair Francis 182a7d2d98cSAlistair Francis /* Disable the TX_WATERMARK IRQ */ 183a7d2d98cSAlistair Francis if (s->tx_level < tx_fifo_level) { 18459093cc4SAlistair Francis s->uart_intr_state &= ~R_INTR_STATE_TX_WATERMARK_MASK; 185a7d2d98cSAlistair Francis } 186a7d2d98cSAlistair Francis 187a7d2d98cSAlistair Francis /* Set TX empty */ 188a7d2d98cSAlistair Francis if (s->tx_level == 0) { 18959093cc4SAlistair Francis s->uart_status |= R_STATUS_TXEMPTY_MASK; 19059093cc4SAlistair Francis s->uart_intr_state |= R_INTR_STATE_TX_EMPTY_MASK; 191a7d2d98cSAlistair Francis } 192a7d2d98cSAlistair Francis 193a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 194a7d2d98cSAlistair Francis return FALSE; 195a7d2d98cSAlistair Francis } 196a7d2d98cSAlistair Francis 197a7d2d98cSAlistair Francis static void uart_write_tx_fifo(IbexUartState *s, const uint8_t *buf, 198a7d2d98cSAlistair Francis int size) 199a7d2d98cSAlistair Francis { 200a7d2d98cSAlistair Francis uint64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 20159093cc4SAlistair Francis uint8_t tx_fifo_level = (s->uart_fifo_ctrl & R_FIFO_CTRL_TXILVL_MASK) 20259093cc4SAlistair Francis >> R_FIFO_CTRL_TXILVL_SHIFT; 203a7d2d98cSAlistair Francis 204a7d2d98cSAlistair Francis if (size > IBEX_UART_TX_FIFO_SIZE - s->tx_level) { 205a7d2d98cSAlistair Francis size = IBEX_UART_TX_FIFO_SIZE - s->tx_level; 206a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, "ibex_uart: TX FIFO overflow"); 207a7d2d98cSAlistair Francis } 208a7d2d98cSAlistair Francis 209a7d2d98cSAlistair Francis memcpy(s->tx_fifo + s->tx_level, buf, size); 210a7d2d98cSAlistair Francis s->tx_level += size; 211a7d2d98cSAlistair Francis 212a7d2d98cSAlistair Francis if (s->tx_level > 0) { 21359093cc4SAlistair Francis s->uart_status &= ~R_STATUS_TXEMPTY_MASK; 214a7d2d98cSAlistair Francis } 215a7d2d98cSAlistair Francis 216a7d2d98cSAlistair Francis if (s->tx_level >= tx_fifo_level) { 21759093cc4SAlistair Francis s->uart_intr_state |= R_INTR_STATE_TX_WATERMARK_MASK; 218a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 219a7d2d98cSAlistair Francis } 220a7d2d98cSAlistair Francis 221a7d2d98cSAlistair Francis if (s->tx_level == IBEX_UART_TX_FIFO_SIZE) { 22259093cc4SAlistair Francis s->uart_status |= R_STATUS_TXFULL_MASK; 223a7d2d98cSAlistair Francis } 224a7d2d98cSAlistair Francis 225a7d2d98cSAlistair Francis timer_mod(s->fifo_trigger_handle, current_time + 226a7d2d98cSAlistair Francis (s->char_tx_time * 4)); 227a7d2d98cSAlistair Francis } 228a7d2d98cSAlistair Francis 229a7d2d98cSAlistair Francis static void ibex_uart_reset(DeviceState *dev) 230a7d2d98cSAlistair Francis { 231a7d2d98cSAlistair Francis IbexUartState *s = IBEX_UART(dev); 232a7d2d98cSAlistair Francis 233a7d2d98cSAlistair Francis s->uart_intr_state = 0x00000000; 234a7d2d98cSAlistair Francis s->uart_intr_state = 0x00000000; 235a7d2d98cSAlistair Francis s->uart_intr_enable = 0x00000000; 236a7d2d98cSAlistair Francis s->uart_ctrl = 0x00000000; 237a7d2d98cSAlistair Francis s->uart_status = 0x0000003c; 238a7d2d98cSAlistair Francis s->uart_rdata = 0x00000000; 239a7d2d98cSAlistair Francis s->uart_fifo_ctrl = 0x00000000; 240a7d2d98cSAlistair Francis s->uart_fifo_status = 0x00000000; 241a7d2d98cSAlistair Francis s->uart_ovrd = 0x00000000; 242a7d2d98cSAlistair Francis s->uart_val = 0x00000000; 243a7d2d98cSAlistair Francis s->uart_timeout_ctrl = 0x00000000; 244a7d2d98cSAlistair Francis 245a7d2d98cSAlistair Francis s->tx_level = 0; 24682a4ed8eSAlexander Wagner s->rx_level = 0; 247a7d2d98cSAlistair Francis 248a7d2d98cSAlistair Francis s->char_tx_time = (NANOSECONDS_PER_SECOND / 230400) * 10; 249a7d2d98cSAlistair Francis 250a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 251a7d2d98cSAlistair Francis } 252a7d2d98cSAlistair Francis 253940aabb9SAlistair Francis static uint64_t ibex_uart_get_baud(IbexUartState *s) 254940aabb9SAlistair Francis { 255940aabb9SAlistair Francis uint64_t baud; 256940aabb9SAlistair Francis 25759093cc4SAlistair Francis baud = ((s->uart_ctrl & R_CTRL_NCO_MASK) >> 16); 258940aabb9SAlistair Francis baud *= clock_get_hz(s->f_clk); 259940aabb9SAlistair Francis baud >>= 20; 260940aabb9SAlistair Francis 261940aabb9SAlistair Francis return baud; 262940aabb9SAlistair Francis } 263940aabb9SAlistair Francis 264a7d2d98cSAlistair Francis static uint64_t ibex_uart_read(void *opaque, hwaddr addr, 265a7d2d98cSAlistair Francis unsigned int size) 266a7d2d98cSAlistair Francis { 267a7d2d98cSAlistair Francis IbexUartState *s = opaque; 268a7d2d98cSAlistair Francis uint64_t retvalue = 0; 269a7d2d98cSAlistair Francis 27059093cc4SAlistair Francis switch (addr >> 2) { 27159093cc4SAlistair Francis case R_INTR_STATE: 272a7d2d98cSAlistair Francis retvalue = s->uart_intr_state; 273a7d2d98cSAlistair Francis break; 27459093cc4SAlistair Francis case R_INTR_ENABLE: 275a7d2d98cSAlistair Francis retvalue = s->uart_intr_enable; 276a7d2d98cSAlistair Francis break; 27759093cc4SAlistair Francis case R_INTR_TEST: 278a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, 279a7d2d98cSAlistair Francis "%s: wdata is write only\n", __func__); 280a7d2d98cSAlistair Francis break; 281a7d2d98cSAlistair Francis 28259093cc4SAlistair Francis case R_CTRL: 283a7d2d98cSAlistair Francis retvalue = s->uart_ctrl; 284a7d2d98cSAlistair Francis break; 28559093cc4SAlistair Francis case R_STATUS: 286a7d2d98cSAlistair Francis retvalue = s->uart_status; 287a7d2d98cSAlistair Francis break; 288a7d2d98cSAlistair Francis 28959093cc4SAlistair Francis case R_RDATA: 290a7d2d98cSAlistair Francis retvalue = s->uart_rdata; 29182a4ed8eSAlexander Wagner if ((s->uart_ctrl & R_CTRL_RX_ENABLE_MASK) && (s->rx_level > 0)) { 292a7d2d98cSAlistair Francis qemu_chr_fe_accept_input(&s->chr); 293a7d2d98cSAlistair Francis 29482a4ed8eSAlexander Wagner s->rx_level -= 1; 29582a4ed8eSAlexander Wagner s->uart_status &= ~R_STATUS_RXFULL_MASK; 29682a4ed8eSAlexander Wagner if (s->rx_level == 0) { 29759093cc4SAlistair Francis s->uart_status |= R_STATUS_RXIDLE_MASK; 29859093cc4SAlistair Francis s->uart_status |= R_STATUS_RXEMPTY_MASK; 299a7d2d98cSAlistair Francis } 30082a4ed8eSAlexander Wagner } 301a7d2d98cSAlistair Francis break; 30259093cc4SAlistair Francis case R_WDATA: 303a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, 304a7d2d98cSAlistair Francis "%s: wdata is write only\n", __func__); 305a7d2d98cSAlistair Francis break; 306a7d2d98cSAlistair Francis 30759093cc4SAlistair Francis case R_FIFO_CTRL: 308a7d2d98cSAlistair Francis retvalue = s->uart_fifo_ctrl; 309a7d2d98cSAlistair Francis break; 31059093cc4SAlistair Francis case R_FIFO_STATUS: 311a7d2d98cSAlistair Francis retvalue = s->uart_fifo_status; 312a7d2d98cSAlistair Francis 31382a4ed8eSAlexander Wagner retvalue |= (s->rx_level & 0x1F) << R_FIFO_STATUS_RXLVL_SHIFT; 31482a4ed8eSAlexander Wagner retvalue |= (s->tx_level & 0x1F) << R_FIFO_STATUS_TXLVL_SHIFT; 315a7d2d98cSAlistair Francis 316a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 317a7d2d98cSAlistair Francis "%s: RX fifos are not supported\n", __func__); 318a7d2d98cSAlistair Francis break; 319a7d2d98cSAlistair Francis 32059093cc4SAlistair Francis case R_OVRD: 321a7d2d98cSAlistair Francis retvalue = s->uart_ovrd; 322a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 323a7d2d98cSAlistair Francis "%s: ovrd is not supported\n", __func__); 324a7d2d98cSAlistair Francis break; 32559093cc4SAlistair Francis case R_VAL: 326a7d2d98cSAlistair Francis retvalue = s->uart_val; 327a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 328a7d2d98cSAlistair Francis "%s: val is not supported\n", __func__); 329a7d2d98cSAlistair Francis break; 33059093cc4SAlistair Francis case R_TIMEOUT_CTRL: 331a7d2d98cSAlistair Francis retvalue = s->uart_timeout_ctrl; 332a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 333a7d2d98cSAlistair Francis "%s: timeout_ctrl is not supported\n", __func__); 334a7d2d98cSAlistair Francis break; 335a7d2d98cSAlistair Francis default: 336a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, 337a7d2d98cSAlistair Francis "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); 338a7d2d98cSAlistair Francis return 0; 339a7d2d98cSAlistair Francis } 340a7d2d98cSAlistair Francis 341a7d2d98cSAlistair Francis return retvalue; 342a7d2d98cSAlistair Francis } 343a7d2d98cSAlistair Francis 344a7d2d98cSAlistair Francis static void ibex_uart_write(void *opaque, hwaddr addr, 345a7d2d98cSAlistair Francis uint64_t val64, unsigned int size) 346a7d2d98cSAlistair Francis { 347a7d2d98cSAlistair Francis IbexUartState *s = opaque; 348a7d2d98cSAlistair Francis uint32_t value = val64; 349a7d2d98cSAlistair Francis 35059093cc4SAlistair Francis switch (addr >> 2) { 35159093cc4SAlistair Francis case R_INTR_STATE: 352a7d2d98cSAlistair Francis /* Write 1 clear */ 353a7d2d98cSAlistair Francis s->uart_intr_state &= ~value; 354a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 355a7d2d98cSAlistair Francis break; 35659093cc4SAlistair Francis case R_INTR_ENABLE: 357a7d2d98cSAlistair Francis s->uart_intr_enable = value; 358a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 359a7d2d98cSAlistair Francis break; 36059093cc4SAlistair Francis case R_INTR_TEST: 361a7d2d98cSAlistair Francis s->uart_intr_state |= value; 362a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 363a7d2d98cSAlistair Francis break; 364a7d2d98cSAlistair Francis 36559093cc4SAlistair Francis case R_CTRL: 366a7d2d98cSAlistair Francis s->uart_ctrl = value; 367a7d2d98cSAlistair Francis 36859093cc4SAlistair Francis if (value & R_CTRL_NF_MASK) { 369a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 370a7d2d98cSAlistair Francis "%s: UART_CTRL_NF is not supported\n", __func__); 371a7d2d98cSAlistair Francis } 37259093cc4SAlistair Francis if (value & R_CTRL_SLPBK_MASK) { 373a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 374a7d2d98cSAlistair Francis "%s: UART_CTRL_SLPBK is not supported\n", __func__); 375a7d2d98cSAlistair Francis } 37659093cc4SAlistair Francis if (value & R_CTRL_LLPBK_MASK) { 377a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 378a7d2d98cSAlistair Francis "%s: UART_CTRL_LLPBK is not supported\n", __func__); 379a7d2d98cSAlistair Francis } 38059093cc4SAlistair Francis if (value & R_CTRL_PARITY_EN_MASK) { 381a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 382a7d2d98cSAlistair Francis "%s: UART_CTRL_PARITY_EN is not supported\n", 383a7d2d98cSAlistair Francis __func__); 384a7d2d98cSAlistair Francis } 38559093cc4SAlistair Francis if (value & R_CTRL_PARITY_ODD_MASK) { 386a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 387a7d2d98cSAlistair Francis "%s: UART_CTRL_PARITY_ODD is not supported\n", 388a7d2d98cSAlistair Francis __func__); 389a7d2d98cSAlistair Francis } 39059093cc4SAlistair Francis if (value & R_CTRL_RXBLVL_MASK) { 391a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 392a7d2d98cSAlistair Francis "%s: UART_CTRL_RXBLVL is not supported\n", __func__); 393a7d2d98cSAlistair Francis } 39459093cc4SAlistair Francis if (value & R_CTRL_NCO_MASK) { 395940aabb9SAlistair Francis uint64_t baud = ibex_uart_get_baud(s); 396a7d2d98cSAlistair Francis 397a7d2d98cSAlistair Francis s->char_tx_time = (NANOSECONDS_PER_SECOND / baud) * 10; 398a7d2d98cSAlistair Francis } 399a7d2d98cSAlistair Francis break; 40059093cc4SAlistair Francis case R_STATUS: 401a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, 402a7d2d98cSAlistair Francis "%s: status is read only\n", __func__); 403a7d2d98cSAlistair Francis break; 404a7d2d98cSAlistair Francis 40559093cc4SAlistair Francis case R_RDATA: 406a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, 407a7d2d98cSAlistair Francis "%s: rdata is read only\n", __func__); 408a7d2d98cSAlistair Francis break; 40959093cc4SAlistair Francis case R_WDATA: 410a7d2d98cSAlistair Francis uart_write_tx_fifo(s, (uint8_t *) &value, 1); 411a7d2d98cSAlistair Francis break; 412a7d2d98cSAlistair Francis 41359093cc4SAlistair Francis case R_FIFO_CTRL: 414a7d2d98cSAlistair Francis s->uart_fifo_ctrl = value; 415a7d2d98cSAlistair Francis 41659093cc4SAlistair Francis if (value & R_FIFO_CTRL_RXRST_MASK) { 41782a4ed8eSAlexander Wagner s->rx_level = 0; 418a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 419a7d2d98cSAlistair Francis "%s: RX fifos are not supported\n", __func__); 420a7d2d98cSAlistair Francis } 42159093cc4SAlistair Francis if (value & R_FIFO_CTRL_TXRST_MASK) { 422a7d2d98cSAlistair Francis s->tx_level = 0; 423a7d2d98cSAlistair Francis } 424a7d2d98cSAlistair Francis break; 42559093cc4SAlistair Francis case R_FIFO_STATUS: 426a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, 427a7d2d98cSAlistair Francis "%s: fifo_status is read only\n", __func__); 428a7d2d98cSAlistair Francis break; 429a7d2d98cSAlistair Francis 43059093cc4SAlistair Francis case R_OVRD: 431a7d2d98cSAlistair Francis s->uart_ovrd = value; 432a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 433a7d2d98cSAlistair Francis "%s: ovrd is not supported\n", __func__); 434a7d2d98cSAlistair Francis break; 43559093cc4SAlistair Francis case R_VAL: 436a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, 437a7d2d98cSAlistair Francis "%s: val is read only\n", __func__); 438a7d2d98cSAlistair Francis break; 43959093cc4SAlistair Francis case R_TIMEOUT_CTRL: 440a7d2d98cSAlistair Francis s->uart_timeout_ctrl = value; 441a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 442a7d2d98cSAlistair Francis "%s: timeout_ctrl is not supported\n", __func__); 443a7d2d98cSAlistair Francis break; 444a7d2d98cSAlistair Francis default: 445a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, 446a7d2d98cSAlistair Francis "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); 447a7d2d98cSAlistair Francis } 448a7d2d98cSAlistair Francis } 449a7d2d98cSAlistair Francis 4505ee0abedSPeter Maydell static void ibex_uart_clk_update(void *opaque, ClockEvent event) 451940aabb9SAlistair Francis { 452940aabb9SAlistair Francis IbexUartState *s = opaque; 453940aabb9SAlistair Francis 454940aabb9SAlistair Francis /* recompute uart's speed on clock change */ 455940aabb9SAlistair Francis uint64_t baud = ibex_uart_get_baud(s); 456940aabb9SAlistair Francis 457940aabb9SAlistair Francis s->char_tx_time = (NANOSECONDS_PER_SECOND / baud) * 10; 458940aabb9SAlistair Francis } 459940aabb9SAlistair Francis 460a7d2d98cSAlistair Francis static void fifo_trigger_update(void *opaque) 461a7d2d98cSAlistair Francis { 462a7d2d98cSAlistair Francis IbexUartState *s = opaque; 463a7d2d98cSAlistair Francis 46459093cc4SAlistair Francis if (s->uart_ctrl & R_CTRL_TX_ENABLE_MASK) { 465a7d2d98cSAlistair Francis ibex_uart_xmit(NULL, G_IO_OUT, s); 466a7d2d98cSAlistair Francis } 467a7d2d98cSAlistair Francis } 468a7d2d98cSAlistair Francis 469a7d2d98cSAlistair Francis static const MemoryRegionOps ibex_uart_ops = { 470a7d2d98cSAlistair Francis .read = ibex_uart_read, 471a7d2d98cSAlistair Francis .write = ibex_uart_write, 472a7d2d98cSAlistair Francis .endianness = DEVICE_NATIVE_ENDIAN, 473a7d2d98cSAlistair Francis .impl.min_access_size = 4, 474a7d2d98cSAlistair Francis .impl.max_access_size = 4, 475a7d2d98cSAlistair Francis }; 476a7d2d98cSAlistair Francis 477a7d2d98cSAlistair Francis static int ibex_uart_post_load(void *opaque, int version_id) 478a7d2d98cSAlistair Francis { 479a7d2d98cSAlistair Francis IbexUartState *s = opaque; 480a7d2d98cSAlistair Francis 481a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 482a7d2d98cSAlistair Francis return 0; 483a7d2d98cSAlistair Francis } 484a7d2d98cSAlistair Francis 485a7d2d98cSAlistair Francis static const VMStateDescription vmstate_ibex_uart = { 486a7d2d98cSAlistair Francis .name = TYPE_IBEX_UART, 487a7d2d98cSAlistair Francis .version_id = 1, 488a7d2d98cSAlistair Francis .minimum_version_id = 1, 489a7d2d98cSAlistair Francis .post_load = ibex_uart_post_load, 490a7d2d98cSAlistair Francis .fields = (VMStateField[]) { 491a7d2d98cSAlistair Francis VMSTATE_UINT8_ARRAY(tx_fifo, IbexUartState, 492a7d2d98cSAlistair Francis IBEX_UART_TX_FIFO_SIZE), 493a7d2d98cSAlistair Francis VMSTATE_UINT32(tx_level, IbexUartState), 494a7d2d98cSAlistair Francis VMSTATE_UINT64(char_tx_time, IbexUartState), 495a7d2d98cSAlistair Francis VMSTATE_TIMER_PTR(fifo_trigger_handle, IbexUartState), 496a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_intr_state, IbexUartState), 497a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_intr_enable, IbexUartState), 498a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_ctrl, IbexUartState), 499a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_status, IbexUartState), 500a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_rdata, IbexUartState), 501a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_fifo_ctrl, IbexUartState), 502a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_fifo_status, IbexUartState), 503a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_ovrd, IbexUartState), 504a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_val, IbexUartState), 505a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_timeout_ctrl, IbexUartState), 506a7d2d98cSAlistair Francis VMSTATE_END_OF_LIST() 507a7d2d98cSAlistair Francis } 508a7d2d98cSAlistair Francis }; 509a7d2d98cSAlistair Francis 510a7d2d98cSAlistair Francis static Property ibex_uart_properties[] = { 511a7d2d98cSAlistair Francis DEFINE_PROP_CHR("chardev", IbexUartState, chr), 512a7d2d98cSAlistair Francis DEFINE_PROP_END_OF_LIST(), 513a7d2d98cSAlistair Francis }; 514a7d2d98cSAlistair Francis 515a7d2d98cSAlistair Francis static void ibex_uart_init(Object *obj) 516a7d2d98cSAlistair Francis { 517a7d2d98cSAlistair Francis IbexUartState *s = IBEX_UART(obj); 518a7d2d98cSAlistair Francis 519940aabb9SAlistair Francis s->f_clk = qdev_init_clock_in(DEVICE(obj), "f_clock", 5205ee0abedSPeter Maydell ibex_uart_clk_update, s, ClockUpdate); 521940aabb9SAlistair Francis clock_set_hz(s->f_clk, IBEX_UART_CLOCK); 522940aabb9SAlistair Francis 523a7d2d98cSAlistair Francis sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_watermark); 524a7d2d98cSAlistair Francis sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_watermark); 525a7d2d98cSAlistair Francis sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_empty); 526a7d2d98cSAlistair Francis sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_overflow); 527a7d2d98cSAlistair Francis 528a7d2d98cSAlistair Francis memory_region_init_io(&s->mmio, obj, &ibex_uart_ops, s, 529a7d2d98cSAlistair Francis TYPE_IBEX_UART, 0x400); 530a7d2d98cSAlistair Francis sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); 531a7d2d98cSAlistair Francis } 532a7d2d98cSAlistair Francis 533a7d2d98cSAlistair Francis static void ibex_uart_realize(DeviceState *dev, Error **errp) 534a7d2d98cSAlistair Francis { 535a7d2d98cSAlistair Francis IbexUartState *s = IBEX_UART(dev); 536a7d2d98cSAlistair Francis 537a7d2d98cSAlistair Francis s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL, 538a7d2d98cSAlistair Francis fifo_trigger_update, s); 539a7d2d98cSAlistair Francis 540a7d2d98cSAlistair Francis qemu_chr_fe_set_handlers(&s->chr, ibex_uart_can_receive, 541a7d2d98cSAlistair Francis ibex_uart_receive, NULL, NULL, 542a7d2d98cSAlistair Francis s, NULL, true); 543a7d2d98cSAlistair Francis } 544a7d2d98cSAlistair Francis 545a7d2d98cSAlistair Francis static void ibex_uart_class_init(ObjectClass *klass, void *data) 546a7d2d98cSAlistair Francis { 547a7d2d98cSAlistair Francis DeviceClass *dc = DEVICE_CLASS(klass); 548a7d2d98cSAlistair Francis 549a7d2d98cSAlistair Francis dc->reset = ibex_uart_reset; 550a7d2d98cSAlistair Francis dc->realize = ibex_uart_realize; 551a7d2d98cSAlistair Francis dc->vmsd = &vmstate_ibex_uart; 552a7d2d98cSAlistair Francis device_class_set_props(dc, ibex_uart_properties); 553a7d2d98cSAlistair Francis } 554a7d2d98cSAlistair Francis 555a7d2d98cSAlistair Francis static const TypeInfo ibex_uart_info = { 556a7d2d98cSAlistair Francis .name = TYPE_IBEX_UART, 557a7d2d98cSAlistair Francis .parent = TYPE_SYS_BUS_DEVICE, 558a7d2d98cSAlistair Francis .instance_size = sizeof(IbexUartState), 559a7d2d98cSAlistair Francis .instance_init = ibex_uart_init, 560a7d2d98cSAlistair Francis .class_init = ibex_uart_class_init, 561a7d2d98cSAlistair Francis }; 562a7d2d98cSAlistair Francis 563a7d2d98cSAlistair Francis static void ibex_uart_register_types(void) 564a7d2d98cSAlistair Francis { 565a7d2d98cSAlistair Francis type_register_static(&ibex_uart_info); 566a7d2d98cSAlistair Francis } 567a7d2d98cSAlistair Francis 568a7d2d98cSAlistair Francis type_init(ibex_uart_register_types) 569