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