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