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 38*bdc36ce6SAlistair Francis REG32(INTR_STATE, 0x00) 39*bdc36ce6SAlistair Francis FIELD(INTR_STATE, TX_WATERMARK, 0, 1) 40*bdc36ce6SAlistair Francis FIELD(INTR_STATE, RX_WATERMARK, 1, 1) 41*bdc36ce6SAlistair Francis FIELD(INTR_STATE, TX_EMPTY, 2, 1) 42*bdc36ce6SAlistair Francis FIELD(INTR_STATE, RX_OVERFLOW, 3, 1) 43*bdc36ce6SAlistair Francis REG32(INTR_ENABLE, 0x04) 44*bdc36ce6SAlistair Francis REG32(INTR_TEST, 0x08) 45*bdc36ce6SAlistair Francis REG32(CTRL, 0x0C) 46*bdc36ce6SAlistair Francis FIELD(CTRL, TX_ENABLE, 0, 1) 47*bdc36ce6SAlistair Francis FIELD(CTRL, RX_ENABLE, 1, 1) 48*bdc36ce6SAlistair Francis FIELD(CTRL, NF, 2, 1) 49*bdc36ce6SAlistair Francis FIELD(CTRL, SLPBK, 4, 1) 50*bdc36ce6SAlistair Francis FIELD(CTRL, LLPBK, 5, 1) 51*bdc36ce6SAlistair Francis FIELD(CTRL, PARITY_EN, 6, 1) 52*bdc36ce6SAlistair Francis FIELD(CTRL, PARITY_ODD, 7, 1) 53*bdc36ce6SAlistair Francis FIELD(CTRL, RXBLVL, 8, 2) 54*bdc36ce6SAlistair Francis FIELD(CTRL, NCO, 16, 16) 55*bdc36ce6SAlistair Francis REG32(STATUS, 0x10) 56*bdc36ce6SAlistair Francis FIELD(STATUS, TXFULL, 0, 1) 57*bdc36ce6SAlistair Francis FIELD(STATUS, RXFULL, 1, 1) 58*bdc36ce6SAlistair Francis FIELD(STATUS, TXEMPTY, 2, 1) 59*bdc36ce6SAlistair Francis FIELD(STATUS, RXIDLE, 4, 1) 60*bdc36ce6SAlistair Francis FIELD(STATUS, RXEMPTY, 5, 1) 61*bdc36ce6SAlistair Francis REG32(RDATA, 0x14) 62*bdc36ce6SAlistair Francis REG32(WDATA, 0x18) 63*bdc36ce6SAlistair Francis REG32(FIFO_CTRL, 0x1c) 64*bdc36ce6SAlistair Francis FIELD(FIFO_CTRL, RXRST, 0, 1) 65*bdc36ce6SAlistair Francis FIELD(FIFO_CTRL, TXRST, 1, 1) 66*bdc36ce6SAlistair Francis FIELD(FIFO_CTRL, RXILVL, 2, 3) 67*bdc36ce6SAlistair Francis FIELD(FIFO_CTRL, TXILVL, 5, 2) 68*bdc36ce6SAlistair Francis REG32(FIFO_STATUS, 0x20) 69*bdc36ce6SAlistair Francis FIELD(FIFO_STATUS, TXLVL, 0, 5) 70*bdc36ce6SAlistair Francis FIELD(FIFO_STATUS, RXLVL, 16, 5) 71*bdc36ce6SAlistair Francis REG32(OVRD, 0x24) 72*bdc36ce6SAlistair Francis REG32(VAL, 0x28) 73*bdc36ce6SAlistair Francis REG32(TIMEOUT_CTRL, 0x2c) 74*bdc36ce6SAlistair Francis 75a7d2d98cSAlistair Francis static void ibex_uart_update_irqs(IbexUartState *s) 76a7d2d98cSAlistair Francis { 7759093cc4SAlistair Francis if (s->uart_intr_state & s->uart_intr_enable & R_INTR_STATE_TX_WATERMARK_MASK) { 78a7d2d98cSAlistair Francis qemu_set_irq(s->tx_watermark, 1); 79a7d2d98cSAlistair Francis } else { 80a7d2d98cSAlistair Francis qemu_set_irq(s->tx_watermark, 0); 81a7d2d98cSAlistair Francis } 82a7d2d98cSAlistair Francis 8359093cc4SAlistair Francis if (s->uart_intr_state & s->uart_intr_enable & R_INTR_STATE_RX_WATERMARK_MASK) { 84a7d2d98cSAlistair Francis qemu_set_irq(s->rx_watermark, 1); 85a7d2d98cSAlistair Francis } else { 86a7d2d98cSAlistair Francis qemu_set_irq(s->rx_watermark, 0); 87a7d2d98cSAlistair Francis } 88a7d2d98cSAlistair Francis 8959093cc4SAlistair Francis if (s->uart_intr_state & s->uart_intr_enable & R_INTR_STATE_TX_EMPTY_MASK) { 90a7d2d98cSAlistair Francis qemu_set_irq(s->tx_empty, 1); 91a7d2d98cSAlistair Francis } else { 92a7d2d98cSAlistair Francis qemu_set_irq(s->tx_empty, 0); 93a7d2d98cSAlistair Francis } 94a7d2d98cSAlistair Francis 9559093cc4SAlistair Francis if (s->uart_intr_state & s->uart_intr_enable & R_INTR_STATE_RX_OVERFLOW_MASK) { 96a7d2d98cSAlistair Francis qemu_set_irq(s->rx_overflow, 1); 97a7d2d98cSAlistair Francis } else { 98a7d2d98cSAlistair Francis qemu_set_irq(s->rx_overflow, 0); 99a7d2d98cSAlistair Francis } 100a7d2d98cSAlistair Francis } 101a7d2d98cSAlistair Francis 102a7d2d98cSAlistair Francis static int ibex_uart_can_receive(void *opaque) 103a7d2d98cSAlistair Francis { 104a7d2d98cSAlistair Francis IbexUartState *s = opaque; 105a7d2d98cSAlistair Francis 10682a4ed8eSAlexander Wagner if ((s->uart_ctrl & R_CTRL_RX_ENABLE_MASK) 10782a4ed8eSAlexander Wagner && !(s->uart_status & R_STATUS_RXFULL_MASK)) { 108a7d2d98cSAlistair Francis return 1; 109a7d2d98cSAlistair Francis } 110a7d2d98cSAlistair Francis 111a7d2d98cSAlistair Francis return 0; 112a7d2d98cSAlistair Francis } 113a7d2d98cSAlistair Francis 114a7d2d98cSAlistair Francis static void ibex_uart_receive(void *opaque, const uint8_t *buf, int size) 115a7d2d98cSAlistair Francis { 116a7d2d98cSAlistair Francis IbexUartState *s = opaque; 11759093cc4SAlistair Francis uint8_t rx_fifo_level = (s->uart_fifo_ctrl & R_FIFO_CTRL_RXILVL_MASK) 11859093cc4SAlistair Francis >> R_FIFO_CTRL_RXILVL_SHIFT; 119a7d2d98cSAlistair Francis 120a7d2d98cSAlistair Francis s->uart_rdata = *buf; 121a7d2d98cSAlistair Francis 12259093cc4SAlistair Francis s->uart_status &= ~R_STATUS_RXIDLE_MASK; 12359093cc4SAlistair Francis s->uart_status &= ~R_STATUS_RXEMPTY_MASK; 12482a4ed8eSAlexander Wagner /* The RXFULL is set after receiving a single byte 12582a4ed8eSAlexander Wagner * as the FIFO buffers are not yet implemented. 12682a4ed8eSAlexander Wagner */ 12782a4ed8eSAlexander Wagner s->uart_status |= R_STATUS_RXFULL_MASK; 12882a4ed8eSAlexander Wagner s->rx_level += 1; 129a7d2d98cSAlistair Francis 130a7d2d98cSAlistair Francis if (size > rx_fifo_level) { 13159093cc4SAlistair Francis s->uart_intr_state |= R_INTR_STATE_RX_WATERMARK_MASK; 132a7d2d98cSAlistair Francis } 133a7d2d98cSAlistair Francis 134a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 135a7d2d98cSAlistair Francis } 136a7d2d98cSAlistair Francis 137a7d2d98cSAlistair Francis static gboolean ibex_uart_xmit(GIOChannel *chan, GIOCondition cond, 138a7d2d98cSAlistair Francis void *opaque) 139a7d2d98cSAlistair Francis { 140a7d2d98cSAlistair Francis IbexUartState *s = opaque; 14159093cc4SAlistair Francis uint8_t tx_fifo_level = (s->uart_fifo_ctrl & R_FIFO_CTRL_TXILVL_MASK) 14259093cc4SAlistair Francis >> R_FIFO_CTRL_TXILVL_SHIFT; 143a7d2d98cSAlistair Francis int ret; 144a7d2d98cSAlistair Francis 145a7d2d98cSAlistair Francis /* instant drain the fifo when there's no back-end */ 146a7d2d98cSAlistair Francis if (!qemu_chr_fe_backend_connected(&s->chr)) { 147a7d2d98cSAlistair Francis s->tx_level = 0; 148a7d2d98cSAlistair Francis return FALSE; 149a7d2d98cSAlistair Francis } 150a7d2d98cSAlistair Francis 151a7d2d98cSAlistair Francis if (!s->tx_level) { 15259093cc4SAlistair Francis s->uart_status &= ~R_STATUS_TXFULL_MASK; 15359093cc4SAlistair Francis s->uart_status |= R_STATUS_TXEMPTY_MASK; 15459093cc4SAlistair Francis s->uart_intr_state |= R_INTR_STATE_TX_EMPTY_MASK; 15559093cc4SAlistair Francis s->uart_intr_state &= ~R_INTR_STATE_TX_WATERMARK_MASK; 156a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 157a7d2d98cSAlistair Francis return FALSE; 158a7d2d98cSAlistair Francis } 159a7d2d98cSAlistair Francis 160a7d2d98cSAlistair Francis ret = qemu_chr_fe_write(&s->chr, s->tx_fifo, s->tx_level); 161a7d2d98cSAlistair Francis 162a7d2d98cSAlistair Francis if (ret >= 0) { 163a7d2d98cSAlistair Francis s->tx_level -= ret; 164a7d2d98cSAlistair Francis memmove(s->tx_fifo, s->tx_fifo + ret, s->tx_level); 165a7d2d98cSAlistair Francis } 166a7d2d98cSAlistair Francis 167a7d2d98cSAlistair Francis if (s->tx_level) { 168a7d2d98cSAlistair Francis guint r = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP, 169a7d2d98cSAlistair Francis ibex_uart_xmit, s); 170a7d2d98cSAlistair Francis if (!r) { 171a7d2d98cSAlistair Francis s->tx_level = 0; 172a7d2d98cSAlistair Francis return FALSE; 173a7d2d98cSAlistair Francis } 174a7d2d98cSAlistair Francis } 175a7d2d98cSAlistair Francis 176a7d2d98cSAlistair Francis /* Clear the TX Full bit */ 177a7d2d98cSAlistair Francis if (s->tx_level != IBEX_UART_TX_FIFO_SIZE) { 17859093cc4SAlistair Francis s->uart_status &= ~R_STATUS_TXFULL_MASK; 179a7d2d98cSAlistair Francis } 180a7d2d98cSAlistair Francis 181a7d2d98cSAlistair Francis /* Disable the TX_WATERMARK IRQ */ 182a7d2d98cSAlistair Francis if (s->tx_level < tx_fifo_level) { 18359093cc4SAlistair Francis s->uart_intr_state &= ~R_INTR_STATE_TX_WATERMARK_MASK; 184a7d2d98cSAlistair Francis } 185a7d2d98cSAlistair Francis 186a7d2d98cSAlistair Francis /* Set TX empty */ 187a7d2d98cSAlistair Francis if (s->tx_level == 0) { 18859093cc4SAlistair Francis s->uart_status |= R_STATUS_TXEMPTY_MASK; 18959093cc4SAlistair Francis s->uart_intr_state |= R_INTR_STATE_TX_EMPTY_MASK; 190a7d2d98cSAlistair Francis } 191a7d2d98cSAlistair Francis 192a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 193a7d2d98cSAlistair Francis return FALSE; 194a7d2d98cSAlistair Francis } 195a7d2d98cSAlistair Francis 196a7d2d98cSAlistair Francis static void uart_write_tx_fifo(IbexUartState *s, const uint8_t *buf, 197a7d2d98cSAlistair Francis int size) 198a7d2d98cSAlistair Francis { 199a7d2d98cSAlistair Francis uint64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 20059093cc4SAlistair Francis uint8_t tx_fifo_level = (s->uart_fifo_ctrl & R_FIFO_CTRL_TXILVL_MASK) 20159093cc4SAlistair Francis >> R_FIFO_CTRL_TXILVL_SHIFT; 202a7d2d98cSAlistair Francis 203a7d2d98cSAlistair Francis if (size > IBEX_UART_TX_FIFO_SIZE - s->tx_level) { 204a7d2d98cSAlistair Francis size = IBEX_UART_TX_FIFO_SIZE - s->tx_level; 205a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, "ibex_uart: TX FIFO overflow"); 206a7d2d98cSAlistair Francis } 207a7d2d98cSAlistair Francis 208a7d2d98cSAlistair Francis memcpy(s->tx_fifo + s->tx_level, buf, size); 209a7d2d98cSAlistair Francis s->tx_level += size; 210a7d2d98cSAlistair Francis 211a7d2d98cSAlistair Francis if (s->tx_level > 0) { 21259093cc4SAlistair Francis s->uart_status &= ~R_STATUS_TXEMPTY_MASK; 213a7d2d98cSAlistair Francis } 214a7d2d98cSAlistair Francis 215a7d2d98cSAlistair Francis if (s->tx_level >= tx_fifo_level) { 21659093cc4SAlistair Francis s->uart_intr_state |= R_INTR_STATE_TX_WATERMARK_MASK; 217a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 218a7d2d98cSAlistair Francis } 219a7d2d98cSAlistair Francis 220a7d2d98cSAlistair Francis if (s->tx_level == IBEX_UART_TX_FIFO_SIZE) { 22159093cc4SAlistair Francis s->uart_status |= R_STATUS_TXFULL_MASK; 222a7d2d98cSAlistair Francis } 223a7d2d98cSAlistair Francis 224a7d2d98cSAlistair Francis timer_mod(s->fifo_trigger_handle, current_time + 225a7d2d98cSAlistair Francis (s->char_tx_time * 4)); 226a7d2d98cSAlistair Francis } 227a7d2d98cSAlistair Francis 228a7d2d98cSAlistair Francis static void ibex_uart_reset(DeviceState *dev) 229a7d2d98cSAlistair Francis { 230a7d2d98cSAlistair Francis IbexUartState *s = IBEX_UART(dev); 231a7d2d98cSAlistair Francis 232a7d2d98cSAlistair Francis s->uart_intr_state = 0x00000000; 233a7d2d98cSAlistair Francis s->uart_intr_state = 0x00000000; 234a7d2d98cSAlistair Francis s->uart_intr_enable = 0x00000000; 235a7d2d98cSAlistair Francis s->uart_ctrl = 0x00000000; 236a7d2d98cSAlistair Francis s->uart_status = 0x0000003c; 237a7d2d98cSAlistair Francis s->uart_rdata = 0x00000000; 238a7d2d98cSAlistair Francis s->uart_fifo_ctrl = 0x00000000; 239a7d2d98cSAlistair Francis s->uart_fifo_status = 0x00000000; 240a7d2d98cSAlistair Francis s->uart_ovrd = 0x00000000; 241a7d2d98cSAlistair Francis s->uart_val = 0x00000000; 242a7d2d98cSAlistair Francis s->uart_timeout_ctrl = 0x00000000; 243a7d2d98cSAlistair Francis 244a7d2d98cSAlistair Francis s->tx_level = 0; 24582a4ed8eSAlexander Wagner s->rx_level = 0; 246a7d2d98cSAlistair Francis 247a7d2d98cSAlistair Francis s->char_tx_time = (NANOSECONDS_PER_SECOND / 230400) * 10; 248a7d2d98cSAlistair Francis 249a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 250a7d2d98cSAlistair Francis } 251a7d2d98cSAlistair Francis 252940aabb9SAlistair Francis static uint64_t ibex_uart_get_baud(IbexUartState *s) 253940aabb9SAlistair Francis { 254940aabb9SAlistair Francis uint64_t baud; 255940aabb9SAlistair Francis 25659093cc4SAlistair Francis baud = ((s->uart_ctrl & R_CTRL_NCO_MASK) >> 16); 257940aabb9SAlistair Francis baud *= clock_get_hz(s->f_clk); 258940aabb9SAlistair Francis baud >>= 20; 259940aabb9SAlistair Francis 260940aabb9SAlistair Francis return baud; 261940aabb9SAlistair Francis } 262940aabb9SAlistair Francis 263a7d2d98cSAlistair Francis static uint64_t ibex_uart_read(void *opaque, hwaddr addr, 264a7d2d98cSAlistair Francis unsigned int size) 265a7d2d98cSAlistair Francis { 266a7d2d98cSAlistair Francis IbexUartState *s = opaque; 267a7d2d98cSAlistair Francis uint64_t retvalue = 0; 268a7d2d98cSAlistair Francis 26959093cc4SAlistair Francis switch (addr >> 2) { 27059093cc4SAlistair Francis case R_INTR_STATE: 271a7d2d98cSAlistair Francis retvalue = s->uart_intr_state; 272a7d2d98cSAlistair Francis break; 27359093cc4SAlistair Francis case R_INTR_ENABLE: 274a7d2d98cSAlistair Francis retvalue = s->uart_intr_enable; 275a7d2d98cSAlistair Francis break; 27659093cc4SAlistair Francis case R_INTR_TEST: 277a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, 278a7d2d98cSAlistair Francis "%s: wdata is write only\n", __func__); 279a7d2d98cSAlistair Francis break; 280a7d2d98cSAlistair Francis 28159093cc4SAlistair Francis case R_CTRL: 282a7d2d98cSAlistair Francis retvalue = s->uart_ctrl; 283a7d2d98cSAlistair Francis break; 28459093cc4SAlistair Francis case R_STATUS: 285a7d2d98cSAlistair Francis retvalue = s->uart_status; 286a7d2d98cSAlistair Francis break; 287a7d2d98cSAlistair Francis 28859093cc4SAlistair Francis case R_RDATA: 289a7d2d98cSAlistair Francis retvalue = s->uart_rdata; 29082a4ed8eSAlexander Wagner if ((s->uart_ctrl & R_CTRL_RX_ENABLE_MASK) && (s->rx_level > 0)) { 291a7d2d98cSAlistair Francis qemu_chr_fe_accept_input(&s->chr); 292a7d2d98cSAlistair Francis 29382a4ed8eSAlexander Wagner s->rx_level -= 1; 29482a4ed8eSAlexander Wagner s->uart_status &= ~R_STATUS_RXFULL_MASK; 29582a4ed8eSAlexander Wagner if (s->rx_level == 0) { 29659093cc4SAlistair Francis s->uart_status |= R_STATUS_RXIDLE_MASK; 29759093cc4SAlistair Francis s->uart_status |= R_STATUS_RXEMPTY_MASK; 298a7d2d98cSAlistair Francis } 29982a4ed8eSAlexander Wagner } 300a7d2d98cSAlistair Francis break; 30159093cc4SAlistair Francis case R_WDATA: 302a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, 303a7d2d98cSAlistair Francis "%s: wdata is write only\n", __func__); 304a7d2d98cSAlistair Francis break; 305a7d2d98cSAlistair Francis 30659093cc4SAlistair Francis case R_FIFO_CTRL: 307a7d2d98cSAlistair Francis retvalue = s->uart_fifo_ctrl; 308a7d2d98cSAlistair Francis break; 30959093cc4SAlistair Francis case R_FIFO_STATUS: 310a7d2d98cSAlistair Francis retvalue = s->uart_fifo_status; 311a7d2d98cSAlistair Francis 31282a4ed8eSAlexander Wagner retvalue |= (s->rx_level & 0x1F) << R_FIFO_STATUS_RXLVL_SHIFT; 31382a4ed8eSAlexander Wagner retvalue |= (s->tx_level & 0x1F) << R_FIFO_STATUS_TXLVL_SHIFT; 314a7d2d98cSAlistair Francis 315a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 316a7d2d98cSAlistair Francis "%s: RX fifos are not supported\n", __func__); 317a7d2d98cSAlistair Francis break; 318a7d2d98cSAlistair Francis 31959093cc4SAlistair Francis case R_OVRD: 320a7d2d98cSAlistair Francis retvalue = s->uart_ovrd; 321a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 322a7d2d98cSAlistair Francis "%s: ovrd is not supported\n", __func__); 323a7d2d98cSAlistair Francis break; 32459093cc4SAlistair Francis case R_VAL: 325a7d2d98cSAlistair Francis retvalue = s->uart_val; 326a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 327a7d2d98cSAlistair Francis "%s: val is not supported\n", __func__); 328a7d2d98cSAlistair Francis break; 32959093cc4SAlistair Francis case R_TIMEOUT_CTRL: 330a7d2d98cSAlistair Francis retvalue = s->uart_timeout_ctrl; 331a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 332a7d2d98cSAlistair Francis "%s: timeout_ctrl is not supported\n", __func__); 333a7d2d98cSAlistair Francis break; 334a7d2d98cSAlistair Francis default: 335a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, 336a7d2d98cSAlistair Francis "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); 337a7d2d98cSAlistair Francis return 0; 338a7d2d98cSAlistair Francis } 339a7d2d98cSAlistair Francis 340a7d2d98cSAlistair Francis return retvalue; 341a7d2d98cSAlistair Francis } 342a7d2d98cSAlistair Francis 343a7d2d98cSAlistair Francis static void ibex_uart_write(void *opaque, hwaddr addr, 344a7d2d98cSAlistair Francis uint64_t val64, unsigned int size) 345a7d2d98cSAlistair Francis { 346a7d2d98cSAlistair Francis IbexUartState *s = opaque; 347a7d2d98cSAlistair Francis uint32_t value = val64; 348a7d2d98cSAlistair Francis 34959093cc4SAlistair Francis switch (addr >> 2) { 35059093cc4SAlistair Francis case R_INTR_STATE: 351a7d2d98cSAlistair Francis /* Write 1 clear */ 352a7d2d98cSAlistair Francis s->uart_intr_state &= ~value; 353a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 354a7d2d98cSAlistair Francis break; 35559093cc4SAlistair Francis case R_INTR_ENABLE: 356a7d2d98cSAlistair Francis s->uart_intr_enable = value; 357a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 358a7d2d98cSAlistair Francis break; 35959093cc4SAlistair Francis case R_INTR_TEST: 360a7d2d98cSAlistair Francis s->uart_intr_state |= value; 361a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 362a7d2d98cSAlistair Francis break; 363a7d2d98cSAlistair Francis 36459093cc4SAlistair Francis case R_CTRL: 365a7d2d98cSAlistair Francis s->uart_ctrl = value; 366a7d2d98cSAlistair Francis 36759093cc4SAlistair Francis if (value & R_CTRL_NF_MASK) { 368a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 369a7d2d98cSAlistair Francis "%s: UART_CTRL_NF is not supported\n", __func__); 370a7d2d98cSAlistair Francis } 37159093cc4SAlistair Francis if (value & R_CTRL_SLPBK_MASK) { 372a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 373a7d2d98cSAlistair Francis "%s: UART_CTRL_SLPBK is not supported\n", __func__); 374a7d2d98cSAlistair Francis } 37559093cc4SAlistair Francis if (value & R_CTRL_LLPBK_MASK) { 376a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 377a7d2d98cSAlistair Francis "%s: UART_CTRL_LLPBK is not supported\n", __func__); 378a7d2d98cSAlistair Francis } 37959093cc4SAlistair Francis if (value & R_CTRL_PARITY_EN_MASK) { 380a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 381a7d2d98cSAlistair Francis "%s: UART_CTRL_PARITY_EN is not supported\n", 382a7d2d98cSAlistair Francis __func__); 383a7d2d98cSAlistair Francis } 38459093cc4SAlistair Francis if (value & R_CTRL_PARITY_ODD_MASK) { 385a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 386a7d2d98cSAlistair Francis "%s: UART_CTRL_PARITY_ODD is not supported\n", 387a7d2d98cSAlistair Francis __func__); 388a7d2d98cSAlistair Francis } 38959093cc4SAlistair Francis if (value & R_CTRL_RXBLVL_MASK) { 390a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 391a7d2d98cSAlistair Francis "%s: UART_CTRL_RXBLVL is not supported\n", __func__); 392a7d2d98cSAlistair Francis } 39359093cc4SAlistair Francis if (value & R_CTRL_NCO_MASK) { 394940aabb9SAlistair Francis uint64_t baud = ibex_uart_get_baud(s); 395a7d2d98cSAlistair Francis 396a7d2d98cSAlistair Francis s->char_tx_time = (NANOSECONDS_PER_SECOND / baud) * 10; 397a7d2d98cSAlistair Francis } 398a7d2d98cSAlistair Francis break; 39959093cc4SAlistair Francis case R_STATUS: 400a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, 401a7d2d98cSAlistair Francis "%s: status is read only\n", __func__); 402a7d2d98cSAlistair Francis break; 403a7d2d98cSAlistair Francis 40459093cc4SAlistair Francis case R_RDATA: 405a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, 406a7d2d98cSAlistair Francis "%s: rdata is read only\n", __func__); 407a7d2d98cSAlistair Francis break; 40859093cc4SAlistair Francis case R_WDATA: 409a7d2d98cSAlistair Francis uart_write_tx_fifo(s, (uint8_t *) &value, 1); 410a7d2d98cSAlistair Francis break; 411a7d2d98cSAlistair Francis 41259093cc4SAlistair Francis case R_FIFO_CTRL: 413a7d2d98cSAlistair Francis s->uart_fifo_ctrl = value; 414a7d2d98cSAlistair Francis 41559093cc4SAlistair Francis if (value & R_FIFO_CTRL_RXRST_MASK) { 41682a4ed8eSAlexander Wagner s->rx_level = 0; 417a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 418a7d2d98cSAlistair Francis "%s: RX fifos are not supported\n", __func__); 419a7d2d98cSAlistair Francis } 42059093cc4SAlistair Francis if (value & R_FIFO_CTRL_TXRST_MASK) { 421a7d2d98cSAlistair Francis s->tx_level = 0; 422a7d2d98cSAlistair Francis } 423a7d2d98cSAlistair Francis break; 42459093cc4SAlistair Francis case R_FIFO_STATUS: 425a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, 426a7d2d98cSAlistair Francis "%s: fifo_status is read only\n", __func__); 427a7d2d98cSAlistair Francis break; 428a7d2d98cSAlistair Francis 42959093cc4SAlistair Francis case R_OVRD: 430a7d2d98cSAlistair Francis s->uart_ovrd = value; 431a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 432a7d2d98cSAlistair Francis "%s: ovrd is not supported\n", __func__); 433a7d2d98cSAlistair Francis break; 43459093cc4SAlistair Francis case R_VAL: 435a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, 436a7d2d98cSAlistair Francis "%s: val is read only\n", __func__); 437a7d2d98cSAlistair Francis break; 43859093cc4SAlistair Francis case R_TIMEOUT_CTRL: 439a7d2d98cSAlistair Francis s->uart_timeout_ctrl = value; 440a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 441a7d2d98cSAlistair Francis "%s: timeout_ctrl is not supported\n", __func__); 442a7d2d98cSAlistair Francis break; 443a7d2d98cSAlistair Francis default: 444a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, 445a7d2d98cSAlistair Francis "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); 446a7d2d98cSAlistair Francis } 447a7d2d98cSAlistair Francis } 448a7d2d98cSAlistair Francis 4495ee0abedSPeter Maydell static void ibex_uart_clk_update(void *opaque, ClockEvent event) 450940aabb9SAlistair Francis { 451940aabb9SAlistair Francis IbexUartState *s = opaque; 452940aabb9SAlistair Francis 453940aabb9SAlistair Francis /* recompute uart's speed on clock change */ 454940aabb9SAlistair Francis uint64_t baud = ibex_uart_get_baud(s); 455940aabb9SAlistair Francis 456940aabb9SAlistair Francis s->char_tx_time = (NANOSECONDS_PER_SECOND / baud) * 10; 457940aabb9SAlistair Francis } 458940aabb9SAlistair Francis 459a7d2d98cSAlistair Francis static void fifo_trigger_update(void *opaque) 460a7d2d98cSAlistair Francis { 461a7d2d98cSAlistair Francis IbexUartState *s = opaque; 462a7d2d98cSAlistair Francis 46359093cc4SAlistair Francis if (s->uart_ctrl & R_CTRL_TX_ENABLE_MASK) { 464a7d2d98cSAlistair Francis ibex_uart_xmit(NULL, G_IO_OUT, s); 465a7d2d98cSAlistair Francis } 466a7d2d98cSAlistair Francis } 467a7d2d98cSAlistair Francis 468a7d2d98cSAlistair Francis static const MemoryRegionOps ibex_uart_ops = { 469a7d2d98cSAlistair Francis .read = ibex_uart_read, 470a7d2d98cSAlistair Francis .write = ibex_uart_write, 471a7d2d98cSAlistair Francis .endianness = DEVICE_NATIVE_ENDIAN, 472a7d2d98cSAlistair Francis .impl.min_access_size = 4, 473a7d2d98cSAlistair Francis .impl.max_access_size = 4, 474a7d2d98cSAlistair Francis }; 475a7d2d98cSAlistair Francis 476a7d2d98cSAlistair Francis static int ibex_uart_post_load(void *opaque, int version_id) 477a7d2d98cSAlistair Francis { 478a7d2d98cSAlistair Francis IbexUartState *s = opaque; 479a7d2d98cSAlistair Francis 480a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 481a7d2d98cSAlistair Francis return 0; 482a7d2d98cSAlistair Francis } 483a7d2d98cSAlistair Francis 484a7d2d98cSAlistair Francis static const VMStateDescription vmstate_ibex_uart = { 485a7d2d98cSAlistair Francis .name = TYPE_IBEX_UART, 486a7d2d98cSAlistair Francis .version_id = 1, 487a7d2d98cSAlistair Francis .minimum_version_id = 1, 488a7d2d98cSAlistair Francis .post_load = ibex_uart_post_load, 489a7d2d98cSAlistair Francis .fields = (VMStateField[]) { 490a7d2d98cSAlistair Francis VMSTATE_UINT8_ARRAY(tx_fifo, IbexUartState, 491a7d2d98cSAlistair Francis IBEX_UART_TX_FIFO_SIZE), 492a7d2d98cSAlistair Francis VMSTATE_UINT32(tx_level, IbexUartState), 493a7d2d98cSAlistair Francis VMSTATE_UINT64(char_tx_time, IbexUartState), 494a7d2d98cSAlistair Francis VMSTATE_TIMER_PTR(fifo_trigger_handle, IbexUartState), 495a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_intr_state, IbexUartState), 496a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_intr_enable, IbexUartState), 497a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_ctrl, IbexUartState), 498a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_status, IbexUartState), 499a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_rdata, IbexUartState), 500a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_fifo_ctrl, IbexUartState), 501a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_fifo_status, IbexUartState), 502a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_ovrd, IbexUartState), 503a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_val, IbexUartState), 504a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_timeout_ctrl, IbexUartState), 505a7d2d98cSAlistair Francis VMSTATE_END_OF_LIST() 506a7d2d98cSAlistair Francis } 507a7d2d98cSAlistair Francis }; 508a7d2d98cSAlistair Francis 509a7d2d98cSAlistair Francis static Property ibex_uart_properties[] = { 510a7d2d98cSAlistair Francis DEFINE_PROP_CHR("chardev", IbexUartState, chr), 511a7d2d98cSAlistair Francis DEFINE_PROP_END_OF_LIST(), 512a7d2d98cSAlistair Francis }; 513a7d2d98cSAlistair Francis 514a7d2d98cSAlistair Francis static void ibex_uart_init(Object *obj) 515a7d2d98cSAlistair Francis { 516a7d2d98cSAlistair Francis IbexUartState *s = IBEX_UART(obj); 517a7d2d98cSAlistair Francis 518940aabb9SAlistair Francis s->f_clk = qdev_init_clock_in(DEVICE(obj), "f_clock", 5195ee0abedSPeter Maydell ibex_uart_clk_update, s, ClockUpdate); 520940aabb9SAlistair Francis clock_set_hz(s->f_clk, IBEX_UART_CLOCK); 521940aabb9SAlistair Francis 522a7d2d98cSAlistair Francis sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_watermark); 523a7d2d98cSAlistair Francis sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_watermark); 524a7d2d98cSAlistair Francis sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_empty); 525a7d2d98cSAlistair Francis sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_overflow); 526a7d2d98cSAlistair Francis 527a7d2d98cSAlistair Francis memory_region_init_io(&s->mmio, obj, &ibex_uart_ops, s, 528a7d2d98cSAlistair Francis TYPE_IBEX_UART, 0x400); 529a7d2d98cSAlistair Francis sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); 530a7d2d98cSAlistair Francis } 531a7d2d98cSAlistair Francis 532a7d2d98cSAlistair Francis static void ibex_uart_realize(DeviceState *dev, Error **errp) 533a7d2d98cSAlistair Francis { 534a7d2d98cSAlistair Francis IbexUartState *s = IBEX_UART(dev); 535a7d2d98cSAlistair Francis 536a7d2d98cSAlistair Francis s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL, 537a7d2d98cSAlistair Francis fifo_trigger_update, s); 538a7d2d98cSAlistair Francis 539a7d2d98cSAlistair Francis qemu_chr_fe_set_handlers(&s->chr, ibex_uart_can_receive, 540a7d2d98cSAlistair Francis ibex_uart_receive, NULL, NULL, 541a7d2d98cSAlistair Francis s, NULL, true); 542a7d2d98cSAlistair Francis } 543a7d2d98cSAlistair Francis 544a7d2d98cSAlistair Francis static void ibex_uart_class_init(ObjectClass *klass, void *data) 545a7d2d98cSAlistair Francis { 546a7d2d98cSAlistair Francis DeviceClass *dc = DEVICE_CLASS(klass); 547a7d2d98cSAlistair Francis 548a7d2d98cSAlistair Francis dc->reset = ibex_uart_reset; 549a7d2d98cSAlistair Francis dc->realize = ibex_uart_realize; 550a7d2d98cSAlistair Francis dc->vmsd = &vmstate_ibex_uart; 551a7d2d98cSAlistair Francis device_class_set_props(dc, ibex_uart_properties); 552a7d2d98cSAlistair Francis } 553a7d2d98cSAlistair Francis 554a7d2d98cSAlistair Francis static const TypeInfo ibex_uart_info = { 555a7d2d98cSAlistair Francis .name = TYPE_IBEX_UART, 556a7d2d98cSAlistair Francis .parent = TYPE_SYS_BUS_DEVICE, 557a7d2d98cSAlistair Francis .instance_size = sizeof(IbexUartState), 558a7d2d98cSAlistair Francis .instance_init = ibex_uart_init, 559a7d2d98cSAlistair Francis .class_init = ibex_uart_class_init, 560a7d2d98cSAlistair Francis }; 561a7d2d98cSAlistair Francis 562a7d2d98cSAlistair Francis static void ibex_uart_register_types(void) 563a7d2d98cSAlistair Francis { 564a7d2d98cSAlistair Francis type_register_static(&ibex_uart_info); 565a7d2d98cSAlistair Francis } 566a7d2d98cSAlistair Francis 567a7d2d98cSAlistair Francis type_init(ibex_uart_register_types) 568