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