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