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