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