|
|
1.1 ! root 1: /* ! 2: * OpenPIC emulation ! 3: * ! 4: * Copyright (c) 2004 Jocelyn Mayer ! 5: * ! 6: * Permission is hereby granted, free of charge, to any person obtaining a copy ! 7: * of this software and associated documentation files (the "Software"), to deal ! 8: * in the Software without restriction, including without limitation the rights ! 9: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell ! 10: * copies of the Software, and to permit persons to whom the Software is ! 11: * furnished to do so, subject to the following conditions: ! 12: * ! 13: * The above copyright notice and this permission notice shall be included in ! 14: * all copies or substantial portions of the Software. ! 15: * ! 16: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ! 17: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ! 19: * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ! 20: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, ! 21: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN ! 22: * THE SOFTWARE. ! 23: */ ! 24: /* ! 25: * ! 26: * Based on OpenPic implementations: ! 27: * - Intel GW80314 I/O compagnion chip developper's manual ! 28: * - Motorola MPC8245 & MPC8540 user manuals. ! 29: * - Motorola MCP750 (aka Raven) programmer manual. ! 30: * - Motorola Harrier programmer manuel ! 31: * ! 32: * Serial interrupts, as implemented in Raven chipset are not supported yet. ! 33: * ! 34: */ ! 35: #include "vl.h" ! 36: ! 37: //#define DEBUG_OPENPIC ! 38: ! 39: #ifdef DEBUG_OPENPIC ! 40: #define DPRINTF(fmt, args...) do { printf(fmt , ##args); } while (0) ! 41: #else ! 42: #define DPRINTF(fmt, args...) do { } while (0) ! 43: #endif ! 44: #define ERROR(fmr, args...) do { printf("ERROR: " fmr , ##args); } while (0) ! 45: ! 46: #define USE_MPCxxx /* Intel model is broken, for now */ ! 47: ! 48: #if defined (USE_INTEL_GW80314) ! 49: /* Intel GW80314 I/O Companion chip */ ! 50: ! 51: #define MAX_CPU 4 ! 52: #define MAX_IRQ 32 ! 53: #define MAX_DBL 4 ! 54: #define MAX_MBX 4 ! 55: #define MAX_TMR 4 ! 56: #define VECTOR_BITS 8 ! 57: #define MAX_IPI 0 ! 58: ! 59: #define VID (0x00000000) ! 60: ! 61: #define OPENPIC_LITTLE_ENDIAN 1 ! 62: #define OPENPIC_BIG_ENDIAN 0 ! 63: ! 64: #elif defined(USE_MPCxxx) ! 65: ! 66: #define MAX_CPU 2 ! 67: #define MAX_IRQ 64 ! 68: #define EXT_IRQ 48 ! 69: #define MAX_DBL 0 ! 70: #define MAX_MBX 0 ! 71: #define MAX_TMR 4 ! 72: #define VECTOR_BITS 8 ! 73: #define MAX_IPI 4 ! 74: #define VID 0x03 /* MPIC version ID */ ! 75: #define VENI 0x00000000 /* Vendor ID */ ! 76: ! 77: enum { ! 78: IRQ_IPVP = 0, ! 79: IRQ_IDE, ! 80: }; ! 81: ! 82: #define OPENPIC_LITTLE_ENDIAN 1 ! 83: #define OPENPIC_BIG_ENDIAN 0 ! 84: ! 85: #else ! 86: #error "Please select which OpenPic implementation is to be emulated" ! 87: #endif ! 88: ! 89: #if (OPENPIC_BIG_ENDIAN && !TARGET_WORDS_BIGENDIAN) || \ ! 90: (OPENPIC_LITTLE_ENDIAN && TARGET_WORDS_BIGENDIAN) ! 91: #define OPENPIC_SWAP ! 92: #endif ! 93: ! 94: /* Interrupt definitions */ ! 95: #define IRQ_FE (EXT_IRQ) /* Internal functional IRQ */ ! 96: #define IRQ_ERR (EXT_IRQ + 1) /* Error IRQ */ ! 97: #define IRQ_TIM0 (EXT_IRQ + 2) /* First timer IRQ */ ! 98: #if MAX_IPI > 0 ! 99: #define IRQ_IPI0 (IRQ_TIM0 + MAX_TMR) /* First IPI IRQ */ ! 100: #define IRQ_DBL0 (IRQ_IPI0 + (MAX_CPU * MAX_IPI)) /* First doorbell IRQ */ ! 101: #else ! 102: #define IRQ_DBL0 (IRQ_TIM0 + MAX_TMR) /* First doorbell IRQ */ ! 103: #define IRQ_MBX0 (IRQ_DBL0 + MAX_DBL) /* First mailbox IRQ */ ! 104: #endif ! 105: ! 106: #define BF_WIDTH(_bits_) \ ! 107: (((_bits_) + (sizeof(uint32_t) * 8) - 1) / (sizeof(uint32_t) * 8)) ! 108: ! 109: static inline void set_bit (uint32_t *field, int bit) ! 110: { ! 111: field[bit >> 5] |= 1 << (bit & 0x1F); ! 112: } ! 113: ! 114: static inline void reset_bit (uint32_t *field, int bit) ! 115: { ! 116: field[bit >> 5] &= ~(1 << (bit & 0x1F)); ! 117: } ! 118: ! 119: static inline int test_bit (uint32_t *field, int bit) ! 120: { ! 121: return (field[bit >> 5] & 1 << (bit & 0x1F)) != 0; ! 122: } ! 123: ! 124: enum { ! 125: IRQ_EXTERNAL = 0x01, ! 126: IRQ_INTERNAL = 0x02, ! 127: IRQ_TIMER = 0x04, ! 128: IRQ_SPECIAL = 0x08, ! 129: } IRQ_src_type; ! 130: ! 131: typedef struct IRQ_queue_t { ! 132: uint32_t queue[BF_WIDTH(MAX_IRQ)]; ! 133: int next; ! 134: int priority; ! 135: } IRQ_queue_t; ! 136: ! 137: typedef struct IRQ_src_t { ! 138: uint32_t ipvp; /* IRQ vector/priority register */ ! 139: uint32_t ide; /* IRQ destination register */ ! 140: int type; ! 141: int last_cpu; ! 142: int pending; /* TRUE if IRQ is pending */ ! 143: } IRQ_src_t; ! 144: ! 145: enum IPVP_bits { ! 146: IPVP_MASK = 31, ! 147: IPVP_ACTIVITY = 30, ! 148: IPVP_MODE = 29, ! 149: IPVP_POLARITY = 23, ! 150: IPVP_SENSE = 22, ! 151: }; ! 152: #define IPVP_PRIORITY_MASK (0x1F << 16) ! 153: #define IPVP_PRIORITY(_ipvpr_) ((int)(((_ipvpr_) & IPVP_PRIORITY_MASK) >> 16)) ! 154: #define IPVP_VECTOR_MASK ((1 << VECTOR_BITS) - 1) ! 155: #define IPVP_VECTOR(_ipvpr_) ((_ipvpr_) & IPVP_VECTOR_MASK) ! 156: ! 157: typedef struct IRQ_dst_t { ! 158: uint32_t pctp; /* CPU current task priority */ ! 159: uint32_t pcsr; /* CPU sensitivity register */ ! 160: IRQ_queue_t raised; ! 161: IRQ_queue_t servicing; ! 162: CPUState *env; /* Needed if we did SMP */ ! 163: } IRQ_dst_t; ! 164: ! 165: struct openpic_t { ! 166: PCIDevice pci_dev; ! 167: int mem_index; ! 168: /* Global registers */ ! 169: uint32_t frep; /* Feature reporting register */ ! 170: uint32_t glbc; /* Global configuration register */ ! 171: uint32_t micr; /* MPIC interrupt configuration register */ ! 172: uint32_t veni; /* Vendor identification register */ ! 173: uint32_t spve; /* Spurious vector register */ ! 174: uint32_t tifr; /* Timer frequency reporting register */ ! 175: /* Source registers */ ! 176: IRQ_src_t src[MAX_IRQ]; ! 177: /* Local registers per output pin */ ! 178: IRQ_dst_t dst[MAX_CPU]; ! 179: int nb_cpus; ! 180: /* Timer registers */ ! 181: struct { ! 182: uint32_t ticc; /* Global timer current count register */ ! 183: uint32_t tibc; /* Global timer base count register */ ! 184: } timers[MAX_TMR]; ! 185: #if MAX_DBL > 0 ! 186: /* Doorbell registers */ ! 187: uint32_t dar; /* Doorbell activate register */ ! 188: struct { ! 189: uint32_t dmr; /* Doorbell messaging register */ ! 190: } doorbells[MAX_DBL]; ! 191: #endif ! 192: #if MAX_MBX > 0 ! 193: /* Mailbox registers */ ! 194: struct { ! 195: uint32_t mbr; /* Mailbox register */ ! 196: } mailboxes[MAX_MAILBOXES]; ! 197: #endif ! 198: }; ! 199: ! 200: static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ) ! 201: { ! 202: set_bit(q->queue, n_IRQ); ! 203: } ! 204: ! 205: static inline void IRQ_resetbit (IRQ_queue_t *q, int n_IRQ) ! 206: { ! 207: reset_bit(q->queue, n_IRQ); ! 208: } ! 209: ! 210: static inline int IRQ_testbit (IRQ_queue_t *q, int n_IRQ) ! 211: { ! 212: return test_bit(q->queue, n_IRQ); ! 213: } ! 214: ! 215: static void IRQ_check (openpic_t *opp, IRQ_queue_t *q) ! 216: { ! 217: int next, i; ! 218: int priority; ! 219: ! 220: next = -1; ! 221: priority = -1; ! 222: for (i = 0; i < MAX_IRQ; i++) { ! 223: if (IRQ_testbit(q, i)) { ! 224: DPRINTF("IRQ_check: irq %d set ipvp_pr=%d pr=%d\n", ! 225: i, IPVP_PRIORITY(opp->src[i].ipvp), priority); ! 226: if (IPVP_PRIORITY(opp->src[i].ipvp) > priority) { ! 227: next = i; ! 228: priority = IPVP_PRIORITY(opp->src[i].ipvp); ! 229: } ! 230: } ! 231: } ! 232: q->next = next; ! 233: q->priority = priority; ! 234: } ! 235: ! 236: static int IRQ_get_next (openpic_t *opp, IRQ_queue_t *q) ! 237: { ! 238: if (q->next == -1) { ! 239: /* XXX: optimize */ ! 240: IRQ_check(opp, q); ! 241: } ! 242: ! 243: return q->next; ! 244: } ! 245: ! 246: static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ) ! 247: { ! 248: IRQ_dst_t *dst; ! 249: IRQ_src_t *src; ! 250: int priority; ! 251: ! 252: dst = &opp->dst[n_CPU]; ! 253: src = &opp->src[n_IRQ]; ! 254: priority = IPVP_PRIORITY(src->ipvp); ! 255: if (priority <= dst->pctp) { ! 256: /* Too low priority */ ! 257: return; ! 258: } ! 259: if (IRQ_testbit(&dst->raised, n_IRQ)) { ! 260: /* Interrupt miss */ ! 261: return; ! 262: } ! 263: set_bit(&src->ipvp, IPVP_ACTIVITY); ! 264: IRQ_setbit(&dst->raised, n_IRQ); ! 265: if (priority > dst->raised.priority) { ! 266: IRQ_get_next(opp, &dst->raised); ! 267: DPRINTF("Raise CPU IRQ\n"); ! 268: cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); ! 269: } ! 270: } ! 271: ! 272: /* update pic state because registers for n_IRQ have changed value */ ! 273: static void openpic_update_irq(openpic_t *opp, int n_IRQ) ! 274: { ! 275: IRQ_src_t *src; ! 276: int i; ! 277: ! 278: src = &opp->src[n_IRQ]; ! 279: ! 280: if (!src->pending) { ! 281: /* no irq pending */ ! 282: return; ! 283: } ! 284: if (test_bit(&src->ipvp, IPVP_MASK)) { ! 285: /* Interrupt source is disabled */ ! 286: return; ! 287: } ! 288: if (IPVP_PRIORITY(src->ipvp) == 0) { ! 289: /* Priority set to zero */ ! 290: return; ! 291: } ! 292: if (test_bit(&src->ipvp, IPVP_ACTIVITY)) { ! 293: /* IRQ already active */ ! 294: return; ! 295: } ! 296: if (src->ide == 0x00000000) { ! 297: /* No target */ ! 298: return; ! 299: } ! 300: ! 301: if (!test_bit(&src->ipvp, IPVP_MODE) || ! 302: src->ide == (1 << src->last_cpu)) { ! 303: /* Directed delivery mode */ ! 304: for (i = 0; i < opp->nb_cpus; i++) { ! 305: if (test_bit(&src->ide, i)) ! 306: IRQ_local_pipe(opp, i, n_IRQ); ! 307: } ! 308: } else { ! 309: /* Distributed delivery mode */ ! 310: /* XXX: incorrect code */ ! 311: for (i = src->last_cpu; i < src->last_cpu; i++) { ! 312: if (i == MAX_IRQ) ! 313: i = 0; ! 314: if (test_bit(&src->ide, i)) { ! 315: IRQ_local_pipe(opp, i, n_IRQ); ! 316: src->last_cpu = i; ! 317: break; ! 318: } ! 319: } ! 320: } ! 321: } ! 322: ! 323: void openpic_set_irq(void *opaque, int n_IRQ, int level) ! 324: { ! 325: openpic_t *opp = opaque; ! 326: IRQ_src_t *src; ! 327: ! 328: src = &opp->src[n_IRQ]; ! 329: DPRINTF("openpic: set irq %d = %d ipvp=%08x\n", ! 330: n_IRQ, level, src->ipvp); ! 331: if (test_bit(&src->ipvp, IPVP_SENSE)) { ! 332: /* level-sensitive irq */ ! 333: src->pending = level; ! 334: if (!level) ! 335: reset_bit(&src->ipvp, IPVP_ACTIVITY); ! 336: } else { ! 337: /* edge-sensitive irq */ ! 338: if (level) ! 339: src->pending = 1; ! 340: } ! 341: openpic_update_irq(opp, n_IRQ); ! 342: } ! 343: ! 344: static void openpic_reset (openpic_t *opp) ! 345: { ! 346: int i; ! 347: ! 348: opp->glbc = 0x80000000; ! 349: /* Initialise controller registers */ ! 350: opp->frep = ((EXT_IRQ - 1) << 16) | ((MAX_CPU - 1) << 8) | VID; ! 351: opp->veni = VENI; ! 352: opp->spve = 0x000000FF; ! 353: opp->tifr = 0x003F7A00; ! 354: /* ? */ ! 355: opp->micr = 0x00000000; ! 356: /* Initialise IRQ sources */ ! 357: for (i = 0; i < MAX_IRQ; i++) { ! 358: opp->src[i].ipvp = 0xA0000000; ! 359: opp->src[i].ide = 0x00000000; ! 360: } ! 361: /* Initialise IRQ destinations */ ! 362: for (i = 0; i < opp->nb_cpus; i++) { ! 363: opp->dst[i].pctp = 0x0000000F; ! 364: opp->dst[i].pcsr = 0x00000000; ! 365: memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t)); ! 366: memset(&opp->dst[i].servicing, 0, sizeof(IRQ_queue_t)); ! 367: } ! 368: /* Initialise timers */ ! 369: for (i = 0; i < MAX_TMR; i++) { ! 370: opp->timers[i].ticc = 0x00000000; ! 371: opp->timers[i].tibc = 0x80000000; ! 372: } ! 373: /* Initialise doorbells */ ! 374: #if MAX_DBL > 0 ! 375: opp->dar = 0x00000000; ! 376: for (i = 0; i < MAX_DBL; i++) { ! 377: opp->doorbells[i].dmr = 0x00000000; ! 378: } ! 379: #endif ! 380: /* Initialise mailboxes */ ! 381: #if MAX_MBX > 0 ! 382: for (i = 0; i < MAX_MBX; i++) { /* ? */ ! 383: opp->mailboxes[i].mbr = 0x00000000; ! 384: } ! 385: #endif ! 386: /* Go out of RESET state */ ! 387: opp->glbc = 0x00000000; ! 388: } ! 389: ! 390: static inline uint32_t read_IRQreg (openpic_t *opp, int n_IRQ, uint32_t reg) ! 391: { ! 392: uint32_t retval; ! 393: ! 394: switch (reg) { ! 395: case IRQ_IPVP: ! 396: retval = opp->src[n_IRQ].ipvp; ! 397: break; ! 398: case IRQ_IDE: ! 399: retval = opp->src[n_IRQ].ide; ! 400: break; ! 401: } ! 402: ! 403: return retval; ! 404: } ! 405: ! 406: static inline void write_IRQreg (openpic_t *opp, int n_IRQ, ! 407: uint32_t reg, uint32_t val) ! 408: { ! 409: uint32_t tmp; ! 410: ! 411: switch (reg) { ! 412: case IRQ_IPVP: ! 413: /* NOTE: not fully accurate for special IRQs, but simple and ! 414: sufficient */ ! 415: /* ACTIVITY bit is read-only */ ! 416: opp->src[n_IRQ].ipvp = ! 417: (opp->src[n_IRQ].ipvp & 0x40000000) | ! 418: (val & 0x800F00FF); ! 419: openpic_update_irq(opp, n_IRQ); ! 420: DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n", ! 421: n_IRQ, val, opp->src[n_IRQ].ipvp); ! 422: break; ! 423: case IRQ_IDE: ! 424: tmp = val & 0xC0000000; ! 425: tmp |= val & ((1 << MAX_CPU) - 1); ! 426: opp->src[n_IRQ].ide = tmp; ! 427: DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide); ! 428: break; ! 429: } ! 430: } ! 431: ! 432: #if 0 // Code provision for Intel model ! 433: #if MAX_DBL > 0 ! 434: static uint32_t read_doorbell_register (openpic_t *opp, ! 435: int n_dbl, uint32_t offset) ! 436: { ! 437: uint32_t retval; ! 438: ! 439: switch (offset) { ! 440: case DBL_IPVP_OFFSET: ! 441: retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP); ! 442: break; ! 443: case DBL_IDE_OFFSET: ! 444: retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE); ! 445: break; ! 446: case DBL_DMR_OFFSET: ! 447: retval = opp->doorbells[n_dbl].dmr; ! 448: break; ! 449: } ! 450: ! 451: return retval; ! 452: } ! 453: ! 454: static void write_doorbell_register (penpic_t *opp, int n_dbl, ! 455: uint32_t offset, uint32_t value) ! 456: { ! 457: switch (offset) { ! 458: case DBL_IVPR_OFFSET: ! 459: write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP, value); ! 460: break; ! 461: case DBL_IDE_OFFSET: ! 462: write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE, value); ! 463: break; ! 464: case DBL_DMR_OFFSET: ! 465: opp->doorbells[n_dbl].dmr = value; ! 466: break; ! 467: } ! 468: } ! 469: #endif ! 470: ! 471: #if MAX_MBX > 0 ! 472: static uint32_t read_mailbox_register (openpic_t *opp, ! 473: int n_mbx, uint32_t offset) ! 474: { ! 475: uint32_t retval; ! 476: ! 477: switch (offset) { ! 478: case MBX_MBR_OFFSET: ! 479: retval = opp->mailboxes[n_mbx].mbr; ! 480: break; ! 481: case MBX_IVPR_OFFSET: ! 482: retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP); ! 483: break; ! 484: case MBX_DMR_OFFSET: ! 485: retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE); ! 486: break; ! 487: } ! 488: ! 489: return retval; ! 490: } ! 491: ! 492: static void write_mailbox_register (openpic_t *opp, int n_mbx, ! 493: uint32_t address, uint32_t value) ! 494: { ! 495: switch (offset) { ! 496: case MBX_MBR_OFFSET: ! 497: opp->mailboxes[n_mbx].mbr = value; ! 498: break; ! 499: case MBX_IVPR_OFFSET: ! 500: write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP, value); ! 501: break; ! 502: case MBX_DMR_OFFSET: ! 503: write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE, value); ! 504: break; ! 505: } ! 506: } ! 507: #endif ! 508: #endif /* 0 : Code provision for Intel model */ ! 509: ! 510: static void openpic_gbl_write (void *opaque, uint32_t addr, uint32_t val) ! 511: { ! 512: openpic_t *opp = opaque; ! 513: ! 514: DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); ! 515: if (addr & 0xF) ! 516: return; ! 517: #if defined OPENPIC_SWAP ! 518: val = bswap32(val); ! 519: #endif ! 520: addr &= 0xFF; ! 521: switch (addr) { ! 522: case 0x00: /* FREP */ ! 523: break; ! 524: case 0x20: /* GLBC */ ! 525: if (val & 0x80000000) ! 526: openpic_reset(opp); ! 527: opp->glbc = val & ~0x80000000; ! 528: break; ! 529: case 0x80: /* VENI */ ! 530: break; ! 531: case 0x90: /* PINT */ ! 532: /* XXX: Should be able to reset any CPU */ ! 533: if (val & 1) { ! 534: DPRINTF("Reset CPU IRQ\n"); ! 535: // cpu_interrupt(cpu_single_env, CPU_INTERRUPT_RESET); ! 536: } ! 537: break; ! 538: #if MAX_IPI > 0 ! 539: case 0xA0: /* IPI_IPVP */ ! 540: case 0xB0: ! 541: case 0xC0: ! 542: case 0xD0: ! 543: { ! 544: int idx; ! 545: idx = (addr - 0xA0) >> 4; ! 546: write_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IPVP, val); ! 547: } ! 548: break; ! 549: #endif ! 550: case 0xE0: /* SPVE */ ! 551: opp->spve = val & 0x000000FF; ! 552: break; ! 553: case 0xF0: /* TIFR */ ! 554: opp->tifr = val; ! 555: break; ! 556: default: ! 557: break; ! 558: } ! 559: } ! 560: ! 561: static uint32_t openpic_gbl_read (void *opaque, uint32_t addr) ! 562: { ! 563: openpic_t *opp = opaque; ! 564: uint32_t retval; ! 565: ! 566: DPRINTF("%s: addr %08x\n", __func__, addr); ! 567: retval = 0xFFFFFFFF; ! 568: if (addr & 0xF) ! 569: return retval; ! 570: addr &= 0xFF; ! 571: switch (addr) { ! 572: case 0x00: /* FREP */ ! 573: retval = opp->frep; ! 574: break; ! 575: case 0x20: /* GLBC */ ! 576: retval = opp->glbc; ! 577: break; ! 578: case 0x80: /* VENI */ ! 579: retval = opp->veni; ! 580: break; ! 581: case 0x90: /* PINT */ ! 582: retval = 0x00000000; ! 583: break; ! 584: #if MAX_IPI > 0 ! 585: case 0xA0: /* IPI_IPVP */ ! 586: case 0xB0: ! 587: case 0xC0: ! 588: case 0xD0: ! 589: { ! 590: int idx; ! 591: idx = (addr - 0xA0) >> 4; ! 592: retval = read_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IPVP); ! 593: } ! 594: break; ! 595: #endif ! 596: case 0xE0: /* SPVE */ ! 597: retval = opp->spve; ! 598: break; ! 599: case 0xF0: /* TIFR */ ! 600: retval = opp->tifr; ! 601: break; ! 602: default: ! 603: break; ! 604: } ! 605: DPRINTF("%s: => %08x\n", __func__, retval); ! 606: #if defined OPENPIC_SWAP ! 607: retval = bswap32(retval); ! 608: #endif ! 609: ! 610: return retval; ! 611: } ! 612: ! 613: static void openpic_timer_write (void *opaque, uint32_t addr, uint32_t val) ! 614: { ! 615: openpic_t *opp = opaque; ! 616: int idx; ! 617: ! 618: DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); ! 619: if (addr & 0xF) ! 620: return; ! 621: #if defined OPENPIC_SWAP ! 622: val = bswap32(val); ! 623: #endif ! 624: addr -= 0x1100; ! 625: addr &= 0xFFFF; ! 626: idx = (addr & 0xFFF0) >> 6; ! 627: addr = addr & 0x30; ! 628: switch (addr) { ! 629: case 0x00: /* TICC */ ! 630: break; ! 631: case 0x10: /* TIBC */ ! 632: if ((opp->timers[idx].ticc & 0x80000000) != 0 && ! 633: (val & 0x80000000) == 0 && ! 634: (opp->timers[idx].tibc & 0x80000000) != 0) ! 635: opp->timers[idx].ticc &= ~0x80000000; ! 636: opp->timers[idx].tibc = val; ! 637: break; ! 638: case 0x20: /* TIVP */ ! 639: write_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IPVP, val); ! 640: break; ! 641: case 0x30: /* TIDE */ ! 642: write_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IDE, val); ! 643: break; ! 644: } ! 645: } ! 646: ! 647: static uint32_t openpic_timer_read (void *opaque, uint32_t addr) ! 648: { ! 649: openpic_t *opp = opaque; ! 650: uint32_t retval; ! 651: int idx; ! 652: ! 653: DPRINTF("%s: addr %08x\n", __func__, addr); ! 654: retval = 0xFFFFFFFF; ! 655: if (addr & 0xF) ! 656: return retval; ! 657: addr -= 0x1100; ! 658: addr &= 0xFFFF; ! 659: idx = (addr & 0xFFF0) >> 6; ! 660: addr = addr & 0x30; ! 661: switch (addr) { ! 662: case 0x00: /* TICC */ ! 663: retval = opp->timers[idx].ticc; ! 664: break; ! 665: case 0x10: /* TIBC */ ! 666: retval = opp->timers[idx].tibc; ! 667: break; ! 668: case 0x20: /* TIPV */ ! 669: retval = read_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IPVP); ! 670: break; ! 671: case 0x30: /* TIDE */ ! 672: retval = read_IRQreg(opp, IRQ_TIM0 + idx, IRQ_IDE); ! 673: break; ! 674: } ! 675: DPRINTF("%s: => %08x\n", __func__, retval); ! 676: #if defined OPENPIC_SWAP ! 677: retval = bswap32(retval); ! 678: #endif ! 679: ! 680: return retval; ! 681: } ! 682: ! 683: static void openpic_src_write (void *opaque, uint32_t addr, uint32_t val) ! 684: { ! 685: openpic_t *opp = opaque; ! 686: int idx; ! 687: ! 688: DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); ! 689: if (addr & 0xF) ! 690: return; ! 691: #if defined OPENPIC_SWAP ! 692: val = tswap32(val); ! 693: #endif ! 694: addr = addr & 0xFFF0; ! 695: idx = addr >> 5; ! 696: if (addr & 0x10) { ! 697: /* EXDE / IFEDE / IEEDE */ ! 698: write_IRQreg(opp, idx, IRQ_IDE, val); ! 699: } else { ! 700: /* EXVP / IFEVP / IEEVP */ ! 701: write_IRQreg(opp, idx, IRQ_IPVP, val); ! 702: } ! 703: } ! 704: ! 705: static uint32_t openpic_src_read (void *opaque, uint32_t addr) ! 706: { ! 707: openpic_t *opp = opaque; ! 708: uint32_t retval; ! 709: int idx; ! 710: ! 711: DPRINTF("%s: addr %08x\n", __func__, addr); ! 712: retval = 0xFFFFFFFF; ! 713: if (addr & 0xF) ! 714: return retval; ! 715: addr = addr & 0xFFF0; ! 716: idx = addr >> 5; ! 717: if (addr & 0x10) { ! 718: /* EXDE / IFEDE / IEEDE */ ! 719: retval = read_IRQreg(opp, idx, IRQ_IDE); ! 720: } else { ! 721: /* EXVP / IFEVP / IEEVP */ ! 722: retval = read_IRQreg(opp, idx, IRQ_IPVP); ! 723: } ! 724: DPRINTF("%s: => %08x\n", __func__, retval); ! 725: #if defined OPENPIC_SWAP ! 726: retval = tswap32(retval); ! 727: #endif ! 728: ! 729: return retval; ! 730: } ! 731: ! 732: static void openpic_cpu_write (void *opaque, uint32_t addr, uint32_t val) ! 733: { ! 734: openpic_t *opp = opaque; ! 735: IRQ_src_t *src; ! 736: IRQ_dst_t *dst; ! 737: int idx, n_IRQ; ! 738: ! 739: DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); ! 740: if (addr & 0xF) ! 741: return; ! 742: #if defined OPENPIC_SWAP ! 743: val = bswap32(val); ! 744: #endif ! 745: addr &= 0x1FFF0; ! 746: idx = addr / 0x1000; ! 747: dst = &opp->dst[idx]; ! 748: addr &= 0xFF0; ! 749: switch (addr) { ! 750: #if MAX_IPI > 0 ! 751: case 0x40: /* PIPD */ ! 752: case 0x50: ! 753: case 0x60: ! 754: case 0x70: ! 755: idx = (addr - 0x40) >> 4; ! 756: write_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IDE, val); ! 757: openpic_set_irq(opp, IRQ_IPI0 + idx, 1); ! 758: openpic_set_irq(opp, IRQ_IPI0 + idx, 0); ! 759: break; ! 760: #endif ! 761: case 0x80: /* PCTP */ ! 762: dst->pctp = val & 0x0000000F; ! 763: break; ! 764: case 0x90: /* WHOAMI */ ! 765: /* Read-only register */ ! 766: break; ! 767: case 0xA0: /* PIAC */ ! 768: /* Read-only register */ ! 769: break; ! 770: case 0xB0: /* PEOI */ ! 771: DPRINTF("PEOI\n"); ! 772: n_IRQ = IRQ_get_next(opp, &dst->servicing); ! 773: IRQ_resetbit(&dst->servicing, n_IRQ); ! 774: dst->servicing.next = -1; ! 775: src = &opp->src[n_IRQ]; ! 776: /* Set up next servicing IRQ */ ! 777: IRQ_get_next(opp, &dst->servicing); ! 778: /* Check queued interrupts. */ ! 779: n_IRQ = IRQ_get_next(opp, &dst->raised); ! 780: if (n_IRQ != -1) { ! 781: src = &opp->src[n_IRQ]; ! 782: if (IPVP_PRIORITY(src->ipvp) > dst->servicing.priority) { ! 783: DPRINTF("Raise CPU IRQ\n"); ! 784: cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD); ! 785: } ! 786: } ! 787: break; ! 788: default: ! 789: break; ! 790: } ! 791: } ! 792: ! 793: static uint32_t openpic_cpu_read (void *opaque, uint32_t addr) ! 794: { ! 795: openpic_t *opp = opaque; ! 796: IRQ_src_t *src; ! 797: IRQ_dst_t *dst; ! 798: uint32_t retval; ! 799: int idx, n_IRQ; ! 800: ! 801: DPRINTF("%s: addr %08x\n", __func__, addr); ! 802: retval = 0xFFFFFFFF; ! 803: if (addr & 0xF) ! 804: return retval; ! 805: addr &= 0x1FFF0; ! 806: idx = addr / 0x1000; ! 807: dst = &opp->dst[idx]; ! 808: addr &= 0xFF0; ! 809: switch (addr) { ! 810: case 0x80: /* PCTP */ ! 811: retval = dst->pctp; ! 812: break; ! 813: case 0x90: /* WHOAMI */ ! 814: retval = idx; ! 815: break; ! 816: case 0xA0: /* PIAC */ ! 817: n_IRQ = IRQ_get_next(opp, &dst->raised); ! 818: DPRINTF("PIAC: irq=%d\n", n_IRQ); ! 819: if (n_IRQ == -1) { ! 820: /* No more interrupt pending */ ! 821: retval = opp->spve; ! 822: } else { ! 823: src = &opp->src[n_IRQ]; ! 824: if (!test_bit(&src->ipvp, IPVP_ACTIVITY) || ! 825: !(IPVP_PRIORITY(src->ipvp) > dst->pctp)) { ! 826: /* - Spurious level-sensitive IRQ ! 827: * - Priorities has been changed ! 828: * and the pending IRQ isn't allowed anymore ! 829: */ ! 830: reset_bit(&src->ipvp, IPVP_ACTIVITY); ! 831: retval = IPVP_VECTOR(opp->spve); ! 832: } else { ! 833: /* IRQ enter servicing state */ ! 834: IRQ_setbit(&dst->servicing, n_IRQ); ! 835: retval = IPVP_VECTOR(src->ipvp); ! 836: } ! 837: IRQ_resetbit(&dst->raised, n_IRQ); ! 838: dst->raised.next = -1; ! 839: if (!test_bit(&src->ipvp, IPVP_SENSE)) { ! 840: /* edge-sensitive IRQ */ ! 841: reset_bit(&src->ipvp, IPVP_ACTIVITY); ! 842: src->pending = 0; ! 843: } ! 844: } ! 845: break; ! 846: case 0xB0: /* PEOI */ ! 847: retval = 0; ! 848: break; ! 849: #if MAX_IPI > 0 ! 850: case 0x40: /* IDE */ ! 851: case 0x50: ! 852: idx = (addr - 0x40) >> 4; ! 853: retval = read_IRQreg(opp, IRQ_IPI0 + idx, IRQ_IDE); ! 854: break; ! 855: #endif ! 856: default: ! 857: break; ! 858: } ! 859: DPRINTF("%s: => %08x\n", __func__, retval); ! 860: #if defined OPENPIC_SWAP ! 861: retval= bswap32(retval); ! 862: #endif ! 863: ! 864: return retval; ! 865: } ! 866: ! 867: static void openpic_buggy_write (void *opaque, ! 868: target_phys_addr_t addr, uint32_t val) ! 869: { ! 870: printf("Invalid OPENPIC write access !\n"); ! 871: } ! 872: ! 873: static uint32_t openpic_buggy_read (void *opaque, target_phys_addr_t addr) ! 874: { ! 875: printf("Invalid OPENPIC read access !\n"); ! 876: ! 877: return -1; ! 878: } ! 879: ! 880: static void openpic_writel (void *opaque, ! 881: target_phys_addr_t addr, uint32_t val) ! 882: { ! 883: openpic_t *opp = opaque; ! 884: ! 885: addr &= 0x3FFFF; ! 886: DPRINTF("%s: offset %08x val: %08x\n", __func__, (int)addr, val); ! 887: if (addr < 0x1100) { ! 888: /* Global registers */ ! 889: openpic_gbl_write(opp, addr, val); ! 890: } else if (addr < 0x10000) { ! 891: /* Timers registers */ ! 892: openpic_timer_write(opp, addr, val); ! 893: } else if (addr < 0x20000) { ! 894: /* Source registers */ ! 895: openpic_src_write(opp, addr, val); ! 896: } else { ! 897: /* CPU registers */ ! 898: openpic_cpu_write(opp, addr, val); ! 899: } ! 900: } ! 901: ! 902: static uint32_t openpic_readl (void *opaque,target_phys_addr_t addr) ! 903: { ! 904: openpic_t *opp = opaque; ! 905: uint32_t retval; ! 906: ! 907: addr &= 0x3FFFF; ! 908: DPRINTF("%s: offset %08x\n", __func__, (int)addr); ! 909: if (addr < 0x1100) { ! 910: /* Global registers */ ! 911: retval = openpic_gbl_read(opp, addr); ! 912: } else if (addr < 0x10000) { ! 913: /* Timers registers */ ! 914: retval = openpic_timer_read(opp, addr); ! 915: } else if (addr < 0x20000) { ! 916: /* Source registers */ ! 917: retval = openpic_src_read(opp, addr); ! 918: } else { ! 919: /* CPU registers */ ! 920: retval = openpic_cpu_read(opp, addr); ! 921: } ! 922: ! 923: return retval; ! 924: } ! 925: ! 926: static CPUWriteMemoryFunc *openpic_write[] = { ! 927: &openpic_buggy_write, ! 928: &openpic_buggy_write, ! 929: &openpic_writel, ! 930: }; ! 931: ! 932: static CPUReadMemoryFunc *openpic_read[] = { ! 933: &openpic_buggy_read, ! 934: &openpic_buggy_read, ! 935: &openpic_readl, ! 936: }; ! 937: ! 938: static void openpic_map(PCIDevice *pci_dev, int region_num, ! 939: uint32_t addr, uint32_t size, int type) ! 940: { ! 941: openpic_t *opp; ! 942: ! 943: DPRINTF("Map OpenPIC\n"); ! 944: opp = (openpic_t *)pci_dev; ! 945: /* Global registers */ ! 946: DPRINTF("Register OPENPIC gbl %08x => %08x\n", ! 947: addr + 0x1000, addr + 0x1000 + 0x100); ! 948: /* Timer registers */ ! 949: DPRINTF("Register OPENPIC timer %08x => %08x\n", ! 950: addr + 0x1100, addr + 0x1100 + 0x40 * MAX_TMR); ! 951: /* Interrupt source registers */ ! 952: DPRINTF("Register OPENPIC src %08x => %08x\n", ! 953: addr + 0x10000, addr + 0x10000 + 0x20 * (EXT_IRQ + 2)); ! 954: /* Per CPU registers */ ! 955: DPRINTF("Register OPENPIC dst %08x => %08x\n", ! 956: addr + 0x20000, addr + 0x20000 + 0x1000 * MAX_CPU); ! 957: cpu_register_physical_memory(addr, 0x40000, opp->mem_index); ! 958: #if 0 // Don't implement ISU for now ! 959: opp_io_memory = cpu_register_io_memory(0, openpic_src_read, ! 960: openpic_src_write); ! 961: cpu_register_physical_memory(isu_base, 0x20 * (EXT_IRQ + 2), ! 962: opp_io_memory); ! 963: #endif ! 964: } ! 965: ! 966: openpic_t *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus) ! 967: { ! 968: openpic_t *opp; ! 969: uint8_t *pci_conf; ! 970: int i, m; ! 971: ! 972: /* XXX: for now, only one CPU is supported */ ! 973: if (nb_cpus != 1) ! 974: return NULL; ! 975: if (bus) { ! 976: opp = (openpic_t *)pci_register_device(bus, "OpenPIC", sizeof(openpic_t), ! 977: -1, NULL, NULL); ! 978: if (opp == NULL) ! 979: return NULL; ! 980: pci_conf = opp->pci_dev.config; ! 981: pci_conf[0x00] = 0x14; // IBM MPIC2 ! 982: pci_conf[0x01] = 0x10; ! 983: pci_conf[0x02] = 0xFF; ! 984: pci_conf[0x03] = 0xFF; ! 985: pci_conf[0x0a] = 0x80; // PIC ! 986: pci_conf[0x0b] = 0x08; ! 987: pci_conf[0x0e] = 0x00; // header_type ! 988: pci_conf[0x3d] = 0x00; // no interrupt pin ! 989: ! 990: /* Register I/O spaces */ ! 991: pci_register_io_region((PCIDevice *)opp, 0, 0x40000, ! 992: PCI_ADDRESS_SPACE_MEM, &openpic_map); ! 993: } else { ! 994: opp = qemu_mallocz(sizeof(openpic_t)); ! 995: } ! 996: ! 997: opp->mem_index = cpu_register_io_memory(0, openpic_read, ! 998: openpic_write, opp); ! 999: ! 1000: // isu_base &= 0xFFFC0000; ! 1001: opp->nb_cpus = nb_cpus; ! 1002: /* Set IRQ types */ ! 1003: for (i = 0; i < EXT_IRQ; i++) { ! 1004: opp->src[i].type = IRQ_EXTERNAL; ! 1005: } ! 1006: for (; i < IRQ_TIM0; i++) { ! 1007: opp->src[i].type = IRQ_SPECIAL; ! 1008: } ! 1009: #if MAX_IPI > 0 ! 1010: m = IRQ_IPI0; ! 1011: #else ! 1012: m = IRQ_DBL0; ! 1013: #endif ! 1014: for (; i < m; i++) { ! 1015: opp->src[i].type = IRQ_TIMER; ! 1016: } ! 1017: for (; i < MAX_IRQ; i++) { ! 1018: opp->src[i].type = IRQ_INTERNAL; ! 1019: } ! 1020: openpic_reset(opp); ! 1021: if (pmem_index) ! 1022: *pmem_index = opp->mem_index; ! 1023: return opp; ! 1024: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.