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