Commit dbda808a4ad5744fded19bf6a750e7aecbf993d8

Authored by bellard
1 parent a0497918

OpenPIC support (Jocelyn Mayer)


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