diff options
Diffstat (limited to 'hw/openpic.c')
-rw-r--r-- | hw/openpic.c | 1397 |
1 files changed, 486 insertions, 911 deletions
diff --git a/hw/openpic.c b/hw/openpic.c index 8b3784a6bd..3cbcea8eb3 100644 --- a/hw/openpic.c +++ b/hw/openpic.c @@ -37,6 +37,8 @@ #include "ppc_mac.h" #include "pci.h" #include "openpic.h" +#include "sysbus.h" +#include "msi.h" //#define DEBUG_OPENPIC @@ -46,89 +48,61 @@ #define DPRINTF(fmt, ...) do { } while (0) #endif -#define USE_MPCxxx /* Intel model is broken, for now */ - -#if defined (USE_INTEL_GW80314) -/* Intel GW80314 I/O Companion chip */ - -#define MAX_CPU 4 -#define MAX_IRQ 32 -#define MAX_DBL 4 -#define MAX_MBX 4 -#define MAX_TMR 4 -#define VECTOR_BITS 8 -#define MAX_IPI 4 - -#define VID (0x00000000) - -#elif defined(USE_MPCxxx) - -#define MAX_CPU 15 -#define MAX_IRQ 128 -#define MAX_DBL 0 -#define MAX_MBX 0 +#define MAX_CPU 15 +#define MAX_SRC 256 #define MAX_TMR 4 #define VECTOR_BITS 8 #define MAX_IPI 4 +#define MAX_MSI 8 +#define MAX_IRQ (MAX_SRC + MAX_IPI + MAX_TMR) #define VID 0x03 /* MPIC version ID */ -#define VENI 0x00000000 /* Vendor ID */ - -enum { - IRQ_IPVP = 0, - IRQ_IDE, -}; -/* OpenPIC */ -#define OPENPIC_MAX_CPU 2 -#define OPENPIC_MAX_IRQ 64 -#define OPENPIC_EXT_IRQ 48 -#define OPENPIC_MAX_TMR MAX_TMR -#define OPENPIC_MAX_IPI MAX_IPI +/* OpenPIC capability flags */ +#define OPENPIC_FLAG_IDE_CRIT (1 << 0) + +/* OpenPIC address map */ +#define OPENPIC_GLB_REG_START 0x0 +#define OPENPIC_GLB_REG_SIZE 0x10F0 +#define OPENPIC_TMR_REG_START 0x10F0 +#define OPENPIC_TMR_REG_SIZE 0x220 +#define OPENPIC_MSI_REG_START 0x1600 +#define OPENPIC_MSI_REG_SIZE 0x200 +#define OPENPIC_SRC_REG_START 0x10000 +#define OPENPIC_SRC_REG_SIZE (MAX_SRC * 0x20) +#define OPENPIC_CPU_REG_START 0x20000 +#define OPENPIC_CPU_REG_SIZE 0x100 + ((MAX_CPU - 1) * 0x1000) + +/* Raven */ +#define RAVEN_MAX_CPU 2 +#define RAVEN_MAX_EXT 48 +#define RAVEN_MAX_IRQ 64 +#define RAVEN_MAX_TMR MAX_TMR +#define RAVEN_MAX_IPI MAX_IPI /* Interrupt definitions */ -#define OPENPIC_IRQ_FE (OPENPIC_EXT_IRQ) /* Internal functional IRQ */ -#define OPENPIC_IRQ_ERR (OPENPIC_EXT_IRQ + 1) /* Error IRQ */ -#define OPENPIC_IRQ_TIM0 (OPENPIC_EXT_IRQ + 2) /* First timer IRQ */ -#if OPENPIC_MAX_IPI > 0 -#define OPENPIC_IRQ_IPI0 (OPENPIC_IRQ_TIM0 + OPENPIC_MAX_TMR) /* First IPI IRQ */ -#define OPENPIC_IRQ_DBL0 (OPENPIC_IRQ_IPI0 + (OPENPIC_MAX_CPU * OPENPIC_MAX_IPI)) /* First doorbell IRQ */ -#else -#define OPENPIC_IRQ_DBL0 (OPENPIC_IRQ_TIM0 + OPENPIC_MAX_TMR) /* First doorbell IRQ */ -#define OPENPIC_IRQ_MBX0 (OPENPIC_IRQ_DBL0 + OPENPIC_MAX_DBL) /* First mailbox IRQ */ -#endif - -/* MPIC */ -#define MPIC_MAX_CPU 1 -#define MPIC_MAX_EXT 12 -#define MPIC_MAX_INT 64 -#define MPIC_MAX_MSG 4 -#define MPIC_MAX_MSI 8 -#define MPIC_MAX_TMR MAX_TMR -#define MPIC_MAX_IPI MAX_IPI -#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)) +#define RAVEN_FE_IRQ (RAVEN_MAX_EXT) /* Internal functional IRQ */ +#define RAVEN_ERR_IRQ (RAVEN_MAX_EXT + 1) /* Error IRQ */ +#define RAVEN_TMR_IRQ (RAVEN_MAX_EXT + 2) /* First timer IRQ */ +#define RAVEN_IPI_IRQ (RAVEN_TMR_IRQ + RAVEN_MAX_TMR) /* First IPI IRQ */ +/* First doorbell IRQ */ +#define RAVEN_DBL_IRQ (RAVEN_IPI_IRQ + (RAVEN_MAX_CPU * RAVEN_MAX_IPI)) + +/* FSL_MPIC_20 */ +#define FSL_MPIC_20_MAX_CPU 1 +#define FSL_MPIC_20_MAX_EXT 12 +#define FSL_MPIC_20_MAX_INT 64 +#define FSL_MPIC_20_MAX_IRQ MAX_IRQ /* Interrupt definitions */ -#define MPIC_EXT_IRQ 0 -#define MPIC_INT_IRQ (MPIC_EXT_IRQ + MPIC_MAX_EXT) -#define MPIC_TMR_IRQ (MPIC_INT_IRQ + MPIC_MAX_INT) -#define MPIC_MSG_IRQ (MPIC_TMR_IRQ + MPIC_MAX_TMR) -#define MPIC_MSI_IRQ (MPIC_MSG_IRQ + MPIC_MAX_MSG) -#define MPIC_IPI_IRQ (MPIC_MSI_IRQ + MPIC_MAX_MSI) - -#define MPIC_GLB_REG_START 0x0 -#define MPIC_GLB_REG_SIZE 0x10F0 -#define MPIC_TMR_REG_START 0x10F0 -#define MPIC_TMR_REG_SIZE 0x220 -#define MPIC_EXT_REG_START 0x10000 -#define MPIC_EXT_REG_SIZE 0x180 -#define MPIC_INT_REG_START 0x10200 -#define MPIC_INT_REG_SIZE 0x800 -#define MPIC_MSG_REG_START 0x11600 -#define MPIC_MSG_REG_SIZE 0x100 -#define MPIC_MSI_REG_START 0x11C00 -#define MPIC_MSI_REG_SIZE 0x100 -#define MPIC_CPU_REG_START 0x20000 -#define MPIC_CPU_REG_SIZE 0x100 + ((MAX_CPU - 1) * 0x1000) +/* IRQs, accessible through the IRQ region */ +#define FSL_MPIC_20_EXT_IRQ 0x00 +#define FSL_MPIC_20_INT_IRQ 0x10 +#define FSL_MPIC_20_MSG_IRQ 0xb0 +#define FSL_MPIC_20_MSI_IRQ 0xe0 +/* These are available through separate regions, but + for simplicity's sake mapped into the same number space */ +#define FSL_MPIC_20_TMR_IRQ 0x100 +#define FSL_MPIC_20_IPI_IRQ 0x104 /* * Block Revision Register1 (BRR1): QEMU does not fully emulate @@ -141,34 +115,42 @@ enum { #define FSL_BRR1_IPMJ (0x00 << 8) /* 8 bit IP major number */ #define FSL_BRR1_IPMN 0x00 /* 8 bit IP minor number */ -enum mpic_ide_bits { - IDR_EP = 31, - IDR_CI0 = 30, - IDR_CI1 = 29, - IDR_P1 = 1, - IDR_P0 = 0, -}; +#define FREP_NIRQ_SHIFT 16 +#define FREP_NCPU_SHIFT 8 +#define FREP_VID_SHIFT 0 -#else -#error "Please select which OpenPic implementation is to be emulated" -#endif +#define VID_REVISION_1_2 2 +#define VID_REVISION_1_3 3 -#define OPENPIC_PAGE_SIZE 4096 +#define VENI_GENERIC 0x00000000 /* Generic Vendor ID */ + +#define IDR_EP_SHIFT 31 +#define IDR_EP_MASK (1 << IDR_EP_SHIFT) +#define IDR_CI0_SHIFT 30 +#define IDR_CI1_SHIFT 29 +#define IDR_P1_SHIFT 1 +#define IDR_P0_SHIFT 0 + +#define MSIIR_OFFSET 0x140 +#define MSIIR_SRS_SHIFT 29 +#define MSIIR_SRS_MASK (0x7 << MSIIR_SRS_SHIFT) +#define MSIIR_IBS_SHIFT 24 +#define MSIIR_IBS_MASK (0x1f << MSIIR_IBS_SHIFT) #define BF_WIDTH(_bits_) \ (((_bits_) + (sizeof(uint32_t) * 8) - 1) / (sizeof(uint32_t) * 8)) -static inline void set_bit (uint32_t *field, int bit) +static inline void set_bit(uint32_t *field, int bit) { field[bit >> 5] |= 1 << (bit & 0x1F); } -static inline void reset_bit (uint32_t *field, int bit) +static inline void reset_bit(uint32_t *field, int bit) { field[bit >> 5] &= ~(1 << (bit & 0x1F)); } -static inline int test_bit (uint32_t *field, int bit) +static inline int test_bit(uint32_t *field, int bit) { return (field[bit >> 5] & 1 << (bit & 0x1F)) != 0; } @@ -183,41 +165,37 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, static void openpic_cpu_write_internal(void *opaque, hwaddr addr, uint32_t val, int idx); -enum { - IRQ_EXTERNAL = 0x01, - IRQ_INTERNAL = 0x02, - IRQ_TIMER = 0x04, - IRQ_SPECIAL = 0x08, -}; - typedef struct IRQ_queue_t { uint32_t queue[BF_WIDTH(MAX_IRQ)]; int next; int priority; + int pending; /* nr of pending bits in queue */ } IRQ_queue_t; typedef struct IRQ_src_t { uint32_t ipvp; /* IRQ vector/priority register */ uint32_t ide; /* IRQ destination register */ - int type; int last_cpu; int pending; /* TRUE if IRQ is pending */ } IRQ_src_t; -enum IPVP_bits { - IPVP_MASK = 31, - IPVP_ACTIVITY = 30, - IPVP_MODE = 29, - IPVP_POLARITY = 23, - IPVP_SENSE = 22, -}; +#define IPVP_MASK_SHIFT 31 +#define IPVP_MASK_MASK (1 << IPVP_MASK_SHIFT) +#define IPVP_ACTIVITY_SHIFT 30 +#define IPVP_ACTIVITY_MASK (1 << IPVP_ACTIVITY_SHIFT) +#define IPVP_MODE_SHIFT 29 +#define IPVP_MODE_MASK (1 << IPVP_MODE_SHIFT) +#define IPVP_POLARITY_SHIFT 23 +#define IPVP_POLARITY_MASK (1 << IPVP_POLARITY_SHIFT) +#define IPVP_SENSE_SHIFT 22 +#define IPVP_SENSE_MASK (1 << IPVP_SENSE_SHIFT) + #define IPVP_PRIORITY_MASK (0x1F << 16) #define IPVP_PRIORITY(_ipvpr_) ((int)(((_ipvpr_) & IPVP_PRIORITY_MASK) >> 16)) #define IPVP_VECTOR_MASK ((1 << VECTOR_BITS) - 1) #define IPVP_VECTOR(_ipvpr_) ((_ipvpr_) & IPVP_VECTOR_MASK) typedef struct IRQ_dst_t { - uint32_t tfrr; uint32_t pctp; /* CPU current task priority */ uint32_t pcsr; /* CPU sensitivity register */ IRQ_queue_t raised; @@ -225,18 +203,28 @@ typedef struct IRQ_dst_t { qemu_irq *irqs; } IRQ_dst_t; -typedef struct openpic_t { - PCIDevice pci_dev; +typedef struct OpenPICState { + SysBusDevice busdev; MemoryRegion mem; + /* Behavior control */ + uint32_t model; + uint32_t flags; + uint32_t nb_irqs; + uint32_t vid; + uint32_t veni; /* Vendor identification register */ + uint32_t spve_mask; + uint32_t tifr_reset; + uint32_t ipvp_reset; + uint32_t ide_reset; + uint32_t brr1; + /* Sub-regions */ - MemoryRegion sub_io_mem[7]; + MemoryRegion sub_io_mem[5]; /* Global registers */ uint32_t frep; /* Feature reporting register */ uint32_t glbc; /* Global configuration register */ - uint32_t micr; /* MPIC interrupt configuration register */ - uint32_t veni; /* Vendor identification register */ uint32_t pint; /* Processor initialization register */ uint32_t spve; /* Spurious vector register */ uint32_t tifr; /* Timer frequency reporting register */ @@ -244,56 +232,54 @@ typedef struct openpic_t { IRQ_src_t src[MAX_IRQ]; /* Local registers per output pin */ IRQ_dst_t dst[MAX_CPU]; - int nb_cpus; + uint32_t nb_cpus; /* Timer registers */ struct { uint32_t ticc; /* Global timer current count register */ uint32_t tibc; /* Global timer base count register */ } timers[MAX_TMR]; -#if MAX_DBL > 0 - /* Doorbell registers */ - uint32_t dar; /* Doorbell activate register */ + /* Shared MSI registers */ struct { - uint32_t dmr; /* Doorbell messaging register */ - } doorbells[MAX_DBL]; -#endif -#if MAX_MBX > 0 - /* Mailbox registers */ - struct { - uint32_t mbr; /* Mailbox register */ - } mailboxes[MAX_MAILBOXES]; -#endif - /* IRQ out is used when in bypass mode (not implemented) */ - qemu_irq irq_out; - int max_irq; - int irq_ipi0; - int irq_tim0; - void (*reset) (void *); - void (*irq_raise) (struct openpic_t *, int, IRQ_src_t *); -} openpic_t; - -static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ) + uint32_t msir; /* Shared Message Signaled Interrupt Register */ + } msi[MAX_MSI]; + uint32_t max_irq; + uint32_t irq_ipi0; + uint32_t irq_tim0; + uint32_t irq_msi; +} OpenPICState; + +static void openpic_irq_raise(OpenPICState *opp, int n_CPU, IRQ_src_t *src); + +static inline void IRQ_setbit(IRQ_queue_t *q, int n_IRQ) { + q->pending++; set_bit(q->queue, n_IRQ); } -static inline void IRQ_resetbit (IRQ_queue_t *q, int n_IRQ) +static inline void IRQ_resetbit(IRQ_queue_t *q, int n_IRQ) { + q->pending--; reset_bit(q->queue, n_IRQ); } -static inline int IRQ_testbit (IRQ_queue_t *q, int n_IRQ) +static inline int IRQ_testbit(IRQ_queue_t *q, int n_IRQ) { return test_bit(q->queue, n_IRQ); } -static void IRQ_check (openpic_t *opp, IRQ_queue_t *q) +static void IRQ_check(OpenPICState *opp, IRQ_queue_t *q) { int next, i; int priority; next = -1; priority = -1; + + if (!q->pending) { + /* IRQ bitmap is empty */ + goto out; + } + for (i = 0; i < opp->max_irq; i++) { if (IRQ_testbit(q, i)) { DPRINTF("IRQ_check: irq %d set ipvp_pr=%d pr=%d\n", @@ -304,11 +290,13 @@ static void IRQ_check (openpic_t *opp, IRQ_queue_t *q) } } } + +out: q->next = next; q->priority = priority; } -static int IRQ_get_next (openpic_t *opp, IRQ_queue_t *q) +static int IRQ_get_next(OpenPICState *opp, IRQ_queue_t *q) { if (q->next == -1) { /* XXX: optimize */ @@ -318,7 +306,7 @@ static int IRQ_get_next (openpic_t *opp, IRQ_queue_t *q) return q->next; } -static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ) +static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ) { IRQ_dst_t *dst; IRQ_src_t *src; @@ -339,7 +327,7 @@ static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ) __func__, n_IRQ, n_CPU); return; } - set_bit(&src->ipvp, IPVP_ACTIVITY); + src->ipvp |= IPVP_ACTIVITY_MASK; IRQ_setbit(&dst->raised, n_IRQ); if (priority < dst->raised.priority) { /* An higher priority IRQ is already raised */ @@ -356,11 +344,11 @@ static void IRQ_local_pipe (openpic_t *opp, int n_CPU, int n_IRQ) return; } DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", n_CPU, n_IRQ); - opp->irq_raise(opp, n_CPU, src); + openpic_irq_raise(opp, n_CPU, src); } /* update pic state because registers for n_IRQ have changed value */ -static void openpic_update_irq(openpic_t *opp, int n_IRQ) +static void openpic_update_irq(OpenPICState *opp, int n_IRQ) { IRQ_src_t *src; int i; @@ -372,7 +360,7 @@ static void openpic_update_irq(openpic_t *opp, int n_IRQ) DPRINTF("%s: IRQ %d is not pending\n", __func__, n_IRQ); return; } - if (test_bit(&src->ipvp, IPVP_MASK)) { + if (src->ipvp & IPVP_MASK_MASK) { /* Interrupt source is disabled */ DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ); return; @@ -382,7 +370,7 @@ static void openpic_update_irq(openpic_t *opp, int n_IRQ) DPRINTF("%s: IRQ %d has 0 priority\n", __func__, n_IRQ); return; } - if (test_bit(&src->ipvp, IPVP_ACTIVITY)) { + if (src->ipvp & IPVP_ACTIVITY_MASK) { /* IRQ already active */ DPRINTF("%s: IRQ %d is already active\n", __func__, n_IRQ); return; @@ -396,18 +384,19 @@ static void openpic_update_irq(openpic_t *opp, int n_IRQ) if (src->ide == (1 << src->last_cpu)) { /* Only one CPU is allowed to receive this IRQ */ IRQ_local_pipe(opp, src->last_cpu, n_IRQ); - } else if (!test_bit(&src->ipvp, IPVP_MODE)) { + } else if (!(src->ipvp & IPVP_MODE_MASK)) { /* Directed delivery mode */ for (i = 0; i < opp->nb_cpus; i++) { - if (test_bit(&src->ide, i)) + if (src->ide & (1 << i)) { IRQ_local_pipe(opp, i, n_IRQ); + } } } else { /* Distributed delivery mode */ for (i = src->last_cpu + 1; i != src->last_cpu; i++) { if (i == opp->nb_cpus) i = 0; - if (test_bit(&src->ide, i)) { + if (src->ide & (1 << i)) { IRQ_local_pipe(opp, i, n_IRQ); src->last_cpu = i; break; @@ -418,17 +407,18 @@ static void openpic_update_irq(openpic_t *opp, int n_IRQ) static void openpic_set_irq(void *opaque, int n_IRQ, int level) { - openpic_t *opp = opaque; + OpenPICState *opp = opaque; IRQ_src_t *src; src = &opp->src[n_IRQ]; DPRINTF("openpic: set irq %d = %d ipvp=%08x\n", n_IRQ, level, src->ipvp); - if (test_bit(&src->ipvp, IPVP_SENSE)) { + if (src->ipvp & IPVP_SENSE_MASK) { /* level-sensitive irq */ src->pending = level; - if (!level) - reset_bit(&src->ipvp, IPVP_ACTIVITY); + if (!level) { + src->ipvp &= ~IPVP_ACTIVITY_MASK; + } } else { /* edge-sensitive irq */ if (level) @@ -437,24 +427,24 @@ static void openpic_set_irq(void *opaque, int n_IRQ, int level) openpic_update_irq(opp, n_IRQ); } -static void openpic_reset (void *opaque) +static void openpic_reset(DeviceState *d) { - openpic_t *opp = (openpic_t *)opaque; + OpenPICState *opp = FROM_SYSBUS(typeof (*opp), sysbus_from_qdev(d)); int i; opp->glbc = 0x80000000; /* Initialise controller registers */ - opp->frep = ((OPENPIC_EXT_IRQ - 1) << 16) | ((MAX_CPU - 1) << 8) | VID; - opp->veni = VENI; + opp->frep = ((opp->nb_irqs -1) << FREP_NIRQ_SHIFT) | + ((opp->nb_cpus -1) << FREP_NCPU_SHIFT) | + (opp->vid << FREP_VID_SHIFT); + opp->pint = 0x00000000; - opp->spve = 0x000000FF; - opp->tifr = 0x003F7A00; - /* ? */ - opp->micr = 0x00000000; + opp->spve = -1 & opp->spve_mask; + opp->tifr = opp->tifr_reset; /* Initialise IRQ sources */ for (i = 0; i < opp->max_irq; i++) { - opp->src[i].ipvp = 0xA0000000; - opp->src[i].ide = 0x00000000; + opp->src[i].ipvp = opp->ipvp_reset; + opp->src[i].ide = opp->ide_reset; } /* Initialise IRQ destinations */ for (i = 0; i < MAX_CPU; i++) { @@ -470,34 +460,21 @@ static void openpic_reset (void *opaque) opp->timers[i].ticc = 0x00000000; opp->timers[i].tibc = 0x80000000; } - /* Initialise doorbells */ -#if MAX_DBL > 0 - opp->dar = 0x00000000; - for (i = 0; i < MAX_DBL; i++) { - opp->doorbells[i].dmr = 0x00000000; - } -#endif - /* Initialise mailboxes */ -#if MAX_MBX > 0 - for (i = 0; i < MAX_MBX; i++) { /* ? */ - opp->mailboxes[i].mbr = 0x00000000; - } -#endif /* Go out of RESET state */ opp->glbc = 0x00000000; } -static inline uint32_t read_IRQreg_ide(openpic_t *opp, int n_IRQ) +static inline uint32_t read_IRQreg_ide(OpenPICState *opp, int n_IRQ) { return opp->src[n_IRQ].ide; } -static inline uint32_t read_IRQreg_ipvp(openpic_t *opp, int n_IRQ) +static inline uint32_t read_IRQreg_ipvp(OpenPICState *opp, int n_IRQ) { return opp->src[n_IRQ].ipvp; } -static inline void write_IRQreg_ide(openpic_t *opp, int n_IRQ, uint32_t val) +static inline void write_IRQreg_ide(OpenPICState *opp, int n_IRQ, uint32_t val) { uint32_t tmp; @@ -507,7 +484,7 @@ static inline void write_IRQreg_ide(openpic_t *opp, int n_IRQ, uint32_t val) DPRINTF("Set IDE %d to 0x%08x\n", n_IRQ, opp->src[n_IRQ].ide); } -static inline void write_IRQreg_ipvp(openpic_t *opp, int n_IRQ, uint32_t val) +static inline void write_IRQreg_ipvp(OpenPICState *opp, int n_IRQ, uint32_t val) { /* NOTE: not fully accurate for special IRQs, but simple and sufficient */ /* ACTIVITY bit is read-only */ @@ -518,87 +495,10 @@ static inline void write_IRQreg_ipvp(openpic_t *opp, int n_IRQ, uint32_t val) opp->src[n_IRQ].ipvp); } -#if 0 // Code provision for Intel model -#if MAX_DBL > 0 -static uint32_t read_doorbell_register (openpic_t *opp, - int n_dbl, uint32_t offset) -{ - uint32_t retval; - - switch (offset) { - case DBL_IPVP_OFFSET: - retval = read_IRQreg_ipvp(opp, IRQ_DBL0 + n_dbl); - break; - case DBL_IDE_OFFSET: - retval = read_IRQreg_ide(opp, IRQ_DBL0 + n_dbl); - break; - case DBL_DMR_OFFSET: - retval = opp->doorbells[n_dbl].dmr; - break; - } - - return retval; -} - -static void write_doorbell_register (penpic_t *opp, int n_dbl, - uint32_t offset, uint32_t value) -{ - switch (offset) { - case DBL_IVPR_OFFSET: - write_IRQreg_ipvp(opp, IRQ_DBL0 + n_dbl, value); - break; - case DBL_IDE_OFFSET: - write_IRQreg_ide(opp, IRQ_DBL0 + n_dbl, value); - break; - case DBL_DMR_OFFSET: - opp->doorbells[n_dbl].dmr = value; - break; - } -} -#endif - -#if MAX_MBX > 0 -static uint32_t read_mailbox_register (openpic_t *opp, - int n_mbx, uint32_t offset) -{ - uint32_t retval; - - switch (offset) { - case MBX_MBR_OFFSET: - retval = opp->mailboxes[n_mbx].mbr; - break; - case MBX_IVPR_OFFSET: - retval = read_IRQreg_ipvp(opp, IRQ_MBX0 + n_mbx); - break; - case MBX_DMR_OFFSET: - retval = read_IRQreg_ide(opp, IRQ_MBX0 + n_mbx); - break; - } - - return retval; -} - -static void write_mailbox_register (openpic_t *opp, int n_mbx, - uint32_t address, uint32_t value) -{ - switch (offset) { - case MBX_MBR_OFFSET: - opp->mailboxes[n_mbx].mbr = value; - break; - case MBX_IVPR_OFFSET: - write_IRQreg_ipvp(opp, IRQ_MBX0 + n_mbx, value); - break; - case MBX_DMR_OFFSET: - write_IRQreg_ide(opp, IRQ_MBX0 + n_mbx, value); - break; - } -} -#endif -#endif /* 0 : Code provision for Intel model */ - -static void openpic_gbl_write (void *opaque, hwaddr addr, uint32_t val) +static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val, + unsigned len) { - openpic_t *opp = opaque; + OpenPICState *opp = opaque; IRQ_dst_t *dst; int idx; @@ -621,9 +521,9 @@ static void openpic_gbl_write (void *opaque, hwaddr addr, uint32_t val) case 0x1000: /* FREP */ break; case 0x1020: /* GLBC */ - if (val & 0x80000000 && opp->reset) - opp->reset(opp); - opp->glbc = val & ~0x80000000; + if (val & 0x80000000) { + openpic_reset(&opp->busdev.qdev); + } break; case 0x1080: /* VENI */ break; @@ -652,19 +552,16 @@ static void openpic_gbl_write (void *opaque, hwaddr addr, uint32_t val) } break; case 0x10E0: /* SPVE */ - opp->spve = val & 0x000000FF; - break; - case 0x10F0: /* TIFR */ - opp->tifr = val; + opp->spve = val & opp->spve_mask; break; default: break; } } -static uint32_t openpic_gbl_read (void *opaque, hwaddr addr) +static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len) { - openpic_t *opp = opaque; + OpenPICState *opp = opaque; uint32_t retval; DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr); @@ -708,9 +605,6 @@ static uint32_t openpic_gbl_read (void *opaque, hwaddr addr) case 0x10E0: /* SPVE */ retval = opp->spve; break; - case 0x10F0: /* TIFR */ - retval = opp->tifr; - break; default: break; } @@ -719,73 +613,83 @@ static uint32_t openpic_gbl_read (void *opaque, hwaddr addr) return retval; } -static void openpic_timer_write (void *opaque, uint32_t addr, uint32_t val) +static void openpic_tmr_write(void *opaque, hwaddr addr, uint64_t val, + unsigned len) { - openpic_t *opp = opaque; + OpenPICState *opp = opaque; int idx; DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); if (addr & 0xF) return; - addr -= 0x10; - addr &= 0xFFFF; - idx = (addr & 0xFFF0) >> 6; + idx = (addr >> 6) & 0x3; addr = addr & 0x30; - switch (addr) { - case 0x00: /* TICC */ + + if (addr == 0x0) { + /* TIFR (TFRR) */ + opp->tifr = val; + return; + } + switch (addr & 0x30) { + case 0x00: /* TICC (GTCCR) */ break; - case 0x10: /* TIBC */ + case 0x10: /* TIBC (GTBCR) */ if ((opp->timers[idx].ticc & 0x80000000) != 0 && (val & 0x80000000) == 0 && (opp->timers[idx].tibc & 0x80000000) != 0) opp->timers[idx].ticc &= ~0x80000000; opp->timers[idx].tibc = val; break; - case 0x20: /* TIVP */ + case 0x20: /* TIVP (GTIVPR) */ write_IRQreg_ipvp(opp, opp->irq_tim0 + idx, val); break; - case 0x30: /* TIDE */ + case 0x30: /* TIDE (GTIDR) */ write_IRQreg_ide(opp, opp->irq_tim0 + idx, val); break; } } -static uint32_t openpic_timer_read (void *opaque, uint32_t addr) +static uint64_t openpic_tmr_read(void *opaque, hwaddr addr, unsigned len) { - openpic_t *opp = opaque; - uint32_t retval; + OpenPICState *opp = opaque; + uint32_t retval = -1; int idx; DPRINTF("%s: addr %08x\n", __func__, addr); - retval = 0xFFFFFFFF; - if (addr & 0xF) - return retval; - addr -= 0x10; - addr &= 0xFFFF; - idx = (addr & 0xFFF0) >> 6; - addr = addr & 0x30; - switch (addr) { - case 0x00: /* TICC */ + if (addr & 0xF) { + goto out; + } + idx = (addr >> 6) & 0x3; + if (addr == 0x0) { + /* TIFR (TFRR) */ + retval = opp->tifr; + goto out; + } + switch (addr & 0x30) { + case 0x00: /* TICC (GTCCR) */ retval = opp->timers[idx].ticc; break; - case 0x10: /* TIBC */ + case 0x10: /* TIBC (GTBCR) */ retval = opp->timers[idx].tibc; break; - case 0x20: /* TIPV */ + case 0x20: /* TIPV (TIPV) */ retval = read_IRQreg_ipvp(opp, opp->irq_tim0 + idx); break; - case 0x30: /* TIDE */ + case 0x30: /* TIDE (TIDR) */ retval = read_IRQreg_ide(opp, opp->irq_tim0 + idx); break; } + +out: DPRINTF("%s: => %08x\n", __func__, retval); return retval; } -static void openpic_src_write (void *opaque, uint32_t addr, uint32_t val) +static void openpic_src_write(void *opaque, hwaddr addr, uint64_t val, + unsigned len) { - openpic_t *opp = opaque; + OpenPICState *opp = opaque; int idx; DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val); @@ -802,9 +706,9 @@ static void openpic_src_write (void *opaque, uint32_t addr, uint32_t val) } } -static uint32_t openpic_src_read (void *opaque, uint32_t addr) +static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len) { - openpic_t *opp = opaque; + OpenPICState *opp = opaque; uint32_t retval; int idx; @@ -826,10 +730,72 @@ static uint32_t openpic_src_read (void *opaque, uint32_t addr) return retval; } +static void openpic_msi_write(void *opaque, hwaddr addr, uint64_t val, + unsigned size) +{ + OpenPICState *opp = opaque; + int idx = opp->irq_msi; + int srs, ibs; + + DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val); + if (addr & 0xF) { + return; + } + + switch (addr) { + case MSIIR_OFFSET: + srs = val >> MSIIR_SRS_SHIFT; + idx += srs; + ibs = (val & MSIIR_IBS_MASK) >> MSIIR_IBS_SHIFT; + opp->msi[srs].msir |= 1 << ibs; + openpic_set_irq(opp, idx, 1); + break; + default: + /* most registers are read-only, thus ignored */ + break; + } +} + +static uint64_t openpic_msi_read(void *opaque, hwaddr addr, unsigned size) +{ + OpenPICState *opp = opaque; + uint64_t r = 0; + int i, srs; + + DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr); + if (addr & 0xF) { + return -1; + } + + srs = addr >> 4; + + switch (addr) { + case 0x00: + case 0x10: + case 0x20: + case 0x30: + case 0x40: + case 0x50: + case 0x60: + case 0x70: /* MSIRs */ + r = opp->msi[srs].msir; + /* Clear on read */ + opp->msi[srs].msir = 0; + break; + case 0x120: /* MSISR */ + for (i = 0; i < MAX_MSI; i++) { + r |= (opp->msi[i].msir ? 1 : 0) << i; + } + break; + } + + return r; +} + static void openpic_cpu_write_internal(void *opaque, hwaddr addr, uint32_t val, int idx) { - openpic_t *opp = opaque; + OpenPICState *opp = opaque; IRQ_src_t *src; IRQ_dst_t *dst; int s_IRQ, n_IRQ; @@ -841,7 +807,6 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, dst = &opp->dst[idx]; addr &= 0xFF0; switch (addr) { -#if MAX_IPI > 0 case 0x40: /* IPIDR */ case 0x50: case 0x60: @@ -853,7 +818,6 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, openpic_set_irq(opp, opp->irq_ipi0 + idx, 1); openpic_set_irq(opp, opp->irq_ipi0 + idx, 0); break; -#endif case 0x80: /* PCTP */ dst->pctp = val & 0x0000000F; break; @@ -878,7 +842,7 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, IPVP_PRIORITY(src->ipvp) > dst->servicing.priority)) { DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", idx, n_IRQ); - opp->irq_raise(opp, idx, src); + openpic_irq_raise(opp, idx, src); } break; default: @@ -886,7 +850,8 @@ static void openpic_cpu_write_internal(void *opaque, hwaddr addr, } } -static void openpic_cpu_write(void *opaque, hwaddr addr, uint32_t val) +static void openpic_cpu_write(void *opaque, hwaddr addr, uint64_t val, + unsigned len) { openpic_cpu_write_internal(opaque, addr, val, (addr & 0x1f000) >> 12); } @@ -894,7 +859,7 @@ static void openpic_cpu_write(void *opaque, hwaddr addr, uint32_t val) static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, int idx) { - openpic_t *opp = opaque; + OpenPICState *opp = opaque; IRQ_src_t *src; IRQ_dst_t *dst; uint32_t retval; @@ -908,7 +873,7 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, addr &= 0xFF0; switch (addr) { case 0x00: /* Block Revision Register1 (BRR1) */ - retval = FSL_BRR1_IPID | FSL_BRR1_IPMJ | FSL_BRR1_IPMN; + retval = opp->brr1; break; case 0x80: /* PCTP */ retval = dst->pctp; @@ -926,13 +891,13 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, retval = IPVP_VECTOR(opp->spve); } else { src = &opp->src[n_IRQ]; - if (!test_bit(&src->ipvp, IPVP_ACTIVITY) || + if (!(src->ipvp & IPVP_ACTIVITY_MASK) || !(IPVP_PRIORITY(src->ipvp) > dst->pctp)) { /* - Spurious level-sensitive IRQ * - Priorities has been changed * and the pending IRQ isn't allowed anymore */ - reset_bit(&src->ipvp, IPVP_ACTIVITY); + src->ipvp &= ~IPVP_ACTIVITY_MASK; retval = IPVP_VECTOR(opp->spve); } else { /* IRQ enter servicing state */ @@ -941,20 +906,20 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, } IRQ_resetbit(&dst->raised, n_IRQ); dst->raised.next = -1; - if (!test_bit(&src->ipvp, IPVP_SENSE)) { + if (!(src->ipvp & IPVP_SENSE_MASK)) { /* edge-sensitive IRQ */ - reset_bit(&src->ipvp, IPVP_ACTIVITY); + src->ipvp &= ~IPVP_ACTIVITY_MASK; src->pending = 0; } if ((n_IRQ >= opp->irq_ipi0) && (n_IRQ < (opp->irq_ipi0 + MAX_IPI))) { src->ide &= ~(1 << idx); - if (src->ide && !test_bit(&src->ipvp, IPVP_SENSE)) { + if (src->ide && !(src->ipvp & IPVP_SENSE_MASK)) { /* trigger on CPUs that didn't know about it yet */ openpic_set_irq(opp, n_IRQ, 1); openpic_set_irq(opp, n_IRQ, 0); /* if all CPUs knew about it, set active bit again */ - set_bit(&src->ipvp, IPVP_ACTIVITY); + src->ipvp |= IPVP_ACTIVITY_MASK; } } } @@ -970,96 +935,109 @@ static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, return retval; } -static uint32_t openpic_cpu_read(void *opaque, hwaddr addr) +static uint64_t openpic_cpu_read(void *opaque, hwaddr addr, unsigned len) { return openpic_cpu_read_internal(opaque, addr, (addr & 0x1f000) >> 12); } -static void openpic_buggy_write (void *opaque, - hwaddr addr, uint32_t val) -{ - printf("Invalid OPENPIC write access !\n"); -} - -static uint32_t openpic_buggy_read (void *opaque, hwaddr addr) -{ - printf("Invalid OPENPIC read access !\n"); - - return -1; -} - -static void openpic_writel (void *opaque, - hwaddr addr, uint32_t val) -{ - openpic_t *opp = opaque; - - addr &= 0x3FFFF; - DPRINTF("%s: offset %08x val: %08x\n", __func__, (int)addr, val); - if (addr < 0x1100) { - /* Global registers */ - openpic_gbl_write(opp, addr, val); - } else if (addr < 0x10000) { - /* Timers registers */ - openpic_timer_write(opp, addr, val); - } else if (addr < 0x20000) { - /* Source registers */ - openpic_src_write(opp, addr, val); - } else { - /* CPU registers */ - openpic_cpu_write(opp, addr, val); - } -} +static const MemoryRegionOps openpic_glb_ops_le = { + .write = openpic_gbl_write, + .read = openpic_gbl_read, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; -static uint32_t openpic_readl (void *opaque,hwaddr addr) -{ - openpic_t *opp = opaque; - uint32_t retval; +static const MemoryRegionOps openpic_glb_ops_be = { + .write = openpic_gbl_write, + .read = openpic_gbl_read, + .endianness = DEVICE_BIG_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; - addr &= 0x3FFFF; - DPRINTF("%s: offset %08x\n", __func__, (int)addr); - if (addr < 0x1100) { - /* Global registers */ - retval = openpic_gbl_read(opp, addr); - } else if (addr < 0x10000) { - /* Timers registers */ - retval = openpic_timer_read(opp, addr); - } else if (addr < 0x20000) { - /* Source registers */ - retval = openpic_src_read(opp, addr); - } else { - /* CPU registers */ - retval = openpic_cpu_read(opp, addr); - } +static const MemoryRegionOps openpic_tmr_ops_le = { + .write = openpic_tmr_write, + .read = openpic_tmr_read, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; - return retval; -} +static const MemoryRegionOps openpic_tmr_ops_be = { + .write = openpic_tmr_write, + .read = openpic_tmr_read, + .endianness = DEVICE_BIG_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; -static uint64_t openpic_read(void *opaque, hwaddr addr, - unsigned size) -{ - openpic_t *opp = opaque; +static const MemoryRegionOps openpic_cpu_ops_le = { + .write = openpic_cpu_write, + .read = openpic_cpu_read, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; - switch (size) { - case 4: return openpic_readl(opp, addr); - default: return openpic_buggy_read(opp, addr); - } -} +static const MemoryRegionOps openpic_cpu_ops_be = { + .write = openpic_cpu_write, + .read = openpic_cpu_read, + .endianness = DEVICE_BIG_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; -static void openpic_write(void *opaque, hwaddr addr, - uint64_t data, unsigned size) -{ - openpic_t *opp = opaque; +static const MemoryRegionOps openpic_src_ops_le = { + .write = openpic_src_write, + .read = openpic_src_read, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; - switch (size) { - case 4: return openpic_writel(opp, addr, data); - default: return openpic_buggy_write(opp, addr, data); - } -} +static const MemoryRegionOps openpic_src_ops_be = { + .write = openpic_src_write, + .read = openpic_src_read, + .endianness = DEVICE_BIG_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; -static const MemoryRegionOps openpic_ops = { - .read = openpic_read, - .write = openpic_write, +static const MemoryRegionOps openpic_msi_ops_le = { + .read = openpic_msi_read, + .write = openpic_msi_write, .endianness = DEVICE_LITTLE_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, +}; + +static const MemoryRegionOps openpic_msi_ops_be = { + .read = openpic_msi_read, + .write = openpic_msi_write, + .endianness = DEVICE_BIG_ENDIAN, + .impl = { + .min_access_size = 4, + .max_access_size = 4, + }, }; static void openpic_save_IRQ_queue(QEMUFile* f, IRQ_queue_t *q) @@ -1075,12 +1053,10 @@ static void openpic_save_IRQ_queue(QEMUFile* f, IRQ_queue_t *q) static void openpic_save(QEMUFile* f, void *opaque) { - openpic_t *opp = (openpic_t *)opaque; + OpenPICState *opp = (OpenPICState *)opaque; unsigned int i; - qemu_put_be32s(f, &opp->frep); qemu_put_be32s(f, &opp->glbc); - qemu_put_be32s(f, &opp->micr); qemu_put_be32s(f, &opp->veni); qemu_put_be32s(f, &opp->pint); qemu_put_be32s(f, &opp->spve); @@ -1089,15 +1065,13 @@ static void openpic_save(QEMUFile* f, void *opaque) for (i = 0; i < opp->max_irq; i++) { qemu_put_be32s(f, &opp->src[i].ipvp); qemu_put_be32s(f, &opp->src[i].ide); - qemu_put_sbe32s(f, &opp->src[i].type); qemu_put_sbe32s(f, &opp->src[i].last_cpu); qemu_put_sbe32s(f, &opp->src[i].pending); } - qemu_put_sbe32s(f, &opp->nb_cpus); + qemu_put_be32s(f, &opp->nb_cpus); for (i = 0; i < opp->nb_cpus; i++) { - qemu_put_be32s(f, &opp->dst[i].tfrr); qemu_put_be32s(f, &opp->dst[i].pctp); qemu_put_be32s(f, &opp->dst[i].pcsr); openpic_save_IRQ_queue(f, &opp->dst[i].raised); @@ -1108,22 +1082,6 @@ static void openpic_save(QEMUFile* f, void *opaque) qemu_put_be32s(f, &opp->timers[i].ticc); qemu_put_be32s(f, &opp->timers[i].tibc); } - -#if MAX_DBL > 0 - qemu_put_be32s(f, &opp->dar); - - for (i = 0; i < MAX_DBL; i++) { - qemu_put_be32s(f, &opp->doorbells[i].dmr); - } -#endif - -#if MAX_MBX > 0 - for (i = 0; i < MAX_MAILBOXES; i++) { - qemu_put_be32s(f, &opp->mailboxes[i].mbr); - } -#endif - - pci_device_save(&opp->pci_dev, f); } static void openpic_load_IRQ_queue(QEMUFile* f, IRQ_queue_t *q) @@ -1139,15 +1097,13 @@ static void openpic_load_IRQ_queue(QEMUFile* f, IRQ_queue_t *q) static int openpic_load(QEMUFile* f, void *opaque, int version_id) { - openpic_t *opp = (openpic_t *)opaque; + OpenPICState *opp = (OpenPICState *)opaque; unsigned int i; if (version_id != 1) return -EINVAL; - qemu_get_be32s(f, &opp->frep); qemu_get_be32s(f, &opp->glbc); - qemu_get_be32s(f, &opp->micr); qemu_get_be32s(f, &opp->veni); qemu_get_be32s(f, &opp->pint); qemu_get_be32s(f, &opp->spve); @@ -1156,15 +1112,13 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id) for (i = 0; i < opp->max_irq; i++) { qemu_get_be32s(f, &opp->src[i].ipvp); qemu_get_be32s(f, &opp->src[i].ide); - qemu_get_sbe32s(f, &opp->src[i].type); qemu_get_sbe32s(f, &opp->src[i].last_cpu); qemu_get_sbe32s(f, &opp->src[i].pending); } - qemu_get_sbe32s(f, &opp->nb_cpus); + qemu_get_be32s(f, &opp->nb_cpus); for (i = 0; i < opp->nb_cpus; i++) { - qemu_get_be32s(f, &opp->dst[i].tfrr); qemu_get_be32s(f, &opp->dst[i].pctp); qemu_get_be32s(f, &opp->dst[i].pcsr); openpic_load_IRQ_queue(f, &opp->dst[i].raised); @@ -1176,535 +1130,156 @@ static int openpic_load(QEMUFile* f, void *opaque, int version_id) qemu_get_be32s(f, &opp->timers[i].tibc); } -#if MAX_DBL > 0 - qemu_get_be32s(f, &opp->dar); - - for (i = 0; i < MAX_DBL; i++) { - qemu_get_be32s(f, &opp->doorbells[i].dmr); - } -#endif - -#if MAX_MBX > 0 - for (i = 0; i < MAX_MAILBOXES; i++) { - qemu_get_be32s(f, &opp->mailboxes[i].mbr); - } -#endif - - return pci_device_load(&opp->pci_dev, f); -} - -static void openpic_irq_raise(openpic_t *opp, int n_CPU, IRQ_src_t *src) -{ - qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]); -} - -qemu_irq *openpic_init (MemoryRegion **pmem, int nb_cpus, - qemu_irq **irqs, qemu_irq irq_out) -{ - openpic_t *opp; - int i, m; - - /* XXX: for now, only one CPU is supported */ - if (nb_cpus != 1) - return NULL; - opp = g_malloc0(sizeof(openpic_t)); - memory_region_init_io(&opp->mem, &openpic_ops, opp, "openpic", 0x40000); - - // isu_base &= 0xFFFC0000; - opp->nb_cpus = nb_cpus; - opp->max_irq = OPENPIC_MAX_IRQ; - opp->irq_ipi0 = OPENPIC_IRQ_IPI0; - opp->irq_tim0 = OPENPIC_IRQ_TIM0; - /* Set IRQ types */ - for (i = 0; i < OPENPIC_EXT_IRQ; i++) { - opp->src[i].type = IRQ_EXTERNAL; - } - for (; i < OPENPIC_IRQ_TIM0; i++) { - opp->src[i].type = IRQ_SPECIAL; - } -#if MAX_IPI > 0 - m = OPENPIC_IRQ_IPI0; -#else - m = OPENPIC_IRQ_DBL0; -#endif - for (; i < m; i++) { - opp->src[i].type = IRQ_TIMER; - } - for (; i < OPENPIC_MAX_IRQ; i++) { - opp->src[i].type = IRQ_INTERNAL; - } - for (i = 0; i < nb_cpus; i++) - opp->dst[i].irqs = irqs[i]; - opp->irq_out = irq_out; - - register_savevm(&opp->pci_dev.qdev, "openpic", 0, 2, - openpic_save, openpic_load, opp); - qemu_register_reset(openpic_reset, opp); - - opp->irq_raise = openpic_irq_raise; - opp->reset = openpic_reset; - - if (pmem) - *pmem = &opp->mem; - - return qemu_allocate_irqs(openpic_set_irq, opp, opp->max_irq); -} - -static void mpic_irq_raise(openpic_t *mpp, int n_CPU, IRQ_src_t *src) -{ - int n_ci = IDR_CI0 - n_CPU; - - if(test_bit(&src->ide, n_ci)) { - qemu_irq_raise(mpp->dst[n_CPU].irqs[OPENPIC_OUTPUT_CINT]); - } - else { - qemu_irq_raise(mpp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]); - } + return 0; } -static void mpic_reset (void *opaque) +static void openpic_irq_raise(OpenPICState *opp, int n_CPU, IRQ_src_t *src) { - openpic_t *mpp = (openpic_t *)opaque; - int i; + int n_ci = IDR_CI0_SHIFT - n_CPU; - mpp->glbc = 0x80000000; - /* Initialise controller registers */ - mpp->frep = 0x004f0002 | ((mpp->nb_cpus - 1) << 8); - mpp->veni = VENI; - mpp->pint = 0x00000000; - mpp->spve = 0x0000FFFF; - /* Initialise IRQ sources */ - for (i = 0; i < mpp->max_irq; i++) { - mpp->src[i].ipvp = 0x80800000; - mpp->src[i].ide = 0x00000001; - } - /* Set IDE for IPIs to 0 so we don't get spurious interrupts */ - for (i = mpp->irq_ipi0; i < (mpp->irq_ipi0 + MAX_IPI); i++) { - mpp->src[i].ide = 0; - } - /* Initialise IRQ destinations */ - for (i = 0; i < MAX_CPU; i++) { - mpp->dst[i].pctp = 0x0000000F; - mpp->dst[i].tfrr = 0x00000000; - memset(&mpp->dst[i].raised, 0, sizeof(IRQ_queue_t)); - mpp->dst[i].raised.next = -1; - memset(&mpp->dst[i].servicing, 0, sizeof(IRQ_queue_t)); - mpp->dst[i].servicing.next = -1; - } - /* Initialise timers */ - for (i = 0; i < MAX_TMR; i++) { - mpp->timers[i].ticc = 0x00000000; - mpp->timers[i].tibc = 0x80000000; + if ((opp->flags & OPENPIC_FLAG_IDE_CRIT) && (src->ide & (1 << n_ci))) { + qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_CINT]); + } else { + qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]); } - /* Go out of RESET state */ - mpp->glbc = 0x00000000; } -static void mpic_timer_write (void *opaque, hwaddr addr, uint32_t val) -{ - openpic_t *mpp = opaque; - int idx, cpu; - - DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val); - if (addr & 0xF) - return; - addr &= 0xFFFF; - cpu = addr >> 12; - idx = (addr >> 6) & 0x3; - switch (addr & 0x30) { - case 0x00: /* gtccr */ - break; - case 0x10: /* gtbcr */ - if ((mpp->timers[idx].ticc & 0x80000000) != 0 && - (val & 0x80000000) == 0 && - (mpp->timers[idx].tibc & 0x80000000) != 0) - mpp->timers[idx].ticc &= ~0x80000000; - mpp->timers[idx].tibc = val; - break; - case 0x20: /* GTIVPR */ - write_IRQreg_ipvp(mpp, MPIC_TMR_IRQ + idx, val); - break; - case 0x30: /* GTIDR & TFRR */ - if ((addr & 0xF0) == 0xF0) - mpp->dst[cpu].tfrr = val; - else - write_IRQreg_ide(mpp, MPIC_TMR_IRQ + idx, val); - break; - } -} +struct memreg { + const char *name; + MemoryRegionOps const *ops; + bool map; + hwaddr start_addr; + ram_addr_t size; +}; -static uint32_t mpic_timer_read (void *opaque, hwaddr addr) +static int openpic_init(SysBusDevice *dev) { - openpic_t *mpp = opaque; - uint32_t retval; - int idx, cpu; + OpenPICState *opp = FROM_SYSBUS(typeof (*opp), dev); + int i, j; + struct memreg list_le[] = { + {"glb", &openpic_glb_ops_le, true, + OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE}, + {"tmr", &openpic_tmr_ops_le, true, + OPENPIC_TMR_REG_START, OPENPIC_TMR_REG_SIZE}, + {"msi", &openpic_msi_ops_le, true, + OPENPIC_MSI_REG_START, OPENPIC_MSI_REG_SIZE}, + {"src", &openpic_src_ops_le, true, + OPENPIC_SRC_REG_START, OPENPIC_SRC_REG_SIZE}, + {"cpu", &openpic_cpu_ops_le, true, + OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE}, + }; + struct memreg list_be[] = { + {"glb", &openpic_glb_ops_be, true, + OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE}, + {"tmr", &openpic_tmr_ops_be, true, + OPENPIC_TMR_REG_START, OPENPIC_TMR_REG_SIZE}, + {"msi", &openpic_msi_ops_be, true, + OPENPIC_MSI_REG_START, OPENPIC_MSI_REG_SIZE}, + {"src", &openpic_src_ops_be, true, + OPENPIC_SRC_REG_START, OPENPIC_SRC_REG_SIZE}, + {"cpu", &openpic_cpu_ops_be, true, + OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE}, + }; + struct memreg *list; - DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr); - retval = 0xFFFFFFFF; - if (addr & 0xF) - return retval; - addr &= 0xFFFF; - cpu = addr >> 12; - idx = (addr >> 6) & 0x3; - switch (addr & 0x30) { - case 0x00: /* gtccr */ - retval = mpp->timers[idx].ticc; - break; - case 0x10: /* gtbcr */ - retval = mpp->timers[idx].tibc; - break; - case 0x20: /* TIPV */ - retval = read_IRQreg_ipvp(mpp, MPIC_TMR_IRQ + idx); - break; - case 0x30: /* TIDR */ - if ((addr &0xF0) == 0XF0) - retval = mpp->dst[cpu].tfrr; - else - retval = read_IRQreg_ide(mpp, MPIC_TMR_IRQ + idx); + switch (opp->model) { + case OPENPIC_MODEL_FSL_MPIC_20: + default: + opp->flags |= OPENPIC_FLAG_IDE_CRIT; + opp->nb_irqs = 80; + opp->vid = VID_REVISION_1_2; + opp->veni = VENI_GENERIC; + opp->spve_mask = 0xFFFF; + opp->tifr_reset = 0x00000000; + opp->ipvp_reset = 0x80000000; + opp->ide_reset = 0x00000001; + opp->max_irq = FSL_MPIC_20_MAX_IRQ; + opp->irq_ipi0 = FSL_MPIC_20_IPI_IRQ; + opp->irq_tim0 = FSL_MPIC_20_TMR_IRQ; + opp->irq_msi = FSL_MPIC_20_MSI_IRQ; + opp->brr1 = FSL_BRR1_IPID | FSL_BRR1_IPMJ | FSL_BRR1_IPMN; + msi_supported = true; + list = list_be; break; - } - DPRINTF("%s: => %08x\n", __func__, retval); - - return retval; -} - -static void mpic_src_ext_write (void *opaque, hwaddr addr, - uint32_t val) -{ - openpic_t *mpp = opaque; - int idx = MPIC_EXT_IRQ; - - DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val); - if (addr & 0xF) - return; - - if (addr < MPIC_EXT_REG_SIZE) { - idx += (addr & 0xFFF0) >> 5; - if (addr & 0x10) { - /* EXDE / IFEDE / IEEDE */ - write_IRQreg_ide(mpp, idx, val); - } else { - /* EXVP / IFEVP / IEEVP */ - write_IRQreg_ipvp(mpp, idx, val); + case OPENPIC_MODEL_RAVEN: + opp->nb_irqs = RAVEN_MAX_EXT; + opp->vid = VID_REVISION_1_3; + opp->veni = VENI_GENERIC; + opp->spve_mask = 0xFF; + opp->tifr_reset = 0x003F7A00; + opp->ipvp_reset = 0xA0000000; + opp->ide_reset = 0x00000000; + opp->max_irq = RAVEN_MAX_IRQ; + opp->irq_ipi0 = RAVEN_IPI_IRQ; + opp->irq_tim0 = RAVEN_TMR_IRQ; + opp->brr1 = -1; + list = list_le; + /* Don't map MSI region */ + list[2].map = false; + + /* Only UP supported today */ + if (opp->nb_cpus != 1) { + return -EINVAL; } + break; } -} -static uint32_t mpic_src_ext_read (void *opaque, hwaddr addr) -{ - openpic_t *mpp = opaque; - uint32_t retval; - int idx = MPIC_EXT_IRQ; + memory_region_init(&opp->mem, "openpic", 0x40000); - DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr); - retval = 0xFFFFFFFF; - if (addr & 0xF) - return retval; - - if (addr < MPIC_EXT_REG_SIZE) { - idx += (addr & 0xFFF0) >> 5; - if (addr & 0x10) { - /* EXDE / IFEDE / IEEDE */ - retval = read_IRQreg_ide(mpp, idx); - } else { - /* EXVP / IFEVP / IEEVP */ - retval = read_IRQreg_ipvp(mpp, idx); + for (i = 0; i < ARRAY_SIZE(list_le); i++) { + if (!list[i].map) { + continue; } - DPRINTF("%s: => %08x\n", __func__, retval); - } - - return retval; -} - -static void mpic_src_int_write (void *opaque, hwaddr addr, - uint32_t val) -{ - openpic_t *mpp = opaque; - int idx = MPIC_INT_IRQ; - DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val); - if (addr & 0xF) - return; - - if (addr < MPIC_INT_REG_SIZE) { - idx += (addr & 0xFFF0) >> 5; - if (addr & 0x10) { - /* EXDE / IFEDE / IEEDE */ - write_IRQreg_ide(mpp, idx, val); - } else { - /* EXVP / IFEVP / IEEVP */ - write_IRQreg_ipvp(mpp, idx, val); - } - } -} - -static uint32_t mpic_src_int_read (void *opaque, hwaddr addr) -{ - openpic_t *mpp = opaque; - uint32_t retval; - int idx = MPIC_INT_IRQ; - - DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr); - retval = 0xFFFFFFFF; - if (addr & 0xF) - return retval; + memory_region_init_io(&opp->sub_io_mem[i], list[i].ops, opp, + list[i].name, list[i].size); - if (addr < MPIC_INT_REG_SIZE) { - idx += (addr & 0xFFF0) >> 5; - if (addr & 0x10) { - /* EXDE / IFEDE / IEEDE */ - retval = read_IRQreg_ide(mpp, idx); - } else { - /* EXVP / IFEVP / IEEVP */ - retval = read_IRQreg_ipvp(mpp, idx); - } - DPRINTF("%s: => %08x\n", __func__, retval); + memory_region_add_subregion(&opp->mem, list[i].start_addr, + &opp->sub_io_mem[i]); } - return retval; -} - -static void mpic_src_msg_write (void *opaque, hwaddr addr, - uint32_t val) -{ - openpic_t *mpp = opaque; - int idx = MPIC_MSG_IRQ; - - DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val); - if (addr & 0xF) - return; - - if (addr < MPIC_MSG_REG_SIZE) { - idx += (addr & 0xFFF0) >> 5; - if (addr & 0x10) { - /* EXDE / IFEDE / IEEDE */ - write_IRQreg_ide(mpp, idx, val); - } else { - /* EXVP / IFEVP / IEEVP */ - write_IRQreg_ipvp(mpp, idx, val); + for (i = 0; i < opp->nb_cpus; i++) { + opp->dst[i].irqs = g_new(qemu_irq, OPENPIC_OUTPUT_NB); + for (j = 0; j < OPENPIC_OUTPUT_NB; j++) { + sysbus_init_irq(dev, &opp->dst[i].irqs[j]); } } -} -static uint32_t mpic_src_msg_read (void *opaque, hwaddr addr) -{ - openpic_t *mpp = opaque; - uint32_t retval; - int idx = MPIC_MSG_IRQ; - - DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr); - retval = 0xFFFFFFFF; - if (addr & 0xF) - return retval; + register_savevm(&opp->busdev.qdev, "openpic", 0, 2, + openpic_save, openpic_load, opp); - if (addr < MPIC_MSG_REG_SIZE) { - idx += (addr & 0xFFF0) >> 5; - if (addr & 0x10) { - /* EXDE / IFEDE / IEEDE */ - retval = read_IRQreg_ide(mpp, idx); - } else { - /* EXVP / IFEVP / IEEVP */ - retval = read_IRQreg_ipvp(mpp, idx); - } - DPRINTF("%s: => %08x\n", __func__, retval); - } + sysbus_init_mmio(dev, &opp->mem); + qdev_init_gpio_in(&dev->qdev, openpic_set_irq, opp->max_irq); - return retval; + return 0; } -static void mpic_src_msi_write (void *opaque, hwaddr addr, - uint32_t val) -{ - openpic_t *mpp = opaque; - int idx = MPIC_MSI_IRQ; - - DPRINTF("%s: addr " TARGET_FMT_plx " <= %08x\n", __func__, addr, val); - if (addr & 0xF) - return; +static Property openpic_properties[] = { + DEFINE_PROP_UINT32("model", OpenPICState, model, OPENPIC_MODEL_FSL_MPIC_20), + DEFINE_PROP_UINT32("nb_cpus", OpenPICState, nb_cpus, 1), + DEFINE_PROP_END_OF_LIST(), +}; - if (addr < MPIC_MSI_REG_SIZE) { - idx += (addr & 0xFFF0) >> 5; - if (addr & 0x10) { - /* EXDE / IFEDE / IEEDE */ - write_IRQreg_ide(mpp, idx, val); - } else { - /* EXVP / IFEVP / IEEVP */ - write_IRQreg_ipvp(mpp, idx, val); - } - } -} -static uint32_t mpic_src_msi_read (void *opaque, hwaddr addr) +static void openpic_class_init(ObjectClass *klass, void *data) { - openpic_t *mpp = opaque; - uint32_t retval; - int idx = MPIC_MSI_IRQ; + DeviceClass *dc = DEVICE_CLASS(klass); + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - DPRINTF("%s: addr " TARGET_FMT_plx "\n", __func__, addr); - retval = 0xFFFFFFFF; - if (addr & 0xF) - return retval; - - if (addr < MPIC_MSI_REG_SIZE) { - idx += (addr & 0xFFF0) >> 5; - if (addr & 0x10) { - /* EXDE / IFEDE / IEEDE */ - retval = read_IRQreg_ide(mpp, idx); - } else { - /* EXVP / IFEVP / IEEVP */ - retval = read_IRQreg_ipvp(mpp, idx); - } - DPRINTF("%s: => %08x\n", __func__, retval); - } - - return retval; + k->init = openpic_init; + dc->props = openpic_properties; + dc->reset = openpic_reset; } -static const MemoryRegionOps mpic_glb_ops = { - .old_mmio = { - .write = { openpic_buggy_write, - openpic_buggy_write, - openpic_gbl_write, - }, - .read = { openpic_buggy_read, - openpic_buggy_read, - openpic_gbl_read, - }, - }, - .endianness = DEVICE_BIG_ENDIAN, +static TypeInfo openpic_info = { + .name = "openpic", + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(OpenPICState), + .class_init = openpic_class_init, }; -static const MemoryRegionOps mpic_tmr_ops = { - .old_mmio = { - .write = { openpic_buggy_write, - openpic_buggy_write, - mpic_timer_write, - }, - .read = { openpic_buggy_read, - openpic_buggy_read, - mpic_timer_read, - }, - }, - .endianness = DEVICE_BIG_ENDIAN, -}; - -static const MemoryRegionOps mpic_cpu_ops = { - .old_mmio = { - .write = { openpic_buggy_write, - openpic_buggy_write, - openpic_cpu_write, - }, - .read = { openpic_buggy_read, - openpic_buggy_read, - openpic_cpu_read, - }, - }, - .endianness = DEVICE_BIG_ENDIAN, -}; - -static const MemoryRegionOps mpic_ext_ops = { - .old_mmio = { - .write = { openpic_buggy_write, - openpic_buggy_write, - mpic_src_ext_write, - }, - .read = { openpic_buggy_read, - openpic_buggy_read, - mpic_src_ext_read, - }, - }, - .endianness = DEVICE_BIG_ENDIAN, -}; - -static const MemoryRegionOps mpic_int_ops = { - .old_mmio = { - .write = { openpic_buggy_write, - openpic_buggy_write, - mpic_src_int_write, - }, - .read = { openpic_buggy_read, - openpic_buggy_read, - mpic_src_int_read, - }, - }, - .endianness = DEVICE_BIG_ENDIAN, -}; - -static const MemoryRegionOps mpic_msg_ops = { - .old_mmio = { - .write = { openpic_buggy_write, - openpic_buggy_write, - mpic_src_msg_write, - }, - .read = { openpic_buggy_read, - openpic_buggy_read, - mpic_src_msg_read, - }, - }, - .endianness = DEVICE_BIG_ENDIAN, -}; - -static const MemoryRegionOps mpic_msi_ops = { - .old_mmio = { - .write = { openpic_buggy_write, - openpic_buggy_write, - mpic_src_msi_write, - }, - .read = { openpic_buggy_read, - openpic_buggy_read, - mpic_src_msi_read, - }, - }, - .endianness = DEVICE_BIG_ENDIAN, -}; - -qemu_irq *mpic_init (MemoryRegion *address_space, hwaddr base, - int nb_cpus, qemu_irq **irqs, qemu_irq irq_out) +static void openpic_register_types(void) { - openpic_t *mpp; - int i; - struct { - const char *name; - MemoryRegionOps const *ops; - hwaddr start_addr; - ram_addr_t size; - } const list[] = { - {"glb", &mpic_glb_ops, MPIC_GLB_REG_START, MPIC_GLB_REG_SIZE}, - {"tmr", &mpic_tmr_ops, MPIC_TMR_REG_START, MPIC_TMR_REG_SIZE}, - {"ext", &mpic_ext_ops, MPIC_EXT_REG_START, MPIC_EXT_REG_SIZE}, - {"int", &mpic_int_ops, MPIC_INT_REG_START, MPIC_INT_REG_SIZE}, - {"msg", &mpic_msg_ops, MPIC_MSG_REG_START, MPIC_MSG_REG_SIZE}, - {"msi", &mpic_msi_ops, MPIC_MSI_REG_START, MPIC_MSI_REG_SIZE}, - {"cpu", &mpic_cpu_ops, MPIC_CPU_REG_START, MPIC_CPU_REG_SIZE}, - }; - - mpp = g_malloc0(sizeof(openpic_t)); - - memory_region_init(&mpp->mem, "mpic", 0x40000); - memory_region_add_subregion(address_space, base, &mpp->mem); - - for (i = 0; i < sizeof(list)/sizeof(list[0]); i++) { - - memory_region_init_io(&mpp->sub_io_mem[i], list[i].ops, mpp, - list[i].name, list[i].size); - - memory_region_add_subregion(&mpp->mem, list[i].start_addr, - &mpp->sub_io_mem[i]); - } - - mpp->nb_cpus = nb_cpus; - mpp->max_irq = MPIC_MAX_IRQ; - mpp->irq_ipi0 = MPIC_IPI_IRQ; - mpp->irq_tim0 = MPIC_TMR_IRQ; - - for (i = 0; i < nb_cpus; i++) - mpp->dst[i].irqs = irqs[i]; - mpp->irq_out = irq_out; - - mpp->irq_raise = mpic_irq_raise; - mpp->reset = mpic_reset; - - register_savevm(NULL, "mpic", 0, 2, openpic_save, openpic_load, mpp); - qemu_register_reset(mpic_reset, mpp); - - return qemu_allocate_irqs(openpic_set_irq, mpp, mpp->max_irq); + type_register_static(&openpic_info); } + +type_init(openpic_register_types) |