1 /* 2 * QEMU model of Xilinx uartlite. 3 * 4 * Copyright (c) 2009 Edgar E. Iglesias. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a copy 7 * of this software and associated documentation files (the "Software"), to deal 8 * in the Software without restriction, including without limitation the rights 9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 * copies of the Software, and to permit persons to whom the Software is 11 * furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 * THE SOFTWARE. 23 */ 24 25 #include "qemu/osdep.h" 26 #include "qemu/log.h" 27 #include "qapi/error.h" 28 #include "hw/char/xilinx_uartlite.h" 29 #include "hw/irq.h" 30 #include "hw/qdev-properties.h" 31 #include "hw/qdev-properties-system.h" 32 #include "hw/sysbus.h" 33 #include "qemu/module.h" 34 #include "chardev/char-fe.h" 35 #include "qom/object.h" 36 37 #define DUART(x) 38 39 #define R_RX 0 40 #define R_TX 1 41 #define R_STATUS 2 42 #define R_CTRL 3 43 #define R_MAX 4 44 45 #define STATUS_RXVALID 0x01 46 #define STATUS_RXFULL 0x02 47 #define STATUS_TXEMPTY 0x04 48 #define STATUS_TXFULL 0x08 49 #define STATUS_IE 0x10 50 #define STATUS_OVERRUN 0x20 51 #define STATUS_FRAME 0x40 52 #define STATUS_PARITY 0x80 53 54 #define CONTROL_RST_TX 0x01 55 #define CONTROL_RST_RX 0x02 56 #define CONTROL_IE 0x10 57 58 struct XilinxUARTLite { 59 SysBusDevice parent_obj; 60 61 EndianMode model_endianness; 62 MemoryRegion mmio; 63 CharBackend chr; 64 qemu_irq irq; 65 66 uint8_t rx_fifo[8]; 67 unsigned int rx_fifo_pos; 68 unsigned int rx_fifo_len; 69 70 uint32_t regs[R_MAX]; 71 }; 72 73 static void uart_update_irq(XilinxUARTLite *s) 74 { 75 unsigned int irq; 76 77 if (s->rx_fifo_len) 78 s->regs[R_STATUS] |= STATUS_IE; 79 80 irq = (s->regs[R_STATUS] & STATUS_IE) && (s->regs[R_CTRL] & CONTROL_IE); 81 qemu_set_irq(s->irq, irq); 82 } 83 84 static void uart_update_status(XilinxUARTLite *s) 85 { 86 uint32_t r; 87 88 r = s->regs[R_STATUS]; 89 r &= ~7; 90 r |= 1 << 2; /* Tx fifo is always empty. We are fast :) */ 91 r |= (s->rx_fifo_len == sizeof (s->rx_fifo)) << 1; 92 r |= (!!s->rx_fifo_len); 93 s->regs[R_STATUS] = r; 94 } 95 96 static void xilinx_uartlite_reset(DeviceState *dev) 97 { 98 uart_update_status(XILINX_UARTLITE(dev)); 99 } 100 101 static uint64_t 102 uart_read(void *opaque, hwaddr addr, unsigned int size) 103 { 104 XilinxUARTLite *s = opaque; 105 uint32_t r = 0; 106 addr >>= 2; 107 switch (addr) 108 { 109 case R_RX: 110 r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 7]; 111 if (s->rx_fifo_len) 112 s->rx_fifo_len--; 113 uart_update_status(s); 114 uart_update_irq(s); 115 qemu_chr_fe_accept_input(&s->chr); 116 break; 117 118 default: 119 if (addr < ARRAY_SIZE(s->regs)) 120 r = s->regs[addr]; 121 DUART(qemu_log("%s addr=%x v=%x\n", __func__, addr, r)); 122 break; 123 } 124 return r; 125 } 126 127 static void 128 uart_write(void *opaque, hwaddr addr, 129 uint64_t val64, unsigned int size) 130 { 131 XilinxUARTLite *s = opaque; 132 uint32_t value = val64; 133 unsigned char ch = value; 134 135 addr >>= 2; 136 switch (addr) 137 { 138 case R_STATUS: 139 qemu_log_mask(LOG_GUEST_ERROR, "%s: write to UART STATUS\n", 140 __func__); 141 break; 142 143 case R_CTRL: 144 if (value & CONTROL_RST_RX) { 145 s->rx_fifo_pos = 0; 146 s->rx_fifo_len = 0; 147 } 148 s->regs[addr] = value; 149 break; 150 151 case R_TX: 152 /* XXX this blocks entire thread. Rewrite to use 153 * qemu_chr_fe_write and background I/O callbacks */ 154 qemu_chr_fe_write_all(&s->chr, &ch, 1); 155 s->regs[addr] = value; 156 157 /* hax. */ 158 s->regs[R_STATUS] |= STATUS_IE; 159 break; 160 161 default: 162 DUART(printf("%s addr=%x v=%x\n", __func__, addr, value)); 163 if (addr < ARRAY_SIZE(s->regs)) 164 s->regs[addr] = value; 165 break; 166 } 167 uart_update_status(s); 168 uart_update_irq(s); 169 } 170 171 static const MemoryRegionOps uart_ops[2] = { 172 [0 ... 1] = { 173 .read = uart_read, 174 .write = uart_write, 175 .valid = { 176 .min_access_size = 1, 177 .max_access_size = 4, 178 }, 179 }, 180 [0].endianness = DEVICE_LITTLE_ENDIAN, 181 [1].endianness = DEVICE_BIG_ENDIAN, 182 }; 183 184 static const Property xilinx_uartlite_properties[] = { 185 DEFINE_PROP_ENDIAN_NODEFAULT("endianness", XilinxUARTLite, model_endianness), 186 DEFINE_PROP_CHR("chardev", XilinxUARTLite, chr), 187 }; 188 189 static void uart_rx(void *opaque, const uint8_t *buf, int size) 190 { 191 XilinxUARTLite *s = opaque; 192 193 /* Got a byte. */ 194 if (s->rx_fifo_len >= 8) { 195 printf("WARNING: UART dropped char.\n"); 196 return; 197 } 198 s->rx_fifo[s->rx_fifo_pos] = *buf; 199 s->rx_fifo_pos++; 200 s->rx_fifo_pos &= 0x7; 201 s->rx_fifo_len++; 202 203 uart_update_status(s); 204 uart_update_irq(s); 205 } 206 207 static int uart_can_rx(void *opaque) 208 { 209 XilinxUARTLite *s = opaque; 210 211 return s->rx_fifo_len < sizeof(s->rx_fifo); 212 } 213 214 static void uart_event(void *opaque, QEMUChrEvent event) 215 { 216 217 } 218 219 static void xilinx_uartlite_realize(DeviceState *dev, Error **errp) 220 { 221 XilinxUARTLite *s = XILINX_UARTLITE(dev); 222 223 if (s->model_endianness == ENDIAN_MODE_UNSPECIFIED) { 224 error_setg(errp, TYPE_XILINX_UARTLITE " property 'endianness'" 225 " must be set to 'big' or 'little'"); 226 return; 227 } 228 229 memory_region_init_io(&s->mmio, OBJECT(dev), 230 &uart_ops[s->model_endianness == ENDIAN_MODE_BIG], 231 s, "xlnx.xps-uartlite", R_MAX * 4); 232 qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx, 233 uart_event, NULL, s, NULL, true); 234 } 235 236 static void xilinx_uartlite_init(Object *obj) 237 { 238 XilinxUARTLite *s = XILINX_UARTLITE(obj); 239 240 sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); 241 sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); 242 } 243 244 static void xilinx_uartlite_class_init(ObjectClass *klass, const void *data) 245 { 246 DeviceClass *dc = DEVICE_CLASS(klass); 247 248 device_class_set_legacy_reset(dc, xilinx_uartlite_reset); 249 dc->realize = xilinx_uartlite_realize; 250 device_class_set_props(dc, xilinx_uartlite_properties); 251 } 252 253 static const TypeInfo xilinx_uartlite_info = { 254 .name = TYPE_XILINX_UARTLITE, 255 .parent = TYPE_SYS_BUS_DEVICE, 256 .instance_size = sizeof(XilinxUARTLite), 257 .instance_init = xilinx_uartlite_init, 258 .class_init = xilinx_uartlite_class_init, 259 }; 260 261 static void xilinx_uart_register_types(void) 262 { 263 type_register_static(&xilinx_uartlite_info); 264 } 265 266 type_init(xilinx_uart_register_types) 267