120dcee94Spbrook /* 220dcee94Spbrook * ColdFire UART emulation. 320dcee94Spbrook * 420dcee94Spbrook * Copyright (c) 2007 CodeSourcery. 520dcee94Spbrook * 68e31bf38SMatthew Fernandez * This code is licensed under the GPL 720dcee94Spbrook */ 80430891cSPeter Maydell #include "qemu/osdep.h" 983c9f4caSPaolo Bonzini #include "hw/hw.h" 100d09e41aSPaolo Bonzini #include "hw/m68k/mcf.h" 11dccfcd0eSPaolo Bonzini #include "sysemu/char.h" 12022c62cbSPaolo Bonzini #include "exec/address-spaces.h" 1332a6ebecSMarc-André Lureau #include "qapi/error.h" 1420dcee94Spbrook 1520dcee94Spbrook typedef struct { 16aa6e4986SBenoît Canet MemoryRegion iomem; 1720dcee94Spbrook uint8_t mr[2]; 1820dcee94Spbrook uint8_t sr; 1920dcee94Spbrook uint8_t isr; 2020dcee94Spbrook uint8_t imr; 2120dcee94Spbrook uint8_t bg1; 2220dcee94Spbrook uint8_t bg2; 2320dcee94Spbrook uint8_t fifo[4]; 2420dcee94Spbrook uint8_t tb; 2520dcee94Spbrook int current_mr; 2620dcee94Spbrook int fifo_len; 2720dcee94Spbrook int tx_enabled; 2820dcee94Spbrook int rx_enabled; 2920dcee94Spbrook qemu_irq irq; 3032a6ebecSMarc-André Lureau CharBackend chr; 3120dcee94Spbrook } mcf_uart_state; 3220dcee94Spbrook 3320dcee94Spbrook /* UART Status Register bits. */ 3420dcee94Spbrook #define MCF_UART_RxRDY 0x01 3520dcee94Spbrook #define MCF_UART_FFULL 0x02 3620dcee94Spbrook #define MCF_UART_TxRDY 0x04 3720dcee94Spbrook #define MCF_UART_TxEMP 0x08 3820dcee94Spbrook #define MCF_UART_OE 0x10 3920dcee94Spbrook #define MCF_UART_PE 0x20 4020dcee94Spbrook #define MCF_UART_FE 0x40 4120dcee94Spbrook #define MCF_UART_RB 0x80 4220dcee94Spbrook 4320dcee94Spbrook /* Interrupt flags. */ 4420dcee94Spbrook #define MCF_UART_TxINT 0x01 4520dcee94Spbrook #define MCF_UART_RxINT 0x02 4620dcee94Spbrook #define MCF_UART_DBINT 0x04 4720dcee94Spbrook #define MCF_UART_COSINT 0x80 4820dcee94Spbrook 4920dcee94Spbrook /* UMR1 flags. */ 5020dcee94Spbrook #define MCF_UART_BC0 0x01 5120dcee94Spbrook #define MCF_UART_BC1 0x02 5220dcee94Spbrook #define MCF_UART_PT 0x04 5320dcee94Spbrook #define MCF_UART_PM0 0x08 5420dcee94Spbrook #define MCF_UART_PM1 0x10 5520dcee94Spbrook #define MCF_UART_ERR 0x20 5620dcee94Spbrook #define MCF_UART_RxIRQ 0x40 5720dcee94Spbrook #define MCF_UART_RxRTS 0x80 5820dcee94Spbrook 5920dcee94Spbrook static void mcf_uart_update(mcf_uart_state *s) 6020dcee94Spbrook { 6120dcee94Spbrook s->isr &= ~(MCF_UART_TxINT | MCF_UART_RxINT); 6220dcee94Spbrook if (s->sr & MCF_UART_TxRDY) 6320dcee94Spbrook s->isr |= MCF_UART_TxINT; 6420dcee94Spbrook if ((s->sr & ((s->mr[0] & MCF_UART_RxIRQ) 6520dcee94Spbrook ? MCF_UART_FFULL : MCF_UART_RxRDY)) != 0) 6620dcee94Spbrook s->isr |= MCF_UART_RxINT; 6720dcee94Spbrook 6820dcee94Spbrook qemu_set_irq(s->irq, (s->isr & s->imr) != 0); 6920dcee94Spbrook } 7020dcee94Spbrook 71a8170e5eSAvi Kivity uint64_t mcf_uart_read(void *opaque, hwaddr addr, 72aa6e4986SBenoît Canet unsigned size) 7320dcee94Spbrook { 7420dcee94Spbrook mcf_uart_state *s = (mcf_uart_state *)opaque; 7520dcee94Spbrook switch (addr & 0x3f) { 7620dcee94Spbrook case 0x00: 7720dcee94Spbrook return s->mr[s->current_mr]; 7820dcee94Spbrook case 0x04: 7920dcee94Spbrook return s->sr; 8020dcee94Spbrook case 0x0c: 8120dcee94Spbrook { 8220dcee94Spbrook uint8_t val; 8320dcee94Spbrook int i; 8420dcee94Spbrook 8520dcee94Spbrook if (s->fifo_len == 0) 8620dcee94Spbrook return 0; 8720dcee94Spbrook 8820dcee94Spbrook val = s->fifo[0]; 8920dcee94Spbrook s->fifo_len--; 9020dcee94Spbrook for (i = 0; i < s->fifo_len; i++) 9120dcee94Spbrook s->fifo[i] = s->fifo[i + 1]; 9220dcee94Spbrook s->sr &= ~MCF_UART_FFULL; 9320dcee94Spbrook if (s->fifo_len == 0) 9420dcee94Spbrook s->sr &= ~MCF_UART_RxRDY; 9520dcee94Spbrook mcf_uart_update(s); 96*5345fdb4SMarc-André Lureau qemu_chr_fe_accept_input(&s->chr); 9720dcee94Spbrook return val; 9820dcee94Spbrook } 9920dcee94Spbrook case 0x10: 10020dcee94Spbrook /* TODO: Implement IPCR. */ 10120dcee94Spbrook return 0; 10220dcee94Spbrook case 0x14: 10320dcee94Spbrook return s->isr; 10420dcee94Spbrook case 0x18: 10520dcee94Spbrook return s->bg1; 10620dcee94Spbrook case 0x1c: 10720dcee94Spbrook return s->bg2; 10820dcee94Spbrook default: 10920dcee94Spbrook return 0; 11020dcee94Spbrook } 11120dcee94Spbrook } 11220dcee94Spbrook 11320dcee94Spbrook /* Update TxRDY flag and set data if present and enabled. */ 11420dcee94Spbrook static void mcf_uart_do_tx(mcf_uart_state *s) 11520dcee94Spbrook { 11620dcee94Spbrook if (s->tx_enabled && (s->sr & MCF_UART_TxEMP) == 0) { 11732a6ebecSMarc-André Lureau if (s->chr.chr) { 1186ab3fc32SDaniel P. Berrange /* XXX this blocks entire thread. Rewrite to use 1196ab3fc32SDaniel P. Berrange * qemu_chr_fe_write and background I/O callbacks */ 120*5345fdb4SMarc-André Lureau qemu_chr_fe_write_all(&s->chr, (unsigned char *)&s->tb, 1); 12132a6ebecSMarc-André Lureau } 12220dcee94Spbrook s->sr |= MCF_UART_TxEMP; 12320dcee94Spbrook } 12420dcee94Spbrook if (s->tx_enabled) { 12520dcee94Spbrook s->sr |= MCF_UART_TxRDY; 12620dcee94Spbrook } else { 12720dcee94Spbrook s->sr &= ~MCF_UART_TxRDY; 12820dcee94Spbrook } 12920dcee94Spbrook } 13020dcee94Spbrook 13120dcee94Spbrook static void mcf_do_command(mcf_uart_state *s, uint8_t cmd) 13220dcee94Spbrook { 13320dcee94Spbrook /* Misc command. */ 134491ffc1fSPaolo Bonzini switch ((cmd >> 4) & 7) { 13520dcee94Spbrook case 0: /* No-op. */ 13620dcee94Spbrook break; 13720dcee94Spbrook case 1: /* Reset mode register pointer. */ 13820dcee94Spbrook s->current_mr = 0; 13920dcee94Spbrook break; 14020dcee94Spbrook case 2: /* Reset receiver. */ 14120dcee94Spbrook s->rx_enabled = 0; 14220dcee94Spbrook s->fifo_len = 0; 14320dcee94Spbrook s->sr &= ~(MCF_UART_RxRDY | MCF_UART_FFULL); 14420dcee94Spbrook break; 14520dcee94Spbrook case 3: /* Reset transmitter. */ 14620dcee94Spbrook s->tx_enabled = 0; 14720dcee94Spbrook s->sr |= MCF_UART_TxEMP; 14820dcee94Spbrook s->sr &= ~MCF_UART_TxRDY; 14920dcee94Spbrook break; 15020dcee94Spbrook case 4: /* Reset error status. */ 15120dcee94Spbrook break; 15220dcee94Spbrook case 5: /* Reset break-change interrupt. */ 15320dcee94Spbrook s->isr &= ~MCF_UART_DBINT; 15420dcee94Spbrook break; 15520dcee94Spbrook case 6: /* Start break. */ 15620dcee94Spbrook case 7: /* Stop break. */ 15720dcee94Spbrook break; 15820dcee94Spbrook } 15920dcee94Spbrook 16020dcee94Spbrook /* Transmitter command. */ 16120dcee94Spbrook switch ((cmd >> 2) & 3) { 16220dcee94Spbrook case 0: /* No-op. */ 16320dcee94Spbrook break; 16420dcee94Spbrook case 1: /* Enable. */ 16520dcee94Spbrook s->tx_enabled = 1; 16620dcee94Spbrook mcf_uart_do_tx(s); 16720dcee94Spbrook break; 16820dcee94Spbrook case 2: /* Disable. */ 16920dcee94Spbrook s->tx_enabled = 0; 17020dcee94Spbrook mcf_uart_do_tx(s); 17120dcee94Spbrook break; 17220dcee94Spbrook case 3: /* Reserved. */ 17320dcee94Spbrook fprintf(stderr, "mcf_uart: Bad TX command\n"); 17420dcee94Spbrook break; 17520dcee94Spbrook } 17620dcee94Spbrook 17720dcee94Spbrook /* Receiver command. */ 17820dcee94Spbrook switch (cmd & 3) { 17920dcee94Spbrook case 0: /* No-op. */ 18020dcee94Spbrook break; 18120dcee94Spbrook case 1: /* Enable. */ 18220dcee94Spbrook s->rx_enabled = 1; 18320dcee94Spbrook break; 18420dcee94Spbrook case 2: 18520dcee94Spbrook s->rx_enabled = 0; 18620dcee94Spbrook break; 18720dcee94Spbrook case 3: /* Reserved. */ 18820dcee94Spbrook fprintf(stderr, "mcf_uart: Bad RX command\n"); 18920dcee94Spbrook break; 19020dcee94Spbrook } 19120dcee94Spbrook } 19220dcee94Spbrook 193a8170e5eSAvi Kivity void mcf_uart_write(void *opaque, hwaddr addr, 194aa6e4986SBenoît Canet uint64_t val, unsigned size) 19520dcee94Spbrook { 19620dcee94Spbrook mcf_uart_state *s = (mcf_uart_state *)opaque; 19720dcee94Spbrook switch (addr & 0x3f) { 19820dcee94Spbrook case 0x00: 19920dcee94Spbrook s->mr[s->current_mr] = val; 20020dcee94Spbrook s->current_mr = 1; 20120dcee94Spbrook break; 20220dcee94Spbrook case 0x04: 20320dcee94Spbrook /* CSR is ignored. */ 20420dcee94Spbrook break; 20520dcee94Spbrook case 0x08: /* Command Register. */ 20620dcee94Spbrook mcf_do_command(s, val); 20720dcee94Spbrook break; 20820dcee94Spbrook case 0x0c: /* Transmit Buffer. */ 20920dcee94Spbrook s->sr &= ~MCF_UART_TxEMP; 21020dcee94Spbrook s->tb = val; 21120dcee94Spbrook mcf_uart_do_tx(s); 21220dcee94Spbrook break; 21320dcee94Spbrook case 0x10: 21420dcee94Spbrook /* ACR is ignored. */ 21520dcee94Spbrook break; 21620dcee94Spbrook case 0x14: 21720dcee94Spbrook s->imr = val; 21820dcee94Spbrook break; 21920dcee94Spbrook default: 22020dcee94Spbrook break; 22120dcee94Spbrook } 22220dcee94Spbrook mcf_uart_update(s); 22320dcee94Spbrook } 22420dcee94Spbrook 22520dcee94Spbrook static void mcf_uart_reset(mcf_uart_state *s) 22620dcee94Spbrook { 22720dcee94Spbrook s->fifo_len = 0; 22820dcee94Spbrook s->mr[0] = 0; 22920dcee94Spbrook s->mr[1] = 0; 23020dcee94Spbrook s->sr = MCF_UART_TxEMP; 23120dcee94Spbrook s->tx_enabled = 0; 23220dcee94Spbrook s->rx_enabled = 0; 23320dcee94Spbrook s->isr = 0; 23420dcee94Spbrook s->imr = 0; 23520dcee94Spbrook } 23620dcee94Spbrook 23720dcee94Spbrook static void mcf_uart_push_byte(mcf_uart_state *s, uint8_t data) 23820dcee94Spbrook { 23920dcee94Spbrook /* Break events overwrite the last byte if the fifo is full. */ 24020dcee94Spbrook if (s->fifo_len == 4) 24120dcee94Spbrook s->fifo_len--; 24220dcee94Spbrook 24320dcee94Spbrook s->fifo[s->fifo_len] = data; 24420dcee94Spbrook s->fifo_len++; 24520dcee94Spbrook s->sr |= MCF_UART_RxRDY; 24620dcee94Spbrook if (s->fifo_len == 4) 24720dcee94Spbrook s->sr |= MCF_UART_FFULL; 24820dcee94Spbrook 24920dcee94Spbrook mcf_uart_update(s); 25020dcee94Spbrook } 25120dcee94Spbrook 25220dcee94Spbrook static void mcf_uart_event(void *opaque, int event) 25320dcee94Spbrook { 25420dcee94Spbrook mcf_uart_state *s = (mcf_uart_state *)opaque; 25520dcee94Spbrook 25620dcee94Spbrook switch (event) { 25720dcee94Spbrook case CHR_EVENT_BREAK: 25820dcee94Spbrook s->isr |= MCF_UART_DBINT; 25920dcee94Spbrook mcf_uart_push_byte(s, 0); 26020dcee94Spbrook break; 26120dcee94Spbrook default: 26220dcee94Spbrook break; 26320dcee94Spbrook } 26420dcee94Spbrook } 26520dcee94Spbrook 26620dcee94Spbrook static int mcf_uart_can_receive(void *opaque) 26720dcee94Spbrook { 26820dcee94Spbrook mcf_uart_state *s = (mcf_uart_state *)opaque; 26920dcee94Spbrook 27020dcee94Spbrook return s->rx_enabled && (s->sr & MCF_UART_FFULL) == 0; 27120dcee94Spbrook } 27220dcee94Spbrook 27320dcee94Spbrook static void mcf_uart_receive(void *opaque, const uint8_t *buf, int size) 27420dcee94Spbrook { 27520dcee94Spbrook mcf_uart_state *s = (mcf_uart_state *)opaque; 27620dcee94Spbrook 27720dcee94Spbrook mcf_uart_push_byte(s, buf[0]); 27820dcee94Spbrook } 27920dcee94Spbrook 28020dcee94Spbrook void *mcf_uart_init(qemu_irq irq, CharDriverState *chr) 28120dcee94Spbrook { 28220dcee94Spbrook mcf_uart_state *s; 28320dcee94Spbrook 2847267c094SAnthony Liguori s = g_malloc0(sizeof(mcf_uart_state)); 28520dcee94Spbrook s->irq = irq; 28620dcee94Spbrook if (chr) { 28732a6ebecSMarc-André Lureau qemu_chr_fe_init(&s->chr, chr, &error_abort); 288456d6069SHans de Goede qemu_chr_fe_claim_no_fail(chr); 289*5345fdb4SMarc-André Lureau qemu_chr_fe_set_handlers(&s->chr, mcf_uart_can_receive, 290*5345fdb4SMarc-André Lureau mcf_uart_receive, mcf_uart_event, s, NULL); 29120dcee94Spbrook } 29220dcee94Spbrook mcf_uart_reset(s); 29320dcee94Spbrook return s; 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 302aa6e4986SBenoît Canet void mcf_uart_mm_init(MemoryRegion *sysmem, 303a8170e5eSAvi Kivity hwaddr base, 304aa6e4986SBenoît Canet qemu_irq irq, 30520dcee94Spbrook CharDriverState *chr) 30620dcee94Spbrook { 30720dcee94Spbrook mcf_uart_state *s; 30820dcee94Spbrook 30920dcee94Spbrook s = mcf_uart_init(irq, chr); 3102c9b15caSPaolo Bonzini memory_region_init_io(&s->iomem, NULL, &mcf_uart_ops, s, "uart", 0x40); 311aa6e4986SBenoît Canet memory_region_add_subregion(sysmem, base, &s->iomem); 31220dcee94Spbrook } 313