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 "hw/sysbus.h" 27 #include "qemu/module.h" 28 #include "chardev/char-fe.h" 29 30 #define DUART(x) 31 32 #define R_RX 0 33 #define R_TX 1 34 #define R_STATUS 2 35 #define R_CTRL 3 36 #define R_MAX 4 37 38 #define STATUS_RXVALID 0x01 39 #define STATUS_RXFULL 0x02 40 #define STATUS_TXEMPTY 0x04 41 #define STATUS_TXFULL 0x08 42 #define STATUS_IE 0x10 43 #define STATUS_OVERRUN 0x20 44 #define STATUS_FRAME 0x40 45 #define STATUS_PARITY 0x80 46 47 #define CONTROL_RST_TX 0x01 48 #define CONTROL_RST_RX 0x02 49 #define CONTROL_IE 0x10 50 51 #define TYPE_XILINX_UARTLITE "xlnx.xps-uartlite" 52 #define XILINX_UARTLITE(obj) \ 53 OBJECT_CHECK(XilinxUARTLite, (obj), TYPE_XILINX_UARTLITE) 54 55 typedef struct XilinxUARTLite { 56 SysBusDevice parent_obj; 57 58 MemoryRegion mmio; 59 CharBackend chr; 60 qemu_irq irq; 61 62 uint8_t rx_fifo[8]; 63 unsigned int rx_fifo_pos; 64 unsigned int rx_fifo_len; 65 66 uint32_t regs[R_MAX]; 67 } XilinxUARTLite; 68 69 static void uart_update_irq(XilinxUARTLite *s) 70 { 71 unsigned int irq; 72 73 if (s->rx_fifo_len) 74 s->regs[R_STATUS] |= STATUS_IE; 75 76 irq = (s->regs[R_STATUS] & STATUS_IE) && (s->regs[R_CTRL] & CONTROL_IE); 77 qemu_set_irq(s->irq, irq); 78 } 79 80 static void uart_update_status(XilinxUARTLite *s) 81 { 82 uint32_t r; 83 84 r = s->regs[R_STATUS]; 85 r &= ~7; 86 r |= 1 << 2; /* Tx fifo is always empty. We are fast :) */ 87 r |= (s->rx_fifo_len == sizeof (s->rx_fifo)) << 1; 88 r |= (!!s->rx_fifo_len); 89 s->regs[R_STATUS] = r; 90 } 91 92 static void xilinx_uartlite_reset(DeviceState *dev) 93 { 94 uart_update_status(XILINX_UARTLITE(dev)); 95 } 96 97 static uint64_t 98 uart_read(void *opaque, hwaddr addr, unsigned int size) 99 { 100 XilinxUARTLite *s = opaque; 101 uint32_t r = 0; 102 addr >>= 2; 103 switch (addr) 104 { 105 case R_RX: 106 r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 7]; 107 if (s->rx_fifo_len) 108 s->rx_fifo_len--; 109 uart_update_status(s); 110 uart_update_irq(s); 111 qemu_chr_fe_accept_input(&s->chr); 112 break; 113 114 default: 115 if (addr < ARRAY_SIZE(s->regs)) 116 r = s->regs[addr]; 117 DUART(qemu_log("%s addr=%x v=%x\n", __func__, addr, r)); 118 break; 119 } 120 return r; 121 } 122 123 static void 124 uart_write(void *opaque, hwaddr addr, 125 uint64_t val64, unsigned int size) 126 { 127 XilinxUARTLite *s = opaque; 128 uint32_t value = val64; 129 unsigned char ch = value; 130 131 addr >>= 2; 132 switch (addr) 133 { 134 case R_STATUS: 135 hw_error("write to UART STATUS?\n"); 136 break; 137 138 case R_CTRL: 139 if (value & CONTROL_RST_RX) { 140 s->rx_fifo_pos = 0; 141 s->rx_fifo_len = 0; 142 } 143 s->regs[addr] = value; 144 break; 145 146 case R_TX: 147 /* XXX this blocks entire thread. Rewrite to use 148 * qemu_chr_fe_write and background I/O callbacks */ 149 qemu_chr_fe_write_all(&s->chr, &ch, 1); 150 s->regs[addr] = value; 151 152 /* hax. */ 153 s->regs[R_STATUS] |= STATUS_IE; 154 break; 155 156 default: 157 DUART(printf("%s addr=%x v=%x\n", __func__, addr, value)); 158 if (addr < ARRAY_SIZE(s->regs)) 159 s->regs[addr] = value; 160 break; 161 } 162 uart_update_status(s); 163 uart_update_irq(s); 164 } 165 166 static const MemoryRegionOps uart_ops = { 167 .read = uart_read, 168 .write = uart_write, 169 .endianness = DEVICE_NATIVE_ENDIAN, 170 .valid = { 171 .min_access_size = 1, 172 .max_access_size = 4 173 } 174 }; 175 176 static Property xilinx_uartlite_properties[] = { 177 DEFINE_PROP_CHR("chardev", XilinxUARTLite, chr), 178 DEFINE_PROP_END_OF_LIST(), 179 }; 180 181 static void uart_rx(void *opaque, const uint8_t *buf, int size) 182 { 183 XilinxUARTLite *s = opaque; 184 185 /* Got a byte. */ 186 if (s->rx_fifo_len >= 8) { 187 printf("WARNING: UART dropped char.\n"); 188 return; 189 } 190 s->rx_fifo[s->rx_fifo_pos] = *buf; 191 s->rx_fifo_pos++; 192 s->rx_fifo_pos &= 0x7; 193 s->rx_fifo_len++; 194 195 uart_update_status(s); 196 uart_update_irq(s); 197 } 198 199 static int uart_can_rx(void *opaque) 200 { 201 XilinxUARTLite *s = opaque; 202 203 return s->rx_fifo_len < sizeof(s->rx_fifo); 204 } 205 206 static void uart_event(void *opaque, int event) 207 { 208 209 } 210 211 static void xilinx_uartlite_realize(DeviceState *dev, Error **errp) 212 { 213 XilinxUARTLite *s = XILINX_UARTLITE(dev); 214 215 qemu_chr_fe_set_handlers(&s->chr, uart_can_rx, uart_rx, 216 uart_event, NULL, s, NULL, true); 217 } 218 219 static void xilinx_uartlite_init(Object *obj) 220 { 221 XilinxUARTLite *s = XILINX_UARTLITE(obj); 222 223 sysbus_init_irq(SYS_BUS_DEVICE(obj), &s->irq); 224 225 memory_region_init_io(&s->mmio, obj, &uart_ops, s, 226 "xlnx.xps-uartlite", R_MAX * 4); 227 sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->mmio); 228 } 229 230 static void xilinx_uartlite_class_init(ObjectClass *klass, void *data) 231 { 232 DeviceClass *dc = DEVICE_CLASS(klass); 233 234 dc->reset = xilinx_uartlite_reset; 235 dc->realize = xilinx_uartlite_realize; 236 dc->props = xilinx_uartlite_properties; 237 } 238 239 static const TypeInfo xilinx_uartlite_info = { 240 .name = TYPE_XILINX_UARTLITE, 241 .parent = TYPE_SYS_BUS_DEVICE, 242 .instance_size = sizeof(XilinxUARTLite), 243 .instance_init = xilinx_uartlite_init, 244 .class_init = xilinx_uartlite_class_init, 245 }; 246 247 static void xilinx_uart_register_types(void) 248 { 249 type_register_static(&xilinx_uartlite_info); 250 } 251 252 type_init(xilinx_uart_register_types) 253