120dcee94Spbrook /* 220dcee94Spbrook * ColdFire UART emulation. 320dcee94Spbrook * 420dcee94Spbrook * Copyright (c) 2007 CodeSourcery. 520dcee94Spbrook * 68e31bf38SMatthew Fernandez * This code is licensed under the GPL 720dcee94Spbrook */ 80b8fa32fSMarkus Armbruster 90430891cSPeter Maydell #include "qemu/osdep.h" 1064552b6bSMarkus Armbruster #include "hw/irq.h" 11d9ff1d35SThomas Huth #include "hw/sysbus.h" 120b8fa32fSMarkus Armbruster #include "qemu/module.h" 133e80f690SMarkus Armbruster #include "qapi/error.h" 140d09e41aSPaolo Bonzini #include "hw/m68k/mcf.h" 15a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h" 16ce35e229SEduardo Habkost #include "hw/qdev-properties-system.h" 174d43a603SMarc-André Lureau #include "chardev/char-fe.h" 18db1015e9SEduardo Habkost #include "qom/object.h" 1920dcee94Spbrook 203d978e7bSPhilippe Mathieu-Daudé #define FIFO_DEPTH 4 213d978e7bSPhilippe Mathieu-Daudé 22db1015e9SEduardo Habkost struct mcf_uart_state { 23d9ff1d35SThomas Huth SysBusDevice parent_obj; 24d9ff1d35SThomas Huth 25aa6e4986SBenoît Canet MemoryRegion iomem; 2620dcee94Spbrook uint8_t mr[2]; 2720dcee94Spbrook uint8_t sr; 2820dcee94Spbrook uint8_t isr; 2920dcee94Spbrook uint8_t imr; 3020dcee94Spbrook uint8_t bg1; 3120dcee94Spbrook uint8_t bg2; 323d978e7bSPhilippe Mathieu-Daudé uint8_t fifo[FIFO_DEPTH]; 3320dcee94Spbrook uint8_t tb; 3420dcee94Spbrook int current_mr; 3520dcee94Spbrook int fifo_len; 3620dcee94Spbrook int tx_enabled; 3720dcee94Spbrook int rx_enabled; 3820dcee94Spbrook qemu_irq irq; 3932a6ebecSMarc-André Lureau CharBackend chr; 40db1015e9SEduardo Habkost }; 4120dcee94Spbrook 42d9ff1d35SThomas Huth #define TYPE_MCF_UART "mcf-uart" 438063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(mcf_uart_state, MCF_UART) 44d9ff1d35SThomas Huth 4520dcee94Spbrook /* UART Status Register bits. */ 4620dcee94Spbrook #define MCF_UART_RxRDY 0x01 4720dcee94Spbrook #define MCF_UART_FFULL 0x02 4820dcee94Spbrook #define MCF_UART_TxRDY 0x04 4920dcee94Spbrook #define MCF_UART_TxEMP 0x08 5020dcee94Spbrook #define MCF_UART_OE 0x10 5120dcee94Spbrook #define MCF_UART_PE 0x20 5220dcee94Spbrook #define MCF_UART_FE 0x40 5320dcee94Spbrook #define MCF_UART_RB 0x80 5420dcee94Spbrook 5520dcee94Spbrook /* Interrupt flags. */ 5620dcee94Spbrook #define MCF_UART_TxINT 0x01 5720dcee94Spbrook #define MCF_UART_RxINT 0x02 5820dcee94Spbrook #define MCF_UART_DBINT 0x04 5920dcee94Spbrook #define MCF_UART_COSINT 0x80 6020dcee94Spbrook 6120dcee94Spbrook /* UMR1 flags. */ 6220dcee94Spbrook #define MCF_UART_BC0 0x01 6320dcee94Spbrook #define MCF_UART_BC1 0x02 6420dcee94Spbrook #define MCF_UART_PT 0x04 6520dcee94Spbrook #define MCF_UART_PM0 0x08 6620dcee94Spbrook #define MCF_UART_PM1 0x10 6720dcee94Spbrook #define MCF_UART_ERR 0x20 6820dcee94Spbrook #define MCF_UART_RxIRQ 0x40 6920dcee94Spbrook #define MCF_UART_RxRTS 0x80 7020dcee94Spbrook 7120dcee94Spbrook static void mcf_uart_update(mcf_uart_state *s) 7220dcee94Spbrook { 7320dcee94Spbrook s->isr &= ~(MCF_UART_TxINT | MCF_UART_RxINT); 7420dcee94Spbrook if (s->sr & MCF_UART_TxRDY) 7520dcee94Spbrook s->isr |= MCF_UART_TxINT; 7620dcee94Spbrook if ((s->sr & ((s->mr[0] & MCF_UART_RxIRQ) 7720dcee94Spbrook ? MCF_UART_FFULL : MCF_UART_RxRDY)) != 0) 7820dcee94Spbrook s->isr |= MCF_UART_RxINT; 7920dcee94Spbrook 8020dcee94Spbrook qemu_set_irq(s->irq, (s->isr & s->imr) != 0); 8120dcee94Spbrook } 8220dcee94Spbrook 83a8170e5eSAvi Kivity uint64_t mcf_uart_read(void *opaque, hwaddr addr, 84aa6e4986SBenoît Canet unsigned size) 8520dcee94Spbrook { 8620dcee94Spbrook mcf_uart_state *s = (mcf_uart_state *)opaque; 8720dcee94Spbrook switch (addr & 0x3f) { 8820dcee94Spbrook case 0x00: 8920dcee94Spbrook return s->mr[s->current_mr]; 9020dcee94Spbrook case 0x04: 9120dcee94Spbrook return s->sr; 9220dcee94Spbrook case 0x0c: 9320dcee94Spbrook { 9420dcee94Spbrook uint8_t val; 9520dcee94Spbrook int i; 9620dcee94Spbrook 9720dcee94Spbrook if (s->fifo_len == 0) 9820dcee94Spbrook return 0; 9920dcee94Spbrook 10020dcee94Spbrook val = s->fifo[0]; 10120dcee94Spbrook s->fifo_len--; 10220dcee94Spbrook for (i = 0; i < s->fifo_len; i++) 10320dcee94Spbrook s->fifo[i] = s->fifo[i + 1]; 10420dcee94Spbrook s->sr &= ~MCF_UART_FFULL; 10520dcee94Spbrook if (s->fifo_len == 0) 10620dcee94Spbrook s->sr &= ~MCF_UART_RxRDY; 10720dcee94Spbrook mcf_uart_update(s); 1085345fdb4SMarc-André Lureau qemu_chr_fe_accept_input(&s->chr); 10920dcee94Spbrook return val; 11020dcee94Spbrook } 11120dcee94Spbrook case 0x10: 11220dcee94Spbrook /* TODO: Implement IPCR. */ 11320dcee94Spbrook return 0; 11420dcee94Spbrook case 0x14: 11520dcee94Spbrook return s->isr; 11620dcee94Spbrook case 0x18: 11720dcee94Spbrook return s->bg1; 11820dcee94Spbrook case 0x1c: 11920dcee94Spbrook return s->bg2; 12020dcee94Spbrook default: 12120dcee94Spbrook return 0; 12220dcee94Spbrook } 12320dcee94Spbrook } 12420dcee94Spbrook 12520dcee94Spbrook /* Update TxRDY flag and set data if present and enabled. */ 12620dcee94Spbrook static void mcf_uart_do_tx(mcf_uart_state *s) 12720dcee94Spbrook { 12820dcee94Spbrook if (s->tx_enabled && (s->sr & MCF_UART_TxEMP) == 0) { 1296ab3fc32SDaniel P. Berrange /* XXX this blocks entire thread. Rewrite to use 1306ab3fc32SDaniel P. Berrange * qemu_chr_fe_write and background I/O callbacks */ 1315345fdb4SMarc-André Lureau qemu_chr_fe_write_all(&s->chr, (unsigned char *)&s->tb, 1); 13220dcee94Spbrook s->sr |= MCF_UART_TxEMP; 13320dcee94Spbrook } 13420dcee94Spbrook if (s->tx_enabled) { 13520dcee94Spbrook s->sr |= MCF_UART_TxRDY; 13620dcee94Spbrook } else { 13720dcee94Spbrook s->sr &= ~MCF_UART_TxRDY; 13820dcee94Spbrook } 13920dcee94Spbrook } 14020dcee94Spbrook 14120dcee94Spbrook static void mcf_do_command(mcf_uart_state *s, uint8_t cmd) 14220dcee94Spbrook { 14320dcee94Spbrook /* Misc command. */ 144491ffc1fSPaolo Bonzini switch ((cmd >> 4) & 7) { 14520dcee94Spbrook case 0: /* No-op. */ 14620dcee94Spbrook break; 14720dcee94Spbrook case 1: /* Reset mode register pointer. */ 14820dcee94Spbrook s->current_mr = 0; 14920dcee94Spbrook break; 15020dcee94Spbrook case 2: /* Reset receiver. */ 15120dcee94Spbrook s->rx_enabled = 0; 15220dcee94Spbrook s->fifo_len = 0; 15320dcee94Spbrook s->sr &= ~(MCF_UART_RxRDY | MCF_UART_FFULL); 15420dcee94Spbrook break; 15520dcee94Spbrook case 3: /* Reset transmitter. */ 15620dcee94Spbrook s->tx_enabled = 0; 15720dcee94Spbrook s->sr |= MCF_UART_TxEMP; 15820dcee94Spbrook s->sr &= ~MCF_UART_TxRDY; 15920dcee94Spbrook break; 16020dcee94Spbrook case 4: /* Reset error status. */ 16120dcee94Spbrook break; 16220dcee94Spbrook case 5: /* Reset break-change interrupt. */ 16320dcee94Spbrook s->isr &= ~MCF_UART_DBINT; 16420dcee94Spbrook break; 16520dcee94Spbrook case 6: /* Start break. */ 16620dcee94Spbrook case 7: /* Stop break. */ 16720dcee94Spbrook break; 16820dcee94Spbrook } 16920dcee94Spbrook 17020dcee94Spbrook /* Transmitter command. */ 17120dcee94Spbrook switch ((cmd >> 2) & 3) { 17220dcee94Spbrook case 0: /* No-op. */ 17320dcee94Spbrook break; 17420dcee94Spbrook case 1: /* Enable. */ 17520dcee94Spbrook s->tx_enabled = 1; 17620dcee94Spbrook mcf_uart_do_tx(s); 17720dcee94Spbrook break; 17820dcee94Spbrook case 2: /* Disable. */ 17920dcee94Spbrook s->tx_enabled = 0; 18020dcee94Spbrook mcf_uart_do_tx(s); 18120dcee94Spbrook break; 18220dcee94Spbrook case 3: /* Reserved. */ 18320dcee94Spbrook fprintf(stderr, "mcf_uart: Bad TX command\n"); 18420dcee94Spbrook break; 18520dcee94Spbrook } 18620dcee94Spbrook 18720dcee94Spbrook /* Receiver command. */ 18820dcee94Spbrook switch (cmd & 3) { 18920dcee94Spbrook case 0: /* No-op. */ 19020dcee94Spbrook break; 19120dcee94Spbrook case 1: /* Enable. */ 19220dcee94Spbrook s->rx_enabled = 1; 19320dcee94Spbrook break; 19420dcee94Spbrook case 2: 19520dcee94Spbrook s->rx_enabled = 0; 19620dcee94Spbrook break; 19720dcee94Spbrook case 3: /* Reserved. */ 19820dcee94Spbrook fprintf(stderr, "mcf_uart: Bad RX command\n"); 19920dcee94Spbrook break; 20020dcee94Spbrook } 20120dcee94Spbrook } 20220dcee94Spbrook 203a8170e5eSAvi Kivity void mcf_uart_write(void *opaque, hwaddr addr, 204aa6e4986SBenoît Canet uint64_t val, unsigned size) 20520dcee94Spbrook { 20620dcee94Spbrook mcf_uart_state *s = (mcf_uart_state *)opaque; 20720dcee94Spbrook switch (addr & 0x3f) { 20820dcee94Spbrook case 0x00: 20920dcee94Spbrook s->mr[s->current_mr] = val; 21020dcee94Spbrook s->current_mr = 1; 21120dcee94Spbrook break; 21220dcee94Spbrook case 0x04: 21320dcee94Spbrook /* CSR is ignored. */ 21420dcee94Spbrook break; 21520dcee94Spbrook case 0x08: /* Command Register. */ 21620dcee94Spbrook mcf_do_command(s, val); 21720dcee94Spbrook break; 21820dcee94Spbrook case 0x0c: /* Transmit Buffer. */ 21920dcee94Spbrook s->sr &= ~MCF_UART_TxEMP; 22020dcee94Spbrook s->tb = val; 22120dcee94Spbrook mcf_uart_do_tx(s); 22220dcee94Spbrook break; 22320dcee94Spbrook case 0x10: 22420dcee94Spbrook /* ACR is ignored. */ 22520dcee94Spbrook break; 22620dcee94Spbrook case 0x14: 22720dcee94Spbrook s->imr = val; 22820dcee94Spbrook break; 22920dcee94Spbrook default: 23020dcee94Spbrook break; 23120dcee94Spbrook } 23220dcee94Spbrook mcf_uart_update(s); 23320dcee94Spbrook } 23420dcee94Spbrook 235d9ff1d35SThomas Huth static void mcf_uart_reset(DeviceState *dev) 23620dcee94Spbrook { 237d9ff1d35SThomas Huth mcf_uart_state *s = MCF_UART(dev); 238d9ff1d35SThomas Huth 23920dcee94Spbrook s->fifo_len = 0; 24020dcee94Spbrook s->mr[0] = 0; 24120dcee94Spbrook s->mr[1] = 0; 24220dcee94Spbrook s->sr = MCF_UART_TxEMP; 24320dcee94Spbrook s->tx_enabled = 0; 24420dcee94Spbrook s->rx_enabled = 0; 24520dcee94Spbrook s->isr = 0; 24620dcee94Spbrook s->imr = 0; 24720dcee94Spbrook } 24820dcee94Spbrook 24920dcee94Spbrook static void mcf_uart_push_byte(mcf_uart_state *s, uint8_t data) 25020dcee94Spbrook { 25120dcee94Spbrook /* Break events overwrite the last byte if the fifo is full. */ 2523d978e7bSPhilippe Mathieu-Daudé if (s->fifo_len == FIFO_DEPTH) { 25320dcee94Spbrook s->fifo_len--; 2543d978e7bSPhilippe Mathieu-Daudé } 25520dcee94Spbrook 25620dcee94Spbrook s->fifo[s->fifo_len] = data; 25720dcee94Spbrook s->fifo_len++; 25820dcee94Spbrook s->sr |= MCF_UART_RxRDY; 2593d978e7bSPhilippe Mathieu-Daudé if (s->fifo_len == FIFO_DEPTH) { 26020dcee94Spbrook s->sr |= MCF_UART_FFULL; 2613d978e7bSPhilippe Mathieu-Daudé } 26220dcee94Spbrook 26320dcee94Spbrook mcf_uart_update(s); 26420dcee94Spbrook } 26520dcee94Spbrook 266083b266fSPhilippe Mathieu-Daudé static void mcf_uart_event(void *opaque, QEMUChrEvent event) 26720dcee94Spbrook { 26820dcee94Spbrook mcf_uart_state *s = (mcf_uart_state *)opaque; 26920dcee94Spbrook 27020dcee94Spbrook switch (event) { 27120dcee94Spbrook case CHR_EVENT_BREAK: 27220dcee94Spbrook s->isr |= MCF_UART_DBINT; 27320dcee94Spbrook mcf_uart_push_byte(s, 0); 27420dcee94Spbrook break; 27520dcee94Spbrook default: 27620dcee94Spbrook break; 27720dcee94Spbrook } 27820dcee94Spbrook } 27920dcee94Spbrook 28020dcee94Spbrook static int mcf_uart_can_receive(void *opaque) 28120dcee94Spbrook { 28220dcee94Spbrook mcf_uart_state *s = (mcf_uart_state *)opaque; 28320dcee94Spbrook 2843ca8af54SPhilippe Mathieu-Daudé return s->rx_enabled ? FIFO_DEPTH - s->fifo_len : 0; 28520dcee94Spbrook } 28620dcee94Spbrook 28720dcee94Spbrook static void mcf_uart_receive(void *opaque, const uint8_t *buf, int size) 28820dcee94Spbrook { 28920dcee94Spbrook mcf_uart_state *s = (mcf_uart_state *)opaque; 29020dcee94Spbrook 2913ca8af54SPhilippe Mathieu-Daudé for (int i = 0; i < size; i++) { 2923ca8af54SPhilippe Mathieu-Daudé mcf_uart_push_byte(s, buf[i]); 2933ca8af54SPhilippe Mathieu-Daudé } 29420dcee94Spbrook } 29520dcee94Spbrook 296aa6e4986SBenoît Canet static const MemoryRegionOps mcf_uart_ops = { 297aa6e4986SBenoît Canet .read = mcf_uart_read, 298aa6e4986SBenoît Canet .write = mcf_uart_write, 299aa6e4986SBenoît Canet .endianness = DEVICE_NATIVE_ENDIAN, 30020dcee94Spbrook }; 30120dcee94Spbrook 302d9ff1d35SThomas Huth static void mcf_uart_instance_init(Object *obj) 30320dcee94Spbrook { 304d9ff1d35SThomas Huth SysBusDevice *dev = SYS_BUS_DEVICE(obj); 305d9ff1d35SThomas Huth mcf_uart_state *s = MCF_UART(dev); 30620dcee94Spbrook 307d9ff1d35SThomas Huth memory_region_init_io(&s->iomem, obj, &mcf_uart_ops, s, "uart", 0x40); 308d9ff1d35SThomas Huth sysbus_init_mmio(dev, &s->iomem); 309d9ff1d35SThomas Huth 310d9ff1d35SThomas Huth sysbus_init_irq(dev, &s->irq); 311d9ff1d35SThomas Huth } 312d9ff1d35SThomas Huth 313d9ff1d35SThomas Huth static void mcf_uart_realize(DeviceState *dev, Error **errp) 314d9ff1d35SThomas Huth { 315d9ff1d35SThomas Huth mcf_uart_state *s = MCF_UART(dev); 316d9ff1d35SThomas Huth 317d9ff1d35SThomas Huth qemu_chr_fe_set_handlers(&s->chr, mcf_uart_can_receive, mcf_uart_receive, 31881517ba3SAnton Nefedov mcf_uart_event, NULL, s, NULL, true); 319d9ff1d35SThomas Huth } 320d9ff1d35SThomas Huth 321312f37d1SRichard Henderson static const Property mcf_uart_properties[] = { 322d9ff1d35SThomas Huth DEFINE_PROP_CHR("chardev", mcf_uart_state, chr), 323d9ff1d35SThomas Huth }; 324d9ff1d35SThomas Huth 325*12d1a768SPhilippe Mathieu-Daudé static void mcf_uart_class_init(ObjectClass *oc, const void *data) 326d9ff1d35SThomas Huth { 327d9ff1d35SThomas Huth DeviceClass *dc = DEVICE_CLASS(oc); 328d9ff1d35SThomas Huth 329d9ff1d35SThomas Huth dc->realize = mcf_uart_realize; 330e3d08143SPeter Maydell device_class_set_legacy_reset(dc, mcf_uart_reset); 3314f67d30bSMarc-André Lureau device_class_set_props(dc, mcf_uart_properties); 332d9ff1d35SThomas Huth set_bit(DEVICE_CATEGORY_INPUT, dc->categories); 333d9ff1d35SThomas Huth } 334d9ff1d35SThomas Huth 335d9ff1d35SThomas Huth static const TypeInfo mcf_uart_info = { 336d9ff1d35SThomas Huth .name = TYPE_MCF_UART, 337d9ff1d35SThomas Huth .parent = TYPE_SYS_BUS_DEVICE, 338d9ff1d35SThomas Huth .instance_size = sizeof(mcf_uart_state), 339d9ff1d35SThomas Huth .instance_init = mcf_uart_instance_init, 340d9ff1d35SThomas Huth .class_init = mcf_uart_class_init, 341d9ff1d35SThomas Huth }; 342d9ff1d35SThomas Huth 343d9ff1d35SThomas Huth static void mcf_uart_register(void) 344d9ff1d35SThomas Huth { 345d9ff1d35SThomas Huth type_register_static(&mcf_uart_info); 346d9ff1d35SThomas Huth } 347d9ff1d35SThomas Huth 348d9ff1d35SThomas Huth type_init(mcf_uart_register) 349d9ff1d35SThomas Huth 350f213ccc9SPhilippe Mathieu-Daudé DeviceState *mcf_uart_create(qemu_irq irq, Chardev *chrdrv) 351d9ff1d35SThomas Huth { 352d9ff1d35SThomas Huth DeviceState *dev; 353d9ff1d35SThomas Huth 3543e80f690SMarkus Armbruster dev = qdev_new(TYPE_MCF_UART); 355d9ff1d35SThomas Huth if (chrdrv) { 356d9ff1d35SThomas Huth qdev_prop_set_chr(dev, "chardev", chrdrv); 357d9ff1d35SThomas Huth } 3583c6ef471SMarkus Armbruster sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); 359d9ff1d35SThomas Huth sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq); 360d9ff1d35SThomas Huth 361d9ff1d35SThomas Huth return dev; 362d9ff1d35SThomas Huth } 363d9ff1d35SThomas Huth 364f213ccc9SPhilippe Mathieu-Daudé DeviceState *mcf_uart_create_mmap(hwaddr base, qemu_irq irq, Chardev *chrdrv) 365d9ff1d35SThomas Huth { 366d9ff1d35SThomas Huth DeviceState *dev; 367d9ff1d35SThomas Huth 368f213ccc9SPhilippe Mathieu-Daudé dev = mcf_uart_create(irq, chrdrv); 369d9ff1d35SThomas Huth sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base); 370f213ccc9SPhilippe Mathieu-Daudé 371f213ccc9SPhilippe Mathieu-Daudé return dev; 37220dcee94Spbrook } 373