1*a7d2d98cSAlistair Francis /* 2*a7d2d98cSAlistair Francis * QEMU lowRISC Ibex UART device 3*a7d2d98cSAlistair Francis * 4*a7d2d98cSAlistair Francis * Copyright (c) 2020 Western Digital 5*a7d2d98cSAlistair Francis * 6*a7d2d98cSAlistair Francis * For details check the documentation here: 7*a7d2d98cSAlistair Francis * https://docs.opentitan.org/hw/ip/uart/doc/ 8*a7d2d98cSAlistair Francis * 9*a7d2d98cSAlistair Francis * Permission is hereby granted, free of charge, to any person obtaining a copy 10*a7d2d98cSAlistair Francis * of this software and associated documentation files (the "Software"), to deal 11*a7d2d98cSAlistair Francis * in the Software without restriction, including without limitation the rights 12*a7d2d98cSAlistair Francis * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13*a7d2d98cSAlistair Francis * copies of the Software, and to permit persons to whom the Software is 14*a7d2d98cSAlistair Francis * furnished to do so, subject to the following conditions: 15*a7d2d98cSAlistair Francis * 16*a7d2d98cSAlistair Francis * The above copyright notice and this permission notice shall be included in 17*a7d2d98cSAlistair Francis * all copies or substantial portions of the Software. 18*a7d2d98cSAlistair Francis * 19*a7d2d98cSAlistair Francis * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20*a7d2d98cSAlistair Francis * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21*a7d2d98cSAlistair Francis * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22*a7d2d98cSAlistair Francis * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23*a7d2d98cSAlistair Francis * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24*a7d2d98cSAlistair Francis * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25*a7d2d98cSAlistair Francis * THE SOFTWARE. 26*a7d2d98cSAlistair Francis */ 27*a7d2d98cSAlistair Francis 28*a7d2d98cSAlistair Francis #include "qemu/osdep.h" 29*a7d2d98cSAlistair Francis #include "hw/char/ibex_uart.h" 30*a7d2d98cSAlistair Francis #include "hw/irq.h" 31*a7d2d98cSAlistair Francis #include "hw/qdev-properties.h" 32*a7d2d98cSAlistair Francis #include "migration/vmstate.h" 33*a7d2d98cSAlistair Francis #include "qemu/log.h" 34*a7d2d98cSAlistair Francis #include "qemu/module.h" 35*a7d2d98cSAlistair Francis 36*a7d2d98cSAlistair Francis static void ibex_uart_update_irqs(IbexUartState *s) 37*a7d2d98cSAlistair Francis { 38*a7d2d98cSAlistair Francis if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_TX_WATERMARK) { 39*a7d2d98cSAlistair Francis qemu_set_irq(s->tx_watermark, 1); 40*a7d2d98cSAlistair Francis } else { 41*a7d2d98cSAlistair Francis qemu_set_irq(s->tx_watermark, 0); 42*a7d2d98cSAlistair Francis } 43*a7d2d98cSAlistair Francis 44*a7d2d98cSAlistair Francis if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_RX_WATERMARK) { 45*a7d2d98cSAlistair Francis qemu_set_irq(s->rx_watermark, 1); 46*a7d2d98cSAlistair Francis } else { 47*a7d2d98cSAlistair Francis qemu_set_irq(s->rx_watermark, 0); 48*a7d2d98cSAlistair Francis } 49*a7d2d98cSAlistair Francis 50*a7d2d98cSAlistair Francis if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_TX_EMPTY) { 51*a7d2d98cSAlistair Francis qemu_set_irq(s->tx_empty, 1); 52*a7d2d98cSAlistair Francis } else { 53*a7d2d98cSAlistair Francis qemu_set_irq(s->tx_empty, 0); 54*a7d2d98cSAlistair Francis } 55*a7d2d98cSAlistair Francis 56*a7d2d98cSAlistair Francis if (s->uart_intr_state & s->uart_intr_enable & INTR_STATE_RX_OVERFLOW) { 57*a7d2d98cSAlistair Francis qemu_set_irq(s->rx_overflow, 1); 58*a7d2d98cSAlistair Francis } else { 59*a7d2d98cSAlistair Francis qemu_set_irq(s->rx_overflow, 0); 60*a7d2d98cSAlistair Francis } 61*a7d2d98cSAlistair Francis } 62*a7d2d98cSAlistair Francis 63*a7d2d98cSAlistair Francis static int ibex_uart_can_receive(void *opaque) 64*a7d2d98cSAlistair Francis { 65*a7d2d98cSAlistair Francis IbexUartState *s = opaque; 66*a7d2d98cSAlistair Francis 67*a7d2d98cSAlistair Francis if (s->uart_ctrl & UART_CTRL_RX_ENABLE) { 68*a7d2d98cSAlistair Francis return 1; 69*a7d2d98cSAlistair Francis } 70*a7d2d98cSAlistair Francis 71*a7d2d98cSAlistair Francis return 0; 72*a7d2d98cSAlistair Francis } 73*a7d2d98cSAlistair Francis 74*a7d2d98cSAlistair Francis static void ibex_uart_receive(void *opaque, const uint8_t *buf, int size) 75*a7d2d98cSAlistair Francis { 76*a7d2d98cSAlistair Francis IbexUartState *s = opaque; 77*a7d2d98cSAlistair Francis uint8_t rx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_RXILVL) 78*a7d2d98cSAlistair Francis >> FIFO_CTRL_RXILVL_SHIFT; 79*a7d2d98cSAlistair Francis 80*a7d2d98cSAlistair Francis s->uart_rdata = *buf; 81*a7d2d98cSAlistair Francis 82*a7d2d98cSAlistair Francis s->uart_status &= ~UART_STATUS_RXIDLE; 83*a7d2d98cSAlistair Francis s->uart_status &= ~UART_STATUS_RXEMPTY; 84*a7d2d98cSAlistair Francis 85*a7d2d98cSAlistair Francis if (size > rx_fifo_level) { 86*a7d2d98cSAlistair Francis s->uart_intr_state |= INTR_STATE_RX_WATERMARK; 87*a7d2d98cSAlistair Francis } 88*a7d2d98cSAlistair Francis 89*a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 90*a7d2d98cSAlistair Francis } 91*a7d2d98cSAlistair Francis 92*a7d2d98cSAlistair Francis static gboolean ibex_uart_xmit(GIOChannel *chan, GIOCondition cond, 93*a7d2d98cSAlistair Francis void *opaque) 94*a7d2d98cSAlistair Francis { 95*a7d2d98cSAlistair Francis IbexUartState *s = opaque; 96*a7d2d98cSAlistair Francis uint8_t tx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_TXILVL) 97*a7d2d98cSAlistair Francis >> FIFO_CTRL_TXILVL_SHIFT; 98*a7d2d98cSAlistair Francis int ret; 99*a7d2d98cSAlistair Francis 100*a7d2d98cSAlistair Francis /* instant drain the fifo when there's no back-end */ 101*a7d2d98cSAlistair Francis if (!qemu_chr_fe_backend_connected(&s->chr)) { 102*a7d2d98cSAlistair Francis s->tx_level = 0; 103*a7d2d98cSAlistair Francis return FALSE; 104*a7d2d98cSAlistair Francis } 105*a7d2d98cSAlistair Francis 106*a7d2d98cSAlistair Francis if (!s->tx_level) { 107*a7d2d98cSAlistair Francis s->uart_status &= ~UART_STATUS_TXFULL; 108*a7d2d98cSAlistair Francis s->uart_status |= UART_STATUS_TXEMPTY; 109*a7d2d98cSAlistair Francis s->uart_intr_state |= INTR_STATE_TX_EMPTY; 110*a7d2d98cSAlistair Francis s->uart_intr_state &= ~INTR_STATE_TX_WATERMARK; 111*a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 112*a7d2d98cSAlistair Francis return FALSE; 113*a7d2d98cSAlistair Francis } 114*a7d2d98cSAlistair Francis 115*a7d2d98cSAlistair Francis ret = qemu_chr_fe_write(&s->chr, s->tx_fifo, s->tx_level); 116*a7d2d98cSAlistair Francis 117*a7d2d98cSAlistair Francis if (ret >= 0) { 118*a7d2d98cSAlistair Francis s->tx_level -= ret; 119*a7d2d98cSAlistair Francis memmove(s->tx_fifo, s->tx_fifo + ret, s->tx_level); 120*a7d2d98cSAlistair Francis } 121*a7d2d98cSAlistair Francis 122*a7d2d98cSAlistair Francis if (s->tx_level) { 123*a7d2d98cSAlistair Francis guint r = qemu_chr_fe_add_watch(&s->chr, G_IO_OUT | G_IO_HUP, 124*a7d2d98cSAlistair Francis ibex_uart_xmit, s); 125*a7d2d98cSAlistair Francis if (!r) { 126*a7d2d98cSAlistair Francis s->tx_level = 0; 127*a7d2d98cSAlistair Francis return FALSE; 128*a7d2d98cSAlistair Francis } 129*a7d2d98cSAlistair Francis } 130*a7d2d98cSAlistair Francis 131*a7d2d98cSAlistair Francis /* Clear the TX Full bit */ 132*a7d2d98cSAlistair Francis if (s->tx_level != IBEX_UART_TX_FIFO_SIZE) { 133*a7d2d98cSAlistair Francis s->uart_status &= ~UART_STATUS_TXFULL; 134*a7d2d98cSAlistair Francis } 135*a7d2d98cSAlistair Francis 136*a7d2d98cSAlistair Francis /* Disable the TX_WATERMARK IRQ */ 137*a7d2d98cSAlistair Francis if (s->tx_level < tx_fifo_level) { 138*a7d2d98cSAlistair Francis s->uart_intr_state &= ~INTR_STATE_TX_WATERMARK; 139*a7d2d98cSAlistair Francis } 140*a7d2d98cSAlistair Francis 141*a7d2d98cSAlistair Francis /* Set TX empty */ 142*a7d2d98cSAlistair Francis if (s->tx_level == 0) { 143*a7d2d98cSAlistair Francis s->uart_status |= UART_STATUS_TXEMPTY; 144*a7d2d98cSAlistair Francis s->uart_intr_state |= INTR_STATE_TX_EMPTY; 145*a7d2d98cSAlistair Francis } 146*a7d2d98cSAlistair Francis 147*a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 148*a7d2d98cSAlistair Francis return FALSE; 149*a7d2d98cSAlistair Francis } 150*a7d2d98cSAlistair Francis 151*a7d2d98cSAlistair Francis static void uart_write_tx_fifo(IbexUartState *s, const uint8_t *buf, 152*a7d2d98cSAlistair Francis int size) 153*a7d2d98cSAlistair Francis { 154*a7d2d98cSAlistair Francis uint64_t current_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 155*a7d2d98cSAlistair Francis uint8_t tx_fifo_level = (s->uart_fifo_ctrl & FIFO_CTRL_TXILVL) 156*a7d2d98cSAlistair Francis >> FIFO_CTRL_TXILVL_SHIFT; 157*a7d2d98cSAlistair Francis 158*a7d2d98cSAlistair Francis if (size > IBEX_UART_TX_FIFO_SIZE - s->tx_level) { 159*a7d2d98cSAlistair Francis size = IBEX_UART_TX_FIFO_SIZE - s->tx_level; 160*a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, "ibex_uart: TX FIFO overflow"); 161*a7d2d98cSAlistair Francis } 162*a7d2d98cSAlistair Francis 163*a7d2d98cSAlistair Francis memcpy(s->tx_fifo + s->tx_level, buf, size); 164*a7d2d98cSAlistair Francis s->tx_level += size; 165*a7d2d98cSAlistair Francis 166*a7d2d98cSAlistair Francis if (s->tx_level > 0) { 167*a7d2d98cSAlistair Francis s->uart_status &= ~UART_STATUS_TXEMPTY; 168*a7d2d98cSAlistair Francis } 169*a7d2d98cSAlistair Francis 170*a7d2d98cSAlistair Francis if (s->tx_level >= tx_fifo_level) { 171*a7d2d98cSAlistair Francis s->uart_intr_state |= INTR_STATE_TX_WATERMARK; 172*a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 173*a7d2d98cSAlistair Francis } 174*a7d2d98cSAlistair Francis 175*a7d2d98cSAlistair Francis if (s->tx_level == IBEX_UART_TX_FIFO_SIZE) { 176*a7d2d98cSAlistair Francis s->uart_status |= UART_STATUS_TXFULL; 177*a7d2d98cSAlistair Francis } 178*a7d2d98cSAlistair Francis 179*a7d2d98cSAlistair Francis timer_mod(s->fifo_trigger_handle, current_time + 180*a7d2d98cSAlistair Francis (s->char_tx_time * 4)); 181*a7d2d98cSAlistair Francis } 182*a7d2d98cSAlistair Francis 183*a7d2d98cSAlistair Francis static void ibex_uart_reset(DeviceState *dev) 184*a7d2d98cSAlistair Francis { 185*a7d2d98cSAlistair Francis IbexUartState *s = IBEX_UART(dev); 186*a7d2d98cSAlistair Francis 187*a7d2d98cSAlistair Francis s->uart_intr_state = 0x00000000; 188*a7d2d98cSAlistair Francis s->uart_intr_state = 0x00000000; 189*a7d2d98cSAlistair Francis s->uart_intr_enable = 0x00000000; 190*a7d2d98cSAlistair Francis s->uart_ctrl = 0x00000000; 191*a7d2d98cSAlistair Francis s->uart_status = 0x0000003c; 192*a7d2d98cSAlistair Francis s->uart_rdata = 0x00000000; 193*a7d2d98cSAlistair Francis s->uart_fifo_ctrl = 0x00000000; 194*a7d2d98cSAlistair Francis s->uart_fifo_status = 0x00000000; 195*a7d2d98cSAlistair Francis s->uart_ovrd = 0x00000000; 196*a7d2d98cSAlistair Francis s->uart_val = 0x00000000; 197*a7d2d98cSAlistair Francis s->uart_timeout_ctrl = 0x00000000; 198*a7d2d98cSAlistair Francis 199*a7d2d98cSAlistair Francis s->tx_level = 0; 200*a7d2d98cSAlistair Francis 201*a7d2d98cSAlistair Francis s->char_tx_time = (NANOSECONDS_PER_SECOND / 230400) * 10; 202*a7d2d98cSAlistair Francis 203*a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 204*a7d2d98cSAlistair Francis } 205*a7d2d98cSAlistair Francis 206*a7d2d98cSAlistair Francis static uint64_t ibex_uart_read(void *opaque, hwaddr addr, 207*a7d2d98cSAlistair Francis unsigned int size) 208*a7d2d98cSAlistair Francis { 209*a7d2d98cSAlistair Francis IbexUartState *s = opaque; 210*a7d2d98cSAlistair Francis uint64_t retvalue = 0; 211*a7d2d98cSAlistair Francis 212*a7d2d98cSAlistair Francis switch (addr) { 213*a7d2d98cSAlistair Francis case IBEX_UART_INTR_STATE: 214*a7d2d98cSAlistair Francis retvalue = s->uart_intr_state; 215*a7d2d98cSAlistair Francis break; 216*a7d2d98cSAlistair Francis case IBEX_UART_INTR_ENABLE: 217*a7d2d98cSAlistair Francis retvalue = s->uart_intr_enable; 218*a7d2d98cSAlistair Francis break; 219*a7d2d98cSAlistair Francis case IBEX_UART_INTR_TEST: 220*a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, 221*a7d2d98cSAlistair Francis "%s: wdata is write only\n", __func__); 222*a7d2d98cSAlistair Francis break; 223*a7d2d98cSAlistair Francis 224*a7d2d98cSAlistair Francis case IBEX_UART_CTRL: 225*a7d2d98cSAlistair Francis retvalue = s->uart_ctrl; 226*a7d2d98cSAlistair Francis break; 227*a7d2d98cSAlistair Francis case IBEX_UART_STATUS: 228*a7d2d98cSAlistair Francis retvalue = s->uart_status; 229*a7d2d98cSAlistair Francis break; 230*a7d2d98cSAlistair Francis 231*a7d2d98cSAlistair Francis case IBEX_UART_RDATA: 232*a7d2d98cSAlistair Francis retvalue = s->uart_rdata; 233*a7d2d98cSAlistair Francis if (s->uart_ctrl & UART_CTRL_RX_ENABLE) { 234*a7d2d98cSAlistair Francis qemu_chr_fe_accept_input(&s->chr); 235*a7d2d98cSAlistair Francis 236*a7d2d98cSAlistair Francis s->uart_status |= UART_STATUS_RXIDLE; 237*a7d2d98cSAlistair Francis s->uart_status |= UART_STATUS_RXEMPTY; 238*a7d2d98cSAlistair Francis } 239*a7d2d98cSAlistair Francis break; 240*a7d2d98cSAlistair Francis case IBEX_UART_WDATA: 241*a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, 242*a7d2d98cSAlistair Francis "%s: wdata is write only\n", __func__); 243*a7d2d98cSAlistair Francis break; 244*a7d2d98cSAlistair Francis 245*a7d2d98cSAlistair Francis case IBEX_UART_FIFO_CTRL: 246*a7d2d98cSAlistair Francis retvalue = s->uart_fifo_ctrl; 247*a7d2d98cSAlistair Francis break; 248*a7d2d98cSAlistair Francis case IBEX_UART_FIFO_STATUS: 249*a7d2d98cSAlistair Francis retvalue = s->uart_fifo_status; 250*a7d2d98cSAlistair Francis 251*a7d2d98cSAlistair Francis retvalue |= s->tx_level & 0x1F; 252*a7d2d98cSAlistair Francis 253*a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 254*a7d2d98cSAlistair Francis "%s: RX fifos are not supported\n", __func__); 255*a7d2d98cSAlistair Francis break; 256*a7d2d98cSAlistair Francis 257*a7d2d98cSAlistair Francis case IBEX_UART_OVRD: 258*a7d2d98cSAlistair Francis retvalue = s->uart_ovrd; 259*a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 260*a7d2d98cSAlistair Francis "%s: ovrd is not supported\n", __func__); 261*a7d2d98cSAlistair Francis break; 262*a7d2d98cSAlistair Francis case IBEX_UART_VAL: 263*a7d2d98cSAlistair Francis retvalue = s->uart_val; 264*a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 265*a7d2d98cSAlistair Francis "%s: val is not supported\n", __func__); 266*a7d2d98cSAlistair Francis break; 267*a7d2d98cSAlistair Francis case IBEX_UART_TIMEOUT_CTRL: 268*a7d2d98cSAlistair Francis retvalue = s->uart_timeout_ctrl; 269*a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 270*a7d2d98cSAlistair Francis "%s: timeout_ctrl is not supported\n", __func__); 271*a7d2d98cSAlistair Francis break; 272*a7d2d98cSAlistair Francis default: 273*a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, 274*a7d2d98cSAlistair Francis "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); 275*a7d2d98cSAlistair Francis return 0; 276*a7d2d98cSAlistair Francis } 277*a7d2d98cSAlistair Francis 278*a7d2d98cSAlistair Francis return retvalue; 279*a7d2d98cSAlistair Francis } 280*a7d2d98cSAlistair Francis 281*a7d2d98cSAlistair Francis static void ibex_uart_write(void *opaque, hwaddr addr, 282*a7d2d98cSAlistair Francis uint64_t val64, unsigned int size) 283*a7d2d98cSAlistair Francis { 284*a7d2d98cSAlistair Francis IbexUartState *s = opaque; 285*a7d2d98cSAlistair Francis uint32_t value = val64; 286*a7d2d98cSAlistair Francis 287*a7d2d98cSAlistair Francis switch (addr) { 288*a7d2d98cSAlistair Francis case IBEX_UART_INTR_STATE: 289*a7d2d98cSAlistair Francis /* Write 1 clear */ 290*a7d2d98cSAlistair Francis s->uart_intr_state &= ~value; 291*a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 292*a7d2d98cSAlistair Francis break; 293*a7d2d98cSAlistair Francis case IBEX_UART_INTR_ENABLE: 294*a7d2d98cSAlistair Francis s->uart_intr_enable = value; 295*a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 296*a7d2d98cSAlistair Francis break; 297*a7d2d98cSAlistair Francis case IBEX_UART_INTR_TEST: 298*a7d2d98cSAlistair Francis s->uart_intr_state |= value; 299*a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 300*a7d2d98cSAlistair Francis break; 301*a7d2d98cSAlistair Francis 302*a7d2d98cSAlistair Francis case IBEX_UART_CTRL: 303*a7d2d98cSAlistair Francis s->uart_ctrl = value; 304*a7d2d98cSAlistair Francis 305*a7d2d98cSAlistair Francis if (value & UART_CTRL_NF) { 306*a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 307*a7d2d98cSAlistair Francis "%s: UART_CTRL_NF is not supported\n", __func__); 308*a7d2d98cSAlistair Francis } 309*a7d2d98cSAlistair Francis if (value & UART_CTRL_SLPBK) { 310*a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 311*a7d2d98cSAlistair Francis "%s: UART_CTRL_SLPBK is not supported\n", __func__); 312*a7d2d98cSAlistair Francis } 313*a7d2d98cSAlistair Francis if (value & UART_CTRL_LLPBK) { 314*a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 315*a7d2d98cSAlistair Francis "%s: UART_CTRL_LLPBK is not supported\n", __func__); 316*a7d2d98cSAlistair Francis } 317*a7d2d98cSAlistair Francis if (value & UART_CTRL_PARITY_EN) { 318*a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 319*a7d2d98cSAlistair Francis "%s: UART_CTRL_PARITY_EN is not supported\n", 320*a7d2d98cSAlistair Francis __func__); 321*a7d2d98cSAlistair Francis } 322*a7d2d98cSAlistair Francis if (value & UART_CTRL_PARITY_ODD) { 323*a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 324*a7d2d98cSAlistair Francis "%s: UART_CTRL_PARITY_ODD is not supported\n", 325*a7d2d98cSAlistair Francis __func__); 326*a7d2d98cSAlistair Francis } 327*a7d2d98cSAlistair Francis if (value & UART_CTRL_RXBLVL) { 328*a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 329*a7d2d98cSAlistair Francis "%s: UART_CTRL_RXBLVL is not supported\n", __func__); 330*a7d2d98cSAlistair Francis } 331*a7d2d98cSAlistair Francis if (value & UART_CTRL_NCO) { 332*a7d2d98cSAlistair Francis uint64_t baud = ((value & UART_CTRL_NCO) >> 16); 333*a7d2d98cSAlistair Francis baud *= 1000; 334*a7d2d98cSAlistair Francis baud /= 2 ^ 20; 335*a7d2d98cSAlistair Francis 336*a7d2d98cSAlistair Francis s->char_tx_time = (NANOSECONDS_PER_SECOND / baud) * 10; 337*a7d2d98cSAlistair Francis } 338*a7d2d98cSAlistair Francis break; 339*a7d2d98cSAlistair Francis case IBEX_UART_STATUS: 340*a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, 341*a7d2d98cSAlistair Francis "%s: status is read only\n", __func__); 342*a7d2d98cSAlistair Francis break; 343*a7d2d98cSAlistair Francis 344*a7d2d98cSAlistair Francis case IBEX_UART_RDATA: 345*a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, 346*a7d2d98cSAlistair Francis "%s: rdata is read only\n", __func__); 347*a7d2d98cSAlistair Francis break; 348*a7d2d98cSAlistair Francis case IBEX_UART_WDATA: 349*a7d2d98cSAlistair Francis uart_write_tx_fifo(s, (uint8_t *) &value, 1); 350*a7d2d98cSAlistair Francis break; 351*a7d2d98cSAlistair Francis 352*a7d2d98cSAlistair Francis case IBEX_UART_FIFO_CTRL: 353*a7d2d98cSAlistair Francis s->uart_fifo_ctrl = value; 354*a7d2d98cSAlistair Francis 355*a7d2d98cSAlistair Francis if (value & FIFO_CTRL_RXRST) { 356*a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 357*a7d2d98cSAlistair Francis "%s: RX fifos are not supported\n", __func__); 358*a7d2d98cSAlistair Francis } 359*a7d2d98cSAlistair Francis if (value & FIFO_CTRL_TXRST) { 360*a7d2d98cSAlistair Francis s->tx_level = 0; 361*a7d2d98cSAlistair Francis } 362*a7d2d98cSAlistair Francis break; 363*a7d2d98cSAlistair Francis case IBEX_UART_FIFO_STATUS: 364*a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, 365*a7d2d98cSAlistair Francis "%s: fifo_status is read only\n", __func__); 366*a7d2d98cSAlistair Francis break; 367*a7d2d98cSAlistair Francis 368*a7d2d98cSAlistair Francis case IBEX_UART_OVRD: 369*a7d2d98cSAlistair Francis s->uart_ovrd = value; 370*a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 371*a7d2d98cSAlistair Francis "%s: ovrd is not supported\n", __func__); 372*a7d2d98cSAlistair Francis break; 373*a7d2d98cSAlistair Francis case IBEX_UART_VAL: 374*a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, 375*a7d2d98cSAlistair Francis "%s: val is read only\n", __func__); 376*a7d2d98cSAlistair Francis break; 377*a7d2d98cSAlistair Francis case IBEX_UART_TIMEOUT_CTRL: 378*a7d2d98cSAlistair Francis s->uart_timeout_ctrl = value; 379*a7d2d98cSAlistair Francis qemu_log_mask(LOG_UNIMP, 380*a7d2d98cSAlistair Francis "%s: timeout_ctrl is not supported\n", __func__); 381*a7d2d98cSAlistair Francis break; 382*a7d2d98cSAlistair Francis default: 383*a7d2d98cSAlistair Francis qemu_log_mask(LOG_GUEST_ERROR, 384*a7d2d98cSAlistair Francis "%s: Bad offset 0x%"HWADDR_PRIx"\n", __func__, addr); 385*a7d2d98cSAlistair Francis } 386*a7d2d98cSAlistair Francis } 387*a7d2d98cSAlistair Francis 388*a7d2d98cSAlistair Francis static void fifo_trigger_update(void *opaque) 389*a7d2d98cSAlistair Francis { 390*a7d2d98cSAlistair Francis IbexUartState *s = opaque; 391*a7d2d98cSAlistair Francis 392*a7d2d98cSAlistair Francis if (s->uart_ctrl & UART_CTRL_TX_ENABLE) { 393*a7d2d98cSAlistair Francis ibex_uart_xmit(NULL, G_IO_OUT, s); 394*a7d2d98cSAlistair Francis } 395*a7d2d98cSAlistair Francis } 396*a7d2d98cSAlistair Francis 397*a7d2d98cSAlistair Francis static const MemoryRegionOps ibex_uart_ops = { 398*a7d2d98cSAlistair Francis .read = ibex_uart_read, 399*a7d2d98cSAlistair Francis .write = ibex_uart_write, 400*a7d2d98cSAlistair Francis .endianness = DEVICE_NATIVE_ENDIAN, 401*a7d2d98cSAlistair Francis .impl.min_access_size = 4, 402*a7d2d98cSAlistair Francis .impl.max_access_size = 4, 403*a7d2d98cSAlistair Francis }; 404*a7d2d98cSAlistair Francis 405*a7d2d98cSAlistair Francis static int ibex_uart_post_load(void *opaque, int version_id) 406*a7d2d98cSAlistair Francis { 407*a7d2d98cSAlistair Francis IbexUartState *s = opaque; 408*a7d2d98cSAlistair Francis 409*a7d2d98cSAlistair Francis ibex_uart_update_irqs(s); 410*a7d2d98cSAlistair Francis return 0; 411*a7d2d98cSAlistair Francis } 412*a7d2d98cSAlistair Francis 413*a7d2d98cSAlistair Francis static const VMStateDescription vmstate_ibex_uart = { 414*a7d2d98cSAlistair Francis .name = TYPE_IBEX_UART, 415*a7d2d98cSAlistair Francis .version_id = 1, 416*a7d2d98cSAlistair Francis .minimum_version_id = 1, 417*a7d2d98cSAlistair Francis .post_load = ibex_uart_post_load, 418*a7d2d98cSAlistair Francis .fields = (VMStateField[]) { 419*a7d2d98cSAlistair Francis VMSTATE_UINT8_ARRAY(tx_fifo, IbexUartState, 420*a7d2d98cSAlistair Francis IBEX_UART_TX_FIFO_SIZE), 421*a7d2d98cSAlistair Francis VMSTATE_UINT32(tx_level, IbexUartState), 422*a7d2d98cSAlistair Francis VMSTATE_UINT64(char_tx_time, IbexUartState), 423*a7d2d98cSAlistair Francis VMSTATE_TIMER_PTR(fifo_trigger_handle, IbexUartState), 424*a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_intr_state, IbexUartState), 425*a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_intr_enable, IbexUartState), 426*a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_ctrl, IbexUartState), 427*a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_status, IbexUartState), 428*a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_rdata, IbexUartState), 429*a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_fifo_ctrl, IbexUartState), 430*a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_fifo_status, IbexUartState), 431*a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_ovrd, IbexUartState), 432*a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_val, IbexUartState), 433*a7d2d98cSAlistair Francis VMSTATE_UINT32(uart_timeout_ctrl, IbexUartState), 434*a7d2d98cSAlistair Francis VMSTATE_END_OF_LIST() 435*a7d2d98cSAlistair Francis } 436*a7d2d98cSAlistair Francis }; 437*a7d2d98cSAlistair Francis 438*a7d2d98cSAlistair Francis static Property ibex_uart_properties[] = { 439*a7d2d98cSAlistair Francis DEFINE_PROP_CHR("chardev", IbexUartState, chr), 440*a7d2d98cSAlistair Francis DEFINE_PROP_END_OF_LIST(), 441*a7d2d98cSAlistair Francis }; 442*a7d2d98cSAlistair Francis 443*a7d2d98cSAlistair Francis static void ibex_uart_init(Object *obj) 444*a7d2d98cSAlistair Francis { 445*a7d2d98cSAlistair Francis IbexUartState *s = IBEX_UART(obj); 446*a7d2d98cSAlistair Francis 447*a7d2d98cSAlistair Francis sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_watermark); 448*a7d2d98cSAlistair Francis sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_watermark); 449*a7d2d98cSAlistair Francis sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->tx_empty); 450*a7d2d98cSAlistair Francis sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->rx_overflow); 451*a7d2d98cSAlistair Francis 452*a7d2d98cSAlistair Francis memory_region_init_io(&s->mmio, obj, &ibex_uart_ops, s, 453*a7d2d98cSAlistair Francis TYPE_IBEX_UART, 0x400); 454*a7d2d98cSAlistair Francis sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); 455*a7d2d98cSAlistair Francis } 456*a7d2d98cSAlistair Francis 457*a7d2d98cSAlistair Francis static void ibex_uart_realize(DeviceState *dev, Error **errp) 458*a7d2d98cSAlistair Francis { 459*a7d2d98cSAlistair Francis IbexUartState *s = IBEX_UART(dev); 460*a7d2d98cSAlistair Francis 461*a7d2d98cSAlistair Francis s->fifo_trigger_handle = timer_new_ns(QEMU_CLOCK_VIRTUAL, 462*a7d2d98cSAlistair Francis fifo_trigger_update, s); 463*a7d2d98cSAlistair Francis 464*a7d2d98cSAlistair Francis qemu_chr_fe_set_handlers(&s->chr, ibex_uart_can_receive, 465*a7d2d98cSAlistair Francis ibex_uart_receive, NULL, NULL, 466*a7d2d98cSAlistair Francis s, NULL, true); 467*a7d2d98cSAlistair Francis } 468*a7d2d98cSAlistair Francis 469*a7d2d98cSAlistair Francis static void ibex_uart_class_init(ObjectClass *klass, void *data) 470*a7d2d98cSAlistair Francis { 471*a7d2d98cSAlistair Francis DeviceClass *dc = DEVICE_CLASS(klass); 472*a7d2d98cSAlistair Francis 473*a7d2d98cSAlistair Francis dc->reset = ibex_uart_reset; 474*a7d2d98cSAlistair Francis dc->realize = ibex_uart_realize; 475*a7d2d98cSAlistair Francis dc->vmsd = &vmstate_ibex_uart; 476*a7d2d98cSAlistair Francis device_class_set_props(dc, ibex_uart_properties); 477*a7d2d98cSAlistair Francis } 478*a7d2d98cSAlistair Francis 479*a7d2d98cSAlistair Francis static const TypeInfo ibex_uart_info = { 480*a7d2d98cSAlistair Francis .name = TYPE_IBEX_UART, 481*a7d2d98cSAlistair Francis .parent = TYPE_SYS_BUS_DEVICE, 482*a7d2d98cSAlistair Francis .instance_size = sizeof(IbexUartState), 483*a7d2d98cSAlistair Francis .instance_init = ibex_uart_init, 484*a7d2d98cSAlistair Francis .class_init = ibex_uart_class_init, 485*a7d2d98cSAlistair Francis }; 486*a7d2d98cSAlistair Francis 487*a7d2d98cSAlistair Francis static void ibex_uart_register_types(void) 488*a7d2d98cSAlistair Francis { 489*a7d2d98cSAlistair Francis type_register_static(&ibex_uart_info); 490*a7d2d98cSAlistair Francis } 491*a7d2d98cSAlistair Francis 492*a7d2d98cSAlistair Francis type_init(ibex_uart_register_types) 493