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