qemu/hw/openpic.c
<<
>>
Prefs
   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 companion chip developer'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 "hw.h"
  36#include "ppc_mac.h"
  37#include "pci.h"
  38#include "openpic.h"
  39
  40//#define DEBUG_OPENPIC
  41
  42#ifdef DEBUG_OPENPIC
  43#define DPRINTF(fmt, ...) do { printf(fmt , ## __VA_ARGS__); } while (0)
  44#else
  45#define DPRINTF(fmt, ...) do { } while (0)
  46#endif
  47
  48#define USE_MPCxxx /* Intel model is broken, for now */
  49
  50#if defined (USE_INTEL_GW80314)
  51/* Intel GW80314 I/O Companion chip */
  52
  53#define MAX_CPU     4
  54#define MAX_IRQ    32
  55#define MAX_DBL     4
  56#define MAX_MBX     4
  57#define MAX_TMR     4
  58#define VECTOR_BITS 8
  59#define MAX_IPI     0
  60
  61#define VID (0x00000000)
  62
  63#elif defined(USE_MPCxxx)
  64
  65#define MAX_CPU     2
  66#define MAX_IRQ   128
  67#define MAX_DBL     0
  68#define MAX_MBX     0
  69#define MAX_TMR     4
  70#define VECTOR_BITS 8
  71#define MAX_IPI     4
  72#define VID         0x03 /* MPIC version ID */
  73#define VENI        0x00000000 /* Vendor ID */
  74
  75enum {
  76    IRQ_IPVP = 0,
  77    IRQ_IDE,
  78};
  79
  80/* OpenPIC */
  81#define OPENPIC_MAX_CPU      2
  82#define OPENPIC_MAX_IRQ     64
  83#define OPENPIC_EXT_IRQ     48
  84#define OPENPIC_MAX_TMR      MAX_TMR
  85#define OPENPIC_MAX_IPI      MAX_IPI
  86
  87/* Interrupt definitions */
  88#define OPENPIC_IRQ_FE     (OPENPIC_EXT_IRQ)     /* Internal functional IRQ */
  89#define OPENPIC_IRQ_ERR    (OPENPIC_EXT_IRQ + 1) /* Error IRQ */
  90#define OPENPIC_IRQ_TIM0   (OPENPIC_EXT_IRQ + 2) /* First timer IRQ */
  91#if OPENPIC_MAX_IPI > 0
  92#define OPENPIC_IRQ_IPI0   (OPENPIC_IRQ_TIM0 + OPENPIC_MAX_TMR) /* First IPI IRQ */
  93#define OPENPIC_IRQ_DBL0   (OPENPIC_IRQ_IPI0 + (OPENPIC_MAX_CPU * OPENPIC_MAX_IPI)) /* First doorbell IRQ */
  94#else
  95#define OPENPIC_IRQ_DBL0   (OPENPIC_IRQ_TIM0 + OPENPIC_MAX_TMR) /* First doorbell IRQ */
  96#define OPENPIC_IRQ_MBX0   (OPENPIC_IRQ_DBL0 + OPENPIC_MAX_DBL) /* First mailbox IRQ */
  97#endif
  98
  99/* MPIC */
 100#define MPIC_MAX_CPU      1
 101#define MPIC_MAX_EXT     12
 102#define MPIC_MAX_INT     64
 103#define MPIC_MAX_MSG      4
 104#define MPIC_MAX_MSI      8
 105#define MPIC_MAX_TMR      MAX_TMR
 106#define MPIC_MAX_IPI      MAX_IPI
 107#define MPIC_MAX_IRQ     (MPIC_MAX_EXT + MPIC_MAX_INT + MPIC_MAX_TMR + MPIC_MAX_MSG + MPIC_MAX_MSI + (MPIC_MAX_IPI * MPIC_MAX_CPU))
 108
 109/* Interrupt definitions */
 110#define MPIC_EXT_IRQ      0
 111#define MPIC_INT_IRQ      (MPIC_EXT_IRQ + MPIC_MAX_EXT)
 112#define MPIC_TMR_IRQ      (MPIC_INT_IRQ + MPIC_MAX_INT)
 113#define MPIC_MSG_IRQ      (MPIC_TMR_IRQ + MPIC_MAX_TMR)
 114#define MPIC_MSI_IRQ      (MPIC_MSG_IRQ + MPIC_MAX_MSG)
 115#define MPIC_IPI_IRQ      (MPIC_MSI_IRQ + MPIC_MAX_MSI)
 116
 117#define MPIC_GLB_REG_START        0x0
 118#define MPIC_GLB_REG_SIZE         0x10F0
 119#define MPIC_TMR_REG_START        0x10F0
 120#define MPIC_TMR_REG_SIZE         0x220
 121#define MPIC_EXT_REG_START        0x10000
 122#define MPIC_EXT_REG_SIZE         0x180
 123#define MPIC_INT_REG_START        0x10200
 124#define MPIC_INT_REG_SIZE         0x800
 125#define MPIC_MSG_REG_START        0x11600
 126#define MPIC_MSG_REG_SIZE         0x100
 127#define MPIC_MSI_REG_START        0x11C00
 128#define MPIC_MSI_REG_SIZE         0x100
 129#define MPIC_CPU_REG_START        0x20000
 130#define MPIC_CPU_REG_SIZE         0x100
 131
 132enum mpic_ide_bits {
 133    IDR_EP     = 0,
 134    IDR_CI0     = 1,
 135    IDR_CI1     = 2,
 136    IDR_P1     = 30,
 137    IDR_P0     = 31,
 138};
 139
 140#else
 141#error "Please select which OpenPic implementation is to be emulated"
 142#endif
 143
 144#define OPENPIC_PAGE_SIZE 4096
 145
 146#define BF_WIDTH(_bits_) \
 147(((_bits_) + (sizeof(uint32_t) * 8) - 1) / (sizeof(uint32_t) * 8))
 148
 149static inline void set_bit (uint32_t *field, int bit)
 150{
 151    field[bit >> 5] |= 1 << (bit & 0x1F);
 152}
 153
 154static inline void reset_bit (uint32_t *field, int bit)
 155{
 156    field[bit >> 5] &= ~(1 << (bit & 0x1F));
 157}
 158
 159static inline int test_bit (uint32_t *field, int bit)
 160{
 161    return (field[bit >> 5] & 1 << (bit & 0x1F)) != 0;
 162}
 163
 164enum {
 165    IRQ_EXTERNAL = 0x01,
 166    IRQ_INTERNAL = 0x02,
 167    IRQ_TIMER    = 0x04,
 168    IRQ_SPECIAL  = 0x08,
 169};
 170
 171typedef struct IRQ_queue_t {
 172    uint32_t queue[BF_WIDTH(MAX_IRQ)];
 173    int next;
 174    int priority;
 175} IRQ_queue_t;
 176
 177typedef struct IRQ_src_t {
 178    uint32_t ipvp;  /* IRQ vector/priority register */
 179    uint32_t ide;   /* IRQ destination register */
 180    int type;
 181    int last_cpu;
 182    int pending;    /* TRUE if IRQ is pending */
 183} IRQ_src_t;
 184
 185enum IPVP_bits {
 186    IPVP_MASK     = 31,
 187    IPVP_ACTIVITY = 30,
 188    IPVP_MODE     = 29,
 189    IPVP_POLARITY = 23,
 190    IPVP_SENSE    = 22,
 191};
 192#define IPVP_PRIORITY_MASK     (0x1F << 16)
 193#define IPVP_PRIORITY(_ipvpr_) ((int)(((_ipvpr_) & IPVP_PRIORITY_MASK) >> 16))
 194#define IPVP_VECTOR_MASK       ((1 << VECTOR_BITS) - 1)
 195#define IPVP_VECTOR(_ipvpr_)   ((_ipvpr_) & IPVP_VECTOR_MASK)
 196
 197typedef struct IRQ_dst_t {
 198    uint32_t tfrr;
 199    uint32_t pctp; /* CPU current task priority */
 200    uint32_t pcsr; /* CPU sensitivity register */
 201    IRQ_queue_t raised;
 202    IRQ_queue_t servicing;
 203    qemu_irq *irqs;
 204} IRQ_dst_t;
 205
 206typedef struct openpic_t {
 207    PCIDevice pci_dev;
 208    int mem_index;
 209    /* Global registers */
 210    uint32_t frep; /* Feature reporting register */
 211    uint32_t glbc; /* Global configuration register  */
 212    uint32_t micr; /* MPIC interrupt configuration register */
 213    uint32_t veni; /* Vendor identification register */
 214    uint32_t pint; /* Processor initialization register */
 215    uint32_t spve; /* Spurious vector register */
 216    uint32_t tifr; /* Timer frequency reporting register */
 217    /* Source registers */
 218    IRQ_src_t src[MAX_IRQ];
 219    /* Local registers per output pin */
 220    IRQ_dst_t dst[MAX_CPU];
 221    int nb_cpus;
 222    /* Timer registers */
 223    struct {
 224        uint32_t ticc;  /* Global timer current count register */
 225        uint32_t tibc;  /* Global timer base count register */
 226    } timers[MAX_TMR];
 227#if MAX_DBL > 0
 228    /* Doorbell registers */
 229    uint32_t dar;        /* Doorbell activate register */
 230    struct {
 231        uint32_t dmr;    /* Doorbell messaging register */
 232    } doorbells[MAX_DBL];
 233#endif
 234#if MAX_MBX > 0
 235    /* Mailbox registers */
 236    struct {
 237        uint32_t mbr;    /* Mailbox register */
 238    } mailboxes[MAX_MAILBOXES];
 239#endif
 240    /* IRQ out is used when in bypass mode (not implemented) */
 241    qemu_irq irq_out;
 242    int max_irq;
 243    int irq_ipi0;
 244    int irq_tim0;
 245    void (*reset) (void *);
 246    void (*irq_raise) (struct openpic_t *, int, IRQ_src_t *);
 247} openpic_t;
 248
 249static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ)
 250{
 251    set_bit(q->queue, n_IRQ);
 252}
 253
 254static inline void IRQ_resetbit (IRQ_queue_t *q, int n_IRQ)
 255{
 256    reset_bit(q->queue, n_IRQ);
 257}
 258
 259static inline int IRQ_testbit (IRQ_queue_t *q, int n_IRQ)
 260{
 261    return test_bit(q->queue, n_IRQ);
 262}
 263
 264static void IRQ_check (openpic_t *opp, IRQ_queue_t *q)
 265{
 266    int next, i;
 267    int priority;
 268
 269    next = -1;
 270    priority = -1;
 271    for (i = 0; i < opp->max_irq; i++) {
 272        if (IRQ_testbit(q, i)) {
 273            DPRINTF("IRQ_check: irq %d set ipvp_pr=%d pr=%d\n",
 274                    i, IPVP_PRIORITY(opp->src[i].ipvp), priority);
 275            if (IPVP_PRIORITY(opp->src[i].ipvp) > priority) {
 276                next = i;
 277                priority = IPVP_PRIORITY(opp->src[i].ipvp);
 278            }
 279        }
 280    }
 281    q->next = next;
 282    q->priority = priority;
 283}
 284
 285static int IRQ_get_next (openpic_t *opp, IRQ_queue_t *q)
 286{
 287    if (q->next == -1) {
 288        /* XXX: optimize */
 289        IRQ_check(opp, q);
 290    }
 291
 292    return q->next;
 293}
 294
 295static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ)
 296{
 297    IRQ_dst_t *dst;
 298    IRQ_src_t *src;
 299    int priority;
 300
 301    dst = &opp->dst[n_CPU];
 302    src = &opp->src[n_IRQ];
 303    priority = IPVP_PRIORITY(src->ipvp);
 304    if (priority <= dst->pctp) {
 305        /* Too low priority */
 306        DPRINTF("%s: IRQ %d has too low priority on CPU %d\n",
 307                __func__, n_IRQ, n_CPU);
 308        return;
 309    }
 310    if (IRQ_testbit(&dst->raised, n_IRQ)) {
 311        /* Interrupt miss */
 312        DPRINTF("%s: IRQ %d was missed on CPU %d\n",
 313                __func__, n_IRQ, n_CPU);
 314        return;
 315    }
 316    set_bit(&src->ipvp, IPVP_ACTIVITY);
 317    IRQ_setbit(&dst->raised, n_IRQ);
 318    if (priority < dst->raised.priority) {
 319        /* An higher priority IRQ is already raised */
 320        DPRINTF("%s: IRQ %d is hidden by raised IRQ %d on CPU %d\n",
 321                __func__, n_IRQ, dst->raised.next, n_CPU);
 322        return;
 323    }
 324    IRQ_get_next(opp, &dst->raised);
 325    if (IRQ_get_next(opp, &dst->servicing) != -1 &&
 326        priority <= dst->servicing.priority) {
 327        DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n",
 328                __func__, n_IRQ, dst->servicing.next, n_CPU);
 329        /* Already servicing a higher priority IRQ */
 330        return;
 331    }
 332    DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", n_CPU, n_IRQ);
 333    opp->irq_raise(opp, n_CPU, src);
 334}
 335
 336/* update pic state because registers for n_IRQ have changed value */
 337static void openpic_update_irq(openpic_t *opp, int n_IRQ)
 338{
 339    IRQ_src_t *src;
 340    int i;
 341
 342    src = &opp->src[n_IRQ];
 343
 344    if (!src->pending) {
 345        /* no irq pending */
 346        DPRINTF("%s: IRQ %d is not pending\n", __func__, n_IRQ);
 347        return;
 348    }
 349    if (test_bit(&src->ipvp, IPVP_MASK)) {
 350        /* Interrupt source is disabled */
 351        DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ);
 352        return;
 353    }
 354    if (IPVP_PRIORITY(src->ipvp) == 0) {
 355        /* Priority set to zero */
 356        DPRINTF("%s: IRQ %d has 0 priority\n", __func__, n_IRQ);
 357        return;
 358    }
 359    if (test_bit(&src->ipvp, IPVP_ACTIVITY)) {
 360        /* IRQ already active */
 361        DPRINTF("%s: IRQ %d is already active\n", __func__, n_IRQ);
 362        return;
 363    }
 364    if (src->ide == 0x00000000) {
 365        /* No target */
 366        DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ);
 367        return;
 368    }
 369
 370    if (src->ide == (1 << src->last_cpu)) {
 371        /* Only one CPU is allowed to receive this IRQ */
 372        IRQ_local_pipe(opp, src->last_cpu, n_IRQ);
 373    } else if (!test_bit(&src->ipvp, IPVP_MODE)) {
 374        /* Directed delivery mode */
 375        for (i = 0; i < opp->nb_cpus; i++) {
 376            if (test_bit(&src->ide, i))
 377                IRQ_local_pipe(opp, i, n_IRQ);
 378        }
 379    } else {
 380        /* Distributed delivery mode */
 381        for (i = src->last_cpu + 1; i != src->last_cpu; i++) {
 382            if (i == opp->nb_cpus)
 383                i = 0;
 384            if (test_bit(&src->ide, i)) {
 385                IRQ_local_pipe(opp, i, n_IRQ);
 386                src->last_cpu = i;
 387                break;
 388            }
 389        }
 390    }
 391}
 392
 393static void openpic_set_irq(void *opaque, int n_IRQ, int level)
 394{
 395    openpic_t *opp = opaque;
 396    IRQ_src_t *src;
 397
 398    src = &opp->src[n_IRQ];
 399    DPRINTF("openpic: set irq %d = %d ipvp=%08x\n",
 400            n_IRQ, level, src->ipvp);
 401    if (test_bit(&src->ipvp, IPVP_SENSE)) {
 402        /* level-sensitive irq */
 403        src->pending = level;
 404        if (!level)
 405            reset_bit(&src->ipvp, IPVP_ACTIVITY);
 406    } else {
 407        /* edge-sensitive irq */
 408        if (level)
 409            src->pending = 1;
 410    }
 411    openpic_update_irq(opp, n_IRQ);
 412}
 413
 414static void openpic_reset (void *opaque)
 415{
 416    openpic_t *opp = (openpic_t *)opaque;
 417    int i;
 418
 419    opp->glbc = 0x80000000;
 420    /* Initialise controller registers */
 421    opp->frep = ((OPENPIC_EXT_IRQ - 1) << 16) | ((MAX_CPU - 1) << 8) | VID;
 422    opp->veni = VENI;
 423    opp->pint = 0x00000000;
 424    opp->spve = 0x000000FF;
 425    opp->tifr = 0x003F7A00;
 426    /* ? */
 427    opp->micr = 0x00000000;
 428    /* Initialise IRQ sources */
 429    for (i = 0; i < opp->max_irq; i++) {
 430        opp->src[i].ipvp = 0xA0000000;
 431        opp->src[i].ide  = 0x00000000;
 432    }
 433    /* Initialise IRQ destinations */
 434    for (i = 0; i < MAX_CPU; i++) {
 435        opp->dst[i].pctp      = 0x0000000F;
 436        opp->dst[i].pcsr      = 0x00000000;
 437        memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t));
 438        opp->dst[i].raised.next = -1;
 439        memset(&opp->dst[i].servicing, 0, sizeof(IRQ_queue_t));
 440        opp->dst[i].servicing.next = -1;
 441    }
 442    /* Initialise timers */
 443    for (i = 0; i < MAX_TMR; i++) {
 444        opp->timers[i].ticc = 0x00000000;
 445        opp->timers[i].tibc = 0x80000000;
 446    }
 447    /* Initialise doorbells */
 448#if MAX_DBL > 0
 449    opp->dar = 0x00000000;
 450    for (i = 0; i < MAX_DBL; i++) {
 451        opp->doorbells[i].dmr  = 0x00000000;
 452    }
 453#endif
 454    /* Initialise mailboxes */
 455#if MAX_MBX > 0
 456    for (i = 0; i < MAX_MBX; i++) { /* ? */
 457        opp->mailboxes[i].mbr   = 0x00000000;
 458    }
 459#endif
 460    /* Go out of RESET state */
 461    opp->glbc = 0x00000000;
 462}
 463
 464static inline uint32_t read_IRQreg (openpic_t *opp, int n_IRQ, uint32_t reg)
 465{
 466    uint32_t retval;
 467
 468    switch (reg) {
 469    case IRQ_IPVP:
 470        retval = opp->src[n_IRQ].ipvp;
 471        break;
 472    case IRQ_IDE:
 473        retval = opp->src[n_IRQ].ide;
 474        break;
 475    }
 476
 477    return retval;
 478}
 479
 480static inline void write_IRQreg (openpic_t *opp, int n_IRQ,
 481                                 uint32_t reg, uint32_t val)
 482{
 483    uint32_t tmp;
 484
 485    switch (reg) {
 486    case IRQ_IPVP:
 487        /* NOTE: not fully accurate for special IRQs, but simple and
 488           sufficient */
 489        /* ACTIVITY bit is read-only */
 490        opp->src[n_IRQ].ipvp =
 491            (opp->src[n_IRQ].ipvp & 0x40000000) |
 492            (val & 0x800F00FF);
 493        openpic_update_irq(opp, n_IRQ);
 494        DPRINTF("Set IPVP %d to 0x%08x -> 0x%08x\n",
 495                n_IRQ, val, opp->src[n_IRQ].ipvp);
 496        break;
 497    case IRQ_IDE:
 498        tmp = val & 0xC0000000;
 499        tmp |= val & ((1 << MAX_CPU) - 1);
 500        opp->src[n_IRQ].ide = tmp;
 501        DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide);
 502        break;
 503    }
 504}
 505
 506#if 0 // Code provision for Intel model
 507#if MAX_DBL > 0
 508static uint32_t read_doorbell_register (openpic_t *opp,
 509                                        int n_dbl, uint32_t offset)
 510{
 511    uint32_t retval;
 512
 513    switch (offset) {
 514    case DBL_IPVP_OFFSET:
 515        retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP);
 516        break;
 517    case DBL_IDE_OFFSET:
 518        retval = read_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE);
 519        break;
 520    case DBL_DMR_OFFSET:
 521        retval = opp->doorbells[n_dbl].dmr;
 522        break;
 523    }
 524
 525    return retval;
 526}
 527
 528static void write_doorbell_register (penpic_t *opp, int n_dbl,
 529                                     uint32_t offset, uint32_t value)
 530{
 531    switch (offset) {
 532    case DBL_IVPR_OFFSET:
 533        write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IPVP, value);
 534        break;
 535    case DBL_IDE_OFFSET:
 536        write_IRQreg(opp, IRQ_DBL0 + n_dbl, IRQ_IDE, value);
 537        break;
 538    case DBL_DMR_OFFSET:
 539        opp->doorbells[n_dbl].dmr = value;
 540        break;
 541    }
 542}
 543#endif
 544
 545#if MAX_MBX > 0
 546static uint32_t read_mailbox_register (openpic_t *opp,
 547                                       int n_mbx, uint32_t offset)
 548{
 549    uint32_t retval;
 550
 551    switch (offset) {
 552    case MBX_MBR_OFFSET:
 553        retval = opp->mailboxes[n_mbx].mbr;
 554        break;
 555    case MBX_IVPR_OFFSET:
 556        retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP);
 557        break;
 558    case MBX_DMR_OFFSET:
 559        retval = read_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE);
 560        break;
 561    }
 562
 563    return retval;
 564}
 565
 566static void write_mailbox_register (openpic_t *opp, int n_mbx,
 567                                    uint32_t address, uint32_t value)
 568{
 569    switch (offset) {
 570    case MBX_MBR_OFFSET:
 571        opp->mailboxes[n_mbx].mbr = value;
 572        break;
 573    case MBX_IVPR_OFFSET:
 574        write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IPVP, value);
 575        break;
 576    case MBX_DMR_OFFSET:
 577        write_IRQreg(opp, IRQ_MBX0 + n_mbx, IRQ_IDE, value);
 578        break;
 579    }
 580}
 581#endif
 582#endif /* 0 : Code provision for Intel model */
 583
 584static void openpic_gbl_write (void *opaque, target_phys_addr_t addr, uint32_t val)
 585{
 586    openpic_t *opp = opaque;
 587    IRQ_dst_t *dst;
 588    int idx;
 589
 590    DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
 591    if (addr & 0xF)
 592        return;
 593    addr &= 0xFF;
 594    switch (addr) {
 595    case 0x00: /* FREP */
 596        break;
 597    case 0x20: /* GLBC */
 598        if (val & 0x80000000 && opp->reset)
 599            opp->reset(opp);
 600        opp->glbc = val & ~0x80000000;
 601        break;
 602    case 0x80: /* VENI */
 603        break;
 604    case 0x90: /* PINT */
 605        for (idx = 0; idx < opp->nb_cpus; idx++) {
 606            if ((val & (1 << idx)) && !(opp->pint & (1 << idx))) {
 607                DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx);
 608                dst = &opp->dst[idx];
 609                qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_RESET]);
 610            } else if (!(val & (1 << idx)) && (opp->pint & (1 << idx))) {
 611                DPRINTF("Lower OpenPIC RESET output for CPU %d\n", idx);
 612                dst = &opp->dst[idx];
 613                qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_RESET]);
 614            }
 615        }
 616        opp->pint = val;
 617        break;
 618#if MAX_IPI > 0
 619    case 0xA0: /* IPI_IPVP */
 620    case 0xB0:
 621    case 0xC0:
 622    case 0xD0:
 623        {
 624            int idx;
 625            idx = (addr - 0xA0) >> 4;
 626            write_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IPVP, val);
 627        }
 628        break;
 629#endif
 630    case 0xE0: /* SPVE */
 631        opp->spve = val & 0x000000FF;
 632        break;
 633    case 0xF0: /* TIFR */
 634        opp->tifr = val;
 635        break;
 636    default:
 637        break;
 638    }
 639}
 640
 641static uint32_t openpic_gbl_read (void *opaque, target_phys_addr_t addr)
 642{
 643    openpic_t *opp = opaque;
 644    uint32_t retval;
 645
 646    DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
 647    retval = 0xFFFFFFFF;
 648    if (addr & 0xF)
 649        return retval;
 650    addr &= 0xFF;
 651    switch (addr) {
 652    case 0x00: /* FREP */
 653        retval = opp->frep;
 654        break;
 655    case 0x20: /* GLBC */
 656        retval = opp->glbc;
 657        break;
 658    case 0x80: /* VENI */
 659        retval = opp->veni;
 660        break;
 661    case 0x90: /* PINT */
 662        retval = 0x00000000;
 663        break;
 664#if MAX_IPI > 0
 665    case 0xA0: /* IPI_IPVP */
 666    case 0xB0:
 667    case 0xC0:
 668    case 0xD0:
 669        {
 670            int idx;
 671            idx = (addr - 0xA0) >> 4;
 672            retval = read_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IPVP);
 673        }
 674        break;
 675#endif
 676    case 0xE0: /* SPVE */
 677        retval = opp->spve;
 678        break;
 679    case 0xF0: /* TIFR */
 680        retval = opp->tifr;
 681        break;
 682    default:
 683        break;
 684    }
 685    DPRINTF("%s: => %08x\n", __func__, retval);
 686
 687    return retval;
 688}
 689
 690static void openpic_timer_write (void *opaque, uint32_t addr, uint32_t val)
 691{
 692    openpic_t *opp = opaque;
 693    int idx;
 694
 695    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
 696    if (addr & 0xF)
 697        return;
 698    addr -= 0x1100;
 699    addr &= 0xFFFF;
 700    idx = (addr & 0xFFF0) >> 6;
 701    addr = addr & 0x30;
 702    switch (addr) {
 703    case 0x00: /* TICC */
 704        break;
 705    case 0x10: /* TIBC */
 706        if ((opp->timers[idx].ticc & 0x80000000) != 0 &&
 707            (val & 0x80000000) == 0 &&
 708            (opp->timers[idx].tibc & 0x80000000) != 0)
 709            opp->timers[idx].ticc &= ~0x80000000;
 710        opp->timers[idx].tibc = val;
 711        break;
 712    case 0x20: /* TIVP */
 713        write_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IPVP, val);
 714        break;
 715    case 0x30: /* TIDE */
 716        write_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IDE, val);
 717        break;
 718    }
 719}
 720
 721static uint32_t openpic_timer_read (void *opaque, uint32_t addr)
 722{
 723    openpic_t *opp = opaque;
 724    uint32_t retval;
 725    int idx;
 726
 727    DPRINTF("%s: addr %08x\n", __func__, addr);
 728    retval = 0xFFFFFFFF;
 729    if (addr & 0xF)
 730        return retval;
 731    addr -= 0x1100;
 732    addr &= 0xFFFF;
 733    idx = (addr & 0xFFF0) >> 6;
 734    addr = addr & 0x30;
 735    switch (addr) {
 736    case 0x00: /* TICC */
 737        retval = opp->timers[idx].ticc;
 738        break;
 739    case 0x10: /* TIBC */
 740        retval = opp->timers[idx].tibc;
 741        break;
 742    case 0x20: /* TIPV */
 743        retval = read_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IPVP);
 744        break;
 745    case 0x30: /* TIDE */
 746        retval = read_IRQreg(opp, opp->irq_tim0 + idx, IRQ_IDE);
 747        break;
 748    }
 749    DPRINTF("%s: => %08x\n", __func__, retval);
 750
 751    return retval;
 752}
 753
 754static void openpic_src_write (void *opaque, uint32_t addr, uint32_t val)
 755{
 756    openpic_t *opp = opaque;
 757    int idx;
 758
 759    DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
 760    if (addr & 0xF)
 761        return;
 762    addr = addr & 0xFFF0;
 763    idx = addr >> 5;
 764    if (addr & 0x10) {
 765        /* EXDE / IFEDE / IEEDE */
 766        write_IRQreg(opp, idx, IRQ_IDE, val);
 767    } else {
 768        /* EXVP / IFEVP / IEEVP */
 769        write_IRQreg(opp, idx, IRQ_IPVP, val);
 770    }
 771}
 772
 773static uint32_t openpic_src_read (void *opaque, uint32_t addr)
 774{
 775    openpic_t *opp = opaque;
 776    uint32_t retval;
 777    int idx;
 778
 779    DPRINTF("%s: addr %08x\n", __func__, addr);
 780    retval = 0xFFFFFFFF;
 781    if (addr & 0xF)
 782        return retval;
 783    addr = addr & 0xFFF0;
 784    idx = addr >> 5;
 785    if (addr & 0x10) {
 786        /* EXDE / IFEDE / IEEDE */
 787        retval = read_IRQreg(opp, idx, IRQ_IDE);
 788    } else {
 789        /* EXVP / IFEVP / IEEVP */
 790        retval = read_IRQreg(opp, idx, IRQ_IPVP);
 791    }
 792    DPRINTF("%s: => %08x\n", __func__, retval);
 793
 794    return retval;
 795}
 796
 797static void openpic_cpu_write (void *opaque, target_phys_addr_t addr, uint32_t val)
 798{
 799    openpic_t *opp = opaque;
 800    IRQ_src_t *src;
 801    IRQ_dst_t *dst;
 802    int idx, s_IRQ, n_IRQ;
 803
 804    DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
 805    if (addr & 0xF)
 806        return;
 807    addr &= 0x1FFF0;
 808    idx = addr / 0x1000;
 809    dst = &opp->dst[idx];
 810    addr &= 0xFF0;
 811    switch (addr) {
 812#if MAX_IPI > 0
 813    case 0x40: /* PIPD */
 814    case 0x50:
 815    case 0x60:
 816    case 0x70:
 817        idx = (addr - 0x40) >> 4;
 818        write_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IDE, val);
 819        openpic_set_irq(opp, opp->irq_ipi0 + idx, 1);
 820        openpic_set_irq(opp, opp->irq_ipi0 + idx, 0);
 821        break;
 822#endif
 823    case 0x80: /* PCTP */
 824        dst->pctp = val & 0x0000000F;
 825        break;
 826    case 0x90: /* WHOAMI */
 827        /* Read-only register */
 828        break;
 829    case 0xA0: /* PIAC */
 830        /* Read-only register */
 831        break;
 832    case 0xB0: /* PEOI */
 833        DPRINTF("PEOI\n");
 834        s_IRQ = IRQ_get_next(opp, &dst->servicing);
 835        IRQ_resetbit(&dst->servicing, s_IRQ);
 836        dst->servicing.next = -1;
 837        /* Set up next servicing IRQ */
 838        s_IRQ = IRQ_get_next(opp, &dst->servicing);
 839        /* Check queued interrupts. */
 840        n_IRQ = IRQ_get_next(opp, &dst->raised);
 841        src = &opp->src[n_IRQ];
 842        if (n_IRQ != -1 &&
 843            (s_IRQ == -1 ||
 844             IPVP_PRIORITY(src->ipvp) > dst->servicing.priority)) {
 845            DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n",
 846                    idx, n_IRQ);
 847            opp->irq_raise(opp, idx, src);
 848        }
 849        break;
 850    default:
 851        break;
 852    }
 853}
 854
 855static uint32_t openpic_cpu_read (void *opaque, target_phys_addr_t addr)
 856{
 857    openpic_t *opp = opaque;
 858    IRQ_src_t *src;
 859    IRQ_dst_t *dst;
 860    uint32_t retval;
 861    int idx, n_IRQ;
 862
 863    DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
 864    retval = 0xFFFFFFFF;
 865    if (addr & 0xF)
 866        return retval;
 867    addr &= 0x1FFF0;
 868    idx = addr / 0x1000;
 869    dst = &opp->dst[idx];
 870    addr &= 0xFF0;
 871    switch (addr) {
 872    case 0x80: /* PCTP */
 873        retval = dst->pctp;
 874        break;
 875    case 0x90: /* WHOAMI */
 876        retval = idx;
 877        break;
 878    case 0xA0: /* PIAC */
 879        DPRINTF("Lower OpenPIC INT output\n");
 880        qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]);
 881        n_IRQ = IRQ_get_next(opp, &dst->raised);
 882        DPRINTF("PIAC: irq=%d\n", n_IRQ);
 883        if (n_IRQ == -1) {
 884            /* No more interrupt pending */
 885            retval = IPVP_VECTOR(opp->spve);
 886        } else {
 887            src = &opp->src[n_IRQ];
 888            if (!test_bit(&src->ipvp, IPVP_ACTIVITY) ||
 889                !(IPVP_PRIORITY(src->ipvp) > dst->pctp)) {
 890                /* - Spurious level-sensitive IRQ
 891                 * - Priorities has been changed
 892                 *   and the pending IRQ isn't allowed anymore
 893                 */
 894                reset_bit(&src->ipvp, IPVP_ACTIVITY);
 895                retval = IPVP_VECTOR(opp->spve);
 896            } else {
 897                /* IRQ enter servicing state */
 898                IRQ_setbit(&dst->servicing, n_IRQ);
 899                retval = IPVP_VECTOR(src->ipvp);
 900            }
 901            IRQ_resetbit(&dst->raised, n_IRQ);
 902            dst->raised.next = -1;
 903            if (!test_bit(&src->ipvp, IPVP_SENSE)) {
 904                /* edge-sensitive IRQ */
 905                reset_bit(&src->ipvp, IPVP_ACTIVITY);
 906                src->pending = 0;
 907            }
 908        }
 909        break;
 910    case 0xB0: /* PEOI */
 911        retval = 0;
 912        break;
 913#if MAX_IPI > 0
 914    case 0x40: /* IDE */
 915    case 0x50:
 916        idx = (addr - 0x40) >> 4;
 917        retval = read_IRQreg(opp, opp->irq_ipi0 + idx, IRQ_IDE);
 918        break;
 919#endif
 920    default:
 921        break;
 922    }
 923    DPRINTF("%s: => %08x\n", __func__, retval);
 924
 925    return retval;
 926}
 927
 928static void openpic_buggy_write (void *opaque,
 929                                 target_phys_addr_t addr, uint32_t val)
 930{
 931    printf("Invalid OPENPIC write access !\n");
 932}
 933
 934static uint32_t openpic_buggy_read (void *opaque, target_phys_addr_t addr)
 935{
 936    printf("Invalid OPENPIC read access !\n");
 937
 938    return -1;
 939}
 940
 941static void openpic_writel (void *opaque,
 942                            target_phys_addr_t addr, uint32_t val)
 943{
 944    openpic_t *opp = opaque;
 945
 946    addr &= 0x3FFFF;
 947    DPRINTF("%s: offset %08x val: %08x\n", __func__, (int)addr, val);
 948    if (addr < 0x1100) {
 949        /* Global registers */
 950        openpic_gbl_write(opp, addr, val);
 951    } else if (addr < 0x10000) {
 952        /* Timers registers */
 953        openpic_timer_write(opp, addr, val);
 954    } else if (addr < 0x20000) {
 955        /* Source registers */
 956        openpic_src_write(opp, addr, val);
 957    } else {
 958        /* CPU registers */
 959        openpic_cpu_write(opp, addr, val);
 960    }
 961}
 962
 963static uint32_t openpic_readl (void *opaque,target_phys_addr_t addr)
 964{
 965    openpic_t *opp = opaque;
 966    uint32_t retval;
 967
 968    addr &= 0x3FFFF;
 969    DPRINTF("%s: offset %08x\n", __func__, (int)addr);
 970    if (addr < 0x1100) {
 971        /* Global registers */
 972        retval = openpic_gbl_read(opp, addr);
 973    } else if (addr < 0x10000) {
 974        /* Timers registers */
 975        retval = openpic_timer_read(opp, addr);
 976    } else if (addr < 0x20000) {
 977        /* Source registers */
 978        retval = openpic_src_read(opp, addr);
 979    } else {
 980        /* CPU registers */
 981        retval = openpic_cpu_read(opp, addr);
 982    }
 983
 984    return retval;
 985}
 986
 987static CPUWriteMemoryFunc * const openpic_write[] = {
 988    &openpic_buggy_write,
 989    &openpic_buggy_write,
 990    &openpic_writel,
 991};
 992
 993static CPUReadMemoryFunc * const openpic_read[] = {
 994    &openpic_buggy_read,
 995    &openpic_buggy_read,
 996    &openpic_readl,
 997};
 998
 999static void openpic_map(PCIDevice *pci_dev, int region_num,
1000                        pcibus_t addr, pcibus_t size, int type)
1001{
1002    openpic_t *opp;
1003
1004    DPRINTF("Map OpenPIC\n");
1005    opp = (openpic_t *)pci_dev;
1006    /* Global registers */
1007    DPRINTF("Register OPENPIC gbl   %08x => %08x\n",
1008            addr + 0x1000, addr + 0x1000 + 0x100);
1009    /* Timer registers */
1010    DPRINTF("Register OPENPIC timer %08x => %08x\n",
1011            addr + 0x1100, addr + 0x1100 + 0x40 * MAX_TMR);
1012    /* Interrupt source registers */
1013    DPRINTF("Register OPENPIC src   %08x => %08x\n",
1014            addr + 0x10000, addr + 0x10000 + 0x20 * (OPENPIC_EXT_IRQ + 2));
1015    /* Per CPU registers */
1016    DPRINTF("Register OPENPIC dst   %08x => %08x\n",
1017            addr + 0x20000, addr + 0x20000 + 0x1000 * MAX_CPU);
1018    cpu_register_physical_memory(addr, 0x40000, opp->mem_index);
1019#if 0 // Don't implement ISU for now
1020    opp_io_memory = cpu_register_io_memory(openpic_src_read,
1021                                           openpic_src_write, NULL
1022                                           DEVICE_NATIVE_ENDIAN);
1023    cpu_register_physical_memory(isu_base, 0x20 * (EXT_IRQ + 2),
1024                                 opp_io_memory);
1025#endif
1026}
1027
1028static void openpic_save_IRQ_queue(QEMUFile* f, IRQ_queue_t *q)
1029{
1030    unsigned int i;
1031
1032    for (i = 0; i < BF_WIDTH(MAX_IRQ); i++)
1033        qemu_put_be32s(f, &q->queue[i]);
1034
1035    qemu_put_sbe32s(f, &q->next);
1036    qemu_put_sbe32s(f, &q->priority);
1037}
1038
1039static void openpic_save(QEMUFile* f, void *opaque)
1040{
1041    openpic_t *opp = (openpic_t *)opaque;
1042    unsigned int i;
1043
1044    qemu_put_be32s(f, &opp->frep);
1045    qemu_put_be32s(f, &opp->glbc);
1046    qemu_put_be32s(f, &opp->micr);
1047    qemu_put_be32s(f, &opp->veni);
1048    qemu_put_be32s(f, &opp->pint);
1049    qemu_put_be32s(f, &opp->spve);
1050    qemu_put_be32s(f, &opp->tifr);
1051
1052    for (i = 0; i < opp->max_irq; i++) {
1053        qemu_put_be32s(f, &opp->src[i].ipvp);
1054        qemu_put_be32s(f, &opp->src[i].ide);
1055        qemu_put_sbe32s(f, &opp->src[i].type);
1056        qemu_put_sbe32s(f, &opp->src[i].last_cpu);
1057        qemu_put_sbe32s(f, &opp->src[i].pending);
1058    }
1059
1060    qemu_put_sbe32s(f, &opp->nb_cpus);
1061
1062    for (i = 0; i < opp->nb_cpus; i++) {
1063        qemu_put_be32s(f, &opp->dst[i].tfrr);
1064        qemu_put_be32s(f, &opp->dst[i].pctp);
1065        qemu_put_be32s(f, &opp->dst[i].pcsr);
1066        openpic_save_IRQ_queue(f, &opp->dst[i].raised);
1067        openpic_save_IRQ_queue(f, &opp->dst[i].servicing);
1068    }
1069
1070    for (i = 0; i < MAX_TMR; i++) {
1071        qemu_put_be32s(f, &opp->timers[i].ticc);
1072        qemu_put_be32s(f, &opp->timers[i].tibc);
1073    }
1074
1075#if MAX_DBL > 0
1076    qemu_put_be32s(f, &opp->dar);
1077
1078    for (i = 0; i < MAX_DBL; i++) {
1079        qemu_put_be32s(f, &opp->doorbells[i].dmr);
1080    }
1081#endif
1082
1083#if MAX_MBX > 0
1084    for (i = 0; i < MAX_MAILBOXES; i++) {
1085        qemu_put_be32s(f, &opp->mailboxes[i].mbr);
1086    }
1087#endif
1088
1089    pci_device_save(&opp->pci_dev, f);
1090}
1091
1092static void openpic_load_IRQ_queue(QEMUFile* f, IRQ_queue_t *q)
1093{
1094    unsigned int i;
1095
1096    for (i = 0; i < BF_WIDTH(MAX_IRQ); i++)
1097        qemu_get_be32s(f, &q->queue[i]);
1098
1099    qemu_get_sbe32s(f, &q->next);
1100    qemu_get_sbe32s(f, &q->priority);
1101}
1102
1103static int openpic_load(QEMUFile* f, void *opaque, int version_id)
1104{
1105    openpic_t *opp = (openpic_t *)opaque;
1106    unsigned int i;
1107
1108    if (version_id != 1)
1109        return -EINVAL;
1110
1111    qemu_get_be32s(f, &opp->frep);
1112    qemu_get_be32s(f, &opp->glbc);
1113    qemu_get_be32s(f, &opp->micr);
1114    qemu_get_be32s(f, &opp->veni);
1115    qemu_get_be32s(f, &opp->pint);
1116    qemu_get_be32s(f, &opp->spve);
1117    qemu_get_be32s(f, &opp->tifr);
1118
1119    for (i = 0; i < opp->max_irq; i++) {
1120        qemu_get_be32s(f, &opp->src[i].ipvp);
1121        qemu_get_be32s(f, &opp->src[i].ide);
1122        qemu_get_sbe32s(f, &opp->src[i].type);
1123        qemu_get_sbe32s(f, &opp->src[i].last_cpu);
1124        qemu_get_sbe32s(f, &opp->src[i].pending);
1125    }
1126
1127    qemu_get_sbe32s(f, &opp->nb_cpus);
1128
1129    for (i = 0; i < opp->nb_cpus; i++) {
1130        qemu_get_be32s(f, &opp->dst[i].tfrr);
1131        qemu_get_be32s(f, &opp->dst[i].pctp);
1132        qemu_get_be32s(f, &opp->dst[i].pcsr);
1133        openpic_load_IRQ_queue(f, &opp->dst[i].raised);
1134        openpic_load_IRQ_queue(f, &opp->dst[i].servicing);
1135    }
1136
1137    for (i = 0; i < MAX_TMR; i++) {
1138        qemu_get_be32s(f, &opp->timers[i].ticc);
1139        qemu_get_be32s(f, &opp->timers[i].tibc);
1140    }
1141
1142#if MAX_DBL > 0
1143    qemu_get_be32s(f, &opp->dar);
1144
1145    for (i = 0; i < MAX_DBL; i++) {
1146        qemu_get_be32s(f, &opp->doorbells[i].dmr);
1147    }
1148#endif
1149
1150#if MAX_MBX > 0
1151    for (i = 0; i < MAX_MAILBOXES; i++) {
1152        qemu_get_be32s(f, &opp->mailboxes[i].mbr);
1153    }
1154#endif
1155
1156    return pci_device_load(&opp->pci_dev, f);
1157}
1158
1159static void openpic_irq_raise(openpic_t *opp, int n_CPU, IRQ_src_t *src)
1160{
1161    qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
1162}
1163
1164qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
1165                        qemu_irq **irqs, qemu_irq irq_out)
1166{
1167    openpic_t *opp;
1168    uint8_t *pci_conf;
1169    int i, m;
1170
1171    /* XXX: for now, only one CPU is supported */
1172    if (nb_cpus != 1)
1173        return NULL;
1174    if (bus) {
1175        opp = (openpic_t *)pci_register_device(bus, "OpenPIC", sizeof(openpic_t),
1176                                               -1, NULL, NULL);
1177        pci_conf = opp->pci_dev.config;
1178        pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_IBM);
1179        pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_IBM_OPENPIC2);
1180        pci_config_set_class(pci_conf, PCI_CLASS_SYSTEM_OTHER); // FIXME?
1181        pci_conf[0x3d] = 0x00; // no interrupt pin
1182
1183        /* Register I/O spaces */
1184        pci_register_bar(&opp->pci_dev, 0, 0x40000,
1185                               PCI_BASE_ADDRESS_SPACE_MEMORY, &openpic_map);
1186    } else {
1187        opp = qemu_mallocz(sizeof(openpic_t));
1188    }
1189    opp->mem_index = cpu_register_io_memory(openpic_read, openpic_write, opp,
1190                                            DEVICE_LITTLE_ENDIAN);
1191
1192    //    isu_base &= 0xFFFC0000;
1193    opp->nb_cpus = nb_cpus;
1194    opp->max_irq = OPENPIC_MAX_IRQ;
1195    opp->irq_ipi0 = OPENPIC_IRQ_IPI0;
1196    opp->irq_tim0 = OPENPIC_IRQ_TIM0;
1197    /* Set IRQ types */
1198    for (i = 0; i < OPENPIC_EXT_IRQ; i++) {
1199        opp->src[i].type = IRQ_EXTERNAL;
1200    }
1201    for (; i < OPENPIC_IRQ_TIM0; i++) {
1202        opp->src[i].type = IRQ_SPECIAL;
1203    }
1204#if MAX_IPI > 0
1205    m = OPENPIC_IRQ_IPI0;
1206#else
1207    m = OPENPIC_IRQ_DBL0;
1208#endif
1209    for (; i < m; i++) {
1210        opp->src[i].type = IRQ_TIMER;
1211    }
1212    for (; i < OPENPIC_MAX_IRQ; i++) {
1213        opp->src[i].type = IRQ_INTERNAL;
1214    }
1215    for (i = 0; i < nb_cpus; i++)
1216        opp->dst[i].irqs = irqs[i];
1217    opp->irq_out = irq_out;
1218
1219    register_savevm(&opp->pci_dev.qdev, "openpic", 0, 2,
1220                    openpic_save, openpic_load, opp);
1221    qemu_register_reset(openpic_reset, opp);
1222
1223    opp->irq_raise = openpic_irq_raise;
1224    opp->reset = openpic_reset;
1225
1226    if (pmem_index)
1227        *pmem_index = opp->mem_index;
1228
1229    return qemu_allocate_irqs(openpic_set_irq, opp, opp->max_irq);
1230}
1231
1232static void mpic_irq_raise(openpic_t *mpp, int n_CPU, IRQ_src_t *src)
1233{
1234    int n_ci = IDR_CI0 - n_CPU;
1235
1236    if(test_bit(&src->ide, n_ci)) {
1237        qemu_irq_raise(mpp->dst[n_CPU].irqs[OPENPIC_OUTPUT_CINT]);
1238    }
1239    else {
1240        qemu_irq_raise(mpp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]);
1241    }
1242}
1243
1244static void mpic_reset (void *opaque)
1245{
1246    openpic_t *mpp = (openpic_t *)opaque;
1247    int i;
1248
1249    mpp->glbc = 0x80000000;
1250    /* Initialise controller registers */
1251    mpp->frep = 0x004f0002;
1252    mpp->veni = VENI;
1253    mpp->pint = 0x00000000;
1254    mpp->spve = 0x0000FFFF;
1255    /* Initialise IRQ sources */
1256    for (i = 0; i < mpp->max_irq; i++) {
1257        mpp->src[i].ipvp = 0x80800000;
1258        mpp->src[i].ide  = 0x00000001;
1259    }
1260    /* Initialise IRQ destinations */
1261    for (i = 0; i < MAX_CPU; i++) {
1262        mpp->dst[i].pctp      = 0x0000000F;
1263        mpp->dst[i].tfrr      = 0x00000000;
1264        memset(&mpp->dst[i].raised, 0, sizeof(IRQ_queue_t));
1265        mpp->dst[i].raised.next = -1;
1266        memset(&mpp->dst[i].servicing, 0, sizeof(IRQ_queue_t));
1267        mpp->dst[i].servicing.next = -1;
1268    }
1269    /* Initialise timers */
1270    for (i = 0; i < MAX_TMR; i++) {
1271        mpp->timers[i].ticc = 0x00000000;
1272        mpp->timers[i].tibc = 0x80000000;
1273    }
1274    /* Go out of RESET state */
1275    mpp->glbc = 0x00000000;
1276}
1277
1278static void mpic_timer_write (void *opaque, target_phys_addr_t addr, uint32_t val)
1279{
1280    openpic_t *mpp = opaque;
1281    int idx, cpu;
1282
1283    DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
1284    if (addr & 0xF)
1285        return;
1286    addr &= 0xFFFF;
1287    cpu = addr >> 12;
1288    idx = (addr >> 6) & 0x3;
1289    switch (addr & 0x30) {
1290    case 0x00: /* gtccr */
1291        break;
1292    case 0x10: /* gtbcr */
1293        if ((mpp->timers[idx].ticc & 0x80000000) != 0 &&
1294            (val & 0x80000000) == 0 &&
1295            (mpp->timers[idx].tibc & 0x80000000) != 0)
1296            mpp->timers[idx].ticc &= ~0x80000000;
1297        mpp->timers[idx].tibc = val;
1298        break;
1299    case 0x20: /* GTIVPR */
1300        write_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IPVP, val);
1301        break;
1302    case 0x30: /* GTIDR & TFRR */
1303        if ((addr & 0xF0) == 0xF0)
1304            mpp->dst[cpu].tfrr = val;
1305        else
1306            write_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IDE, val);
1307        break;
1308    }
1309}
1310
1311static uint32_t mpic_timer_read (void *opaque, target_phys_addr_t addr)
1312{
1313    openpic_t *mpp = opaque;
1314    uint32_t retval;
1315    int idx, cpu;
1316
1317    DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1318    retval = 0xFFFFFFFF;
1319    if (addr & 0xF)
1320        return retval;
1321    addr &= 0xFFFF;
1322    cpu = addr >> 12;
1323    idx = (addr >> 6) & 0x3;
1324    switch (addr & 0x30) {
1325    case 0x00: /* gtccr */
1326        retval = mpp->timers[idx].ticc;
1327        break;
1328    case 0x10: /* gtbcr */
1329        retval = mpp->timers[idx].tibc;
1330        break;
1331    case 0x20: /* TIPV */
1332        retval = read_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IPVP);
1333        break;
1334    case 0x30: /* TIDR */
1335        if ((addr &0xF0) == 0XF0)
1336            retval = mpp->dst[cpu].tfrr;
1337        else
1338            retval = read_IRQreg(mpp, MPIC_TMR_IRQ + idx, IRQ_IDE);
1339        break;
1340    }
1341    DPRINTF("%s: => %08x\n", __func__, retval);
1342
1343    return retval;
1344}
1345
1346static void mpic_src_ext_write (void *opaque, target_phys_addr_t addr,
1347                                uint32_t val)
1348{
1349    openpic_t *mpp = opaque;
1350    int idx = MPIC_EXT_IRQ;
1351
1352    DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
1353    if (addr & 0xF)
1354        return;
1355
1356    addr -= MPIC_EXT_REG_START & (OPENPIC_PAGE_SIZE - 1);
1357    if (addr < MPIC_EXT_REG_SIZE) {
1358        idx += (addr & 0xFFF0) >> 5;
1359        if (addr & 0x10) {
1360            /* EXDE / IFEDE / IEEDE */
1361            write_IRQreg(mpp, idx, IRQ_IDE, val);
1362        } else {
1363            /* EXVP / IFEVP / IEEVP */
1364            write_IRQreg(mpp, idx, IRQ_IPVP, val);
1365        }
1366    }
1367}
1368
1369static uint32_t mpic_src_ext_read (void *opaque, target_phys_addr_t addr)
1370{
1371    openpic_t *mpp = opaque;
1372    uint32_t retval;
1373    int idx = MPIC_EXT_IRQ;
1374
1375    DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1376    retval = 0xFFFFFFFF;
1377    if (addr & 0xF)
1378        return retval;
1379
1380    addr -= MPIC_EXT_REG_START & (OPENPIC_PAGE_SIZE - 1);
1381    if (addr < MPIC_EXT_REG_SIZE) {
1382        idx += (addr & 0xFFF0) >> 5;
1383        if (addr & 0x10) {
1384            /* EXDE / IFEDE / IEEDE */
1385            retval = read_IRQreg(mpp, idx, IRQ_IDE);
1386        } else {
1387            /* EXVP / IFEVP / IEEVP */
1388            retval = read_IRQreg(mpp, idx, IRQ_IPVP);
1389        }
1390        DPRINTF("%s: => %08x\n", __func__, retval);
1391    }
1392
1393    return retval;
1394}
1395
1396static void mpic_src_int_write (void *opaque, target_phys_addr_t addr,
1397                                uint32_t val)
1398{
1399    openpic_t *mpp = opaque;
1400    int idx = MPIC_INT_IRQ;
1401
1402    DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
1403    if (addr & 0xF)
1404        return;
1405
1406    addr -= MPIC_INT_REG_START & (OPENPIC_PAGE_SIZE - 1);
1407    if (addr < MPIC_INT_REG_SIZE) {
1408        idx += (addr & 0xFFF0) >> 5;
1409        if (addr & 0x10) {
1410            /* EXDE / IFEDE / IEEDE */
1411            write_IRQreg(mpp, idx, IRQ_IDE, val);
1412        } else {
1413            /* EXVP / IFEVP / IEEVP */
1414            write_IRQreg(mpp, idx, IRQ_IPVP, val);
1415        }
1416    }
1417}
1418
1419static uint32_t mpic_src_int_read (void *opaque, target_phys_addr_t addr)
1420{
1421    openpic_t *mpp = opaque;
1422    uint32_t retval;
1423    int idx = MPIC_INT_IRQ;
1424
1425    DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1426    retval = 0xFFFFFFFF;
1427    if (addr & 0xF)
1428        return retval;
1429
1430    addr -= MPIC_INT_REG_START & (OPENPIC_PAGE_SIZE - 1);
1431    if (addr < MPIC_INT_REG_SIZE) {
1432        idx += (addr & 0xFFF0) >> 5;
1433        if (addr & 0x10) {
1434            /* EXDE / IFEDE / IEEDE */
1435            retval = read_IRQreg(mpp, idx, IRQ_IDE);
1436        } else {
1437            /* EXVP / IFEVP / IEEVP */
1438            retval = read_IRQreg(mpp, idx, IRQ_IPVP);
1439        }
1440        DPRINTF("%s: => %08x\n", __func__, retval);
1441    }
1442
1443    return retval;
1444}
1445
1446static void mpic_src_msg_write (void *opaque, target_phys_addr_t addr,
1447                                uint32_t val)
1448{
1449    openpic_t *mpp = opaque;
1450    int idx = MPIC_MSG_IRQ;
1451
1452    DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
1453    if (addr & 0xF)
1454        return;
1455
1456    addr -= MPIC_MSG_REG_START & (OPENPIC_PAGE_SIZE - 1);
1457    if (addr < MPIC_MSG_REG_SIZE) {
1458        idx += (addr & 0xFFF0) >> 5;
1459        if (addr & 0x10) {
1460            /* EXDE / IFEDE / IEEDE */
1461            write_IRQreg(mpp, idx, IRQ_IDE, val);
1462        } else {
1463            /* EXVP / IFEVP / IEEVP */
1464            write_IRQreg(mpp, idx, IRQ_IPVP, val);
1465        }
1466    }
1467}
1468
1469static uint32_t mpic_src_msg_read (void *opaque, target_phys_addr_t addr)
1470{
1471    openpic_t *mpp = opaque;
1472    uint32_t retval;
1473    int idx = MPIC_MSG_IRQ;
1474
1475    DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1476    retval = 0xFFFFFFFF;
1477    if (addr & 0xF)
1478        return retval;
1479
1480    addr -= MPIC_MSG_REG_START & (OPENPIC_PAGE_SIZE - 1);
1481    if (addr < MPIC_MSG_REG_SIZE) {
1482        idx += (addr & 0xFFF0) >> 5;
1483        if (addr & 0x10) {
1484            /* EXDE / IFEDE / IEEDE */
1485            retval = read_IRQreg(mpp, idx, IRQ_IDE);
1486        } else {
1487            /* EXVP / IFEVP / IEEVP */
1488            retval = read_IRQreg(mpp, idx, IRQ_IPVP);
1489        }
1490        DPRINTF("%s: => %08x\n", __func__, retval);
1491    }
1492
1493    return retval;
1494}
1495
1496static void mpic_src_msi_write (void *opaque, target_phys_addr_t addr,
1497                                uint32_t val)
1498{
1499    openpic_t *mpp = opaque;
1500    int idx = MPIC_MSI_IRQ;
1501
1502    DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val);
1503    if (addr & 0xF)
1504        return;
1505
1506    addr -= MPIC_MSI_REG_START & (OPENPIC_PAGE_SIZE - 1);
1507    if (addr < MPIC_MSI_REG_SIZE) {
1508        idx += (addr & 0xFFF0) >> 5;
1509        if (addr & 0x10) {
1510            /* EXDE / IFEDE / IEEDE */
1511            write_IRQreg(mpp, idx, IRQ_IDE, val);
1512        } else {
1513            /* EXVP / IFEVP / IEEVP */
1514            write_IRQreg(mpp, idx, IRQ_IPVP, val);
1515        }
1516    }
1517}
1518static uint32_t mpic_src_msi_read (void *opaque, target_phys_addr_t addr)
1519{
1520    openpic_t *mpp = opaque;
1521    uint32_t retval;
1522    int idx = MPIC_MSI_IRQ;
1523
1524    DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr);
1525    retval = 0xFFFFFFFF;
1526    if (addr & 0xF)
1527        return retval;
1528
1529    addr -= MPIC_MSI_REG_START & (OPENPIC_PAGE_SIZE - 1);
1530    if (addr < MPIC_MSI_REG_SIZE) {
1531        idx += (addr & 0xFFF0) >> 5;
1532        if (addr & 0x10) {
1533            /* EXDE / IFEDE / IEEDE */
1534            retval = read_IRQreg(mpp, idx, IRQ_IDE);
1535        } else {
1536            /* EXVP / IFEVP / IEEVP */
1537            retval = read_IRQreg(mpp, idx, IRQ_IPVP);
1538        }
1539        DPRINTF("%s: => %08x\n", __func__, retval);
1540    }
1541
1542    return retval;
1543}
1544
1545static CPUWriteMemoryFunc * const mpic_glb_write[] = {
1546    &openpic_buggy_write,
1547    &openpic_buggy_write,
1548    &openpic_gbl_write,
1549};
1550
1551static CPUReadMemoryFunc * const mpic_glb_read[] = {
1552    &openpic_buggy_read,
1553    &openpic_buggy_read,
1554    &openpic_gbl_read,
1555};
1556
1557static CPUWriteMemoryFunc * const mpic_tmr_write[] = {
1558    &openpic_buggy_write,
1559    &openpic_buggy_write,
1560    &mpic_timer_write,
1561};
1562
1563static CPUReadMemoryFunc * const mpic_tmr_read[] = {
1564    &openpic_buggy_read,
1565    &openpic_buggy_read,
1566    &mpic_timer_read,
1567};
1568
1569static CPUWriteMemoryFunc * const mpic_cpu_write[] = {
1570    &openpic_buggy_write,
1571    &openpic_buggy_write,
1572    &openpic_cpu_write,
1573};
1574
1575static CPUReadMemoryFunc * const mpic_cpu_read[] = {
1576    &openpic_buggy_read,
1577    &openpic_buggy_read,
1578    &openpic_cpu_read,
1579};
1580
1581static CPUWriteMemoryFunc * const mpic_ext_write[] = {
1582    &openpic_buggy_write,
1583    &openpic_buggy_write,
1584    &mpic_src_ext_write,
1585};
1586
1587static CPUReadMemoryFunc * const mpic_ext_read[] = {
1588    &openpic_buggy_read,
1589    &openpic_buggy_read,
1590    &mpic_src_ext_read,
1591};
1592
1593static CPUWriteMemoryFunc * const mpic_int_write[] = {
1594    &openpic_buggy_write,
1595    &openpic_buggy_write,
1596    &mpic_src_int_write,
1597};
1598
1599static CPUReadMemoryFunc * const mpic_int_read[] = {
1600    &openpic_buggy_read,
1601    &openpic_buggy_read,
1602    &mpic_src_int_read,
1603};
1604
1605static CPUWriteMemoryFunc * const mpic_msg_write[] = {
1606    &openpic_buggy_write,
1607    &openpic_buggy_write,
1608    &mpic_src_msg_write,
1609};
1610
1611static CPUReadMemoryFunc * const mpic_msg_read[] = {
1612    &openpic_buggy_read,
1613    &openpic_buggy_read,
1614    &mpic_src_msg_read,
1615};
1616static CPUWriteMemoryFunc * const mpic_msi_write[] = {
1617    &openpic_buggy_write,
1618    &openpic_buggy_write,
1619    &mpic_src_msi_write,
1620};
1621
1622static CPUReadMemoryFunc * const mpic_msi_read[] = {
1623    &openpic_buggy_read,
1624    &openpic_buggy_read,
1625    &mpic_src_msi_read,
1626};
1627
1628qemu_irq *mpic_init (target_phys_addr_t base, int nb_cpus,
1629                        qemu_irq **irqs, qemu_irq irq_out)
1630{
1631    openpic_t *mpp;
1632    int i;
1633    struct {
1634        CPUReadMemoryFunc * const *read;
1635        CPUWriteMemoryFunc * const *write;
1636        target_phys_addr_t start_addr;
1637        ram_addr_t size;
1638    } const list[] = {
1639        {mpic_glb_read, mpic_glb_write, MPIC_GLB_REG_START, MPIC_GLB_REG_SIZE},
1640        {mpic_tmr_read, mpic_tmr_write, MPIC_TMR_REG_START, MPIC_TMR_REG_SIZE},
1641        {mpic_ext_read, mpic_ext_write, MPIC_EXT_REG_START, MPIC_EXT_REG_SIZE},
1642        {mpic_int_read, mpic_int_write, MPIC_INT_REG_START, MPIC_INT_REG_SIZE},
1643        {mpic_msg_read, mpic_msg_write, MPIC_MSG_REG_START, MPIC_MSG_REG_SIZE},
1644        {mpic_msi_read, mpic_msi_write, MPIC_MSI_REG_START, MPIC_MSI_REG_SIZE},
1645        {mpic_cpu_read, mpic_cpu_write, MPIC_CPU_REG_START, MPIC_CPU_REG_SIZE},
1646    };
1647
1648    /* XXX: for now, only one CPU is supported */
1649    if (nb_cpus != 1)
1650        return NULL;
1651
1652    mpp = qemu_mallocz(sizeof(openpic_t));
1653
1654    for (i = 0; i < sizeof(list)/sizeof(list[0]); i++) {
1655        int mem_index;
1656
1657        mem_index = cpu_register_io_memory(list[i].read, list[i].write, mpp,
1658                                           DEVICE_BIG_ENDIAN);
1659        if (mem_index < 0) {
1660            goto free;
1661        }
1662        cpu_register_physical_memory(base + list[i].start_addr,
1663                                     list[i].size, mem_index);
1664    }
1665
1666    mpp->nb_cpus = nb_cpus;
1667    mpp->max_irq = MPIC_MAX_IRQ;
1668    mpp->irq_ipi0 = MPIC_IPI_IRQ;
1669    mpp->irq_tim0 = MPIC_TMR_IRQ;
1670
1671    for (i = 0; i < nb_cpus; i++)
1672        mpp->dst[i].irqs = irqs[i];
1673    mpp->irq_out = irq_out;
1674
1675    mpp->irq_raise = mpic_irq_raise;
1676    mpp->reset = mpic_reset;
1677
1678    register_savevm(NULL, "mpic", 0, 2, openpic_save, openpic_load, mpp);
1679    qemu_register_reset(mpic_reset, mpp);
1680
1681    return qemu_allocate_irqs(openpic_set_irq, mpp, mpp->max_irq);
1682
1683free:
1684    qemu_free(mpp);
1685    return NULL;
1686}
1687