mcf_uart.c (8742B)
1/* 2 * ColdFire UART emulation. 3 * 4 * Copyright (c) 2007 CodeSourcery. 5 * 6 * This code is licensed under the GPL 7 */ 8 9#include "qemu/osdep.h" 10#include "hw/irq.h" 11#include "hw/sysbus.h" 12#include "qemu/module.h" 13#include "qapi/error.h" 14#include "hw/m68k/mcf.h" 15#include "hw/qdev-properties.h" 16#include "hw/qdev-properties-system.h" 17#include "chardev/char-fe.h" 18#include "qom/object.h" 19 20struct mcf_uart_state { 21 SysBusDevice parent_obj; 22 23 MemoryRegion iomem; 24 uint8_t mr[2]; 25 uint8_t sr; 26 uint8_t isr; 27 uint8_t imr; 28 uint8_t bg1; 29 uint8_t bg2; 30 uint8_t fifo[4]; 31 uint8_t tb; 32 int current_mr; 33 int fifo_len; 34 int tx_enabled; 35 int rx_enabled; 36 qemu_irq irq; 37 CharBackend chr; 38}; 39 40#define TYPE_MCF_UART "mcf-uart" 41OBJECT_DECLARE_SIMPLE_TYPE(mcf_uart_state, MCF_UART) 42 43/* UART Status Register bits. */ 44#define MCF_UART_RxRDY 0x01 45#define MCF_UART_FFULL 0x02 46#define MCF_UART_TxRDY 0x04 47#define MCF_UART_TxEMP 0x08 48#define MCF_UART_OE 0x10 49#define MCF_UART_PE 0x20 50#define MCF_UART_FE 0x40 51#define MCF_UART_RB 0x80 52 53/* Interrupt flags. */ 54#define MCF_UART_TxINT 0x01 55#define MCF_UART_RxINT 0x02 56#define MCF_UART_DBINT 0x04 57#define MCF_UART_COSINT 0x80 58 59/* UMR1 flags. */ 60#define MCF_UART_BC0 0x01 61#define MCF_UART_BC1 0x02 62#define MCF_UART_PT 0x04 63#define MCF_UART_PM0 0x08 64#define MCF_UART_PM1 0x10 65#define MCF_UART_ERR 0x20 66#define MCF_UART_RxIRQ 0x40 67#define MCF_UART_RxRTS 0x80 68 69static void mcf_uart_update(mcf_uart_state *s) 70{ 71 s->isr &= ~(MCF_UART_TxINT | MCF_UART_RxINT); 72 if (s->sr & MCF_UART_TxRDY) 73 s->isr |= MCF_UART_TxINT; 74 if ((s->sr & ((s->mr[0] & MCF_UART_RxIRQ) 75 ? MCF_UART_FFULL : MCF_UART_RxRDY)) != 0) 76 s->isr |= MCF_UART_RxINT; 77 78 qemu_set_irq(s->irq, (s->isr & s->imr) != 0); 79} 80 81uint64_t mcf_uart_read(void *opaque, hwaddr addr, 82 unsigned size) 83{ 84 mcf_uart_state *s = (mcf_uart_state *)opaque; 85 switch (addr & 0x3f) { 86 case 0x00: 87 return s->mr[s->current_mr]; 88 case 0x04: 89 return s->sr; 90 case 0x0c: 91 { 92 uint8_t val; 93 int i; 94 95 if (s->fifo_len == 0) 96 return 0; 97 98 val = s->fifo[0]; 99 s->fifo_len--; 100 for (i = 0; i < s->fifo_len; i++) 101 s->fifo[i] = s->fifo[i + 1]; 102 s->sr &= ~MCF_UART_FFULL; 103 if (s->fifo_len == 0) 104 s->sr &= ~MCF_UART_RxRDY; 105 mcf_uart_update(s); 106 qemu_chr_fe_accept_input(&s->chr); 107 return val; 108 } 109 case 0x10: 110 /* TODO: Implement IPCR. */ 111 return 0; 112 case 0x14: 113 return s->isr; 114 case 0x18: 115 return s->bg1; 116 case 0x1c: 117 return s->bg2; 118 default: 119 return 0; 120 } 121} 122 123/* Update TxRDY flag and set data if present and enabled. */ 124static void mcf_uart_do_tx(mcf_uart_state *s) 125{ 126 if (s->tx_enabled && (s->sr & MCF_UART_TxEMP) == 0) { 127 /* XXX this blocks entire thread. Rewrite to use 128 * qemu_chr_fe_write and background I/O callbacks */ 129 qemu_chr_fe_write_all(&s->chr, (unsigned char *)&s->tb, 1); 130 s->sr |= MCF_UART_TxEMP; 131 } 132 if (s->tx_enabled) { 133 s->sr |= MCF_UART_TxRDY; 134 } else { 135 s->sr &= ~MCF_UART_TxRDY; 136 } 137} 138 139static void mcf_do_command(mcf_uart_state *s, uint8_t cmd) 140{ 141 /* Misc command. */ 142 switch ((cmd >> 4) & 7) { 143 case 0: /* No-op. */ 144 break; 145 case 1: /* Reset mode register pointer. */ 146 s->current_mr = 0; 147 break; 148 case 2: /* Reset receiver. */ 149 s->rx_enabled = 0; 150 s->fifo_len = 0; 151 s->sr &= ~(MCF_UART_RxRDY | MCF_UART_FFULL); 152 break; 153 case 3: /* Reset transmitter. */ 154 s->tx_enabled = 0; 155 s->sr |= MCF_UART_TxEMP; 156 s->sr &= ~MCF_UART_TxRDY; 157 break; 158 case 4: /* Reset error status. */ 159 break; 160 case 5: /* Reset break-change interrupt. */ 161 s->isr &= ~MCF_UART_DBINT; 162 break; 163 case 6: /* Start break. */ 164 case 7: /* Stop break. */ 165 break; 166 } 167 168 /* Transmitter command. */ 169 switch ((cmd >> 2) & 3) { 170 case 0: /* No-op. */ 171 break; 172 case 1: /* Enable. */ 173 s->tx_enabled = 1; 174 mcf_uart_do_tx(s); 175 break; 176 case 2: /* Disable. */ 177 s->tx_enabled = 0; 178 mcf_uart_do_tx(s); 179 break; 180 case 3: /* Reserved. */ 181 fprintf(stderr, "mcf_uart: Bad TX command\n"); 182 break; 183 } 184 185 /* Receiver command. */ 186 switch (cmd & 3) { 187 case 0: /* No-op. */ 188 break; 189 case 1: /* Enable. */ 190 s->rx_enabled = 1; 191 break; 192 case 2: 193 s->rx_enabled = 0; 194 break; 195 case 3: /* Reserved. */ 196 fprintf(stderr, "mcf_uart: Bad RX command\n"); 197 break; 198 } 199} 200 201void mcf_uart_write(void *opaque, hwaddr addr, 202 uint64_t val, unsigned size) 203{ 204 mcf_uart_state *s = (mcf_uart_state *)opaque; 205 switch (addr & 0x3f) { 206 case 0x00: 207 s->mr[s->current_mr] = val; 208 s->current_mr = 1; 209 break; 210 case 0x04: 211 /* CSR is ignored. */ 212 break; 213 case 0x08: /* Command Register. */ 214 mcf_do_command(s, val); 215 break; 216 case 0x0c: /* Transmit Buffer. */ 217 s->sr &= ~MCF_UART_TxEMP; 218 s->tb = val; 219 mcf_uart_do_tx(s); 220 break; 221 case 0x10: 222 /* ACR is ignored. */ 223 break; 224 case 0x14: 225 s->imr = val; 226 break; 227 default: 228 break; 229 } 230 mcf_uart_update(s); 231} 232 233static void mcf_uart_reset(DeviceState *dev) 234{ 235 mcf_uart_state *s = MCF_UART(dev); 236 237 s->fifo_len = 0; 238 s->mr[0] = 0; 239 s->mr[1] = 0; 240 s->sr = MCF_UART_TxEMP; 241 s->tx_enabled = 0; 242 s->rx_enabled = 0; 243 s->isr = 0; 244 s->imr = 0; 245} 246 247static void mcf_uart_push_byte(mcf_uart_state *s, uint8_t data) 248{ 249 /* Break events overwrite the last byte if the fifo is full. */ 250 if (s->fifo_len == 4) 251 s->fifo_len--; 252 253 s->fifo[s->fifo_len] = data; 254 s->fifo_len++; 255 s->sr |= MCF_UART_RxRDY; 256 if (s->fifo_len == 4) 257 s->sr |= MCF_UART_FFULL; 258 259 mcf_uart_update(s); 260} 261 262static void mcf_uart_event(void *opaque, QEMUChrEvent event) 263{ 264 mcf_uart_state *s = (mcf_uart_state *)opaque; 265 266 switch (event) { 267 case CHR_EVENT_BREAK: 268 s->isr |= MCF_UART_DBINT; 269 mcf_uart_push_byte(s, 0); 270 break; 271 default: 272 break; 273 } 274} 275 276static int mcf_uart_can_receive(void *opaque) 277{ 278 mcf_uart_state *s = (mcf_uart_state *)opaque; 279 280 return s->rx_enabled && (s->sr & MCF_UART_FFULL) == 0; 281} 282 283static void mcf_uart_receive(void *opaque, const uint8_t *buf, int size) 284{ 285 mcf_uart_state *s = (mcf_uart_state *)opaque; 286 287 mcf_uart_push_byte(s, buf[0]); 288} 289 290static const MemoryRegionOps mcf_uart_ops = { 291 .read = mcf_uart_read, 292 .write = mcf_uart_write, 293 .endianness = DEVICE_NATIVE_ENDIAN, 294}; 295 296static void mcf_uart_instance_init(Object *obj) 297{ 298 SysBusDevice *dev = SYS_BUS_DEVICE(obj); 299 mcf_uart_state *s = MCF_UART(dev); 300 301 memory_region_init_io(&s->iomem, obj, &mcf_uart_ops, s, "uart", 0x40); 302 sysbus_init_mmio(dev, &s->iomem); 303 304 sysbus_init_irq(dev, &s->irq); 305} 306 307static void mcf_uart_realize(DeviceState *dev, Error **errp) 308{ 309 mcf_uart_state *s = MCF_UART(dev); 310 311 qemu_chr_fe_set_handlers(&s->chr, mcf_uart_can_receive, mcf_uart_receive, 312 mcf_uart_event, NULL, s, NULL, true); 313} 314 315static Property mcf_uart_properties[] = { 316 DEFINE_PROP_CHR("chardev", mcf_uart_state, chr), 317 DEFINE_PROP_END_OF_LIST(), 318}; 319 320static void mcf_uart_class_init(ObjectClass *oc, void *data) 321{ 322 DeviceClass *dc = DEVICE_CLASS(oc); 323 324 dc->realize = mcf_uart_realize; 325 dc->reset = mcf_uart_reset; 326 device_class_set_props(dc, mcf_uart_properties); 327 set_bit(DEVICE_CATEGORY_INPUT, dc->categories); 328} 329 330static const TypeInfo mcf_uart_info = { 331 .name = TYPE_MCF_UART, 332 .parent = TYPE_SYS_BUS_DEVICE, 333 .instance_size = sizeof(mcf_uart_state), 334 .instance_init = mcf_uart_instance_init, 335 .class_init = mcf_uart_class_init, 336}; 337 338static void mcf_uart_register(void) 339{ 340 type_register_static(&mcf_uart_info); 341} 342 343type_init(mcf_uart_register) 344 345void *mcf_uart_init(qemu_irq irq, Chardev *chrdrv) 346{ 347 DeviceState *dev; 348 349 dev = qdev_new(TYPE_MCF_UART); 350 if (chrdrv) { 351 qdev_prop_set_chr(dev, "chardev", chrdrv); 352 } 353 sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); 354 355 sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); 356 357 return dev; 358} 359 360void mcf_uart_mm_init(hwaddr base, qemu_irq irq, Chardev *chrdrv) 361{ 362 DeviceState *dev; 363 364 dev = mcf_uart_init(irq, chrdrv); 365 sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); 366}