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