1 /* 2 * Motorola ColdFire MCF5206 SoC embedded peripheral emulation. 3 * 4 * Copyright (c) 2007 CodeSourcery. 5 * 6 * This code is licensed under the GPL 7 */ 8 #include "qemu/osdep.h" 9 #include "qemu-common.h" 10 #include "cpu.h" 11 #include "hw/hw.h" 12 #include "hw/m68k/mcf.h" 13 #include "qemu/timer.h" 14 #include "hw/ptimer.h" 15 #include "sysemu/sysemu.h" 16 #include "exec/address-spaces.h" 17 18 /* General purpose timer module. */ 19 typedef struct { 20 uint16_t tmr; 21 uint16_t trr; 22 uint16_t tcr; 23 uint16_t ter; 24 ptimer_state *timer; 25 qemu_irq irq; 26 int irq_state; 27 } m5206_timer_state; 28 29 #define TMR_RST 0x01 30 #define TMR_CLK 0x06 31 #define TMR_FRR 0x08 32 #define TMR_ORI 0x10 33 #define TMR_OM 0x20 34 #define TMR_CE 0xc0 35 36 #define TER_CAP 0x01 37 #define TER_REF 0x02 38 39 static void m5206_timer_update(m5206_timer_state *s) 40 { 41 if ((s->tmr & TMR_ORI) != 0 && (s->ter & TER_REF)) 42 qemu_irq_raise(s->irq); 43 else 44 qemu_irq_lower(s->irq); 45 } 46 47 static void m5206_timer_reset(m5206_timer_state *s) 48 { 49 s->tmr = 0; 50 s->trr = 0; 51 } 52 53 static void m5206_timer_recalibrate(m5206_timer_state *s) 54 { 55 int prescale; 56 int mode; 57 58 ptimer_stop(s->timer); 59 60 if ((s->tmr & TMR_RST) == 0) 61 return; 62 63 prescale = (s->tmr >> 8) + 1; 64 mode = (s->tmr >> 1) & 3; 65 if (mode == 2) 66 prescale *= 16; 67 68 if (mode == 3 || mode == 0) 69 hw_error("m5206_timer: mode %d not implemented\n", mode); 70 if ((s->tmr & TMR_FRR) == 0) 71 hw_error("m5206_timer: free running mode not implemented\n"); 72 73 /* Assume 66MHz system clock. */ 74 ptimer_set_freq(s->timer, 66000000 / prescale); 75 76 ptimer_set_limit(s->timer, s->trr, 0); 77 78 ptimer_run(s->timer, 0); 79 } 80 81 static void m5206_timer_trigger(void *opaque) 82 { 83 m5206_timer_state *s = (m5206_timer_state *)opaque; 84 s->ter |= TER_REF; 85 m5206_timer_update(s); 86 } 87 88 static uint32_t m5206_timer_read(m5206_timer_state *s, uint32_t addr) 89 { 90 switch (addr) { 91 case 0: 92 return s->tmr; 93 case 4: 94 return s->trr; 95 case 8: 96 return s->tcr; 97 case 0xc: 98 return s->trr - ptimer_get_count(s->timer); 99 case 0x11: 100 return s->ter; 101 default: 102 return 0; 103 } 104 } 105 106 static void m5206_timer_write(m5206_timer_state *s, uint32_t addr, uint32_t val) 107 { 108 switch (addr) { 109 case 0: 110 if ((s->tmr & TMR_RST) != 0 && (val & TMR_RST) == 0) { 111 m5206_timer_reset(s); 112 } 113 s->tmr = val; 114 m5206_timer_recalibrate(s); 115 break; 116 case 4: 117 s->trr = val; 118 m5206_timer_recalibrate(s); 119 break; 120 case 8: 121 s->tcr = val; 122 break; 123 case 0xc: 124 ptimer_set_count(s->timer, val); 125 break; 126 case 0x11: 127 s->ter &= ~val; 128 break; 129 default: 130 break; 131 } 132 m5206_timer_update(s); 133 } 134 135 static m5206_timer_state *m5206_timer_init(qemu_irq irq) 136 { 137 m5206_timer_state *s; 138 QEMUBH *bh; 139 140 s = (m5206_timer_state *)g_malloc0(sizeof(m5206_timer_state)); 141 bh = qemu_bh_new(m5206_timer_trigger, s); 142 s->timer = ptimer_init(bh); 143 s->irq = irq; 144 m5206_timer_reset(s); 145 return s; 146 } 147 148 /* System Integration Module. */ 149 150 typedef struct { 151 M68kCPU *cpu; 152 MemoryRegion iomem; 153 m5206_timer_state *timer[2]; 154 void *uart[2]; 155 uint8_t scr; 156 uint8_t icr[14]; 157 uint16_t imr; /* 1 == interrupt is masked. */ 158 uint16_t ipr; 159 uint8_t rsr; 160 uint8_t swivr; 161 uint8_t par; 162 /* Include the UART vector registers here. */ 163 uint8_t uivr[2]; 164 } m5206_mbar_state; 165 166 /* Interrupt controller. */ 167 168 static int m5206_find_pending_irq(m5206_mbar_state *s) 169 { 170 int level; 171 int vector; 172 uint16_t active; 173 int i; 174 175 level = 0; 176 vector = 0; 177 active = s->ipr & ~s->imr; 178 if (!active) 179 return 0; 180 181 for (i = 1; i < 14; i++) { 182 if (active & (1 << i)) { 183 if ((s->icr[i] & 0x1f) > level) { 184 level = s->icr[i] & 0x1f; 185 vector = i; 186 } 187 } 188 } 189 190 if (level < 4) 191 vector = 0; 192 193 return vector; 194 } 195 196 static void m5206_mbar_update(m5206_mbar_state *s) 197 { 198 int irq; 199 int vector; 200 int level; 201 202 irq = m5206_find_pending_irq(s); 203 if (irq) { 204 int tmp; 205 tmp = s->icr[irq]; 206 level = (tmp >> 2) & 7; 207 if (tmp & 0x80) { 208 /* Autovector. */ 209 vector = 24 + level; 210 } else { 211 switch (irq) { 212 case 8: /* SWT */ 213 vector = s->swivr; 214 break; 215 case 12: /* UART1 */ 216 vector = s->uivr[0]; 217 break; 218 case 13: /* UART2 */ 219 vector = s->uivr[1]; 220 break; 221 default: 222 /* Unknown vector. */ 223 fprintf(stderr, "Unhandled vector for IRQ %d\n", irq); 224 vector = 0xf; 225 break; 226 } 227 } 228 } else { 229 level = 0; 230 vector = 0; 231 } 232 m68k_set_irq_level(s->cpu, level, vector); 233 } 234 235 static void m5206_mbar_set_irq(void *opaque, int irq, int level) 236 { 237 m5206_mbar_state *s = (m5206_mbar_state *)opaque; 238 if (level) { 239 s->ipr |= 1 << irq; 240 } else { 241 s->ipr &= ~(1 << irq); 242 } 243 m5206_mbar_update(s); 244 } 245 246 /* System Integration Module. */ 247 248 static void m5206_mbar_reset(m5206_mbar_state *s) 249 { 250 s->scr = 0xc0; 251 s->icr[1] = 0x04; 252 s->icr[2] = 0x08; 253 s->icr[3] = 0x0c; 254 s->icr[4] = 0x10; 255 s->icr[5] = 0x14; 256 s->icr[6] = 0x18; 257 s->icr[7] = 0x1c; 258 s->icr[8] = 0x1c; 259 s->icr[9] = 0x80; 260 s->icr[10] = 0x80; 261 s->icr[11] = 0x80; 262 s->icr[12] = 0x00; 263 s->icr[13] = 0x00; 264 s->imr = 0x3ffe; 265 s->rsr = 0x80; 266 s->swivr = 0x0f; 267 s->par = 0; 268 } 269 270 static uint64_t m5206_mbar_read(m5206_mbar_state *s, 271 uint64_t offset, unsigned size) 272 { 273 if (offset >= 0x100 && offset < 0x120) { 274 return m5206_timer_read(s->timer[0], offset - 0x100); 275 } else if (offset >= 0x120 && offset < 0x140) { 276 return m5206_timer_read(s->timer[1], offset - 0x120); 277 } else if (offset >= 0x140 && offset < 0x160) { 278 return mcf_uart_read(s->uart[0], offset - 0x140, size); 279 } else if (offset >= 0x180 && offset < 0x1a0) { 280 return mcf_uart_read(s->uart[1], offset - 0x180, size); 281 } 282 switch (offset) { 283 case 0x03: return s->scr; 284 case 0x14 ... 0x20: return s->icr[offset - 0x13]; 285 case 0x36: return s->imr; 286 case 0x3a: return s->ipr; 287 case 0x40: return s->rsr; 288 case 0x41: return 0; 289 case 0x42: return s->swivr; 290 case 0x50: 291 /* DRAM mask register. */ 292 /* FIXME: currently hardcoded to 128Mb. */ 293 { 294 uint32_t mask = ~0; 295 while (mask > ram_size) 296 mask >>= 1; 297 return mask & 0x0ffe0000; 298 } 299 case 0x5c: return 1; /* DRAM bank 1 empty. */ 300 case 0xcb: return s->par; 301 case 0x170: return s->uivr[0]; 302 case 0x1b0: return s->uivr[1]; 303 } 304 hw_error("Bad MBAR read offset 0x%x", (int)offset); 305 return 0; 306 } 307 308 static void m5206_mbar_write(m5206_mbar_state *s, uint32_t offset, 309 uint64_t value, unsigned size) 310 { 311 if (offset >= 0x100 && offset < 0x120) { 312 m5206_timer_write(s->timer[0], offset - 0x100, value); 313 return; 314 } else if (offset >= 0x120 && offset < 0x140) { 315 m5206_timer_write(s->timer[1], offset - 0x120, value); 316 return; 317 } else if (offset >= 0x140 && offset < 0x160) { 318 mcf_uart_write(s->uart[0], offset - 0x140, value, size); 319 return; 320 } else if (offset >= 0x180 && offset < 0x1a0) { 321 mcf_uart_write(s->uart[1], offset - 0x180, value, size); 322 return; 323 } 324 switch (offset) { 325 case 0x03: 326 s->scr = value; 327 break; 328 case 0x14 ... 0x20: 329 s->icr[offset - 0x13] = value; 330 m5206_mbar_update(s); 331 break; 332 case 0x36: 333 s->imr = value; 334 m5206_mbar_update(s); 335 break; 336 case 0x40: 337 s->rsr &= ~value; 338 break; 339 case 0x41: 340 /* TODO: implement watchdog. */ 341 break; 342 case 0x42: 343 s->swivr = value; 344 break; 345 case 0xcb: 346 s->par = value; 347 break; 348 case 0x170: 349 s->uivr[0] = value; 350 break; 351 case 0x178: case 0x17c: case 0x1c8: case 0x1bc: 352 /* Not implemented: UART Output port bits. */ 353 break; 354 case 0x1b0: 355 s->uivr[1] = value; 356 break; 357 default: 358 hw_error("Bad MBAR write offset 0x%x", (int)offset); 359 break; 360 } 361 } 362 363 /* Internal peripherals use a variety of register widths. 364 This lookup table allows a single routine to handle all of them. */ 365 static const uint8_t m5206_mbar_width[] = 366 { 367 /* 000-040 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 368 /* 040-080 */ 1, 2, 2, 2, 4, 1, 2, 4, 1, 2, 4, 2, 2, 4, 2, 2, 369 /* 080-0c0 */ 4, 2, 2, 4, 2, 2, 4, 2, 2, 4, 2, 2, 4, 2, 2, 4, 370 /* 0c0-100 */ 2, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 371 /* 100-140 */ 2, 2, 2, 2, 1, 0, 0, 0, 2, 2, 2, 2, 1, 0, 0, 0, 372 /* 140-180 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 373 /* 180-1c0 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 374 /* 1c0-200 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 375 }; 376 377 static uint32_t m5206_mbar_readw(void *opaque, hwaddr offset); 378 static uint32_t m5206_mbar_readl(void *opaque, hwaddr offset); 379 380 static uint32_t m5206_mbar_readb(void *opaque, hwaddr offset) 381 { 382 m5206_mbar_state *s = (m5206_mbar_state *)opaque; 383 offset &= 0x3ff; 384 if (offset >= 0x200) { 385 hw_error("Bad MBAR read offset 0x%x", (int)offset); 386 } 387 if (m5206_mbar_width[offset >> 2] > 1) { 388 uint16_t val; 389 val = m5206_mbar_readw(opaque, offset & ~1); 390 if ((offset & 1) == 0) { 391 val >>= 8; 392 } 393 return val & 0xff; 394 } 395 return m5206_mbar_read(s, offset, 1); 396 } 397 398 static uint32_t m5206_mbar_readw(void *opaque, hwaddr offset) 399 { 400 m5206_mbar_state *s = (m5206_mbar_state *)opaque; 401 int width; 402 offset &= 0x3ff; 403 if (offset >= 0x200) { 404 hw_error("Bad MBAR read offset 0x%x", (int)offset); 405 } 406 width = m5206_mbar_width[offset >> 2]; 407 if (width > 2) { 408 uint32_t val; 409 val = m5206_mbar_readl(opaque, offset & ~3); 410 if ((offset & 3) == 0) 411 val >>= 16; 412 return val & 0xffff; 413 } else if (width < 2) { 414 uint16_t val; 415 val = m5206_mbar_readb(opaque, offset) << 8; 416 val |= m5206_mbar_readb(opaque, offset + 1); 417 return val; 418 } 419 return m5206_mbar_read(s, offset, 2); 420 } 421 422 static uint32_t m5206_mbar_readl(void *opaque, hwaddr offset) 423 { 424 m5206_mbar_state *s = (m5206_mbar_state *)opaque; 425 int width; 426 offset &= 0x3ff; 427 if (offset >= 0x200) { 428 hw_error("Bad MBAR read offset 0x%x", (int)offset); 429 } 430 width = m5206_mbar_width[offset >> 2]; 431 if (width < 4) { 432 uint32_t val; 433 val = m5206_mbar_readw(opaque, offset) << 16; 434 val |= m5206_mbar_readw(opaque, offset + 2); 435 return val; 436 } 437 return m5206_mbar_read(s, offset, 4); 438 } 439 440 static void m5206_mbar_writew(void *opaque, hwaddr offset, 441 uint32_t value); 442 static void m5206_mbar_writel(void *opaque, hwaddr offset, 443 uint32_t value); 444 445 static void m5206_mbar_writeb(void *opaque, hwaddr offset, 446 uint32_t value) 447 { 448 m5206_mbar_state *s = (m5206_mbar_state *)opaque; 449 int width; 450 offset &= 0x3ff; 451 if (offset >= 0x200) { 452 hw_error("Bad MBAR write offset 0x%x", (int)offset); 453 } 454 width = m5206_mbar_width[offset >> 2]; 455 if (width > 1) { 456 uint32_t tmp; 457 tmp = m5206_mbar_readw(opaque, offset & ~1); 458 if (offset & 1) { 459 tmp = (tmp & 0xff00) | value; 460 } else { 461 tmp = (tmp & 0x00ff) | (value << 8); 462 } 463 m5206_mbar_writew(opaque, offset & ~1, tmp); 464 return; 465 } 466 m5206_mbar_write(s, offset, value, 1); 467 } 468 469 static void m5206_mbar_writew(void *opaque, hwaddr offset, 470 uint32_t value) 471 { 472 m5206_mbar_state *s = (m5206_mbar_state *)opaque; 473 int width; 474 offset &= 0x3ff; 475 if (offset >= 0x200) { 476 hw_error("Bad MBAR write offset 0x%x", (int)offset); 477 } 478 width = m5206_mbar_width[offset >> 2]; 479 if (width > 2) { 480 uint32_t tmp; 481 tmp = m5206_mbar_readl(opaque, offset & ~3); 482 if (offset & 3) { 483 tmp = (tmp & 0xffff0000) | value; 484 } else { 485 tmp = (tmp & 0x0000ffff) | (value << 16); 486 } 487 m5206_mbar_writel(opaque, offset & ~3, tmp); 488 return; 489 } else if (width < 2) { 490 m5206_mbar_writeb(opaque, offset, value >> 8); 491 m5206_mbar_writeb(opaque, offset + 1, value & 0xff); 492 return; 493 } 494 m5206_mbar_write(s, offset, value, 2); 495 } 496 497 static void m5206_mbar_writel(void *opaque, hwaddr offset, 498 uint32_t value) 499 { 500 m5206_mbar_state *s = (m5206_mbar_state *)opaque; 501 int width; 502 offset &= 0x3ff; 503 if (offset >= 0x200) { 504 hw_error("Bad MBAR write offset 0x%x", (int)offset); 505 } 506 width = m5206_mbar_width[offset >> 2]; 507 if (width < 4) { 508 m5206_mbar_writew(opaque, offset, value >> 16); 509 m5206_mbar_writew(opaque, offset + 2, value & 0xffff); 510 return; 511 } 512 m5206_mbar_write(s, offset, value, 4); 513 } 514 515 static const MemoryRegionOps m5206_mbar_ops = { 516 .old_mmio = { 517 .read = { 518 m5206_mbar_readb, 519 m5206_mbar_readw, 520 m5206_mbar_readl, 521 }, 522 .write = { 523 m5206_mbar_writeb, 524 m5206_mbar_writew, 525 m5206_mbar_writel, 526 }, 527 }, 528 .endianness = DEVICE_NATIVE_ENDIAN, 529 }; 530 531 qemu_irq *mcf5206_init(MemoryRegion *sysmem, uint32_t base, M68kCPU *cpu) 532 { 533 m5206_mbar_state *s; 534 qemu_irq *pic; 535 536 s = (m5206_mbar_state *)g_malloc0(sizeof(m5206_mbar_state)); 537 538 memory_region_init_io(&s->iomem, NULL, &m5206_mbar_ops, s, 539 "mbar", 0x00001000); 540 memory_region_add_subregion(sysmem, base, &s->iomem); 541 542 pic = qemu_allocate_irqs(m5206_mbar_set_irq, s, 14); 543 s->timer[0] = m5206_timer_init(pic[9]); 544 s->timer[1] = m5206_timer_init(pic[10]); 545 s->uart[0] = mcf_uart_init(pic[12], serial_hds[0]); 546 s->uart[1] = mcf_uart_init(pic[13], serial_hds[1]); 547 s->cpu = cpu; 548 549 m5206_mbar_reset(s); 550 return pic; 551 } 552