120dcee94Spbrook /* 220dcee94Spbrook * ColdFire UART emulation. 320dcee94Spbrook * 420dcee94Spbrook * Copyright (c) 2007 CodeSourcery. 520dcee94Spbrook * 68e31bf38SMatthew Fernandez * This code is licensed under the GPL 720dcee94Spbrook */ 8*0430891cSPeter 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" 1320dcee94Spbrook 1420dcee94Spbrook typedef struct { 15aa6e4986SBenoît Canet MemoryRegion iomem; 1620dcee94Spbrook uint8_t mr[2]; 1720dcee94Spbrook uint8_t sr; 1820dcee94Spbrook uint8_t isr; 1920dcee94Spbrook uint8_t imr; 2020dcee94Spbrook uint8_t bg1; 2120dcee94Spbrook uint8_t bg2; 2220dcee94Spbrook uint8_t fifo[4]; 2320dcee94Spbrook uint8_t tb; 2420dcee94Spbrook int current_mr; 2520dcee94Spbrook int fifo_len; 2620dcee94Spbrook int tx_enabled; 2720dcee94Spbrook int rx_enabled; 2820dcee94Spbrook qemu_irq irq; 2920dcee94Spbrook CharDriverState *chr; 3020dcee94Spbrook } mcf_uart_state; 3120dcee94Spbrook 3220dcee94Spbrook /* UART Status Register bits. */ 3320dcee94Spbrook #define MCF_UART_RxRDY 0x01 3420dcee94Spbrook #define MCF_UART_FFULL 0x02 3520dcee94Spbrook #define MCF_UART_TxRDY 0x04 3620dcee94Spbrook #define MCF_UART_TxEMP 0x08 3720dcee94Spbrook #define MCF_UART_OE 0x10 3820dcee94Spbrook #define MCF_UART_PE 0x20 3920dcee94Spbrook #define MCF_UART_FE 0x40 4020dcee94Spbrook #define MCF_UART_RB 0x80 4120dcee94Spbrook 4220dcee94Spbrook /* Interrupt flags. */ 4320dcee94Spbrook #define MCF_UART_TxINT 0x01 4420dcee94Spbrook #define MCF_UART_RxINT 0x02 4520dcee94Spbrook #define MCF_UART_DBINT 0x04 4620dcee94Spbrook #define MCF_UART_COSINT 0x80 4720dcee94Spbrook 4820dcee94Spbrook /* UMR1 flags. */ 4920dcee94Spbrook #define MCF_UART_BC0 0x01 5020dcee94Spbrook #define MCF_UART_BC1 0x02 5120dcee94Spbrook #define MCF_UART_PT 0x04 5220dcee94Spbrook #define MCF_UART_PM0 0x08 5320dcee94Spbrook #define MCF_UART_PM1 0x10 5420dcee94Spbrook #define MCF_UART_ERR 0x20 5520dcee94Spbrook #define MCF_UART_RxIRQ 0x40 5620dcee94Spbrook #define MCF_UART_RxRTS 0x80 5720dcee94Spbrook 5820dcee94Spbrook static void mcf_uart_update(mcf_uart_state *s) 5920dcee94Spbrook { 6020dcee94Spbrook s->isr &= ~(MCF_UART_TxINT | MCF_UART_RxINT); 6120dcee94Spbrook if (s->sr & MCF_UART_TxRDY) 6220dcee94Spbrook s->isr |= MCF_UART_TxINT; 6320dcee94Spbrook if ((s->sr & ((s->mr[0] & MCF_UART_RxIRQ) 6420dcee94Spbrook ? MCF_UART_FFULL : MCF_UART_RxRDY)) != 0) 6520dcee94Spbrook s->isr |= MCF_UART_RxINT; 6620dcee94Spbrook 6720dcee94Spbrook qemu_set_irq(s->irq, (s->isr & s->imr) != 0); 6820dcee94Spbrook } 6920dcee94Spbrook 70a8170e5eSAvi Kivity uint64_t mcf_uart_read(void *opaque, hwaddr addr, 71aa6e4986SBenoît Canet unsigned size) 7220dcee94Spbrook { 7320dcee94Spbrook mcf_uart_state *s = (mcf_uart_state *)opaque; 7420dcee94Spbrook switch (addr & 0x3f) { 7520dcee94Spbrook case 0x00: 7620dcee94Spbrook return s->mr[s->current_mr]; 7720dcee94Spbrook case 0x04: 7820dcee94Spbrook return s->sr; 7920dcee94Spbrook case 0x0c: 8020dcee94Spbrook { 8120dcee94Spbrook uint8_t val; 8220dcee94Spbrook int i; 8320dcee94Spbrook 8420dcee94Spbrook if (s->fifo_len == 0) 8520dcee94Spbrook return 0; 8620dcee94Spbrook 8720dcee94Spbrook val = s->fifo[0]; 8820dcee94Spbrook s->fifo_len--; 8920dcee94Spbrook for (i = 0; i < s->fifo_len; i++) 9020dcee94Spbrook s->fifo[i] = s->fifo[i + 1]; 9120dcee94Spbrook s->sr &= ~MCF_UART_FFULL; 9220dcee94Spbrook if (s->fifo_len == 0) 9320dcee94Spbrook s->sr &= ~MCF_UART_RxRDY; 9420dcee94Spbrook mcf_uart_update(s); 95bd9bdce6Sbalrog qemu_chr_accept_input(s->chr); 9620dcee94Spbrook return val; 9720dcee94Spbrook } 9820dcee94Spbrook case 0x10: 9920dcee94Spbrook /* TODO: Implement IPCR. */ 10020dcee94Spbrook return 0; 10120dcee94Spbrook case 0x14: 10220dcee94Spbrook return s->isr; 10320dcee94Spbrook case 0x18: 10420dcee94Spbrook return s->bg1; 10520dcee94Spbrook case 0x1c: 10620dcee94Spbrook return s->bg2; 10720dcee94Spbrook default: 10820dcee94Spbrook return 0; 10920dcee94Spbrook } 11020dcee94Spbrook } 11120dcee94Spbrook 11220dcee94Spbrook /* Update TxRDY flag and set data if present and enabled. */ 11320dcee94Spbrook static void mcf_uart_do_tx(mcf_uart_state *s) 11420dcee94Spbrook { 11520dcee94Spbrook if (s->tx_enabled && (s->sr & MCF_UART_TxEMP) == 0) { 11620dcee94Spbrook if (s->chr) 1172cc6e0a1SAnthony Liguori qemu_chr_fe_write(s->chr, (unsigned char *)&s->tb, 1); 11820dcee94Spbrook s->sr |= MCF_UART_TxEMP; 11920dcee94Spbrook } 12020dcee94Spbrook if (s->tx_enabled) { 12120dcee94Spbrook s->sr |= MCF_UART_TxRDY; 12220dcee94Spbrook } else { 12320dcee94Spbrook s->sr &= ~MCF_UART_TxRDY; 12420dcee94Spbrook } 12520dcee94Spbrook } 12620dcee94Spbrook 12720dcee94Spbrook static void mcf_do_command(mcf_uart_state *s, uint8_t cmd) 12820dcee94Spbrook { 12920dcee94Spbrook /* Misc command. */ 130491ffc1fSPaolo Bonzini switch ((cmd >> 4) & 7) { 13120dcee94Spbrook case 0: /* No-op. */ 13220dcee94Spbrook break; 13320dcee94Spbrook case 1: /* Reset mode register pointer. */ 13420dcee94Spbrook s->current_mr = 0; 13520dcee94Spbrook break; 13620dcee94Spbrook case 2: /* Reset receiver. */ 13720dcee94Spbrook s->rx_enabled = 0; 13820dcee94Spbrook s->fifo_len = 0; 13920dcee94Spbrook s->sr &= ~(MCF_UART_RxRDY | MCF_UART_FFULL); 14020dcee94Spbrook break; 14120dcee94Spbrook case 3: /* Reset transmitter. */ 14220dcee94Spbrook s->tx_enabled = 0; 14320dcee94Spbrook s->sr |= MCF_UART_TxEMP; 14420dcee94Spbrook s->sr &= ~MCF_UART_TxRDY; 14520dcee94Spbrook break; 14620dcee94Spbrook case 4: /* Reset error status. */ 14720dcee94Spbrook break; 14820dcee94Spbrook case 5: /* Reset break-change interrupt. */ 14920dcee94Spbrook s->isr &= ~MCF_UART_DBINT; 15020dcee94Spbrook break; 15120dcee94Spbrook case 6: /* Start break. */ 15220dcee94Spbrook case 7: /* Stop break. */ 15320dcee94Spbrook break; 15420dcee94Spbrook } 15520dcee94Spbrook 15620dcee94Spbrook /* Transmitter command. */ 15720dcee94Spbrook switch ((cmd >> 2) & 3) { 15820dcee94Spbrook case 0: /* No-op. */ 15920dcee94Spbrook break; 16020dcee94Spbrook case 1: /* Enable. */ 16120dcee94Spbrook s->tx_enabled = 1; 16220dcee94Spbrook mcf_uart_do_tx(s); 16320dcee94Spbrook break; 16420dcee94Spbrook case 2: /* Disable. */ 16520dcee94Spbrook s->tx_enabled = 0; 16620dcee94Spbrook mcf_uart_do_tx(s); 16720dcee94Spbrook break; 16820dcee94Spbrook case 3: /* Reserved. */ 16920dcee94Spbrook fprintf(stderr, "mcf_uart: Bad TX command\n"); 17020dcee94Spbrook break; 17120dcee94Spbrook } 17220dcee94Spbrook 17320dcee94Spbrook /* Receiver command. */ 17420dcee94Spbrook switch (cmd & 3) { 17520dcee94Spbrook case 0: /* No-op. */ 17620dcee94Spbrook break; 17720dcee94Spbrook case 1: /* Enable. */ 17820dcee94Spbrook s->rx_enabled = 1; 17920dcee94Spbrook break; 18020dcee94Spbrook case 2: 18120dcee94Spbrook s->rx_enabled = 0; 18220dcee94Spbrook break; 18320dcee94Spbrook case 3: /* Reserved. */ 18420dcee94Spbrook fprintf(stderr, "mcf_uart: Bad RX command\n"); 18520dcee94Spbrook break; 18620dcee94Spbrook } 18720dcee94Spbrook } 18820dcee94Spbrook 189a8170e5eSAvi Kivity void mcf_uart_write(void *opaque, hwaddr addr, 190aa6e4986SBenoît Canet uint64_t val, unsigned size) 19120dcee94Spbrook { 19220dcee94Spbrook mcf_uart_state *s = (mcf_uart_state *)opaque; 19320dcee94Spbrook switch (addr & 0x3f) { 19420dcee94Spbrook case 0x00: 19520dcee94Spbrook s->mr[s->current_mr] = val; 19620dcee94Spbrook s->current_mr = 1; 19720dcee94Spbrook break; 19820dcee94Spbrook case 0x04: 19920dcee94Spbrook /* CSR is ignored. */ 20020dcee94Spbrook break; 20120dcee94Spbrook case 0x08: /* Command Register. */ 20220dcee94Spbrook mcf_do_command(s, val); 20320dcee94Spbrook break; 20420dcee94Spbrook case 0x0c: /* Transmit Buffer. */ 20520dcee94Spbrook s->sr &= ~MCF_UART_TxEMP; 20620dcee94Spbrook s->tb = val; 20720dcee94Spbrook mcf_uart_do_tx(s); 20820dcee94Spbrook break; 20920dcee94Spbrook case 0x10: 21020dcee94Spbrook /* ACR is ignored. */ 21120dcee94Spbrook break; 21220dcee94Spbrook case 0x14: 21320dcee94Spbrook s->imr = val; 21420dcee94Spbrook break; 21520dcee94Spbrook default: 21620dcee94Spbrook break; 21720dcee94Spbrook } 21820dcee94Spbrook mcf_uart_update(s); 21920dcee94Spbrook } 22020dcee94Spbrook 22120dcee94Spbrook static void mcf_uart_reset(mcf_uart_state *s) 22220dcee94Spbrook { 22320dcee94Spbrook s->fifo_len = 0; 22420dcee94Spbrook s->mr[0] = 0; 22520dcee94Spbrook s->mr[1] = 0; 22620dcee94Spbrook s->sr = MCF_UART_TxEMP; 22720dcee94Spbrook s->tx_enabled = 0; 22820dcee94Spbrook s->rx_enabled = 0; 22920dcee94Spbrook s->isr = 0; 23020dcee94Spbrook s->imr = 0; 23120dcee94Spbrook } 23220dcee94Spbrook 23320dcee94Spbrook static void mcf_uart_push_byte(mcf_uart_state *s, uint8_t data) 23420dcee94Spbrook { 23520dcee94Spbrook /* Break events overwrite the last byte if the fifo is full. */ 23620dcee94Spbrook if (s->fifo_len == 4) 23720dcee94Spbrook s->fifo_len--; 23820dcee94Spbrook 23920dcee94Spbrook s->fifo[s->fifo_len] = data; 24020dcee94Spbrook s->fifo_len++; 24120dcee94Spbrook s->sr |= MCF_UART_RxRDY; 24220dcee94Spbrook if (s->fifo_len == 4) 24320dcee94Spbrook s->sr |= MCF_UART_FFULL; 24420dcee94Spbrook 24520dcee94Spbrook mcf_uart_update(s); 24620dcee94Spbrook } 24720dcee94Spbrook 24820dcee94Spbrook static void mcf_uart_event(void *opaque, int event) 24920dcee94Spbrook { 25020dcee94Spbrook mcf_uart_state *s = (mcf_uart_state *)opaque; 25120dcee94Spbrook 25220dcee94Spbrook switch (event) { 25320dcee94Spbrook case CHR_EVENT_BREAK: 25420dcee94Spbrook s->isr |= MCF_UART_DBINT; 25520dcee94Spbrook mcf_uart_push_byte(s, 0); 25620dcee94Spbrook break; 25720dcee94Spbrook default: 25820dcee94Spbrook break; 25920dcee94Spbrook } 26020dcee94Spbrook } 26120dcee94Spbrook 26220dcee94Spbrook static int mcf_uart_can_receive(void *opaque) 26320dcee94Spbrook { 26420dcee94Spbrook mcf_uart_state *s = (mcf_uart_state *)opaque; 26520dcee94Spbrook 26620dcee94Spbrook return s->rx_enabled && (s->sr & MCF_UART_FFULL) == 0; 26720dcee94Spbrook } 26820dcee94Spbrook 26920dcee94Spbrook static void mcf_uart_receive(void *opaque, const uint8_t *buf, int size) 27020dcee94Spbrook { 27120dcee94Spbrook mcf_uart_state *s = (mcf_uart_state *)opaque; 27220dcee94Spbrook 27320dcee94Spbrook mcf_uart_push_byte(s, buf[0]); 27420dcee94Spbrook } 27520dcee94Spbrook 27620dcee94Spbrook void *mcf_uart_init(qemu_irq irq, CharDriverState *chr) 27720dcee94Spbrook { 27820dcee94Spbrook mcf_uart_state *s; 27920dcee94Spbrook 2807267c094SAnthony Liguori s = g_malloc0(sizeof(mcf_uart_state)); 28120dcee94Spbrook s->chr = chr; 28220dcee94Spbrook s->irq = irq; 28320dcee94Spbrook if (chr) { 284456d6069SHans de Goede qemu_chr_fe_claim_no_fail(chr); 28520dcee94Spbrook qemu_chr_add_handlers(chr, mcf_uart_can_receive, mcf_uart_receive, 28620dcee94Spbrook mcf_uart_event, s); 28720dcee94Spbrook } 28820dcee94Spbrook mcf_uart_reset(s); 28920dcee94Spbrook return s; 29020dcee94Spbrook } 29120dcee94Spbrook 292aa6e4986SBenoît Canet static const MemoryRegionOps mcf_uart_ops = { 293aa6e4986SBenoît Canet .read = mcf_uart_read, 294aa6e4986SBenoît Canet .write = mcf_uart_write, 295aa6e4986SBenoît Canet .endianness = DEVICE_NATIVE_ENDIAN, 29620dcee94Spbrook }; 29720dcee94Spbrook 298aa6e4986SBenoît Canet void mcf_uart_mm_init(MemoryRegion *sysmem, 299a8170e5eSAvi Kivity hwaddr base, 300aa6e4986SBenoît Canet qemu_irq irq, 30120dcee94Spbrook CharDriverState *chr) 30220dcee94Spbrook { 30320dcee94Spbrook mcf_uart_state *s; 30420dcee94Spbrook 30520dcee94Spbrook s = mcf_uart_init(irq, chr); 3062c9b15caSPaolo Bonzini memory_region_init_io(&s->iomem, NULL, &mcf_uart_ops, s, "uart", 0x40); 307aa6e4986SBenoît Canet memory_region_add_subregion(sysmem, base, &s->iomem); 30820dcee94Spbrook } 309