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