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