--- hw/mips_gcmpregs.h | 122 ++++++++++++++++ hw/mips_gic.c | 418 +++++++++++++++++++++++++++++++++++++++++++++++++++++ hw/mips_gic.h | 378 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 918 insertions(+) create mode 100644 hw/mips_gcmpregs.h create mode 100644 hw/mips_gic.c create mode 100644 hw/mips_gic.h
diff --git a/hw/mips_gcmpregs.h b/hw/mips_gcmpregs.h new file mode 100644 index 0000000..933a5c2 --- /dev/null +++ b/hw/mips_gcmpregs.h @@ -0,0 +1,122 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2000, 07 MIPS Technologies, Inc. + * + * Multiprocessor Subsystem Register Definitions + * + */ +#ifndef _ASM_GCMPREGS_H +#define _ASM_GCMPREGS_H + + +/* Offsets to major blocks within GCMP from GCMP base */ +#define GCMP_GCB_OFS 0x0000 /* Global Control Block */ +#define GCMP_CLCB_OFS 0x2000 /* Core Local Control Block */ +#define GCMP_COCB_OFS 0x4000 /* Core Other Control Block */ +#define GCMP_GDB_OFS 0x8000 /* Global Debug Block */ + +/* Offsets to individual GCMP registers from GCMP base */ +#define GCMPOFS(block, tag, reg) \ + (GCMP_##block##_OFS + GCMP_##tag##_##reg##_OFS) +#define GCMPOFSn(block, tag, reg, n) \ + (GCMP_##block##_OFS + GCMP_##tag##_##reg##_OFS(n)) + +#define GCMPGCBOFS(reg) GCMPOFS(GCB, GCB, reg) +#define GCMPGCBOFSn(reg, n) GCMPOFSn(GCB, GCB, reg, n) +#define GCMPCLCBOFS(reg) GCMPOFS(CLCB, CCB, reg) +#define GCMPCOCBOFS(reg) GCMPOFS(COCB, CCB, reg) +#define GCMPGDBOFS(reg) GCMPOFS(GDB, GDB, reg) + +/* GCMP register access */ +#define GCMPGCB(reg) REGP(_gcmp_base, GCMPGCBOFS(reg)) +#define GCMPGCBn(reg, n) REGP(_gcmp_base, GCMPGCBOFSn(reg, n)) +#define GCMPCLCB(reg) REGP(_gcmp_base, GCMPCLCBOFS(reg)) +#define GCMPCOCB(reg) REGP(_gcmp_base, GCMPCOCBOFS(reg)) +#define GCMPGDB(reg) REGP(_gcmp_base, GCMPGDBOFS(reg)) + +/* Mask generation */ +#define GCMPMSK(block, reg, bits) (MSK(bits)<<GCMP_##block##_##reg##_SHF) +#define GCMPGCBMSK(reg, bits) GCMPMSK(GCB, reg, bits) +#define GCMPCCBMSK(reg, bits) GCMPMSK(CCB, reg, bits) +#define GCMPGDBMSK(reg, bits) GCMPMSK(GDB, reg, bits) + +/* GCB registers */ +#define GCMP_GCB_GC_OFS 0x0000 /* Global Config Register */ +#define GCMP_GCB_GC_NUMIOCU_SHF 8 +#define GCMP_GCB_GC_NUMIOCU_MSK GCMPGCBMSK(GC_NUMIOCU, 4) +#define GCMP_GCB_GC_NUMCORES_SHF 0 +#define GCMP_GCB_GC_NUMCORES_MSK GCMPGCBMSK(GC_NUMCORES, 8) +#define GCMP_GCB_GCMPB_OFS 0x0008 /* Global GCMP Base */ +#define GCMP_GCB_GCMPB_GCMPBASE_SHF 15 +#define GCMP_GCB_GCMPB_GCMPBASE_MSK GCMPGCBMSK(GCMPB_GCMPBASE, 17) +#define GCMP_GCB_GCMPB_CMDEFTGT_SHF 0 +#define GCMP_GCB_GCMPB_CMDEFTGT_MSK GCMPGCBMSK(GCMPB_CMDEFTGT, 2) +#define GCMP_GCB_GCMPB_CMDEFTGT_DISABLED 0 +#define GCMP_GCB_GCMPB_CMDEFTGT_MEM 1 +#define GCMP_GCB_GCMPB_CMDEFTGT_IOCU1 2 +#define GCMP_GCB_GCMPB_CMDEFTGT_IOCU2 3 +#define GCMP_GCB_CCMC_OFS 0x0010 /* Global CM Control */ +#define GCMP_GCB_GCSRAP_OFS 0x0020 /* Global CSR Access Privilege */ +#define GCMP_GCB_GCSRAP_CMACCESS_SHF 0 +#define GCMP_GCB_GCSRAP_CMACCESS_MSK GCMPGCBMSK(GCSRAP_CMACCESS, 8) +#define GCMP_GCB_GCMPREV_OFS 0x0030 /* GCMP Revision Register */ +#define GCMP_GCB_GCMEM_OFS 0x0040 /* Global CM Error Mask */ +#define GCMP_GCB_GCMEC_OFS 0x0048 /* Global CM Error Cause */ +#define GCMP_GCB_GMEC_ERROR_TYPE_SHF 27 +#define GCMP_GCB_GMEC_ERROR_TYPE_MSK GCMPGCBMSK(GMEC_ERROR_TYPE, 5) +#define GCMP_GCB_GMEC_ERROR_INFO_SHF 0 +#define GCMP_GCB_GMEC_ERROR_INFO_MSK GCMPGCBMSK(GMEC_ERROR_INFO, 27) +#define GCMP_GCB_GCMEA_OFS 0x0050 /* Global CM Error Address */ +#define GCMP_GCB_GCMEO_OFS 0x0058 /* Global CM Error Multiple */ +#define GCMP_GCB_GMEO_ERROR_2ND_SHF 0 +#define GCMP_GCB_GMEO_ERROR_2ND_MSK GCMPGCBMSK(GMEO_ERROR_2ND, 5) +#define GCMP_GCB_GICBA_OFS 0x0080 /* Global Interrupt Controller Base Address */ +#define GCMP_GCB_GICBA_BASE_SHF 17 +#define GCMP_GCB_GICBA_BASE_MSK GCMPGCBMSK(GICBA_BASE, 15) +#define GCMP_GCB_GICBA_EN_SHF 0 +#define GCMP_GCB_GICBA_EN_MSK GCMPGCBMSK(GICBA_EN, 1) + +/* GCB Regions */ +#define GCMP_GCB_CMxBASE_OFS(n) (0x0090+16*(n)) /* Global Region[0-3] Base Address */ +#define GCMP_GCB_CMxBASE_BASE_SHF 16 +#define GCMP_GCB_CMxBASE_BASE_MSK GCMPGCBMSK(CMxBASE_BASE, 16) +#define GCMP_GCB_CMxMASK_OFS(n) (0x0098+16*(n)) /* Global Region[0-3] Address Mask */ +#define GCMP_GCB_CMxMASK_MASK_SHF 16 +#define GCMP_GCB_CMxMASK_MASK_MSK GCMPGCBMSK(CMxMASK_MASK, 16) +#define GCMP_GCB_CMxMASK_CMREGTGT_SHF 0 +#define GCMP_GCB_CMxMASK_CMREGTGT_MSK GCMPGCBMSK(CMxMASK_CMREGTGT, 2) +#define GCMP_GCB_CMxMASK_CMREGTGT_MEM 0 +#define GCMP_GCB_CMxMASK_CMREGTGT_MEM1 1 +#define GCMP_GCB_CMxMASK_CMREGTGT_IOCU1 2 +#define GCMP_GCB_CMxMASK_CMREGTGT_IOCU2 3 + + +/* Core local/Core other control block registers */ +#define GCMP_CCB_RESETR_OFS 0x0000 /* Reset Release */ +#define GCMP_CCB_RESETR_INRESET_SHF 0 +#define GCMP_CCB_RESETR_INRESET_MSK GCMPCCBMSK(RESETR_INRESET, 16) +#define GCMP_CCB_COHCTL_OFS 0x0008 /* Coherence Control */ +#define GCMP_CCB_COHCTL_DOMAIN_SHF 0 +#define GCMP_CCB_COHCTL_DOMAIN_MSK GCMPCCBMSK(COHCTL_DOMAIN, 8) +#define GCMP_CCB_CFG_OFS 0x0010 /* Config */ +#define GCMP_CCB_CFG_IOCUTYPE_SHF 10 +#define GCMP_CCB_CFG_IOCUTYPE_MSK GCMPCCBMSK(CFG_IOCUTYPE, 2) +#define GCMP_CCB_CFG_IOCUTYPE_CPU 0 +#define GCMP_CCB_CFG_IOCUTYPE_NCIOCU 1 +#define GCMP_CCB_CFG_IOCUTYPE_CIOCU 2 +#define GCMP_CCB_CFG_NUMVPE_SHF 0 +#define GCMP_CCB_CFG_NUMVPE_MSK GCMPCCBMSK(CFG_NUMVPE, 10) +#define GCMP_CCB_OTHER_OFS 0x0018 /* Other Address */ +#define GCMP_CCB_OTHER_CORENUM_SHF 16 +#define GCMP_CCB_OTHER_CORENUM_MSK GCMPCCBMSK(OTHER_CORENUM, 16) +#define GCMP_CCB_RESETBASE_OFS 0x0020 /* Reset Exception Base */ +#define GCMP_CCB_RESETBASE_BEV_SHF 12 +#define GCMP_CCB_RESETBASE_BEV_MSK GCMPCCBMSK(RESETBASE_BEV, 20) +#define GCMP_CCB_ID_OFS 0x0028 /* Identification */ +#define GCMP_CCB_DINTGROUP_OFS 0x0030 /* DINT Group Participate */ +#define GCMP_CCB_DBGGROUP_OFS 0x0100 /* DebugBreak Group */ + +#endif /* _ASM_GCMPREGS_H */ diff --git a/hw/mips_gic.c b/hw/mips_gic.c new file mode 100644 index 0000000..b477b7a --- /dev/null +++ b/hw/mips_gic.c @@ -0,0 +1,418 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2012 MIPS Technologies, Inc. All rights reserved. + * Authors: Sanjay Lal <sanj...@kymasys.com> +*/ + +#include "hw.h" +#include "qemu/bitmap.h" +#include "exec/memory.h" +#include "sysemu/sysemu.h" + +#ifdef CONFIG_KVM +#include "sysemu/kvm.h" +#include "kvm_mips.h" +#endif + +#include "mips_gic.h" +#include "mips_gcmpregs.h" + +//#define DEBUG + +#ifdef DEBUG +#define DPRINTF(fmt, ...) fprintf(stderr, "%s: " fmt, __FUNCTION__, ##__VA_ARGS__) +#else +#define DPRINTF(fmt, ...) +#endif + +/* Support upto 4 VPEs */ +#define NUMVPES 4 + +/* XXXKYMA: Spoof a bit of the GCR as well, just enough to get Linux to detect it */ +typedef struct gic_t +{ + CPUMIPSState *env[NR_CPUS]; + MemoryRegion gcr_mem, gic_mem; + + qemu_irq *irqs; + + /* GCR Registers */ + uint32_t gcr_gic_base_reg; + + /* Shared Section Registers */ + uint32_t gic_gl_intr_pol_reg[8]; + uint32_t gic_gl_intr_trigtype_reg[8]; + uint32_t gic_gl_intr_pending_reg[8]; + uint32_t gic_gl_intr_mask_reg[8]; + + uint32_t gic_gl_map_pin[256]; + + /* Sparse array, need a better way */ + uint32_t gic_gl_map_vpe[0x7fa]; + + /* VPE Local Section Registers */ + /* VPE Other Section Registers, aliased to local, use the other field to access the correct instance */ + uint32_t gic_local_vpe_regs[NUMVPES][0x1000]; + + /* User Mode Visible Section Registers */ +} gic_t; + + +static uint64_t +gic_read(void *opaque, hwaddr addr, unsigned size) +{ + int reg; + gic_t *gic = (gic_t *) opaque; + + DPRINTF("addr: %#" PRIx64 ", size: %#x\n", addr, size); + + switch (addr) { + case GIC_SH_CONFIG_OFS: + return 0x8040000 | ((NUMVPES - 1) & GIC_SH_CONFIG_NUMVPES_MSK); + break; + + case GIC_SH_POL_31_0_OFS: + case GIC_SH_POL_63_32_OFS: + case GIC_SH_POL_95_64_OFS: + case GIC_SH_POL_127_96_OFS: + case GIC_SH_POL_159_128_OFS: + case GIC_SH_POL_191_160_OFS: + case GIC_SH_POL_223_192_OFS: + case GIC_SH_POL_255_224_OFS: + reg = (addr - GIC_SH_POL_31_0_OFS) / 4; + return gic->gic_gl_intr_pol_reg[reg]; + break; + + case GIC_SH_TRIG_31_0_OFS: + case GIC_SH_TRIG_63_32_OFS: + case GIC_SH_TRIG_95_64_OFS: + case GIC_SH_TRIG_127_96_OFS: + case GIC_SH_TRIG_159_128_OFS: + case GIC_SH_TRIG_191_160_OFS: + case GIC_SH_TRIG_223_192_OFS: + case GIC_SH_TRIG_255_224_OFS: + reg = (addr - GIC_SH_TRIG_31_0_OFS) / 4; + return gic->gic_gl_intr_trigtype_reg[reg]; + break; + + case GIC_SH_RMASK_31_0_OFS: + case GIC_SH_RMASK_63_32_OFS: + case GIC_SH_RMASK_95_64_OFS: + case GIC_SH_RMASK_127_96_OFS: + case GIC_SH_RMASK_159_128_OFS: + case GIC_SH_RMASK_191_160_OFS: + case GIC_SH_RMASK_223_192_OFS: + case GIC_SH_RMASK_255_224_OFS: + break; + + case GIC_SH_PEND_31_0_OFS: + case GIC_SH_PEND_63_32_OFS: + case GIC_SH_PEND_95_64_OFS: + case GIC_SH_PEND_127_96_OFS: + case GIC_SH_PEND_159_128_OFS: + case GIC_SH_PEND_191_160_OFS: + case GIC_SH_PEND_223_192_OFS: + case GIC_SH_PEND_255_224_OFS: + reg = (addr - GIC_SH_PEND_31_0_OFS) / 4; + DPRINTF("pending[%d]: %#" PRIx32 "\n", reg, gic->gic_gl_intr_pending_reg[reg]); + return gic->gic_gl_intr_pending_reg[reg]; + break; + + case GIC_SH_MASK_31_0_OFS: + case GIC_SH_MASK_63_32_OFS: + case GIC_SH_MASK_95_64_OFS: + case GIC_SH_MASK_127_96_OFS: + case GIC_SH_MASK_159_128_OFS: + case GIC_SH_MASK_191_160_OFS: + case GIC_SH_MASK_223_192_OFS: + case GIC_SH_MASK_255_224_OFS: + reg = (addr - GIC_SH_MASK_31_0_OFS) / 4; + return gic->gic_gl_intr_mask_reg[reg]; + break; + + default: + break; + } + + /* Other cases */ + if (addr >= GIC_SH_INTR_MAP_TO_PIN_BASE_OFS + && addr <= GIC_SH_MAP_TO_PIN(255)) { + reg = (addr - GIC_SH_INTR_MAP_TO_PIN_BASE_OFS) / 4; + return gic->gic_gl_map_pin[reg]; + } + + if (addr >= GIC_SH_INTR_MAP_TO_VPE_BASE_OFS + && addr <= GIC_SH_MAP_TO_VPE_REG_OFF(255, 63)) { + reg = (addr - GIC_SH_INTR_MAP_TO_VPE_BASE_OFS) / 4; + return gic->gic_gl_map_vpe[reg]; + } + + if (addr >= GIC_VPELOCAL_BASE_ADDR && addr < GIC_VPEOTHER_BASE_ADDR) { + } + + if (addr >= GIC_VPEOTHER_BASE_ADDR && addr < GIC_USERMODE_BASE_ADDR) { + } + + DPRINTF("%s: unimplemented register @ %#" PRIx64 "\n", __func__, addr); + return 0ULL; +} + +static void +gic_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) +{ + int reg, intr; + gic_t *gic = (gic_t *) opaque; + + DPRINTF("addr: %#" PRIx64 ", data: %#" PRIx64 ", size: %#x\n", addr, data, + size); + + switch (addr) { + case GIC_SH_POL_31_0_OFS: + case GIC_SH_POL_63_32_OFS: + case GIC_SH_POL_95_64_OFS: + case GIC_SH_POL_127_96_OFS: + case GIC_SH_POL_159_128_OFS: + case GIC_SH_POL_191_160_OFS: + case GIC_SH_POL_223_192_OFS: + case GIC_SH_POL_255_224_OFS: + reg = (addr - GIC_SH_POL_31_0_OFS) / 4; + gic->gic_gl_intr_pol_reg[reg] = data; + break; + + case GIC_SH_TRIG_31_0_OFS: + case GIC_SH_TRIG_63_32_OFS: + case GIC_SH_TRIG_95_64_OFS: + case GIC_SH_TRIG_127_96_OFS: + case GIC_SH_TRIG_159_128_OFS: + case GIC_SH_TRIG_191_160_OFS: + case GIC_SH_TRIG_223_192_OFS: + case GIC_SH_TRIG_255_224_OFS: + reg = (addr - GIC_SH_TRIG_31_0_OFS) / 4; + gic->gic_gl_intr_trigtype_reg[reg] = data; + break; + + case GIC_SH_RMASK_31_0_OFS: + case GIC_SH_RMASK_63_32_OFS: + case GIC_SH_RMASK_95_64_OFS: + case GIC_SH_RMASK_127_96_OFS: + case GIC_SH_RMASK_159_128_OFS: + case GIC_SH_RMASK_191_160_OFS: + case GIC_SH_RMASK_223_192_OFS: + case GIC_SH_RMASK_255_224_OFS: + reg = (addr - GIC_SH_RMASK_31_0_OFS) / 4; + gic->gic_gl_intr_mask_reg[reg] &= ~data; + break; + + case GIC_SH_WEDGE_OFS: + DPRINTF("addr: %#" PRIx64 ", data: %#" PRIx64 ", size: %#x\n", addr, + data, size); + + /* Figure out which VPE/HW Interrupt this maps to */ + intr = data & 0x7FFFFFFF; + + /* XXXSL Mask/Enabled Checks */ + if (data & 0x80000000) + qemu_set_irq(gic->irqs[intr], 1); + else + qemu_set_irq(gic->irqs[intr], 0); + + break; + + case GIC_SH_PEND_31_0_OFS: + case GIC_SH_PEND_63_32_OFS: + case GIC_SH_PEND_95_64_OFS: + case GIC_SH_PEND_127_96_OFS: + case GIC_SH_PEND_159_128_OFS: + case GIC_SH_PEND_191_160_OFS: + case GIC_SH_PEND_223_192_OFS: + case GIC_SH_PEND_255_224_OFS: + break; + + case GIC_SH_SMASK_31_0_OFS: + case GIC_SH_SMASK_63_32_OFS: + case GIC_SH_SMASK_95_64_OFS: + case GIC_SH_SMASK_127_96_OFS: + case GIC_SH_SMASK_159_128_OFS: + case GIC_SH_SMASK_191_160_OFS: + case GIC_SH_SMASK_223_192_OFS: + case GIC_SH_SMASK_255_224_OFS: + reg = (addr - GIC_SH_SMASK_31_0_OFS) / 4; + gic->gic_gl_intr_mask_reg[reg] |= data; + break; + + default: + break; + } + + /* Other cases */ + if (addr >= GIC_SH_INTR_MAP_TO_PIN_BASE_OFS + && addr <= GIC_SH_MAP_TO_PIN(255)) { + reg = (addr - GIC_SH_INTR_MAP_TO_PIN_BASE_OFS) / 4; + gic->gic_gl_map_pin[reg] = data; + } + if (addr >= GIC_SH_INTR_MAP_TO_VPE_BASE_OFS + && addr <= GIC_SH_MAP_TO_VPE_REG_OFF(255, 63)) { + reg = (addr - GIC_SH_INTR_MAP_TO_VPE_BASE_OFS) / 4; + gic->gic_gl_map_vpe[reg] = data; + } + + if (addr >= GIC_VPELOCAL_BASE_ADDR && addr < GIC_VPEOTHER_BASE_ADDR) { + } + + if (addr >= GIC_VPEOTHER_BASE_ADDR && addr < GIC_USERMODE_BASE_ADDR) { + } +} + +static uint64_t +gcr_read(void *opaque, hwaddr addr, unsigned size) +{ + gic_t *gic = (gic_t *) opaque; + + DPRINTF("addr: %#" PRIx64 ", size: %#x\n", addr, size); + + switch (addr) { + case GCMP_GCB_GC_OFS: + /* Set PCORES to # cores - 1 */ + return smp_cpus - 1; + break; + + case GCMP_GCB_GCMPB_OFS: + return GCMP_BASE_ADDR; + break; + + case GCMP_GCB_GICBA_OFS: + return gic->gcr_gic_base_reg; + break; + + default: + DPRINTF("Unsupported Reg Read @ offset %#" PRIx64 "\n", addr); + return 0; + } + + return 0ULL; +} + +static void +gcr_write(void *opaque, hwaddr addr, uint64_t data, unsigned size) +{ + gic_t *gic = (gic_t *) opaque; + + DPRINTF("addr: %#" PRIx64 ", data: %#" PRIx64 ", size: %#x\n", addr, data, + size); + + switch (addr) { + case GCMP_GCB_GICBA_OFS: + gic->gcr_gic_base_reg = data; + break; + + default: + break; + } +} + + + +static void +gic_set_irq(void *opaque, int n_IRQ, int level) +{ + int vpe = -1, pin = -1, i; + gic_t *gic = (gic_t *) opaque; + + pin = gic->gic_gl_map_pin[n_IRQ] & 0x7; + + for (i = 0; i < NUMVPES; i++) { + vpe = gic-> gic_gl_map_vpe[(GIC_SH_MAP_TO_VPE_REG_OFF(n_IRQ, i) - GIC_SH_INTR_MAP_TO_VPE_BASE_OFS) / 4]; + if (vpe & GIC_SH_MAP_TO_VPE_REG_BIT(i)) { + vpe = i; + break; + } + } + + if (pin >= 0 && vpe >= 0) { + int offset; + DPRINTF("[%s] INTR %d maps to PIN %d on VPE %d\n", (level ? "ASSERT" : "DEASSERT"), n_IRQ, pin, vpe); + /* Set the Global PEND register */ + offset = GIC_INTR_OFS(n_IRQ) / 4; + if (level) + gic->gic_gl_intr_pending_reg[offset] |= (1 << GIC_INTR_BIT(n_IRQ)); + else + gic->gic_gl_intr_pending_reg[offset] &= ~(1 << GIC_INTR_BIT(n_IRQ)); + +#ifdef CONFIG_KVM + if (kvm_enabled()) { + kvm_mips_set_ipi_interrupt (gic->env[vpe], pin+2, level); + } +#endif + + qemu_set_irq(gic->env[vpe]->irq[pin+2], level); + } +} + +static void +gic_reset(void *opaque) +{ + int i; + gic_t *gic = (gic_t *) opaque; + + /* Rest value is map to pin */ + for (i = 0; i < 256; i++) + gic->gic_gl_map_pin[i] = GIC_MAP_TO_PIN_MSK; + +} + +static const MemoryRegionOps gic_ops = { + .read = gic_read, + .write = gic_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +static const MemoryRegionOps gcr_ops = { + .read = gcr_read, + .write = gcr_write, + .endianness = DEVICE_LITTLE_ENDIAN, +}; + +qemu_irq * +gic_init(uint32_t ncpus, CPUMIPSState *env, MemoryRegion * address_space) +{ + CPUMIPSState *next_env; + gic_t *gic; + uint32_t x; + + if (ncpus > NUMVPES) { + fprintf(stderr, "Unable to initialize GIC - ncpus %d > NUMVPES!", ncpus); + return NULL; + } + + gic = (gic_t *) g_malloc0(sizeof(gic_t)); + + /* Register the CPU env for all cpus with the GIC */ + next_env = env; + for (x = 0; x < ncpus; x++) { + if (next_env != NULL) { + gic->env[x] = next_env; + next_env = next_env->next_cpu; + } else { + fprintf(stderr, "Unable to initialize GIC - CPUMIPSState for CPU #%d not valid!", x); + return NULL; + } + } + + /* Register GCR & GIC regions */ + memory_region_init_io(&gic->gcr_mem, &gcr_ops, gic, "GCR", + GCMP_ADDRSPACE_SZ); + memory_region_init_io(&gic->gic_mem, &gic_ops, gic, "GIC", + GIC_ADDRSPACE_SZ); + + memory_region_add_subregion(address_space, GCMP_BASE_ADDR, &gic->gcr_mem); + memory_region_add_subregion(address_space, GIC_BASE_ADDR, &gic->gic_mem); + + qemu_register_reset(gic_reset, gic); + + gic->irqs = qemu_allocate_irqs(gic_set_irq, gic, GIC_NUM_INTRS); + + return (gic->irqs); +} diff --git a/hw/mips_gic.h b/hw/mips_gic.h new file mode 100644 index 0000000..4a2c828 --- /dev/null +++ b/hw/mips_gic.h @@ -0,0 +1,378 @@ +/* + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2000, 07 MIPS Technologies, Inc. + * + * GIC Register Definitions + * + */ +#ifndef _ASM_GICREGS_H +#define _ASM_GICREGS_H + +#undef GICISBYTELITTLEENDIAN + +#define NR_CPUS 8 +/* + * GCMP Specific definitions + */ + +/* XXXKYMA: Malta Specific base address */ +#define GCMP_BASE_ADDR 0x1fbf8000ULL +#define GCMP_ADDRSPACE_SZ (256 * 1024) + +/* + * GIC Specific definitions + */ + +/* XXXKYMA: Malta Specific base address */ +#define GIC_BASE_ADDR 0x1bdc0000ULL +#define GIC_ADDRSPACE_SZ (128 * 1024) + +/* GIC Address Space Offsets */ +#define GIC_SHARED_BASE_ADDR 0x0000 +#define GIC_VPELOCAL_BASE_ADDR 0x8000 +#define GIC_VPEOTHER_BASE_ADDR 0xC000 +#define GIC_USERMODE_BASE_ADDR 0x10000 + +/* Shared Section Offsets */ +#define GIC_G_INTR_POLARITY_REG0 0x0100 +#define GIC_G_INTR_POLARITY_REG1 0x0104 +#define GIC_G_INTR_TRIGTYPE_REG0 0x0180 +#define GIC_G_INTR_TRIGTYPE_REG1 0x0184 +#define GIC_G_INTR_RESETMASK_REG0 0x0300 +#define GIC_G_INTR_RESETMASK_REG1 0x0304 +#define GIC_G_INTR_SETMASK_REG0 0x0380 + +/* + * MSC01 BIU Specific definitions + * FIXME : These should be elsewhere ? + */ +#define MSC01_BIU_REG_BASE 0x1bc80000 +#define MSC01_BIU_ADDRSPACE_SZ (256 * 1024) +#define MSC01_SC_CFG_OFS 0x0110 +#define MSC01_SC_CFG_GICPRES_MSK 0x00000004 +#define MSC01_SC_CFG_GICPRES_SHF 2 +#define MSC01_SC_CFG_GICENA_SHF 3 + +/* Constants */ +#define GIC_POL_POS 1 +#define GIC_POL_NEG 0 +#define GIC_TRIG_EDGE 1 +#define GIC_TRIG_LEVEL 0 + +#define GIC_NUM_INTRS (24 + NR_CPUS * 2) + +#define MSK(n) ((1 << (n)) - 1) +#define REG32(addr) (*(volatile unsigned int *) (addr)) +#define REG(base, offs) REG32((unsigned long)(base) + offs##_##OFS) +#define REGP(base, phys) REG32((unsigned long)(base) + (phys)) + +/* Accessors */ +#define GIC_REG(segment, offset) \ + REG32(_gic_base + segment##_##SECTION_OFS + offset##_##OFS) +#define GIC_REG_ADDR(segment, offset) \ + REG32(_gic_base + segment##_##SECTION_OFS + offset) + +#define GIC_ABS_REG(segment, offset) \ + (_gic_base + segment##_##SECTION_OFS + offset##_##OFS) +#define GIC_REG_ABS_ADDR(segment, offset) \ + (_gic_base + segment##_##SECTION_OFS + offset) + +#ifdef GICISBYTELITTLEENDIAN +#define GICREAD(reg, data) (data) = (reg), (data) = le32_to_cpu(data) +#define GICWRITE(reg, data) (reg) = cpu_to_le32(data) +#define GICBIS(reg, bits) \ + ({unsigned int data; \ + GICREAD(reg, data); \ + data |= bits; \ + GICWRITE(reg, data); \ + }) + +#else +#define GICREAD(reg, data) (data) = (reg) +#define GICWRITE(reg, data) (reg) = (data) +#define GICBIS(reg, bits) (reg) |= (bits) +#endif + + +/* GIC Address Space */ +#define SHARED_SECTION_OFS 0x0000 +#define SHARED_SECTION_SIZE 0x8000 +#define VPE_LOCAL_SECTION_OFS 0x8000 +#define VPE_LOCAL_SECTION_SIZE 0x4000 +#define VPE_OTHER_SECTION_OFS 0xc000 +#define VPE_OTHER_SECTION_SIZE 0x4000 +#define USM_VISIBLE_SECTION_OFS 0x10000 +#define USM_VISIBLE_SECTION_SIZE 0x10000 + +/* Register Map for Shared Section */ + +#define GIC_SH_CONFIG_OFS 0x0000 + +/* Shared Global Counter */ +#define GIC_SH_COUNTER_31_00_OFS 0x0010 +#define GIC_SH_COUNTER_63_32_OFS 0x0014 +#define GIC_SH_REVISIONID_OFS 0x0020 + +/* Interrupt Polarity */ +#define GIC_SH_POL_31_0_OFS 0x0100 +#define GIC_SH_POL_63_32_OFS 0x0104 +#define GIC_SH_POL_95_64_OFS 0x0108 +#define GIC_SH_POL_127_96_OFS 0x010c +#define GIC_SH_POL_159_128_OFS 0x0110 +#define GIC_SH_POL_191_160_OFS 0x0114 +#define GIC_SH_POL_223_192_OFS 0x0118 +#define GIC_SH_POL_255_224_OFS 0x011c + +/* Edge/Level Triggering */ +#define GIC_SH_TRIG_31_0_OFS 0x0180 +#define GIC_SH_TRIG_63_32_OFS 0x0184 +#define GIC_SH_TRIG_95_64_OFS 0x0188 +#define GIC_SH_TRIG_127_96_OFS 0x018c +#define GIC_SH_TRIG_159_128_OFS 0x0190 +#define GIC_SH_TRIG_191_160_OFS 0x0194 +#define GIC_SH_TRIG_223_192_OFS 0x0198 +#define GIC_SH_TRIG_255_224_OFS 0x019c + +/* Dual Edge Triggering */ +#define GIC_SH_DUAL_31_0_OFS 0x0200 +#define GIC_SH_DUAL_63_32_OFS 0x0204 +#define GIC_SH_DUAL_95_64_OFS 0x0208 +#define GIC_SH_DUAL_127_96_OFS 0x020c +#define GIC_SH_DUAL_159_128_OFS 0x0210 +#define GIC_SH_DUAL_191_160_OFS 0x0214 +#define GIC_SH_DUAL_223_192_OFS 0x0218 +#define GIC_SH_DUAL_255_224_OFS 0x021c + +/* Set/Clear corresponding bit in Edge Detect Register */ +#define GIC_SH_WEDGE_OFS 0x0280 + +/* Reset Mask - Disables Interrupt */ +#define GIC_SH_RMASK_31_0_OFS 0x0300 +#define GIC_SH_RMASK_63_32_OFS 0x0304 +#define GIC_SH_RMASK_95_64_OFS 0x0308 +#define GIC_SH_RMASK_127_96_OFS 0x030c +#define GIC_SH_RMASK_159_128_OFS 0x0310 +#define GIC_SH_RMASK_191_160_OFS 0x0314 +#define GIC_SH_RMASK_223_192_OFS 0x0318 +#define GIC_SH_RMASK_255_224_OFS 0x031c + +/* Set Mask (WO) - Enables Interrupt */ +#define GIC_SH_SMASK_31_0_OFS 0x0380 +#define GIC_SH_SMASK_63_32_OFS 0x0384 +#define GIC_SH_SMASK_95_64_OFS 0x0388 +#define GIC_SH_SMASK_127_96_OFS 0x038c +#define GIC_SH_SMASK_159_128_OFS 0x0390 +#define GIC_SH_SMASK_191_160_OFS 0x0394 +#define GIC_SH_SMASK_223_192_OFS 0x0398 +#define GIC_SH_SMASK_255_224_OFS 0x039c + +/* Global Interrupt Mask Register (RO) - Bit Set == Interrupt enabled */ +#define GIC_SH_MASK_31_0_OFS 0x0400 +#define GIC_SH_MASK_63_32_OFS 0x0404 +#define GIC_SH_MASK_95_64_OFS 0x0408 +#define GIC_SH_MASK_127_96_OFS 0x040c +#define GIC_SH_MASK_159_128_OFS 0x0410 +#define GIC_SH_MASK_191_160_OFS 0x0414 +#define GIC_SH_MASK_223_192_OFS 0x0418 +#define GIC_SH_MASK_255_224_OFS 0x041c + +/* Pending Global Interrupts (RO) */ +#define GIC_SH_PEND_31_0_OFS 0x0480 +#define GIC_SH_PEND_63_32_OFS 0x0484 +#define GIC_SH_PEND_95_64_OFS 0x0488 +#define GIC_SH_PEND_127_96_OFS 0x048c +#define GIC_SH_PEND_159_128_OFS 0x0490 +#define GIC_SH_PEND_191_160_OFS 0x0494 +#define GIC_SH_PEND_223_192_OFS 0x0498 +#define GIC_SH_PEND_255_224_OFS 0x049c + +#define GIC_SH_INTR_MAP_TO_PIN_BASE_OFS 0x0500 + +/* Maps Interrupt X to a Pin */ +#define GIC_SH_MAP_TO_PIN(intr) \ + (GIC_SH_INTR_MAP_TO_PIN_BASE_OFS + (4 * intr)) + +#define GIC_SH_INTR_MAP_TO_VPE_BASE_OFS 0x2000 + +/* Maps Interrupt X to a VPE */ +#define GIC_SH_MAP_TO_VPE_REG_OFF(intr, vpe) \ + (GIC_SH_INTR_MAP_TO_VPE_BASE_OFS + (32 * (intr)) + (((vpe) / 32) * 4)) +#define GIC_SH_MAP_TO_VPE_REG_BIT(vpe) (1 << ((vpe) % 32)) + +/* Convert an interrupt number to a byte offset/bit for multi-word registers */ +#define GIC_INTR_OFS(intr) (((intr) / 32)*4) +#define GIC_INTR_BIT(intr) ((intr) % 32) + +/* Polarity : Reset Value is always 0 */ +#define GIC_SH_SET_POLARITY_OFS 0x0100 +#define GIC_SET_POLARITY(intr, pol) \ + GICBIS(GIC_REG_ADDR(SHARED, GIC_SH_SET_POLARITY_OFS + \ + GIC_INTR_OFS(intr)), (pol) << GIC_INTR_BIT(intr)) + +/* Triggering : Reset Value is always 0 */ +#define GIC_SH_SET_TRIGGER_OFS 0x0180 +#define GIC_SET_TRIGGER(intr, trig) \ + GICBIS(GIC_REG_ADDR(SHARED, GIC_SH_SET_TRIGGER_OFS + \ + GIC_INTR_OFS(intr)), (trig) << GIC_INTR_BIT(intr)) + +/* Mask manipulation */ +#define GIC_SH_SMASK_OFS 0x0380 +#define GIC_SET_INTR_MASK(intr) \ + GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_SMASK_OFS + \ + GIC_INTR_OFS(intr)), 1 << GIC_INTR_BIT(intr)) +#define GIC_SH_RMASK_OFS 0x0300 +#define GIC_CLR_INTR_MASK(intr) \ + GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_RMASK_OFS + \ + GIC_INTR_OFS(intr)), 1 << GIC_INTR_BIT(intr)) + +/* Register Map for Local Section */ +#define GIC_VPE_CTL_OFS 0x0000 +#define GIC_VPE_PEND_OFS 0x0004 +#define GIC_VPE_MASK_OFS 0x0008 +#define GIC_VPE_RMASK_OFS 0x000c +#define GIC_VPE_SMASK_OFS 0x0010 +#define GIC_VPE_WD_MAP_OFS 0x0040 +#define GIC_VPE_COMPARE_MAP_OFS 0x0044 +#define GIC_VPE_TIMER_MAP_OFS 0x0048 +#define GIC_VPE_PERFCTR_MAP_OFS 0x0050 +#define GIC_VPE_SWINT0_MAP_OFS 0x0054 +#define GIC_VPE_SWINT1_MAP_OFS 0x0058 +#define GIC_VPE_OTHER_ADDR_OFS 0x0080 +#define GIC_VPE_WD_CONFIG0_OFS 0x0090 +#define GIC_VPE_WD_COUNT0_OFS 0x0094 +#define GIC_VPE_WD_INITIAL0_OFS 0x0098 +#define GIC_VPE_COMPARE_LO_OFS 0x00a0 +#define GIC_VPE_COMPARE_HI 0x00a4 + +#define GIC_VPE_EIC_SHADOW_SET_BASE 0x0100 +#define GIC_VPE_EIC_SS(intr) \ + (GIC_EIC_SHADOW_SET_BASE + (4 * intr)) + +#define GIC_VPE_EIC_VEC_BASE 0x0800 +#define GIC_VPE_EIC_VEC(intr) \ + (GIC_VPE_EIC_VEC_BASE + (4 * intr)) + +#define GIC_VPE_TENABLE_NMI_OFS 0x1000 +#define GIC_VPE_TENABLE_YQ_OFS 0x1004 +#define GIC_VPE_TENABLE_INT_31_0_OFS 0x1080 +#define GIC_VPE_TENABLE_INT_63_32_OFS 0x1084 + +/* User Mode Visible Section Register Map */ +#define GIC_UMV_SH_COUNTER_31_00_OFS 0x0000 +#define GIC_UMV_SH_COUNTER_63_32_OFS 0x0004 + +/* Masks */ +#define GIC_SH_CONFIG_COUNTSTOP_SHF 28 +#define GIC_SH_CONFIG_COUNTSTOP_MSK (MSK(1) << GIC_SH_CONFIG_COUNTSTOP_SHF) + +#define GIC_SH_CONFIG_COUNTBITS_SHF 24 +#define GIC_SH_CONFIG_COUNTBITS_MSK (MSK(4) << GIC_SH_CONFIG_COUNTBITS_SHF) + +#define GIC_SH_CONFIG_NUMINTRS_SHF 16 +#define GIC_SH_CONFIG_NUMINTRS_MSK (MSK(8) << GIC_SH_CONFIG_NUMINTRS_SHF) + +#define GIC_SH_CONFIG_NUMVPES_SHF 0 +#define GIC_SH_CONFIG_NUMVPES_MSK (MSK(8) << GIC_SH_CONFIG_NUMVPES_SHF) + +#define GIC_SH_WEDGE_SET(intr) (intr | (0x1 << 31)) +#define GIC_SH_WEDGE_CLR(intr) (intr & ~(0x1 << 31)) + +#define GIC_MAP_TO_PIN_SHF 31 +#define GIC_MAP_TO_PIN_MSK (MSK(1) << GIC_MAP_TO_PIN_SHF) +#define GIC_MAP_TO_NMI_SHF 30 +#define GIC_MAP_TO_NMI_MSK (MSK(1) << GIC_MAP_TO_NMI_SHF) +#define GIC_MAP_TO_YQ_SHF 29 +#define GIC_MAP_TO_YQ_MSK (MSK(1) << GIC_MAP_TO_YQ_SHF) +#define GIC_MAP_SHF 0 +#define GIC_MAP_MSK (MSK(6) << GIC_MAP_SHF) + +/* GIC_VPE_CTL Masks */ +#define GIC_VPE_CTL_PERFCNT_RTBL_SHF 2 +#define GIC_VPE_CTL_PERFCNT_RTBL_MSK (MSK(1) << GIC_VPE_CTL_PERFCNT_RTBL_SHF) +#define GIC_VPE_CTL_TIMER_RTBL_SHF 1 +#define GIC_VPE_CTL_TIMER_RTBL_MSK (MSK(1) << GIC_VPE_CTL_TIMER_RTBL_SHF) +#define GIC_VPE_CTL_EIC_MODE_SHF 0 +#define GIC_VPE_CTL_EIC_MODE_MSK (MSK(1) << GIC_VPE_CTL_EIC_MODE_SHF) + +/* GIC_VPE_PEND Masks */ +#define GIC_VPE_PEND_WD_SHF 0 +#define GIC_VPE_PEND_WD_MSK (MSK(1) << GIC_VPE_PEND_WD_SHF) +#define GIC_VPE_PEND_CMP_SHF 1 +#define GIC_VPE_PEND_CMP_MSK (MSK(1) << GIC_VPE_PEND_CMP_SHF) +#define GIC_VPE_PEND_TIMER_SHF 2 +#define GIC_VPE_PEND_TIMER_MSK (MSK(1) << GIC_VPE_PEND_TIMER_SHF) +#define GIC_VPE_PEND_PERFCOUNT_SHF 3 +#define GIC_VPE_PEND_PERFCOUNT_MSK (MSK(1) << GIC_VPE_PEND_PERFCOUNT_SHF) +#define GIC_VPE_PEND_SWINT0_SHF 4 +#define GIC_VPE_PEND_SWINT0_MSK (MSK(1) << GIC_VPE_PEND_SWINT0_SHF) +#define GIC_VPE_PEND_SWINT1_SHF 5 +#define GIC_VPE_PEND_SWINT1_MSK (MSK(1) << GIC_VPE_PEND_SWINT1_SHF) + +/* GIC_VPE_RMASK Masks */ +#define GIC_VPE_RMASK_WD_SHF 0 +#define GIC_VPE_RMASK_WD_MSK (MSK(1) << GIC_VPE_RMASK_WD_SHF) +#define GIC_VPE_RMASK_CMP_SHF 1 +#define GIC_VPE_RMASK_CMP_MSK (MSK(1) << GIC_VPE_RMASK_CMP_SHF) +#define GIC_VPE_RMASK_TIMER_SHF 2 +#define GIC_VPE_RMASK_TIMER_MSK (MSK(1) << GIC_VPE_RMASK_TIMER_SHF) +#define GIC_VPE_RMASK_PERFCNT_SHF 3 +#define GIC_VPE_RMASK_PERFCNT_MSK (MSK(1) << GIC_VPE_RMASK_PERFCNT_SHF) +#define GIC_VPE_RMASK_SWINT0_SHF 4 +#define GIC_VPE_RMASK_SWINT0_MSK (MSK(1) << GIC_VPE_RMASK_SWINT0_SHF) +#define GIC_VPE_RMASK_SWINT1_SHF 5 +#define GIC_VPE_RMASK_SWINT1_MSK (MSK(1) << GIC_VPE_RMASK_SWINT1_SHF) + +/* GIC_VPE_SMASK Masks */ +#define GIC_VPE_SMASK_WD_SHF 0 +#define GIC_VPE_SMASK_WD_MSK (MSK(1) << GIC_VPE_SMASK_WD_SHF) +#define GIC_VPE_SMASK_CMP_SHF 1 +#define GIC_VPE_SMASK_CMP_MSK (MSK(1) << GIC_VPE_SMASK_CMP_SHF) +#define GIC_VPE_SMASK_TIMER_SHF 2 +#define GIC_VPE_SMASK_TIMER_MSK (MSK(1) << GIC_VPE_SMASK_TIMER_SHF) +#define GIC_VPE_SMASK_PERFCNT_SHF 3 +#define GIC_VPE_SMASK_PERFCNT_MSK (MSK(1) << GIC_VPE_SMASK_PERFCNT_SHF) +#define GIC_VPE_SMASK_SWINT0_SHF 4 +#define GIC_VPE_SMASK_SWINT0_MSK (MSK(1) << GIC_VPE_SMASK_SWINT0_SHF) +#define GIC_VPE_SMASK_SWINT1_SHF 5 +#define GIC_VPE_SMASK_SWINT1_MSK (MSK(1) << GIC_VPE_SMASK_SWINT1_SHF) + +/* + * Set the Mapping of Interrupt X to a VPE. + */ +#define GIC_SH_MAP_TO_VPE_SMASK(intr, vpe) \ + GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_VPE_REG_OFF(intr, vpe)), \ + GIC_SH_MAP_TO_VPE_REG_BIT(vpe)) + +struct gic_pcpu_mask { + DECLARE_BITMAP(pcpu_mask, GIC_NUM_INTRS); +}; + +struct gic_pending_regs { + DECLARE_BITMAP(pending, GIC_NUM_INTRS); +}; + +struct gic_intrmask_regs { + DECLARE_BITMAP(intrmask, GIC_NUM_INTRS); +}; + +/* + * Interrupt Meta-data specification. The ipiflag helps + * in building ipi_map. + */ +struct gic_intr_map { + unsigned int cpunum; /* Directed to this CPU */ +#define GIC_UNUSED 0xdead /* Dummy data */ + unsigned int pin; /* Directed to this Pin */ + unsigned int polarity; /* Polarity : +/- */ + unsigned int trigtype; /* Trigger : Edge/Levl */ + unsigned int flags; /* Misc flags */ +#define GIC_FLAG_IPI 0x01 +#define GIC_FLAG_TRANSPARENT 0x02 +}; + +qemu_irq *gic_init (uint32_t ncpus, CPUMIPSState *env, MemoryRegion *address_space); + +#endif /* _ASM_GICREGS_H */ -- 1.7.11.3