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" 33*ce35e229SEduardo 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 38a7d2d98cSAlistair Francis static void ibex_uart_update_irqs(IbexUartState *s) 39a7d2d98cSAlistair Francis { 4059093cc4SAlistair Francis if (s->uart_intr_state & s->uart_intr_enable & R_INTR_STATE_TX_WATERMARK_MASK) { 41a7d2d98cSAlistair Francis qemu_set_irq(s->tx_watermark, 1); 42a7d2d98cSAlistair Francis } else { 43a7d2d98cSAlistair Francis qemu_set_irq(s->tx_watermark, 0); 44a7d2d98cSAlistair Francis } 45a7d2d98cSAlistair Francis 4659093cc4SAlistair Francis if (s->uart_intr_state & s->uart_intr_enable & R_INTR_STATE_RX_WATERMARK_MASK) { 47a7d2d98cSAlistair Francis qemu_set_irq(s->rx_watermark, 1); 48a7d2d98cSAlistair Francis } else { 49a7d2d98cSAlistair Francis qemu_set_irq(s->rx_watermark, 0); 50a7d2d98cSAlistair Francis } 51a7d2d98cSAlistair Francis 5259093cc4SAlistair Francis if (s->uart_intr_state & s->uart_intr_enable & R_INTR_STATE_TX_EMPTY_MASK) { 53a7d2d98cSAlistair Francis qemu_set_irq(s->tx_empty, 1); 54a7d2d98cSAlistair Francis } else { 55a7d2d98cSAlistair Francis qemu_set_irq(s->tx_empty, 0); 56a7d2d98cSAlistair Francis } 57a7d2d98cSAlistair Francis 5859093cc4SAlistair Francis if (s->uart_intr_state & s->uart_intr_enable & R_INTR_STATE_RX_OVERFLOW_MASK) { 59a7d2d98cSAlistair Francis qemu_set_irq(s->rx_overflow, 1); 60a7d2d98cSAlistair Francis } else { 61a7d2d98cSAlistair Francis qemu_set_irq(s->rx_overflow, 0); 62a7d2d98cSAlistair Francis } 63a7d2d98cSAlistair Francis } 64a7d2d98cSAlistair Francis 65a7d2d98cSAlistair Francis static int ibex_uart_can_receive(void *opaque) 66a7d2d98cSAlistair Francis { 67a7d2d98cSAlistair Francis IbexUartState *s = opaque; 68a7d2d98cSAlistair Francis 6959093cc4SAlistair Francis if (s->uart_ctrl & R_CTRL_RX_ENABLE_MASK) { 70a7d2d98cSAlistair Francis return 1; 71a7d2d98cSAlistair Francis } 72a7d2d98cSAlistair Francis 73a7d2d98cSAlistair Francis return 0; 74a7d2d98cSAlistair Francis } 75a7d2d98cSAlistair Francis 76a7d2d98cSAlistair Francis static void ibex_uart_receive(void *opaque, const uint8_t *buf, int size) 77a7d2d98cSAlistair Francis { 78a7d2d98cSAlistair Francis IbexUartState *s = opaque; 7959093cc4SAlistair Francis uint8_t rx_fifo_level = (s->uart_fifo_ctrl & R_FIFO_CTRL_RXILVL_MASK) 8059093cc4SAlistair Francis >> R_FIFO_CTRL_RXILVL_SHIFT; 81a7d2d98cSAlistair Francis 82a7d2d98cSAlistair Francis s->uart_rdata = *buf; 83a7d2d98cSAlistair Francis 8459093cc4SAlistair Francis s->uart_status &= ~R_STATUS_RXIDLE_MASK; 8559093cc4SAlistair Francis s->uart_status &= ~R_STATUS_RXEMPTY_MASK; 86a7d2d98cSAlistair Francis 87a7d2d98cSAlistair Francis if (size > rx_fifo_level) { 8859093cc4SAlistair Francis s->uart_intr_state |= R_INTR_STATE_RX_WATERMARK_MASK; 89a7d2d98cSAlistair Francis } 90a7d2d98cSAlistair Francis 91a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 92a7d2d98cSAlistair Francis } 93a7d2d98cSAlistair Francis 94a7d2d98cSAlistair Francis static gboolean ibex_uart_xmit(GIOChannel *chan, GIOCondition cond, 95a7d2d98cSAlistair Francis void *opaque) 96a7d2d98cSAlistair Francis { 97a7d2d98cSAlistair Francis IbexUartState *s = opaque; 9859093cc4SAlistair Francis uint8_t tx_fifo_level = (s->uart_fifo_ctrl & R_FIFO_CTRL_TXILVL_MASK) 9959093cc4SAlistair Francis >> R_FIFO_CTRL_TXILVL_SHIFT; 100a7d2d98cSAlistair Francis int ret; 101a7d2d98cSAlistair Francis 102a7d2d98cSAlistair Francis /* instant drain the fifo when there's no back-end */ 103a7d2d98cSAlistair Francis if (!qemu_chr_fe_backend_connected(&s->chr)) { 104a7d2d98cSAlistair Francis s->tx_level = 0; 105a7d2d98cSAlistair Francis return FALSE; 106a7d2d98cSAlistair Francis } 107a7d2d98cSAlistair Francis 108a7d2d98cSAlistair Francis if (!s->tx_level) { 10959093cc4SAlistair Francis s->uart_status &= ~R_STATUS_TXFULL_MASK; 11059093cc4SAlistair Francis s->uart_status |= R_STATUS_TXEMPTY_MASK; 11159093cc4SAlistair Francis s->uart_intr_state |= R_INTR_STATE_TX_EMPTY_MASK; 11259093cc4SAlistair Francis s->uart_intr_state &= ~R_INTR_STATE_TX_WATERMARK_MASK; 113a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 114a7d2d98cSAlistair Francis return FALSE; 115a7d2d98cSAlistair Francis } 116a7d2d98cSAlistair Francis 117a7d2d98cSAlistair Francis ret = qemu_chr_fe_write(&s->chr, s->tx_fifo, s->tx_level); 118a7d2d98cSAlistair Francis 119a7d2d98cSAlistair Francis if (ret >= 0) { 120a7d2d98cSAlistair Francis s->tx_level -= ret; 121a7d2d98cSAlistair Francis memmove(s->tx_fifo, s->tx_fifo + ret, s->tx_level); 122a7d2d98cSAlistair Francis } 123a7d2d98cSAlistair Francis 124a7d2d98cSAlistair Francis if (s->tx_level) { 125a7d2d98cSAlistair Francis guint r = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP, 126a7d2d98cSAlistair Francis ibex_uart_xmit, s); 127a7d2d98cSAlistair Francis if (!r) { 128a7d2d98cSAlistair Francis s->tx_level = 0; 129a7d2d98cSAlistair Francis return FALSE; 130a7d2d98cSAlistair Francis } 131a7d2d98cSAlistair Francis } 132a7d2d98cSAlistair Francis 133a7d2d98cSAlistair Francis /* Clear the TX Full bit */ 134a7d2d98cSAlistair Francis if (s->tx_level != IBEX_UART_TX_FIFO_SIZE) { 13559093cc4SAlistair Francis s->uart_status &= ~R_STATUS_TXFULL_MASK; 136a7d2d98cSAlistair Francis } 137a7d2d98cSAlistair Francis 138a7d2d98cSAlistair Francis /* Disable the TX_WATERMARK IRQ */ 139a7d2d98cSAlistair Francis if (s->tx_level < tx_fifo_level) { 14059093cc4SAlistair Francis s->uart_intr_state &= ~R_INTR_STATE_TX_WATERMARK_MASK; 141a7d2d98cSAlistair Francis } 142a7d2d98cSAlistair Francis 143a7d2d98cSAlistair Francis /* Set TX empty */ 144a7d2d98cSAlistair Francis if (s->tx_level == 0) { 14559093cc4SAlistair Francis s->uart_status |= R_STATUS_TXEMPTY_MASK; 14659093cc4SAlistair Francis s->uart_intr_state |= R_INTR_STATE_TX_EMPTY_MASK; 147a7d2d98cSAlistair Francis } 148a7d2d98cSAlistair Francis 149a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 150a7d2d98cSAlistair Francis return FALSE; 151a7d2d98cSAlistair Francis } 152a7d2d98cSAlistair Francis 153a7d2d98cSAlistair Francis static void uart_write_tx_fifo(IbexUartState *s, const uint8_t *buf, 154a7d2d98cSAlistair Francis int size) 155a7d2d98cSAlistair Francis { 156a7d2d98cSAlistair Francis uint64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 15759093cc4SAlistair Francis uint8_t tx_fifo_level = (s->uart_fifo_ctrl & R_FIFO_CTRL_TXILVL_MASK) 15859093cc4SAlistair Francis >> R_FIFO_CTRL_TXILVL_SHIFT; 159a7d2d98cSAlistair Francis 160a7d2d98cSAlistair Francis if (size > IBEX_UART_TX_FIFO_SIZE - s->tx_level) { 161a7d2d98cSAlistair Francis size = IBEX_UART_TX_FIFO_SIZE - s->tx_level; 162a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, "ibex_uart: TX FIFO overflow"); 163a7d2d98cSAlistair Francis } 164a7d2d98cSAlistair Francis 165a7d2d98cSAlistair Francis memcpy(s->tx_fifo + s->tx_level, buf, size); 166a7d2d98cSAlistair Francis s->tx_level += size; 167a7d2d98cSAlistair Francis 168a7d2d98cSAlistair Francis if (s->tx_level > 0) { 16959093cc4SAlistair Francis s->uart_status &= ~R_STATUS_TXEMPTY_MASK; 170a7d2d98cSAlistair Francis } 171a7d2d98cSAlistair Francis 172a7d2d98cSAlistair Francis if (s->tx_level >= tx_fifo_level) { 17359093cc4SAlistair Francis s->uart_intr_state |= R_INTR_STATE_TX_WATERMARK_MASK; 174a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 175a7d2d98cSAlistair Francis } 176a7d2d98cSAlistair Francis 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 timer_mod(s->fifo_trigger_handle, current_time + 182a7d2d98cSAlistair Francis (s->char_tx_time * 4)); 183a7d2d98cSAlistair Francis } 184a7d2d98cSAlistair Francis 185a7d2d98cSAlistair Francis static void ibex_uart_reset(DeviceState *dev) 186a7d2d98cSAlistair Francis { 187a7d2d98cSAlistair Francis IbexUartState *s = IBEX_UART(dev); 188a7d2d98cSAlistair Francis 189a7d2d98cSAlistair Francis s->uart_intr_state = 0x00000000; 190a7d2d98cSAlistair Francis s->uart_intr_state = 0x00000000; 191a7d2d98cSAlistair Francis s->uart_intr_enable = 0x00000000; 192a7d2d98cSAlistair Francis s->uart_ctrl = 0x00000000; 193a7d2d98cSAlistair Francis s->uart_status = 0x0000003c; 194a7d2d98cSAlistair Francis s->uart_rdata = 0x00000000; 195a7d2d98cSAlistair Francis s->uart_fifo_ctrl = 0x00000000; 196a7d2d98cSAlistair Francis s->uart_fifo_status = 0x00000000; 197a7d2d98cSAlistair Francis s->uart_ovrd = 0x00000000; 198a7d2d98cSAlistair Francis s->uart_val = 0x00000000; 199a7d2d98cSAlistair Francis s->uart_timeout_ctrl = 0x00000000; 200a7d2d98cSAlistair Francis 201a7d2d98cSAlistair Francis s->tx_level = 0; 202a7d2d98cSAlistair Francis 203a7d2d98cSAlistair Francis s->char_tx_time = (NANOSECONDS_PER_SECOND / 230400) * 10; 204a7d2d98cSAlistair Francis 205a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 206a7d2d98cSAlistair Francis } 207a7d2d98cSAlistair Francis 208940aabb9SAlistair Francis static uint64_t ibex_uart_get_baud(IbexUartState *s) 209940aabb9SAlistair Francis { 210940aabb9SAlistair Francis uint64_t baud; 211940aabb9SAlistair Francis 21259093cc4SAlistair Francis baud = ((s->uart_ctrl & R_CTRL_NCO_MASK) >> 16); 213940aabb9SAlistair Francis baud *= clock_get_hz(s->f_clk); 214940aabb9SAlistair Francis baud >>= 20; 215940aabb9SAlistair Francis 216940aabb9SAlistair Francis return baud; 217940aabb9SAlistair Francis } 218940aabb9SAlistair Francis 219a7d2d98cSAlistair Francis static uint64_t ibex_uart_read(void *opaque, hwaddr addr, 220a7d2d98cSAlistair Francis unsigned int size) 221a7d2d98cSAlistair Francis { 222a7d2d98cSAlistair Francis IbexUartState *s = opaque; 223a7d2d98cSAlistair Francis uint64_t retvalue = 0; 224a7d2d98cSAlistair Francis 22559093cc4SAlistair Francis switch (addr >> 2) { 22659093cc4SAlistair Francis case R_INTR_STATE: 227a7d2d98cSAlistair Francis retvalue = s->uart_intr_state; 228a7d2d98cSAlistair Francis break; 22959093cc4SAlistair Francis case R_INTR_ENABLE: 230a7d2d98cSAlistair Francis retvalue = s->uart_intr_enable; 231a7d2d98cSAlistair Francis break; 23259093cc4SAlistair Francis case R_INTR_TEST: 233a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, 234a7d2d98cSAlistair Francis "%s: wdata is write only\n", __func__); 235a7d2d98cSAlistair Francis break; 236a7d2d98cSAlistair Francis 23759093cc4SAlistair Francis case R_CTRL: 238a7d2d98cSAlistair Francis retvalue = s->uart_ctrl; 239a7d2d98cSAlistair Francis break; 24059093cc4SAlistair Francis case R_STATUS: 241a7d2d98cSAlistair Francis retvalue = s->uart_status; 242a7d2d98cSAlistair Francis break; 243a7d2d98cSAlistair Francis 24459093cc4SAlistair Francis case R_RDATA: 245a7d2d98cSAlistair Francis retvalue = s->uart_rdata; 24659093cc4SAlistair Francis if (s->uart_ctrl & R_CTRL_RX_ENABLE_MASK) { 247a7d2d98cSAlistair Francis qemu_chr_fe_accept_input(&s->chr); 248a7d2d98cSAlistair Francis 24959093cc4SAlistair Francis s->uart_status |= R_STATUS_RXIDLE_MASK; 25059093cc4SAlistair Francis s->uart_status |= R_STATUS_RXEMPTY_MASK; 251a7d2d98cSAlistair Francis } 252a7d2d98cSAlistair Francis break; 25359093cc4SAlistair Francis case R_WDATA: 254a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, 255a7d2d98cSAlistair Francis "%s: wdata is write only\n", __func__); 256a7d2d98cSAlistair Francis break; 257a7d2d98cSAlistair Francis 25859093cc4SAlistair Francis case R_FIFO_CTRL: 259a7d2d98cSAlistair Francis retvalue = s->uart_fifo_ctrl; 260a7d2d98cSAlistair Francis break; 26159093cc4SAlistair Francis case R_FIFO_STATUS: 262a7d2d98cSAlistair Francis retvalue = s->uart_fifo_status; 263a7d2d98cSAlistair Francis 264a7d2d98cSAlistair Francis retvalue |= s->tx_level & 0x1F; 265a7d2d98cSAlistair Francis 266a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 267a7d2d98cSAlistair Francis "%s: RX fifos are not supported\n", __func__); 268a7d2d98cSAlistair Francis break; 269a7d2d98cSAlistair Francis 27059093cc4SAlistair Francis case R_OVRD: 271a7d2d98cSAlistair Francis retvalue = s->uart_ovrd; 272a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 273a7d2d98cSAlistair Francis "%s: ovrd is not supported\n", __func__); 274a7d2d98cSAlistair Francis break; 27559093cc4SAlistair Francis case R_VAL: 276a7d2d98cSAlistair Francis retvalue = s->uart_val; 277a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 278a7d2d98cSAlistair Francis "%s: val is not supported\n", __func__); 279a7d2d98cSAlistair Francis break; 28059093cc4SAlistair Francis case R_TIMEOUT_CTRL: 281a7d2d98cSAlistair Francis retvalue = s->uart_timeout_ctrl; 282a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 283a7d2d98cSAlistair Francis "%s: timeout_ctrl is not supported\n", __func__); 284a7d2d98cSAlistair Francis break; 285a7d2d98cSAlistair Francis default: 286a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, 287a7d2d98cSAlistair Francis "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); 288a7d2d98cSAlistair Francis return 0; 289a7d2d98cSAlistair Francis } 290a7d2d98cSAlistair Francis 291a7d2d98cSAlistair Francis return retvalue; 292a7d2d98cSAlistair Francis } 293a7d2d98cSAlistair Francis 294a7d2d98cSAlistair Francis static void ibex_uart_write(void *opaque, hwaddr addr, 295a7d2d98cSAlistair Francis uint64_t val64, unsigned int size) 296a7d2d98cSAlistair Francis { 297a7d2d98cSAlistair Francis IbexUartState *s = opaque; 298a7d2d98cSAlistair Francis uint32_t value = val64; 299a7d2d98cSAlistair Francis 30059093cc4SAlistair Francis switch (addr >> 2) { 30159093cc4SAlistair Francis case R_INTR_STATE: 302a7d2d98cSAlistair Francis /* Write 1 clear */ 303a7d2d98cSAlistair Francis s->uart_intr_state &= ~value; 304a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 305a7d2d98cSAlistair Francis break; 30659093cc4SAlistair Francis case R_INTR_ENABLE: 307a7d2d98cSAlistair Francis s->uart_intr_enable = value; 308a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 309a7d2d98cSAlistair Francis break; 31059093cc4SAlistair Francis case R_INTR_TEST: 311a7d2d98cSAlistair Francis s->uart_intr_state |= value; 312a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 313a7d2d98cSAlistair Francis break; 314a7d2d98cSAlistair Francis 31559093cc4SAlistair Francis case R_CTRL: 316a7d2d98cSAlistair Francis s->uart_ctrl = value; 317a7d2d98cSAlistair Francis 31859093cc4SAlistair Francis if (value & R_CTRL_NF_MASK) { 319a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 320a7d2d98cSAlistair Francis "%s: UART_CTRL_NF is not supported\n", __func__); 321a7d2d98cSAlistair Francis } 32259093cc4SAlistair Francis if (value & R_CTRL_SLPBK_MASK) { 323a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 324a7d2d98cSAlistair Francis "%s: UART_CTRL_SLPBK is not supported\n", __func__); 325a7d2d98cSAlistair Francis } 32659093cc4SAlistair Francis if (value & R_CTRL_LLPBK_MASK) { 327a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 328a7d2d98cSAlistair Francis "%s: UART_CTRL_LLPBK is not supported\n", __func__); 329a7d2d98cSAlistair Francis } 33059093cc4SAlistair Francis if (value & R_CTRL_PARITY_EN_MASK) { 331a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 332a7d2d98cSAlistair Francis "%s: UART_CTRL_PARITY_EN is not supported\n", 333a7d2d98cSAlistair Francis __func__); 334a7d2d98cSAlistair Francis } 33559093cc4SAlistair Francis if (value & R_CTRL_PARITY_ODD_MASK) { 336a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 337a7d2d98cSAlistair Francis "%s: UART_CTRL_PARITY_ODD is not supported\n", 338a7d2d98cSAlistair Francis __func__); 339a7d2d98cSAlistair Francis } 34059093cc4SAlistair Francis if (value & R_CTRL_RXBLVL_MASK) { 341a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 342a7d2d98cSAlistair Francis "%s: UART_CTRL_RXBLVL is not supported\n", __func__); 343a7d2d98cSAlistair Francis } 34459093cc4SAlistair Francis if (value & R_CTRL_NCO_MASK) { 345940aabb9SAlistair Francis uint64_t baud = ibex_uart_get_baud(s); 346a7d2d98cSAlistair Francis 347a7d2d98cSAlistair Francis s->char_tx_time = (NANOSECONDS_PER_SECOND / baud) * 10; 348a7d2d98cSAlistair Francis } 349a7d2d98cSAlistair Francis break; 35059093cc4SAlistair Francis case R_STATUS: 351a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, 352a7d2d98cSAlistair Francis "%s: status is read only\n", __func__); 353a7d2d98cSAlistair Francis break; 354a7d2d98cSAlistair Francis 35559093cc4SAlistair Francis case R_RDATA: 356a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, 357a7d2d98cSAlistair Francis "%s: rdata is read only\n", __func__); 358a7d2d98cSAlistair Francis break; 35959093cc4SAlistair Francis case R_WDATA: 360a7d2d98cSAlistair Francis uart_write_tx_fifo(s, (uint8_t *) &value, 1); 361a7d2d98cSAlistair Francis break; 362a7d2d98cSAlistair Francis 36359093cc4SAlistair Francis case R_FIFO_CTRL: 364a7d2d98cSAlistair Francis s->uart_fifo_ctrl = value; 365a7d2d98cSAlistair Francis 36659093cc4SAlistair Francis if (value & R_FIFO_CTRL_RXRST_MASK) { 367a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 368a7d2d98cSAlistair Francis "%s: RX fifos are not supported\n", __func__); 369a7d2d98cSAlistair Francis } 37059093cc4SAlistair Francis if (value & R_FIFO_CTRL_TXRST_MASK) { 371a7d2d98cSAlistair Francis s->tx_level = 0; 372a7d2d98cSAlistair Francis } 373a7d2d98cSAlistair Francis break; 37459093cc4SAlistair Francis case R_FIFO_STATUS: 375a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, 376a7d2d98cSAlistair Francis "%s: fifo_status is read only\n", __func__); 377a7d2d98cSAlistair Francis break; 378a7d2d98cSAlistair Francis 37959093cc4SAlistair Francis case R_OVRD: 380a7d2d98cSAlistair Francis s->uart_ovrd = value; 381a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 382a7d2d98cSAlistair Francis "%s: ovrd is not supported\n", __func__); 383a7d2d98cSAlistair Francis break; 38459093cc4SAlistair Francis case R_VAL: 385a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, 386a7d2d98cSAlistair Francis "%s: val is read only\n", __func__); 387a7d2d98cSAlistair Francis break; 38859093cc4SAlistair Francis case R_TIMEOUT_CTRL: 389a7d2d98cSAlistair Francis s->uart_timeout_ctrl = value; 390a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 391a7d2d98cSAlistair Francis "%s: timeout_ctrl is not supported\n", __func__); 392a7d2d98cSAlistair Francis break; 393a7d2d98cSAlistair Francis default: 394a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, 395a7d2d98cSAlistair Francis "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); 396a7d2d98cSAlistair Francis } 397a7d2d98cSAlistair Francis } 398a7d2d98cSAlistair Francis 399940aabb9SAlistair Francis static void ibex_uart_clk_update(void *opaque) 400940aabb9SAlistair Francis { 401940aabb9SAlistair Francis IbexUartState *s = opaque; 402940aabb9SAlistair Francis 403940aabb9SAlistair Francis /* recompute uart's speed on clock change */ 404940aabb9SAlistair Francis uint64_t baud = ibex_uart_get_baud(s); 405940aabb9SAlistair Francis 406940aabb9SAlistair Francis s->char_tx_time = (NANOSECONDS_PER_SECOND / baud) * 10; 407940aabb9SAlistair Francis } 408940aabb9SAlistair Francis 409a7d2d98cSAlistair Francis static void fifo_trigger_update(void *opaque) 410a7d2d98cSAlistair Francis { 411a7d2d98cSAlistair Francis IbexUartState *s = opaque; 412a7d2d98cSAlistair Francis 41359093cc4SAlistair Francis if (s->uart_ctrl & R_CTRL_TX_ENABLE_MASK) { 414a7d2d98cSAlistair Francis ibex_uart_xmit(NULL, G_IO_OUT, s); 415a7d2d98cSAlistair Francis } 416a7d2d98cSAlistair Francis } 417a7d2d98cSAlistair Francis 418a7d2d98cSAlistair Francis static const MemoryRegionOps ibex_uart_ops = { 419a7d2d98cSAlistair Francis .read = ibex_uart_read, 420a7d2d98cSAlistair Francis .write = ibex_uart_write, 421a7d2d98cSAlistair Francis .endianness = DEVICE_NATIVE_ENDIAN, 422a7d2d98cSAlistair Francis .impl.min_access_size = 4, 423a7d2d98cSAlistair Francis .impl.max_access_size = 4, 424a7d2d98cSAlistair Francis }; 425a7d2d98cSAlistair Francis 426a7d2d98cSAlistair Francis static int ibex_uart_post_load(void *opaque, int version_id) 427a7d2d98cSAlistair Francis { 428a7d2d98cSAlistair Francis IbexUartState *s = opaque; 429a7d2d98cSAlistair Francis 430a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 431a7d2d98cSAlistair Francis return 0; 432a7d2d98cSAlistair Francis } 433a7d2d98cSAlistair Francis 434a7d2d98cSAlistair Francis static const VMStateDescription vmstate_ibex_uart = { 435a7d2d98cSAlistair Francis .name = TYPE_IBEX_UART, 436a7d2d98cSAlistair Francis .version_id = 1, 437a7d2d98cSAlistair Francis .minimum_version_id = 1, 438a7d2d98cSAlistair Francis .post_load = ibex_uart_post_load, 439a7d2d98cSAlistair Francis .fields = (VMStateField[]) { 440a7d2d98cSAlistair Francis VMSTATE_UINT8_ARRAY(tx_fifo, IbexUartState, 441a7d2d98cSAlistair Francis IBEX_UART_TX_FIFO_SIZE), 442a7d2d98cSAlistair Francis VMSTATE_UINT32(tx_level, IbexUartState), 443a7d2d98cSAlistair Francis VMSTATE_UINT64(char_tx_time, IbexUartState), 444a7d2d98cSAlistair Francis VMSTATE_TIMER_PTR(fifo_trigger_handle, IbexUartState), 445a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_intr_state, IbexUartState), 446a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_intr_enable, IbexUartState), 447a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_ctrl, IbexUartState), 448a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_status, IbexUartState), 449a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_rdata, IbexUartState), 450a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_fifo_ctrl, IbexUartState), 451a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_fifo_status, IbexUartState), 452a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_ovrd, IbexUartState), 453a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_val, IbexUartState), 454a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_timeout_ctrl, IbexUartState), 455a7d2d98cSAlistair Francis VMSTATE_END_OF_LIST() 456a7d2d98cSAlistair Francis } 457a7d2d98cSAlistair Francis }; 458a7d2d98cSAlistair Francis 459a7d2d98cSAlistair Francis static Property ibex_uart_properties[] = { 460a7d2d98cSAlistair Francis DEFINE_PROP_CHR("chardev", IbexUartState, chr), 461a7d2d98cSAlistair Francis DEFINE_PROP_END_OF_LIST(), 462a7d2d98cSAlistair Francis }; 463a7d2d98cSAlistair Francis 464a7d2d98cSAlistair Francis static void ibex_uart_init(Object *obj) 465a7d2d98cSAlistair Francis { 466a7d2d98cSAlistair Francis IbexUartState *s = IBEX_UART(obj); 467a7d2d98cSAlistair Francis 468940aabb9SAlistair Francis s->f_clk = qdev_init_clock_in(DEVICE(obj), "f_clock", 469940aabb9SAlistair Francis ibex_uart_clk_update, s); 470940aabb9SAlistair Francis clock_set_hz(s->f_clk, IBEX_UART_CLOCK); 471940aabb9SAlistair Francis 472a7d2d98cSAlistair Francis sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_watermark); 473a7d2d98cSAlistair Francis sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_watermark); 474a7d2d98cSAlistair Francis sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_empty); 475a7d2d98cSAlistair Francis sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_overflow); 476a7d2d98cSAlistair Francis 477a7d2d98cSAlistair Francis memory_region_init_io(&s->mmio, obj, &ibex_uart_ops, s, 478a7d2d98cSAlistair Francis TYPE_IBEX_UART, 0x400); 479a7d2d98cSAlistair Francis sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); 480a7d2d98cSAlistair Francis } 481a7d2d98cSAlistair Francis 482a7d2d98cSAlistair Francis static void ibex_uart_realize(DeviceState *dev, Error **errp) 483a7d2d98cSAlistair Francis { 484a7d2d98cSAlistair Francis IbexUartState *s = IBEX_UART(dev); 485a7d2d98cSAlistair Francis 486a7d2d98cSAlistair Francis s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL, 487a7d2d98cSAlistair Francis fifo_trigger_update, s); 488a7d2d98cSAlistair Francis 489a7d2d98cSAlistair Francis qemu_chr_fe_set_handlers(&s->chr, ibex_uart_can_receive, 490a7d2d98cSAlistair Francis ibex_uart_receive, NULL, NULL, 491a7d2d98cSAlistair Francis s, NULL, true); 492a7d2d98cSAlistair Francis } 493a7d2d98cSAlistair Francis 494a7d2d98cSAlistair Francis static void ibex_uart_class_init(ObjectClass *klass, void *data) 495a7d2d98cSAlistair Francis { 496a7d2d98cSAlistair Francis DeviceClass *dc = DEVICE_CLASS(klass); 497a7d2d98cSAlistair Francis 498a7d2d98cSAlistair Francis dc->reset = ibex_uart_reset; 499a7d2d98cSAlistair Francis dc->realize = ibex_uart_realize; 500a7d2d98cSAlistair Francis dc->vmsd = &vmstate_ibex_uart; 501a7d2d98cSAlistair Francis device_class_set_props(dc, ibex_uart_properties); 502a7d2d98cSAlistair Francis } 503a7d2d98cSAlistair Francis 504a7d2d98cSAlistair Francis static const TypeInfo ibex_uart_info = { 505a7d2d98cSAlistair Francis .name = TYPE_IBEX_UART, 506a7d2d98cSAlistair Francis .parent = TYPE_SYS_BUS_DEVICE, 507a7d2d98cSAlistair Francis .instance_size = sizeof(IbexUartState), 508a7d2d98cSAlistair Francis .instance_init = ibex_uart_init, 509a7d2d98cSAlistair Francis .class_init = ibex_uart_class_init, 510a7d2d98cSAlistair Francis }; 511a7d2d98cSAlistair Francis 512a7d2d98cSAlistair Francis static void ibex_uart_register_types(void) 513a7d2d98cSAlistair Francis { 514a7d2d98cSAlistair Francis type_register_static(&ibex_uart_info); 515a7d2d98cSAlistair Francis } 516a7d2d98cSAlistair Francis 517a7d2d98cSAlistair Francis type_init(ibex_uart_register_types) 518