1 /* 2 * QEMU SCI/SCIF serial port emulation 3 * 4 * Copyright (c) 2007 Magnus Damm 5 * 6 * Based on serial.c - QEMU 16450 UART emulation 7 * Copyright (c) 2003-2004 Fabrice Bellard 8 * 9 * Permission is hereby granted, free of charge, to any person obtaining a copy 10 * of this software and associated documentation files (the "Software"), to deal 11 * in the Software without restriction, including without limitation the rights 12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 * copies of the Software, and to permit persons to whom the Software is 14 * furnished to do so, subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included in 17 * all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 * THE SOFTWARE. 26 */ 27 #include "hw.h" 28 #include "sh.h" 29 #include "qemu-char.h" 30 31 //#define DEBUG_SERIAL 32 33 #define SH_SERIAL_FLAG_TEND (1 << 0) 34 #define SH_SERIAL_FLAG_TDE (1 << 1) 35 #define SH_SERIAL_FLAG_RDF (1 << 2) 36 #define SH_SERIAL_FLAG_BRK (1 << 3) 37 #define SH_SERIAL_FLAG_DR (1 << 4) 38 39 #define SH_RX_FIFO_LENGTH (16) 40 41 typedef struct { 42 uint8_t smr; 43 uint8_t brr; 44 uint8_t scr; 45 uint8_t dr; /* ftdr / tdr */ 46 uint8_t sr; /* fsr / ssr */ 47 uint16_t fcr; 48 uint8_t sptr; 49 50 uint8_t rx_fifo[SH_RX_FIFO_LENGTH]; /* frdr / rdr */ 51 uint8_t rx_cnt; 52 uint8_t rx_tail; 53 uint8_t rx_head; 54 55 int freq; 56 int feat; 57 int flags; 58 int rtrg; 59 60 CharDriverState *chr; 61 62 qemu_irq eri; 63 qemu_irq rxi; 64 qemu_irq txi; 65 qemu_irq tei; 66 qemu_irq bri; 67 } sh_serial_state; 68 69 static void sh_serial_clear_fifo(sh_serial_state * s) 70 { 71 memset(s->rx_fifo, 0, SH_RX_FIFO_LENGTH); 72 s->rx_cnt = 0; 73 s->rx_head = 0; 74 s->rx_tail = 0; 75 } 76 77 static void sh_serial_ioport_write(void *opaque, uint32_t offs, uint32_t val) 78 { 79 sh_serial_state *s = opaque; 80 unsigned char ch; 81 82 #ifdef DEBUG_SERIAL 83 printf("sh_serial: write offs=0x%02x val=0x%02x\n", 84 offs, val); 85 #endif 86 switch(offs) { 87 case 0x00: /* SMR */ 88 s->smr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0x7b : 0xff); 89 return; 90 case 0x04: /* BRR */ 91 s->brr = val; 92 return; 93 case 0x08: /* SCR */ 94 /* TODO : For SH7751, SCIF mask should be 0xfb. */ 95 s->scr = val & ((s->feat & SH_SERIAL_FEAT_SCIF) ? 0xfa : 0xff); 96 if (!(val & (1 << 5))) 97 s->flags |= SH_SERIAL_FLAG_TEND; 98 if ((s->feat & SH_SERIAL_FEAT_SCIF) && s->txi) { 99 qemu_set_irq(s->txi, val & (1 << 7)); 100 } 101 if (!(val & (1 << 6))) { 102 qemu_set_irq(s->rxi, 0); 103 } 104 return; 105 case 0x0c: /* FTDR / TDR */ 106 if (s->chr) { 107 ch = val; 108 qemu_chr_write(s->chr, &ch, 1); 109 } 110 s->dr = val; 111 s->flags &= ~SH_SERIAL_FLAG_TDE; 112 return; 113 #if 0 114 case 0x14: /* FRDR / RDR */ 115 ret = 0; 116 break; 117 #endif 118 } 119 if (s->feat & SH_SERIAL_FEAT_SCIF) { 120 switch(offs) { 121 case 0x10: /* FSR */ 122 if (!(val & (1 << 6))) 123 s->flags &= ~SH_SERIAL_FLAG_TEND; 124 if (!(val & (1 << 5))) 125 s->flags &= ~SH_SERIAL_FLAG_TDE; 126 if (!(val & (1 << 4))) 127 s->flags &= ~SH_SERIAL_FLAG_BRK; 128 if (!(val & (1 << 1))) 129 s->flags &= ~SH_SERIAL_FLAG_RDF; 130 if (!(val & (1 << 0))) 131 s->flags &= ~SH_SERIAL_FLAG_DR; 132 133 if (!(val & (1 << 1)) || !(val & (1 << 0))) { 134 if (s->rxi) { 135 qemu_set_irq(s->rxi, 0); 136 } 137 } 138 return; 139 case 0x18: /* FCR */ 140 s->fcr = val; 141 switch ((val >> 6) & 3) { 142 case 0: 143 s->rtrg = 1; 144 break; 145 case 1: 146 s->rtrg = 4; 147 break; 148 case 2: 149 s->rtrg = 8; 150 break; 151 case 3: 152 s->rtrg = 14; 153 break; 154 } 155 if (val & (1 << 1)) { 156 sh_serial_clear_fifo(s); 157 s->sr &= ~(1 << 1); 158 } 159 160 return; 161 case 0x20: /* SPTR */ 162 s->sptr = val & 0xf3; 163 return; 164 case 0x24: /* LSR */ 165 return; 166 } 167 } 168 else { 169 switch(offs) { 170 #if 0 171 case 0x0c: 172 ret = s->dr; 173 break; 174 case 0x10: 175 ret = 0; 176 break; 177 #endif 178 case 0x1c: 179 s->sptr = val & 0x8f; 180 return; 181 } 182 } 183 184 fprintf(stderr, "sh_serial: unsupported write to 0x%02x\n", offs); 185 assert(0); 186 } 187 188 static uint32_t sh_serial_ioport_read(void *opaque, uint32_t offs) 189 { 190 sh_serial_state *s = opaque; 191 uint32_t ret = ~0; 192 193 #if 0 194 switch(offs) { 195 case 0x00: 196 ret = s->smr; 197 break; 198 case 0x04: 199 ret = s->brr; 200 break; 201 case 0x08: 202 ret = s->scr; 203 break; 204 case 0x14: 205 ret = 0; 206 break; 207 } 208 #endif 209 if (s->feat & SH_SERIAL_FEAT_SCIF) { 210 switch(offs) { 211 case 0x00: /* SMR */ 212 ret = s->smr; 213 break; 214 case 0x08: /* SCR */ 215 ret = s->scr; 216 break; 217 case 0x10: /* FSR */ 218 ret = 0; 219 if (s->flags & SH_SERIAL_FLAG_TEND) 220 ret |= (1 << 6); 221 if (s->flags & SH_SERIAL_FLAG_TDE) 222 ret |= (1 << 5); 223 if (s->flags & SH_SERIAL_FLAG_BRK) 224 ret |= (1 << 4); 225 if (s->flags & SH_SERIAL_FLAG_RDF) 226 ret |= (1 << 1); 227 if (s->flags & SH_SERIAL_FLAG_DR) 228 ret |= (1 << 0); 229 230 if (s->scr & (1 << 5)) 231 s->flags |= SH_SERIAL_FLAG_TDE | SH_SERIAL_FLAG_TEND; 232 233 break; 234 case 0x14: 235 if (s->rx_cnt > 0) { 236 ret = s->rx_fifo[s->rx_tail++]; 237 s->rx_cnt--; 238 if (s->rx_tail == SH_RX_FIFO_LENGTH) 239 s->rx_tail = 0; 240 if (s->rx_cnt < s->rtrg) 241 s->flags &= ~SH_SERIAL_FLAG_RDF; 242 } 243 break; 244 #if 0 245 case 0x18: 246 ret = s->fcr; 247 break; 248 #endif 249 case 0x1c: 250 ret = s->rx_cnt; 251 break; 252 case 0x20: 253 ret = s->sptr; 254 break; 255 case 0x24: 256 ret = 0; 257 break; 258 } 259 } 260 else { 261 switch(offs) { 262 #if 0 263 case 0x0c: 264 ret = s->dr; 265 break; 266 case 0x10: 267 ret = 0; 268 break; 269 case 0x14: 270 ret = s->rx_fifo[0]; 271 break; 272 #endif 273 case 0x1c: 274 ret = s->sptr; 275 break; 276 } 277 } 278 #ifdef DEBUG_SERIAL 279 printf("sh_serial: read offs=0x%02x val=0x%x\n", 280 offs, ret); 281 #endif 282 283 if (ret & ~((1 << 16) - 1)) { 284 fprintf(stderr, "sh_serial: unsupported read from 0x%02x\n", offs); 285 assert(0); 286 } 287 288 return ret; 289 } 290 291 static int sh_serial_can_receive(sh_serial_state *s) 292 { 293 return s->scr & (1 << 4); 294 } 295 296 static void sh_serial_receive_byte(sh_serial_state *s, int ch) 297 { 298 if (s->feat & SH_SERIAL_FEAT_SCIF) { 299 if (s->rx_cnt < SH_RX_FIFO_LENGTH) { 300 s->rx_fifo[s->rx_head++] = ch; 301 if (s->rx_head == SH_RX_FIFO_LENGTH) 302 s->rx_head = 0; 303 s->rx_cnt++; 304 if (s->rx_cnt >= s->rtrg) { 305 s->flags |= SH_SERIAL_FLAG_RDF; 306 if (s->scr & (1 << 6) && s->rxi) { 307 qemu_set_irq(s->rxi, 1); 308 } 309 } 310 } 311 } else { 312 s->rx_fifo[0] = ch; 313 } 314 } 315 316 static void sh_serial_receive_break(sh_serial_state *s) 317 { 318 if (s->feat & SH_SERIAL_FEAT_SCIF) 319 s->sr |= (1 << 4); 320 } 321 322 static int sh_serial_can_receive1(void *opaque) 323 { 324 sh_serial_state *s = opaque; 325 return sh_serial_can_receive(s); 326 } 327 328 static void sh_serial_receive1(void *opaque, const uint8_t *buf, int size) 329 { 330 sh_serial_state *s = opaque; 331 sh_serial_receive_byte(s, buf[0]); 332 } 333 334 static void sh_serial_event(void *opaque, int event) 335 { 336 sh_serial_state *s = opaque; 337 if (event == CHR_EVENT_BREAK) 338 sh_serial_receive_break(s); 339 } 340 341 static uint32_t sh_serial_read (void *opaque, target_phys_addr_t addr) 342 { 343 sh_serial_state *s = opaque; 344 return sh_serial_ioport_read(s, addr); 345 } 346 347 static void sh_serial_write (void *opaque, 348 target_phys_addr_t addr, uint32_t value) 349 { 350 sh_serial_state *s = opaque; 351 sh_serial_ioport_write(s, addr, value); 352 } 353 354 static CPUReadMemoryFunc *sh_serial_readfn[] = { 355 &sh_serial_read, 356 &sh_serial_read, 357 &sh_serial_read, 358 }; 359 360 static CPUWriteMemoryFunc *sh_serial_writefn[] = { 361 &sh_serial_write, 362 &sh_serial_write, 363 &sh_serial_write, 364 }; 365 366 void sh_serial_init (target_phys_addr_t base, int feat, 367 uint32_t freq, CharDriverState *chr, 368 qemu_irq eri_source, 369 qemu_irq rxi_source, 370 qemu_irq txi_source, 371 qemu_irq tei_source, 372 qemu_irq bri_source) 373 { 374 sh_serial_state *s; 375 int s_io_memory; 376 377 s = qemu_mallocz(sizeof(sh_serial_state)); 378 379 s->feat = feat; 380 s->flags = SH_SERIAL_FLAG_TEND | SH_SERIAL_FLAG_TDE; 381 s->rtrg = 1; 382 383 s->smr = 0; 384 s->brr = 0xff; 385 s->scr = 1 << 5; /* pretend that TX is enabled so early printk works */ 386 s->sptr = 0; 387 388 if (feat & SH_SERIAL_FEAT_SCIF) { 389 s->fcr = 0; 390 } 391 else { 392 s->dr = 0xff; 393 } 394 395 sh_serial_clear_fifo(s); 396 397 s_io_memory = cpu_register_io_memory(0, sh_serial_readfn, 398 sh_serial_writefn, s); 399 cpu_register_physical_memory(P4ADDR(base), 0x28, s_io_memory); 400 cpu_register_physical_memory(A7ADDR(base), 0x28, s_io_memory); 401 402 s->chr = chr; 403 404 if (chr) 405 qemu_chr_add_handlers(chr, sh_serial_can_receive1, sh_serial_receive1, 406 sh_serial_event, s); 407 408 s->eri = eri_source; 409 s->rxi = rxi_source; 410 s->txi = txi_source; 411 s->tei = tei_source; 412 s->bri = bri_source; 413 } 414