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