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