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