17702e47cSPaolo Bonzini /* 27702e47cSPaolo Bonzini * OpenPIC emulation 37702e47cSPaolo Bonzini * 47702e47cSPaolo Bonzini * Copyright (c) 2004 Jocelyn Mayer 57702e47cSPaolo Bonzini * 2011 Alexander Graf 67702e47cSPaolo Bonzini * 77702e47cSPaolo Bonzini * Permission is hereby granted, free of charge, to any person obtaining a copy 87702e47cSPaolo Bonzini * of this software and associated documentation files (the "Software"), to deal 97702e47cSPaolo Bonzini * in the Software without restriction, including without limitation the rights 107702e47cSPaolo Bonzini * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 117702e47cSPaolo Bonzini * copies of the Software, and to permit persons to whom the Software is 127702e47cSPaolo Bonzini * furnished to do so, subject to the following conditions: 137702e47cSPaolo Bonzini * 147702e47cSPaolo Bonzini * The above copyright notice and this permission notice shall be included in 157702e47cSPaolo Bonzini * all copies or substantial portions of the Software. 167702e47cSPaolo Bonzini * 177702e47cSPaolo Bonzini * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 187702e47cSPaolo Bonzini * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 197702e47cSPaolo Bonzini * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 207702e47cSPaolo Bonzini * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 217702e47cSPaolo Bonzini * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 227702e47cSPaolo Bonzini * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 237702e47cSPaolo Bonzini * THE SOFTWARE. 247702e47cSPaolo Bonzini */ 257702e47cSPaolo Bonzini /* 267702e47cSPaolo Bonzini * 277702e47cSPaolo Bonzini * Based on OpenPic implementations: 287702e47cSPaolo Bonzini * - Intel GW80314 I/O companion chip developer's manual 297702e47cSPaolo Bonzini * - Motorola MPC8245 & MPC8540 user manuals. 307702e47cSPaolo Bonzini * - Motorola MCP750 (aka Raven) programmer manual. 317702e47cSPaolo Bonzini * - Motorola Harrier programmer manuel 327702e47cSPaolo Bonzini * 337702e47cSPaolo Bonzini * Serial interrupts, as implemented in Raven chipset are not supported yet. 347702e47cSPaolo Bonzini * 357702e47cSPaolo Bonzini */ 3690191d07SPeter Maydell #include "qemu/osdep.h" 377702e47cSPaolo Bonzini #include "hw/hw.h" 387702e47cSPaolo Bonzini #include "hw/ppc/mac.h" 397702e47cSPaolo Bonzini #include "hw/pci/pci.h" 407702e47cSPaolo Bonzini #include "hw/ppc/openpic.h" 412b927571SAndreas Färber #include "hw/ppc/ppc_e500.h" 427702e47cSPaolo Bonzini #include "hw/sysbus.h" 437702e47cSPaolo Bonzini #include "hw/pci/msi.h" 44da34e65cSMarkus Armbruster #include "qapi/error.h" 457702e47cSPaolo Bonzini #include "qemu/bitops.h" 4673d963c0SMichael Roth #include "qapi/qmp/qerror.h" 4703dd024fSPaolo Bonzini #include "qemu/log.h" 48*ddd5140bSAaron Larson #include "qemu/timer.h" 497702e47cSPaolo Bonzini 507702e47cSPaolo Bonzini //#define DEBUG_OPENPIC 517702e47cSPaolo Bonzini 527702e47cSPaolo Bonzini #ifdef DEBUG_OPENPIC 537702e47cSPaolo Bonzini static const int debug_openpic = 1; 547702e47cSPaolo Bonzini #else 557702e47cSPaolo Bonzini static const int debug_openpic = 0; 567702e47cSPaolo Bonzini #endif 577702e47cSPaolo Bonzini 58*ddd5140bSAaron Larson static int get_current_cpu(void); 597702e47cSPaolo Bonzini #define DPRINTF(fmt, ...) do { \ 607702e47cSPaolo Bonzini if (debug_openpic) { \ 61*ddd5140bSAaron Larson printf("Core%d: ", get_current_cpu()); \ 627702e47cSPaolo Bonzini printf(fmt , ## __VA_ARGS__); \ 637702e47cSPaolo Bonzini } \ 647702e47cSPaolo Bonzini } while (0) 657702e47cSPaolo Bonzini 667702e47cSPaolo Bonzini #define MAX_CPU 32 677702e47cSPaolo Bonzini #define MAX_MSI 8 687702e47cSPaolo Bonzini #define VID 0x03 /* MPIC version ID */ 697702e47cSPaolo Bonzini 707702e47cSPaolo Bonzini /* OpenPIC capability flags */ 717702e47cSPaolo Bonzini #define OPENPIC_FLAG_IDR_CRIT (1 << 0) 727702e47cSPaolo Bonzini #define OPENPIC_FLAG_ILR (2 << 0) 737702e47cSPaolo Bonzini 747702e47cSPaolo Bonzini /* OpenPIC address map */ 757702e47cSPaolo Bonzini #define OPENPIC_GLB_REG_START 0x0 767702e47cSPaolo Bonzini #define OPENPIC_GLB_REG_SIZE 0x10F0 777702e47cSPaolo Bonzini #define OPENPIC_TMR_REG_START 0x10F0 787702e47cSPaolo Bonzini #define OPENPIC_TMR_REG_SIZE 0x220 797702e47cSPaolo Bonzini #define OPENPIC_MSI_REG_START 0x1600 807702e47cSPaolo Bonzini #define OPENPIC_MSI_REG_SIZE 0x200 817702e47cSPaolo Bonzini #define OPENPIC_SUMMARY_REG_START 0x3800 827702e47cSPaolo Bonzini #define OPENPIC_SUMMARY_REG_SIZE 0x800 837702e47cSPaolo Bonzini #define OPENPIC_SRC_REG_START 0x10000 848935a442SScott Wood #define OPENPIC_SRC_REG_SIZE (OPENPIC_MAX_SRC * 0x20) 857702e47cSPaolo Bonzini #define OPENPIC_CPU_REG_START 0x20000 867702e47cSPaolo Bonzini #define OPENPIC_CPU_REG_SIZE 0x100 + ((MAX_CPU - 1) * 0x1000) 877702e47cSPaolo Bonzini 887702e47cSPaolo Bonzini /* Raven */ 897702e47cSPaolo Bonzini #define RAVEN_MAX_CPU 2 907702e47cSPaolo Bonzini #define RAVEN_MAX_EXT 48 917702e47cSPaolo Bonzini #define RAVEN_MAX_IRQ 64 928935a442SScott Wood #define RAVEN_MAX_TMR OPENPIC_MAX_TMR 938935a442SScott Wood #define RAVEN_MAX_IPI OPENPIC_MAX_IPI 947702e47cSPaolo Bonzini 957702e47cSPaolo Bonzini /* Interrupt definitions */ 967702e47cSPaolo Bonzini #define RAVEN_FE_IRQ (RAVEN_MAX_EXT) /* Internal functional IRQ */ 977702e47cSPaolo Bonzini #define RAVEN_ERR_IRQ (RAVEN_MAX_EXT + 1) /* Error IRQ */ 987702e47cSPaolo Bonzini #define RAVEN_TMR_IRQ (RAVEN_MAX_EXT + 2) /* First timer IRQ */ 997702e47cSPaolo Bonzini #define RAVEN_IPI_IRQ (RAVEN_TMR_IRQ + RAVEN_MAX_TMR) /* First IPI IRQ */ 1007702e47cSPaolo Bonzini /* First doorbell IRQ */ 1017702e47cSPaolo Bonzini #define RAVEN_DBL_IRQ (RAVEN_IPI_IRQ + (RAVEN_MAX_CPU * RAVEN_MAX_IPI)) 1027702e47cSPaolo Bonzini 1037702e47cSPaolo Bonzini typedef struct FslMpicInfo { 1047702e47cSPaolo Bonzini int max_ext; 1057702e47cSPaolo Bonzini } FslMpicInfo; 1067702e47cSPaolo Bonzini 1077702e47cSPaolo Bonzini static FslMpicInfo fsl_mpic_20 = { 1087702e47cSPaolo Bonzini .max_ext = 12, 1097702e47cSPaolo Bonzini }; 1107702e47cSPaolo Bonzini 1117702e47cSPaolo Bonzini static FslMpicInfo fsl_mpic_42 = { 1127702e47cSPaolo Bonzini .max_ext = 12, 1137702e47cSPaolo Bonzini }; 1147702e47cSPaolo Bonzini 1157702e47cSPaolo Bonzini #define FRR_NIRQ_SHIFT 16 1167702e47cSPaolo Bonzini #define FRR_NCPU_SHIFT 8 1177702e47cSPaolo Bonzini #define FRR_VID_SHIFT 0 1187702e47cSPaolo Bonzini 1197702e47cSPaolo Bonzini #define VID_REVISION_1_2 2 1207702e47cSPaolo Bonzini #define VID_REVISION_1_3 3 1217702e47cSPaolo Bonzini 1227702e47cSPaolo Bonzini #define VIR_GENERIC 0x00000000 /* Generic Vendor ID */ 1237702e47cSPaolo Bonzini 1247702e47cSPaolo Bonzini #define GCR_RESET 0x80000000 1257702e47cSPaolo Bonzini #define GCR_MODE_PASS 0x00000000 1267702e47cSPaolo Bonzini #define GCR_MODE_MIXED 0x20000000 1277702e47cSPaolo Bonzini #define GCR_MODE_PROXY 0x60000000 1287702e47cSPaolo Bonzini 1297702e47cSPaolo Bonzini #define TBCR_CI 0x80000000 /* count inhibit */ 1307702e47cSPaolo Bonzini #define TCCR_TOG 0x80000000 /* toggles when decrement to zero */ 1317702e47cSPaolo Bonzini 1327702e47cSPaolo Bonzini #define IDR_EP_SHIFT 31 133def60298SPeter Maydell #define IDR_EP_MASK (1U << IDR_EP_SHIFT) 1347702e47cSPaolo Bonzini #define IDR_CI0_SHIFT 30 1357702e47cSPaolo Bonzini #define IDR_CI1_SHIFT 29 1367702e47cSPaolo Bonzini #define IDR_P1_SHIFT 1 1377702e47cSPaolo Bonzini #define IDR_P0_SHIFT 0 1387702e47cSPaolo Bonzini 1397702e47cSPaolo Bonzini #define ILR_INTTGT_MASK 0x000000ff 1407702e47cSPaolo Bonzini #define ILR_INTTGT_INT 0x00 1417702e47cSPaolo Bonzini #define ILR_INTTGT_CINT 0x01 /* critical */ 1427702e47cSPaolo Bonzini #define ILR_INTTGT_MCP 0x02 /* machine check */ 1437702e47cSPaolo Bonzini 1447702e47cSPaolo Bonzini /* The currently supported INTTGT values happen to be the same as QEMU's 1457702e47cSPaolo Bonzini * openpic output codes, but don't depend on this. The output codes 1467702e47cSPaolo Bonzini * could change (unlikely, but...) or support could be added for 1477702e47cSPaolo Bonzini * more INTTGT values. 1487702e47cSPaolo Bonzini */ 1497702e47cSPaolo Bonzini static const int inttgt_output[][2] = { 1507702e47cSPaolo Bonzini { ILR_INTTGT_INT, OPENPIC_OUTPUT_INT }, 1517702e47cSPaolo Bonzini { ILR_INTTGT_CINT, OPENPIC_OUTPUT_CINT }, 1527702e47cSPaolo Bonzini { ILR_INTTGT_MCP, OPENPIC_OUTPUT_MCK }, 1537702e47cSPaolo Bonzini }; 1547702e47cSPaolo Bonzini 1557702e47cSPaolo Bonzini static int inttgt_to_output(int inttgt) 1567702e47cSPaolo Bonzini { 1577702e47cSPaolo Bonzini int i; 1587702e47cSPaolo Bonzini 1597702e47cSPaolo Bonzini for (i = 0; i < ARRAY_SIZE(inttgt_output); i++) { 1607702e47cSPaolo Bonzini if (inttgt_output[i][0] == inttgt) { 1617702e47cSPaolo Bonzini return inttgt_output[i][1]; 1627702e47cSPaolo Bonzini } 1637702e47cSPaolo Bonzini } 1647702e47cSPaolo Bonzini 1657702e47cSPaolo Bonzini fprintf(stderr, "%s: unsupported inttgt %d\n", __func__, inttgt); 1667702e47cSPaolo Bonzini return OPENPIC_OUTPUT_INT; 1677702e47cSPaolo Bonzini } 1687702e47cSPaolo Bonzini 1697702e47cSPaolo Bonzini static int output_to_inttgt(int output) 1707702e47cSPaolo Bonzini { 1717702e47cSPaolo Bonzini int i; 1727702e47cSPaolo Bonzini 1737702e47cSPaolo Bonzini for (i = 0; i < ARRAY_SIZE(inttgt_output); i++) { 1747702e47cSPaolo Bonzini if (inttgt_output[i][1] == output) { 1757702e47cSPaolo Bonzini return inttgt_output[i][0]; 1767702e47cSPaolo Bonzini } 1777702e47cSPaolo Bonzini } 1787702e47cSPaolo Bonzini 1797702e47cSPaolo Bonzini abort(); 1807702e47cSPaolo Bonzini } 1817702e47cSPaolo Bonzini 1827702e47cSPaolo Bonzini #define MSIIR_OFFSET 0x140 1837702e47cSPaolo Bonzini #define MSIIR_SRS_SHIFT 29 1847702e47cSPaolo Bonzini #define MSIIR_SRS_MASK (0x7 << MSIIR_SRS_SHIFT) 1857702e47cSPaolo Bonzini #define MSIIR_IBS_SHIFT 24 1867702e47cSPaolo Bonzini #define MSIIR_IBS_MASK (0x1f << MSIIR_IBS_SHIFT) 1877702e47cSPaolo Bonzini 1887702e47cSPaolo Bonzini static int get_current_cpu(void) 1897702e47cSPaolo Bonzini { 1904917cf44SAndreas Färber if (!current_cpu) { 1917702e47cSPaolo Bonzini return -1; 1927702e47cSPaolo Bonzini } 1937702e47cSPaolo Bonzini 1944917cf44SAndreas Färber return current_cpu->cpu_index; 1957702e47cSPaolo Bonzini } 1967702e47cSPaolo Bonzini 1977702e47cSPaolo Bonzini static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, 1987702e47cSPaolo Bonzini int idx); 1997702e47cSPaolo Bonzini static void openpic_cpu_write_internal(void *opaque, hwaddr addr, 2007702e47cSPaolo Bonzini uint32_t val, int idx); 2018ebe65f3SPaul Janzen static void openpic_reset(DeviceState *d); 2027702e47cSPaolo Bonzini 2037702e47cSPaolo Bonzini typedef enum IRQType { 2047702e47cSPaolo Bonzini IRQ_TYPE_NORMAL = 0, 2057702e47cSPaolo Bonzini IRQ_TYPE_FSLINT, /* FSL internal interrupt -- level only */ 2067702e47cSPaolo Bonzini IRQ_TYPE_FSLSPECIAL, /* FSL timer/IPI interrupt, edge, no polarity */ 2077702e47cSPaolo Bonzini } IRQType; 2087702e47cSPaolo Bonzini 2097702e47cSPaolo Bonzini /* Round up to the nearest 64 IRQs so that the queue length 2107702e47cSPaolo Bonzini * won't change when moving between 32 and 64 bit hosts. 2117702e47cSPaolo Bonzini */ 2122ada66f9SMark Cave-Ayland #define IRQQUEUE_SIZE_BITS ((OPENPIC_MAX_IRQ + 63) & ~63) 2132ada66f9SMark Cave-Ayland 2142ada66f9SMark Cave-Ayland typedef struct IRQQueue { 2152ada66f9SMark Cave-Ayland unsigned long *queue; 216e5f6e732SMark Cave-Ayland int32_t queue_size; /* Only used for VMSTATE_BITMAP */ 2177702e47cSPaolo Bonzini int next; 2187702e47cSPaolo Bonzini int priority; 2197702e47cSPaolo Bonzini } IRQQueue; 2207702e47cSPaolo Bonzini 2217702e47cSPaolo Bonzini typedef struct IRQSource { 2227702e47cSPaolo Bonzini uint32_t ivpr; /* IRQ vector/priority register */ 2237702e47cSPaolo Bonzini uint32_t idr; /* IRQ destination register */ 2247702e47cSPaolo Bonzini uint32_t destmask; /* bitmap of CPU destinations */ 2257702e47cSPaolo Bonzini int last_cpu; 2267702e47cSPaolo Bonzini int output; /* IRQ level, e.g. OPENPIC_OUTPUT_INT */ 2277702e47cSPaolo Bonzini int pending; /* TRUE if IRQ is pending */ 2287702e47cSPaolo Bonzini IRQType type; 2297702e47cSPaolo Bonzini bool level:1; /* level-triggered */ 2307702e47cSPaolo Bonzini bool nomask:1; /* critical interrupts ignore mask on some FSL MPICs */ 2317702e47cSPaolo Bonzini } IRQSource; 2327702e47cSPaolo Bonzini 2337702e47cSPaolo Bonzini #define IVPR_MASK_SHIFT 31 234def60298SPeter Maydell #define IVPR_MASK_MASK (1U << IVPR_MASK_SHIFT) 2357702e47cSPaolo Bonzini #define IVPR_ACTIVITY_SHIFT 30 236def60298SPeter Maydell #define IVPR_ACTIVITY_MASK (1U << IVPR_ACTIVITY_SHIFT) 2377702e47cSPaolo Bonzini #define IVPR_MODE_SHIFT 29 238def60298SPeter Maydell #define IVPR_MODE_MASK (1U << IVPR_MODE_SHIFT) 2397702e47cSPaolo Bonzini #define IVPR_POLARITY_SHIFT 23 240def60298SPeter Maydell #define IVPR_POLARITY_MASK (1U << IVPR_POLARITY_SHIFT) 2417702e47cSPaolo Bonzini #define IVPR_SENSE_SHIFT 22 242def60298SPeter Maydell #define IVPR_SENSE_MASK (1U << IVPR_SENSE_SHIFT) 2437702e47cSPaolo Bonzini 244def60298SPeter Maydell #define IVPR_PRIORITY_MASK (0xFU << 16) 2457702e47cSPaolo Bonzini #define IVPR_PRIORITY(_ivprr_) ((int)(((_ivprr_) & IVPR_PRIORITY_MASK) >> 16)) 2467702e47cSPaolo Bonzini #define IVPR_VECTOR(opp, _ivprr_) ((_ivprr_) & (opp)->vector_mask) 2477702e47cSPaolo Bonzini 2487702e47cSPaolo Bonzini /* IDR[EP/CI] are only for FSL MPIC prior to v4.0 */ 2497702e47cSPaolo Bonzini #define IDR_EP 0x80000000 /* external pin */ 2507702e47cSPaolo Bonzini #define IDR_CI 0x40000000 /* critical interrupt */ 2517702e47cSPaolo Bonzini 252*ddd5140bSAaron Larson /* Convert between openpic clock ticks and nanosecs. In the hardware the clock 253*ddd5140bSAaron Larson frequency is driven by board inputs to the PIC which the PIC would then 254*ddd5140bSAaron Larson divide by 4 or 8. For now hard code to 25MZ. 255*ddd5140bSAaron Larson */ 256*ddd5140bSAaron Larson #define OPENPIC_TIMER_FREQ_MHZ 25 257*ddd5140bSAaron Larson #define OPENPIC_TIMER_NS_PER_TICK (1000 / OPENPIC_TIMER_FREQ_MHZ) 258*ddd5140bSAaron Larson static inline uint64_t ns_to_ticks(uint64_t ns) 259*ddd5140bSAaron Larson { 260*ddd5140bSAaron Larson return ns / OPENPIC_TIMER_NS_PER_TICK; 261*ddd5140bSAaron Larson } 262*ddd5140bSAaron Larson static inline uint64_t ticks_to_ns(uint64_t ticks) 263*ddd5140bSAaron Larson { 264*ddd5140bSAaron Larson return ticks * OPENPIC_TIMER_NS_PER_TICK; 265*ddd5140bSAaron Larson } 266*ddd5140bSAaron Larson 267e5f6e732SMark Cave-Ayland typedef struct OpenPICTimer { 268e5f6e732SMark Cave-Ayland uint32_t tccr; /* Global timer current count register */ 269e5f6e732SMark Cave-Ayland uint32_t tbcr; /* Global timer base count register */ 270*ddd5140bSAaron Larson int n_IRQ; 271*ddd5140bSAaron Larson bool qemu_timer_active; /* Is the qemu_timer is running? */ 272*ddd5140bSAaron Larson struct QEMUTimer *qemu_timer; 273*ddd5140bSAaron Larson struct OpenPICState *opp; /* Device timer is part of. */ 274*ddd5140bSAaron Larson /* The QEMU_CLOCK_VIRTUAL time (in ns) corresponding to the last 275*ddd5140bSAaron Larson current_count written or read, only defined if qemu_timer_active. */ 276*ddd5140bSAaron Larson uint64_t origin_time; 277e5f6e732SMark Cave-Ayland } OpenPICTimer; 278e5f6e732SMark Cave-Ayland 279e5f6e732SMark Cave-Ayland typedef struct OpenPICMSI { 280e5f6e732SMark Cave-Ayland uint32_t msir; /* Shared Message Signaled Interrupt Register */ 281e5f6e732SMark Cave-Ayland } OpenPICMSI; 282e5f6e732SMark Cave-Ayland 2837702e47cSPaolo Bonzini typedef struct IRQDest { 2847702e47cSPaolo Bonzini int32_t ctpr; /* CPU current task priority */ 2857702e47cSPaolo Bonzini IRQQueue raised; 2867702e47cSPaolo Bonzini IRQQueue servicing; 2877702e47cSPaolo Bonzini qemu_irq *irqs; 2887702e47cSPaolo Bonzini 2897702e47cSPaolo Bonzini /* Count of IRQ sources asserting on non-INT outputs */ 2907702e47cSPaolo Bonzini uint32_t outputs_active[OPENPIC_OUTPUT_NB]; 2917702e47cSPaolo Bonzini } IRQDest; 2927702e47cSPaolo Bonzini 293e1766344SAndreas Färber #define OPENPIC(obj) OBJECT_CHECK(OpenPICState, (obj), TYPE_OPENPIC) 294e1766344SAndreas Färber 2957702e47cSPaolo Bonzini typedef struct OpenPICState { 296e1766344SAndreas Färber /*< private >*/ 297e1766344SAndreas Färber SysBusDevice parent_obj; 298e1766344SAndreas Färber /*< public >*/ 299e1766344SAndreas Färber 3007702e47cSPaolo Bonzini MemoryRegion mem; 3017702e47cSPaolo Bonzini 3027702e47cSPaolo Bonzini /* Behavior control */ 3037702e47cSPaolo Bonzini FslMpicInfo *fsl; 3047702e47cSPaolo Bonzini uint32_t model; 3057702e47cSPaolo Bonzini uint32_t flags; 3067702e47cSPaolo Bonzini uint32_t nb_irqs; 3077702e47cSPaolo Bonzini uint32_t vid; 3087702e47cSPaolo Bonzini uint32_t vir; /* Vendor identification register */ 3097702e47cSPaolo Bonzini uint32_t vector_mask; 3107702e47cSPaolo Bonzini uint32_t tfrr_reset; 3117702e47cSPaolo Bonzini uint32_t ivpr_reset; 3127702e47cSPaolo Bonzini uint32_t idr_reset; 3137702e47cSPaolo Bonzini uint32_t brr1; 3147702e47cSPaolo Bonzini uint32_t mpic_mode_mask; 3157702e47cSPaolo Bonzini 3167702e47cSPaolo Bonzini /* Sub-regions */ 3177702e47cSPaolo Bonzini MemoryRegion sub_io_mem[6]; 3187702e47cSPaolo Bonzini 3197702e47cSPaolo Bonzini /* Global registers */ 3207702e47cSPaolo Bonzini uint32_t frr; /* Feature reporting register */ 3217702e47cSPaolo Bonzini uint32_t gcr; /* Global configuration register */ 3227702e47cSPaolo Bonzini uint32_t pir; /* Processor initialization register */ 3237702e47cSPaolo Bonzini uint32_t spve; /* Spurious vector register */ 3247702e47cSPaolo Bonzini uint32_t tfrr; /* Timer frequency reporting register */ 3257702e47cSPaolo Bonzini /* Source registers */ 3268935a442SScott Wood IRQSource src[OPENPIC_MAX_IRQ]; 3277702e47cSPaolo Bonzini /* Local registers per output pin */ 3287702e47cSPaolo Bonzini IRQDest dst[MAX_CPU]; 3297702e47cSPaolo Bonzini uint32_t nb_cpus; 3307702e47cSPaolo Bonzini /* Timer registers */ 331e5f6e732SMark Cave-Ayland OpenPICTimer timers[OPENPIC_MAX_TMR]; 3327702e47cSPaolo Bonzini /* Shared MSI registers */ 333e5f6e732SMark Cave-Ayland OpenPICMSI msi[MAX_MSI]; 3347702e47cSPaolo Bonzini uint32_t max_irq; 3357702e47cSPaolo Bonzini uint32_t irq_ipi0; 3367702e47cSPaolo Bonzini uint32_t irq_tim0; 3377702e47cSPaolo Bonzini uint32_t irq_msi; 3387702e47cSPaolo Bonzini } OpenPICState; 3397702e47cSPaolo Bonzini 3407702e47cSPaolo Bonzini static inline void IRQ_setbit(IRQQueue *q, int n_IRQ) 3417702e47cSPaolo Bonzini { 3427702e47cSPaolo Bonzini set_bit(n_IRQ, q->queue); 3437702e47cSPaolo Bonzini } 3447702e47cSPaolo Bonzini 3457702e47cSPaolo Bonzini static inline void IRQ_resetbit(IRQQueue *q, int n_IRQ) 3467702e47cSPaolo Bonzini { 3477702e47cSPaolo Bonzini clear_bit(n_IRQ, q->queue); 3487702e47cSPaolo Bonzini } 3497702e47cSPaolo Bonzini 3507702e47cSPaolo Bonzini static void IRQ_check(OpenPICState *opp, IRQQueue *q) 3517702e47cSPaolo Bonzini { 3527702e47cSPaolo Bonzini int irq = -1; 3537702e47cSPaolo Bonzini int next = -1; 3547702e47cSPaolo Bonzini int priority = -1; 3557702e47cSPaolo Bonzini 3567702e47cSPaolo Bonzini for (;;) { 3577702e47cSPaolo Bonzini irq = find_next_bit(q->queue, opp->max_irq, irq + 1); 3587702e47cSPaolo Bonzini if (irq == opp->max_irq) { 3597702e47cSPaolo Bonzini break; 3607702e47cSPaolo Bonzini } 3617702e47cSPaolo Bonzini 3627702e47cSPaolo Bonzini DPRINTF("IRQ_check: irq %d set ivpr_pr=%d pr=%d\n", 3637702e47cSPaolo Bonzini irq, IVPR_PRIORITY(opp->src[irq].ivpr), priority); 3647702e47cSPaolo Bonzini 3657702e47cSPaolo Bonzini if (IVPR_PRIORITY(opp->src[irq].ivpr) > priority) { 3667702e47cSPaolo Bonzini next = irq; 3677702e47cSPaolo Bonzini priority = IVPR_PRIORITY(opp->src[irq].ivpr); 3687702e47cSPaolo Bonzini } 3697702e47cSPaolo Bonzini } 3707702e47cSPaolo Bonzini 3717702e47cSPaolo Bonzini q->next = next; 3727702e47cSPaolo Bonzini q->priority = priority; 3737702e47cSPaolo Bonzini } 3747702e47cSPaolo Bonzini 3757702e47cSPaolo Bonzini static int IRQ_get_next(OpenPICState *opp, IRQQueue *q) 3767702e47cSPaolo Bonzini { 3777702e47cSPaolo Bonzini /* XXX: optimize */ 3787702e47cSPaolo Bonzini IRQ_check(opp, q); 3797702e47cSPaolo Bonzini 3807702e47cSPaolo Bonzini return q->next; 3817702e47cSPaolo Bonzini } 3827702e47cSPaolo Bonzini 3837702e47cSPaolo Bonzini static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ, 3847702e47cSPaolo Bonzini bool active, bool was_active) 3857702e47cSPaolo Bonzini { 3867702e47cSPaolo Bonzini IRQDest *dst; 3877702e47cSPaolo Bonzini IRQSource *src; 3887702e47cSPaolo Bonzini int priority; 3897702e47cSPaolo Bonzini 3907702e47cSPaolo Bonzini dst = &opp->dst[n_CPU]; 3917702e47cSPaolo Bonzini src = &opp->src[n_IRQ]; 3927702e47cSPaolo Bonzini 3937702e47cSPaolo Bonzini DPRINTF("%s: IRQ %d active %d was %d\n", 3947702e47cSPaolo Bonzini __func__, n_IRQ, active, was_active); 3957702e47cSPaolo Bonzini 3967702e47cSPaolo Bonzini if (src->output != OPENPIC_OUTPUT_INT) { 3977702e47cSPaolo Bonzini DPRINTF("%s: output %d irq %d active %d was %d count %d\n", 3987702e47cSPaolo Bonzini __func__, src->output, n_IRQ, active, was_active, 3997702e47cSPaolo Bonzini dst->outputs_active[src->output]); 4007702e47cSPaolo Bonzini 4017702e47cSPaolo Bonzini /* On Freescale MPIC, critical interrupts ignore priority, 4027702e47cSPaolo Bonzini * IACK, EOI, etc. Before MPIC v4.1 they also ignore 4037702e47cSPaolo Bonzini * masking. 4047702e47cSPaolo Bonzini */ 4057702e47cSPaolo Bonzini if (active) { 4067702e47cSPaolo Bonzini if (!was_active && dst->outputs_active[src->output]++ == 0) { 4077702e47cSPaolo Bonzini DPRINTF("%s: Raise OpenPIC output %d cpu %d irq %d\n", 4087702e47cSPaolo Bonzini __func__, src->output, n_CPU, n_IRQ); 4097702e47cSPaolo Bonzini qemu_irq_raise(dst->irqs[src->output]); 4107702e47cSPaolo Bonzini } 4117702e47cSPaolo Bonzini } else { 4127702e47cSPaolo Bonzini if (was_active && --dst->outputs_active[src->output] == 0) { 4137702e47cSPaolo Bonzini DPRINTF("%s: Lower OpenPIC output %d cpu %d irq %d\n", 4147702e47cSPaolo Bonzini __func__, src->output, n_CPU, n_IRQ); 4157702e47cSPaolo Bonzini qemu_irq_lower(dst->irqs[src->output]); 4167702e47cSPaolo Bonzini } 4177702e47cSPaolo Bonzini } 4187702e47cSPaolo Bonzini 4197702e47cSPaolo Bonzini return; 4207702e47cSPaolo Bonzini } 4217702e47cSPaolo Bonzini 4227702e47cSPaolo Bonzini priority = IVPR_PRIORITY(src->ivpr); 4237702e47cSPaolo Bonzini 4247702e47cSPaolo Bonzini /* Even if the interrupt doesn't have enough priority, 4257702e47cSPaolo Bonzini * it is still raised, in case ctpr is lowered later. 4267702e47cSPaolo Bonzini */ 4277702e47cSPaolo Bonzini if (active) { 4287702e47cSPaolo Bonzini IRQ_setbit(&dst->raised, n_IRQ); 4297702e47cSPaolo Bonzini } else { 4307702e47cSPaolo Bonzini IRQ_resetbit(&dst->raised, n_IRQ); 4317702e47cSPaolo Bonzini } 4327702e47cSPaolo Bonzini 4337702e47cSPaolo Bonzini IRQ_check(opp, &dst->raised); 4347702e47cSPaolo Bonzini 4357702e47cSPaolo Bonzini if (active && priority <= dst->ctpr) { 4367702e47cSPaolo Bonzini DPRINTF("%s: IRQ %d priority %d too low for ctpr %d on CPU %d\n", 4377702e47cSPaolo Bonzini __func__, n_IRQ, priority, dst->ctpr, n_CPU); 4387702e47cSPaolo Bonzini active = 0; 4397702e47cSPaolo Bonzini } 4407702e47cSPaolo Bonzini 4417702e47cSPaolo Bonzini if (active) { 4427702e47cSPaolo Bonzini if (IRQ_get_next(opp, &dst->servicing) >= 0 && 4437702e47cSPaolo Bonzini priority <= dst->servicing.priority) { 4447702e47cSPaolo Bonzini DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n", 4457702e47cSPaolo Bonzini __func__, n_IRQ, dst->servicing.next, n_CPU); 4467702e47cSPaolo Bonzini } else { 4477702e47cSPaolo Bonzini DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d/%d\n", 4487702e47cSPaolo Bonzini __func__, n_CPU, n_IRQ, dst->raised.next); 4497702e47cSPaolo Bonzini qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]); 4507702e47cSPaolo Bonzini } 4517702e47cSPaolo Bonzini } else { 4527702e47cSPaolo Bonzini IRQ_get_next(opp, &dst->servicing); 4537702e47cSPaolo Bonzini if (dst->raised.priority > dst->ctpr && 4547702e47cSPaolo Bonzini dst->raised.priority > dst->servicing.priority) { 4557702e47cSPaolo Bonzini DPRINTF("%s: IRQ %d inactive, IRQ %d prio %d above %d/%d, CPU %d\n", 4567702e47cSPaolo Bonzini __func__, n_IRQ, dst->raised.next, dst->raised.priority, 4577702e47cSPaolo Bonzini dst->ctpr, dst->servicing.priority, n_CPU); 4587702e47cSPaolo Bonzini /* IRQ line stays asserted */ 4597702e47cSPaolo Bonzini } else { 4607702e47cSPaolo Bonzini DPRINTF("%s: IRQ %d inactive, current prio %d/%d, CPU %d\n", 4617702e47cSPaolo Bonzini __func__, n_IRQ, dst->ctpr, dst->servicing.priority, n_CPU); 4627702e47cSPaolo Bonzini qemu_irq_lower(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]); 4637702e47cSPaolo Bonzini } 4647702e47cSPaolo Bonzini } 4657702e47cSPaolo Bonzini } 4667702e47cSPaolo Bonzini 4677702e47cSPaolo Bonzini /* update pic state because registers for n_IRQ have changed value */ 4687702e47cSPaolo Bonzini static void openpic_update_irq(OpenPICState *opp, int n_IRQ) 4697702e47cSPaolo Bonzini { 4707702e47cSPaolo Bonzini IRQSource *src; 4717702e47cSPaolo Bonzini bool active, was_active; 4727702e47cSPaolo Bonzini int i; 4737702e47cSPaolo Bonzini 4747702e47cSPaolo Bonzini src = &opp->src[n_IRQ]; 4757702e47cSPaolo Bonzini active = src->pending; 4767702e47cSPaolo Bonzini 4777702e47cSPaolo Bonzini if ((src->ivpr & IVPR_MASK_MASK) && !src->nomask) { 4787702e47cSPaolo Bonzini /* Interrupt source is disabled */ 4797702e47cSPaolo Bonzini DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ); 4807702e47cSPaolo Bonzini active = false; 4817702e47cSPaolo Bonzini } 4827702e47cSPaolo Bonzini 4837702e47cSPaolo Bonzini was_active = !!(src->ivpr & IVPR_ACTIVITY_MASK); 4847702e47cSPaolo Bonzini 4857702e47cSPaolo Bonzini /* 4867702e47cSPaolo Bonzini * We don't have a similar check for already-active because 4877702e47cSPaolo Bonzini * ctpr may have changed and we need to withdraw the interrupt. 4887702e47cSPaolo Bonzini */ 4897702e47cSPaolo Bonzini if (!active && !was_active) { 4907702e47cSPaolo Bonzini DPRINTF("%s: IRQ %d is already inactive\n", __func__, n_IRQ); 4917702e47cSPaolo Bonzini return; 4927702e47cSPaolo Bonzini } 4937702e47cSPaolo Bonzini 4947702e47cSPaolo Bonzini if (active) { 4957702e47cSPaolo Bonzini src->ivpr |= IVPR_ACTIVITY_MASK; 4967702e47cSPaolo Bonzini } else { 4977702e47cSPaolo Bonzini src->ivpr &= ~IVPR_ACTIVITY_MASK; 4987702e47cSPaolo Bonzini } 4997702e47cSPaolo Bonzini 5007702e47cSPaolo Bonzini if (src->destmask == 0) { 5017702e47cSPaolo Bonzini /* No target */ 5027702e47cSPaolo Bonzini DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ); 5037702e47cSPaolo Bonzini return; 5047702e47cSPaolo Bonzini } 5057702e47cSPaolo Bonzini 5067702e47cSPaolo Bonzini if (src->destmask == (1 << src->last_cpu)) { 5077702e47cSPaolo Bonzini /* Only one CPU is allowed to receive this IRQ */ 5087702e47cSPaolo Bonzini IRQ_local_pipe(opp, src->last_cpu, n_IRQ, active, was_active); 5097702e47cSPaolo Bonzini } else if (!(src->ivpr & IVPR_MODE_MASK)) { 5107702e47cSPaolo Bonzini /* Directed delivery mode */ 5117702e47cSPaolo Bonzini for (i = 0; i < opp->nb_cpus; i++) { 5127702e47cSPaolo Bonzini if (src->destmask & (1 << i)) { 5137702e47cSPaolo Bonzini IRQ_local_pipe(opp, i, n_IRQ, active, was_active); 5147702e47cSPaolo Bonzini } 5157702e47cSPaolo Bonzini } 5167702e47cSPaolo Bonzini } else { 5177702e47cSPaolo Bonzini /* Distributed delivery mode */ 5187702e47cSPaolo Bonzini for (i = src->last_cpu + 1; i != src->last_cpu; i++) { 5197702e47cSPaolo Bonzini if (i == opp->nb_cpus) { 5207702e47cSPaolo Bonzini i = 0; 5217702e47cSPaolo Bonzini } 5227702e47cSPaolo Bonzini if (src->destmask & (1 << i)) { 5237702e47cSPaolo Bonzini IRQ_local_pipe(opp, i, n_IRQ, active, was_active); 5247702e47cSPaolo Bonzini src->last_cpu = i; 5257702e47cSPaolo Bonzini break; 5267702e47cSPaolo Bonzini } 5277702e47cSPaolo Bonzini } 5287702e47cSPaolo Bonzini } 5297702e47cSPaolo Bonzini } 5307702e47cSPaolo Bonzini 5317702e47cSPaolo Bonzini static void openpic_set_irq(void *opaque, int n_IRQ, int level) 5327702e47cSPaolo Bonzini { 5337702e47cSPaolo Bonzini OpenPICState *opp = opaque; 5347702e47cSPaolo Bonzini IRQSource *src; 5357702e47cSPaolo Bonzini 5368935a442SScott Wood if (n_IRQ >= OPENPIC_MAX_IRQ) { 5377702e47cSPaolo Bonzini fprintf(stderr, "%s: IRQ %d out of range\n", __func__, n_IRQ); 5387702e47cSPaolo Bonzini abort(); 5397702e47cSPaolo Bonzini } 5407702e47cSPaolo Bonzini 5417702e47cSPaolo Bonzini src = &opp->src[n_IRQ]; 5427702e47cSPaolo Bonzini DPRINTF("openpic: set irq %d = %d ivpr=0x%08x\n", 5437702e47cSPaolo Bonzini n_IRQ, level, src->ivpr); 5447702e47cSPaolo Bonzini if (src->level) { 5457702e47cSPaolo Bonzini /* level-sensitive irq */ 5467702e47cSPaolo Bonzini src->pending = level; 5477702e47cSPaolo Bonzini openpic_update_irq(opp, n_IRQ); 5487702e47cSPaolo Bonzini } else { 5497702e47cSPaolo Bonzini /* edge-sensitive irq */ 5507702e47cSPaolo Bonzini if (level) { 5517702e47cSPaolo Bonzini src->pending = 1; 5527702e47cSPaolo Bonzini openpic_update_irq(opp, n_IRQ); 5537702e47cSPaolo Bonzini } 5547702e47cSPaolo Bonzini 5557702e47cSPaolo Bonzini if (src->output != OPENPIC_OUTPUT_INT) { 5567702e47cSPaolo Bonzini /* Edge-triggered interrupts shouldn't be used 5577702e47cSPaolo Bonzini * with non-INT delivery, but just in case, 5587702e47cSPaolo Bonzini * try to make it do something sane rather than 5597702e47cSPaolo Bonzini * cause an interrupt storm. This is close to 5607702e47cSPaolo Bonzini * what you'd probably see happen in real hardware. 5617702e47cSPaolo Bonzini */ 5627702e47cSPaolo Bonzini src->pending = 0; 5637702e47cSPaolo Bonzini openpic_update_irq(opp, n_IRQ); 5647702e47cSPaolo Bonzini } 5657702e47cSPaolo Bonzini } 5667702e47cSPaolo Bonzini } 5677702e47cSPaolo Bonzini 5687702e47cSPaolo Bonzini static inline uint32_t read_IRQreg_idr(OpenPICState *opp, int n_IRQ) 5697702e47cSPaolo Bonzini { 5707702e47cSPaolo Bonzini return opp->src[n_IRQ].idr; 5717702e47cSPaolo Bonzini } 5727702e47cSPaolo Bonzini 5737702e47cSPaolo Bonzini static inline uint32_t read_IRQreg_ilr(OpenPICState *opp, int n_IRQ) 5747702e47cSPaolo Bonzini { 5757702e47cSPaolo Bonzini if (opp->flags & OPENPIC_FLAG_ILR) { 5767702e47cSPaolo Bonzini return output_to_inttgt(opp->src[n_IRQ].output); 5777702e47cSPaolo Bonzini } 5787702e47cSPaolo Bonzini 5797702e47cSPaolo Bonzini return 0xffffffff; 5807702e47cSPaolo Bonzini } 5817702e47cSPaolo Bonzini 5827702e47cSPaolo Bonzini static inline uint32_t read_IRQreg_ivpr(OpenPICState *opp, int n_IRQ) 5837702e47cSPaolo Bonzini { 5847702e47cSPaolo Bonzini return opp->src[n_IRQ].ivpr; 5857702e47cSPaolo Bonzini } 5867702e47cSPaolo Bonzini 5877702e47cSPaolo Bonzini static inline void write_IRQreg_idr(OpenPICState *opp, int n_IRQ, uint32_t val) 5887702e47cSPaolo Bonzini { 5897702e47cSPaolo Bonzini IRQSource *src = &opp->src[n_IRQ]; 5907702e47cSPaolo Bonzini uint32_t normal_mask = (1UL << opp->nb_cpus) - 1; 5917702e47cSPaolo Bonzini uint32_t crit_mask = 0; 5927702e47cSPaolo Bonzini uint32_t mask = normal_mask; 5937702e47cSPaolo Bonzini int crit_shift = IDR_EP_SHIFT - opp->nb_cpus; 5947702e47cSPaolo Bonzini int i; 5957702e47cSPaolo Bonzini 5967702e47cSPaolo Bonzini if (opp->flags & OPENPIC_FLAG_IDR_CRIT) { 5977702e47cSPaolo Bonzini crit_mask = mask << crit_shift; 5987702e47cSPaolo Bonzini mask |= crit_mask | IDR_EP; 5997702e47cSPaolo Bonzini } 6007702e47cSPaolo Bonzini 6017702e47cSPaolo Bonzini src->idr = val & mask; 6027702e47cSPaolo Bonzini DPRINTF("Set IDR %d to 0x%08x\n", n_IRQ, src->idr); 6037702e47cSPaolo Bonzini 6047702e47cSPaolo Bonzini if (opp->flags & OPENPIC_FLAG_IDR_CRIT) { 6057702e47cSPaolo Bonzini if (src->idr & crit_mask) { 6067702e47cSPaolo Bonzini if (src->idr & normal_mask) { 6077702e47cSPaolo Bonzini DPRINTF("%s: IRQ configured for multiple output types, using " 6087702e47cSPaolo Bonzini "critical\n", __func__); 6097702e47cSPaolo Bonzini } 6107702e47cSPaolo Bonzini 6117702e47cSPaolo Bonzini src->output = OPENPIC_OUTPUT_CINT; 6127702e47cSPaolo Bonzini src->nomask = true; 6137702e47cSPaolo Bonzini src->destmask = 0; 6147702e47cSPaolo Bonzini 6157702e47cSPaolo Bonzini for (i = 0; i < opp->nb_cpus; i++) { 6167702e47cSPaolo Bonzini int n_ci = IDR_CI0_SHIFT - i; 6177702e47cSPaolo Bonzini 6187702e47cSPaolo Bonzini if (src->idr & (1UL << n_ci)) { 6197702e47cSPaolo Bonzini src->destmask |= 1UL << i; 6207702e47cSPaolo Bonzini } 6217702e47cSPaolo Bonzini } 6227702e47cSPaolo Bonzini } else { 6237702e47cSPaolo Bonzini src->output = OPENPIC_OUTPUT_INT; 6247702e47cSPaolo Bonzini src->nomask = false; 6257702e47cSPaolo Bonzini src->destmask = src->idr & normal_mask; 6267702e47cSPaolo Bonzini } 6277702e47cSPaolo Bonzini } else { 6287702e47cSPaolo Bonzini src->destmask = src->idr; 6297702e47cSPaolo Bonzini } 6307702e47cSPaolo Bonzini } 6317702e47cSPaolo Bonzini 6327702e47cSPaolo Bonzini static inline void write_IRQreg_ilr(OpenPICState *opp, int n_IRQ, uint32_t val) 6337702e47cSPaolo Bonzini { 6347702e47cSPaolo Bonzini if (opp->flags & OPENPIC_FLAG_ILR) { 6357702e47cSPaolo Bonzini IRQSource *src = &opp->src[n_IRQ]; 6367702e47cSPaolo Bonzini 6377702e47cSPaolo Bonzini src->output = inttgt_to_output(val & ILR_INTTGT_MASK); 6387702e47cSPaolo Bonzini DPRINTF("Set ILR %d to 0x%08x, output %d\n", n_IRQ, src->idr, 6397702e47cSPaolo Bonzini src->output); 6407702e47cSPaolo Bonzini 6417702e47cSPaolo Bonzini /* TODO: on MPIC v4.0 only, set nomask for non-INT */ 6427702e47cSPaolo Bonzini } 6437702e47cSPaolo Bonzini } 6447702e47cSPaolo Bonzini 6457702e47cSPaolo Bonzini static inline void write_IRQreg_ivpr(OpenPICState *opp, int n_IRQ, uint32_t val) 6467702e47cSPaolo Bonzini { 6477702e47cSPaolo Bonzini uint32_t mask; 6487702e47cSPaolo Bonzini 6497702e47cSPaolo Bonzini /* NOTE when implementing newer FSL MPIC models: starting with v4.0, 6507702e47cSPaolo Bonzini * the polarity bit is read-only on internal interrupts. 6517702e47cSPaolo Bonzini */ 6527702e47cSPaolo Bonzini mask = IVPR_MASK_MASK | IVPR_PRIORITY_MASK | IVPR_SENSE_MASK | 6537702e47cSPaolo Bonzini IVPR_POLARITY_MASK | opp->vector_mask; 6547702e47cSPaolo Bonzini 6557702e47cSPaolo Bonzini /* ACTIVITY bit is read-only */ 6567702e47cSPaolo Bonzini opp->src[n_IRQ].ivpr = 6577702e47cSPaolo Bonzini (opp->src[n_IRQ].ivpr & IVPR_ACTIVITY_MASK) | (val & mask); 6587702e47cSPaolo Bonzini 6597702e47cSPaolo Bonzini /* For FSL internal interrupts, The sense bit is reserved and zero, 6607702e47cSPaolo Bonzini * and the interrupt is always level-triggered. Timers and IPIs 6617702e47cSPaolo Bonzini * have no sense or polarity bits, and are edge-triggered. 6627702e47cSPaolo Bonzini */ 6637702e47cSPaolo Bonzini switch (opp->src[n_IRQ].type) { 6647702e47cSPaolo Bonzini case IRQ_TYPE_NORMAL: 6657702e47cSPaolo Bonzini opp->src[n_IRQ].level = !!(opp->src[n_IRQ].ivpr & IVPR_SENSE_MASK); 6667702e47cSPaolo Bonzini break; 6677702e47cSPaolo Bonzini 6687702e47cSPaolo Bonzini case IRQ_TYPE_FSLINT: 6697702e47cSPaolo Bonzini opp->src[n_IRQ].ivpr &= ~IVPR_SENSE_MASK; 6707702e47cSPaolo Bonzini break; 6717702e47cSPaolo Bonzini 6727702e47cSPaolo Bonzini case IRQ_TYPE_FSLSPECIAL: 6737702e47cSPaolo Bonzini opp->src[n_IRQ].ivpr &= ~(IVPR_POLARITY_MASK | IVPR_SENSE_MASK); 6747702e47cSPaolo Bonzini break; 6757702e47cSPaolo Bonzini } 6767702e47cSPaolo Bonzini 6777702e47cSPaolo Bonzini openpic_update_irq(opp, n_IRQ); 6787702e47cSPaolo Bonzini DPRINTF("Set IVPR %d to 0x%08x -> 0x%08x\n", n_IRQ, val, 6797702e47cSPaolo Bonzini opp->src[n_IRQ].ivpr); 6807702e47cSPaolo Bonzini } 6817702e47cSPaolo Bonzini 6827702e47cSPaolo Bonzini static void openpic_gcr_write(OpenPICState *opp, uint64_t val) 6837702e47cSPaolo Bonzini { 6847702e47cSPaolo Bonzini bool mpic_proxy = false; 6857702e47cSPaolo Bonzini 6867702e47cSPaolo Bonzini if (val & GCR_RESET) { 687e1766344SAndreas Färber openpic_reset(DEVICE(opp)); 6887702e47cSPaolo Bonzini return; 6897702e47cSPaolo Bonzini } 6907702e47cSPaolo Bonzini 6917702e47cSPaolo Bonzini opp->gcr &= ~opp->mpic_mode_mask; 6927702e47cSPaolo Bonzini opp->gcr |= val & opp->mpic_mode_mask; 6937702e47cSPaolo Bonzini 6947702e47cSPaolo Bonzini /* Set external proxy mode */ 6957702e47cSPaolo Bonzini if ((val & opp->mpic_mode_mask) == GCR_MODE_PROXY) { 6967702e47cSPaolo Bonzini mpic_proxy = true; 6977702e47cSPaolo Bonzini } 6987702e47cSPaolo Bonzini 6997702e47cSPaolo Bonzini ppce500_set_mpic_proxy(mpic_proxy); 7007702e47cSPaolo Bonzini } 7017702e47cSPaolo Bonzini 7027702e47cSPaolo Bonzini static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val, 7037702e47cSPaolo Bonzini unsigned len) 7047702e47cSPaolo Bonzini { 7057702e47cSPaolo Bonzini OpenPICState *opp = opaque; 7067702e47cSPaolo Bonzini IRQDest *dst; 7077702e47cSPaolo Bonzini int idx; 7087702e47cSPaolo Bonzini 7097702e47cSPaolo Bonzini DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n", 7107702e47cSPaolo Bonzini __func__, addr, val); 7117702e47cSPaolo Bonzini if (addr & 0xF) { 7127702e47cSPaolo Bonzini return; 7137702e47cSPaolo Bonzini } 7147702e47cSPaolo Bonzini switch (addr) { 7157702e47cSPaolo Bonzini case 0x00: /* Block Revision Register1 (BRR1) is Readonly */ 7167702e47cSPaolo Bonzini break; 7177702e47cSPaolo Bonzini case 0x40: 7187702e47cSPaolo Bonzini case 0x50: 7197702e47cSPaolo Bonzini case 0x60: 7207702e47cSPaolo Bonzini case 0x70: 7217702e47cSPaolo Bonzini case 0x80: 7227702e47cSPaolo Bonzini case 0x90: 7237702e47cSPaolo Bonzini case 0xA0: 7247702e47cSPaolo Bonzini case 0xB0: 7257702e47cSPaolo Bonzini openpic_cpu_write_internal(opp, addr, val, get_current_cpu()); 7267702e47cSPaolo Bonzini break; 7277702e47cSPaolo Bonzini case 0x1000: /* FRR */ 7287702e47cSPaolo Bonzini break; 7297702e47cSPaolo Bonzini case 0x1020: /* GCR */ 7307702e47cSPaolo Bonzini openpic_gcr_write(opp, val); 7317702e47cSPaolo Bonzini break; 7327702e47cSPaolo Bonzini case 0x1080: /* VIR */ 7337702e47cSPaolo Bonzini break; 7347702e47cSPaolo Bonzini case 0x1090: /* PIR */ 7357702e47cSPaolo Bonzini for (idx = 0; idx < opp->nb_cpus; idx++) { 7367702e47cSPaolo Bonzini if ((val & (1 << idx)) && !(opp->pir & (1 << idx))) { 7377702e47cSPaolo Bonzini DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx); 7387702e47cSPaolo Bonzini dst = &opp->dst[idx]; 7397702e47cSPaolo Bonzini qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_RESET]); 7407702e47cSPaolo Bonzini } else if (!(val & (1 << idx)) && (opp->pir & (1 << idx))) { 7417702e47cSPaolo Bonzini DPRINTF("Lower OpenPIC RESET output for CPU %d\n", idx); 7427702e47cSPaolo Bonzini dst = &opp->dst[idx]; 7437702e47cSPaolo Bonzini qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_RESET]); 7447702e47cSPaolo Bonzini } 7457702e47cSPaolo Bonzini } 7467702e47cSPaolo Bonzini opp->pir = val; 7477702e47cSPaolo Bonzini break; 7487702e47cSPaolo Bonzini case 0x10A0: /* IPI_IVPR */ 7497702e47cSPaolo Bonzini case 0x10B0: 7507702e47cSPaolo Bonzini case 0x10C0: 7517702e47cSPaolo Bonzini case 0x10D0: 7527702e47cSPaolo Bonzini { 7537702e47cSPaolo Bonzini int idx; 7547702e47cSPaolo Bonzini idx = (addr - 0x10A0) >> 4; 7557702e47cSPaolo Bonzini write_IRQreg_ivpr(opp, opp->irq_ipi0 + idx, val); 7567702e47cSPaolo Bonzini } 7577702e47cSPaolo Bonzini break; 7587702e47cSPaolo Bonzini case 0x10E0: /* SPVE */ 7597702e47cSPaolo Bonzini opp->spve = val & opp->vector_mask; 7607702e47cSPaolo Bonzini break; 7617702e47cSPaolo Bonzini default: 7627702e47cSPaolo Bonzini break; 7637702e47cSPaolo Bonzini } 7647702e47cSPaolo Bonzini } 7657702e47cSPaolo Bonzini 7667702e47cSPaolo Bonzini static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len) 7677702e47cSPaolo Bonzini { 7687702e47cSPaolo Bonzini OpenPICState *opp = opaque; 7697702e47cSPaolo Bonzini uint32_t retval; 7707702e47cSPaolo Bonzini 7717702e47cSPaolo Bonzini DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); 7727702e47cSPaolo Bonzini retval = 0xFFFFFFFF; 7737702e47cSPaolo Bonzini if (addr & 0xF) { 7747702e47cSPaolo Bonzini return retval; 7757702e47cSPaolo Bonzini } 7767702e47cSPaolo Bonzini switch (addr) { 7777702e47cSPaolo Bonzini case 0x1000: /* FRR */ 7787702e47cSPaolo Bonzini retval = opp->frr; 7797702e47cSPaolo Bonzini break; 7807702e47cSPaolo Bonzini case 0x1020: /* GCR */ 7817702e47cSPaolo Bonzini retval = opp->gcr; 7827702e47cSPaolo Bonzini break; 7837702e47cSPaolo Bonzini case 0x1080: /* VIR */ 7847702e47cSPaolo Bonzini retval = opp->vir; 7857702e47cSPaolo Bonzini break; 7867702e47cSPaolo Bonzini case 0x1090: /* PIR */ 7877702e47cSPaolo Bonzini retval = 0x00000000; 7887702e47cSPaolo Bonzini break; 7897702e47cSPaolo Bonzini case 0x00: /* Block Revision Register1 (BRR1) */ 7907702e47cSPaolo Bonzini retval = opp->brr1; 7917702e47cSPaolo Bonzini break; 7927702e47cSPaolo Bonzini case 0x40: 7937702e47cSPaolo Bonzini case 0x50: 7947702e47cSPaolo Bonzini case 0x60: 7957702e47cSPaolo Bonzini case 0x70: 7967702e47cSPaolo Bonzini case 0x80: 7977702e47cSPaolo Bonzini case 0x90: 7987702e47cSPaolo Bonzini case 0xA0: 7997702e47cSPaolo Bonzini case 0xB0: 8007702e47cSPaolo Bonzini retval = openpic_cpu_read_internal(opp, addr, get_current_cpu()); 8017702e47cSPaolo Bonzini break; 8027702e47cSPaolo Bonzini case 0x10A0: /* IPI_IVPR */ 8037702e47cSPaolo Bonzini case 0x10B0: 8047702e47cSPaolo Bonzini case 0x10C0: 8057702e47cSPaolo Bonzini case 0x10D0: 8067702e47cSPaolo Bonzini { 8077702e47cSPaolo Bonzini int idx; 8087702e47cSPaolo Bonzini idx = (addr - 0x10A0) >> 4; 8097702e47cSPaolo Bonzini retval = read_IRQreg_ivpr(opp, opp->irq_ipi0 + idx); 8107702e47cSPaolo Bonzini } 8117702e47cSPaolo Bonzini break; 8127702e47cSPaolo Bonzini case 0x10E0: /* SPVE */ 8137702e47cSPaolo Bonzini retval = opp->spve; 8147702e47cSPaolo Bonzini break; 8157702e47cSPaolo Bonzini default: 8167702e47cSPaolo Bonzini break; 8177702e47cSPaolo Bonzini } 8187702e47cSPaolo Bonzini DPRINTF("%s: => 0x%08x\n", __func__, retval); 8197702e47cSPaolo Bonzini 8207702e47cSPaolo Bonzini return retval; 8217702e47cSPaolo Bonzini } 8227702e47cSPaolo Bonzini 823*ddd5140bSAaron Larson static void openpic_tmr_set_tmr(OpenPICTimer *tmr, uint32_t val, bool enabled); 824*ddd5140bSAaron Larson 825*ddd5140bSAaron Larson static void qemu_timer_cb(void *opaque) 826*ddd5140bSAaron Larson { 827*ddd5140bSAaron Larson OpenPICTimer *tmr = opaque; 828*ddd5140bSAaron Larson OpenPICState *opp = tmr->opp; 829*ddd5140bSAaron Larson uint32_t n_IRQ = tmr->n_IRQ; 830*ddd5140bSAaron Larson uint32_t val = tmr->tbcr & ~TBCR_CI; 831*ddd5140bSAaron Larson uint32_t tog = ((tmr->tccr & TCCR_TOG) ^ TCCR_TOG); /* invert toggle. */ 832*ddd5140bSAaron Larson 833*ddd5140bSAaron Larson DPRINTF("%s n_IRQ=%d\n", __func__, n_IRQ); 834*ddd5140bSAaron Larson /* Reload current count from base count and setup timer. */ 835*ddd5140bSAaron Larson tmr->tccr = val | tog; 836*ddd5140bSAaron Larson openpic_tmr_set_tmr(tmr, val, /*enabled=*/true); 837*ddd5140bSAaron Larson /* Raise the interrupt. */ 838*ddd5140bSAaron Larson opp->src[n_IRQ].destmask = read_IRQreg_idr(opp, n_IRQ); 839*ddd5140bSAaron Larson openpic_set_irq(opp, n_IRQ, 1); 840*ddd5140bSAaron Larson openpic_set_irq(opp, n_IRQ, 0); 841*ddd5140bSAaron Larson } 842*ddd5140bSAaron Larson 843*ddd5140bSAaron Larson /* If enabled is true, arranges for an interrupt to be raised val clocks into 844*ddd5140bSAaron Larson the future, if enabled is false cancels the timer. */ 845*ddd5140bSAaron Larson static void openpic_tmr_set_tmr(OpenPICTimer *tmr, uint32_t val, bool enabled) 846*ddd5140bSAaron Larson { 847*ddd5140bSAaron Larson uint64_t ns = ticks_to_ns(val & ~TCCR_TOG); 848*ddd5140bSAaron Larson /* A count of zero causes a timer to be set to expire immediately. This 849*ddd5140bSAaron Larson effectively stops the simulation since the timer is constantly expiring 850*ddd5140bSAaron Larson which prevents guest code execution, so we don't honor that 851*ddd5140bSAaron Larson configuration. On real hardware, this situation would generate an 852*ddd5140bSAaron Larson interrupt on every clock cycle if the interrupt was unmasked. */ 853*ddd5140bSAaron Larson if ((ns == 0) || !enabled) { 854*ddd5140bSAaron Larson tmr->qemu_timer_active = false; 855*ddd5140bSAaron Larson tmr->tccr = tmr->tccr & TCCR_TOG; 856*ddd5140bSAaron Larson timer_del(tmr->qemu_timer); /* set timer to never expire. */ 857*ddd5140bSAaron Larson } else { 858*ddd5140bSAaron Larson tmr->qemu_timer_active = true; 859*ddd5140bSAaron Larson uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 860*ddd5140bSAaron Larson tmr->origin_time = now; 861*ddd5140bSAaron Larson timer_mod(tmr->qemu_timer, now + ns); /* set timer expiration. */ 862*ddd5140bSAaron Larson } 863*ddd5140bSAaron Larson } 864*ddd5140bSAaron Larson 865*ddd5140bSAaron Larson /* Returns the currrent tccr value, i.e., timer value (in clocks) with 866*ddd5140bSAaron Larson appropriate TOG. */ 867*ddd5140bSAaron Larson static uint64_t openpic_tmr_get_timer(OpenPICTimer *tmr) 868*ddd5140bSAaron Larson { 869*ddd5140bSAaron Larson uint64_t retval; 870*ddd5140bSAaron Larson if (!tmr->qemu_timer_active) { 871*ddd5140bSAaron Larson retval = tmr->tccr; 872*ddd5140bSAaron Larson } else { 873*ddd5140bSAaron Larson uint64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); 874*ddd5140bSAaron Larson uint64_t used = now - tmr->origin_time; /* nsecs */ 875*ddd5140bSAaron Larson uint32_t used_ticks = (uint32_t)ns_to_ticks(used); 876*ddd5140bSAaron Larson uint32_t count = (tmr->tccr & ~TCCR_TOG) - used_ticks; 877*ddd5140bSAaron Larson retval = (uint32_t)((tmr->tccr & TCCR_TOG) | (count & ~TCCR_TOG)); 878*ddd5140bSAaron Larson } 879*ddd5140bSAaron Larson return retval; 880*ddd5140bSAaron Larson } 881*ddd5140bSAaron Larson 8827702e47cSPaolo Bonzini static void openpic_tmr_write(void *opaque, hwaddr addr, uint64_t val, 8837702e47cSPaolo Bonzini unsigned len) 8847702e47cSPaolo Bonzini { 8857702e47cSPaolo Bonzini OpenPICState *opp = opaque; 8867702e47cSPaolo Bonzini int idx; 8877702e47cSPaolo Bonzini 8887702e47cSPaolo Bonzini DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n", 889a09f7443SAaron Larson __func__, (addr + 0x10f0), val); 8907702e47cSPaolo Bonzini if (addr & 0xF) { 8917702e47cSPaolo Bonzini return; 8927702e47cSPaolo Bonzini } 8937702e47cSPaolo Bonzini 894a09f7443SAaron Larson if (addr == 0) { 8957702e47cSPaolo Bonzini /* TFRR */ 8967702e47cSPaolo Bonzini opp->tfrr = val; 8977702e47cSPaolo Bonzini return; 8987702e47cSPaolo Bonzini } 899a09f7443SAaron Larson addr -= 0x10; /* correct for TFRR */ 9007702e47cSPaolo Bonzini idx = (addr >> 6) & 0x3; 9017702e47cSPaolo Bonzini 9027702e47cSPaolo Bonzini switch (addr & 0x30) { 9037702e47cSPaolo Bonzini case 0x00: /* TCCR */ 9047702e47cSPaolo Bonzini break; 9057702e47cSPaolo Bonzini case 0x10: /* TBCR */ 906*ddd5140bSAaron Larson /* Did the enable status change? */ 907*ddd5140bSAaron Larson if ((opp->timers[idx].tbcr & TBCR_CI) != (val & TBCR_CI)) { 908*ddd5140bSAaron Larson /* Did "Count Inhibit" transition from 1 to 0? */ 909*ddd5140bSAaron Larson if ((val & TBCR_CI) == 0) { 910*ddd5140bSAaron Larson opp->timers[idx].tccr = val & ~TCCR_TOG; 911*ddd5140bSAaron Larson } 912*ddd5140bSAaron Larson openpic_tmr_set_tmr(&opp->timers[idx], 913*ddd5140bSAaron Larson (val & ~TBCR_CI), 914*ddd5140bSAaron Larson /*enabled=*/((val & TBCR_CI) == 0)); 9157702e47cSPaolo Bonzini } 9167702e47cSPaolo Bonzini opp->timers[idx].tbcr = val; 9177702e47cSPaolo Bonzini break; 9187702e47cSPaolo Bonzini case 0x20: /* TVPR */ 9197702e47cSPaolo Bonzini write_IRQreg_ivpr(opp, opp->irq_tim0 + idx, val); 9207702e47cSPaolo Bonzini break; 9217702e47cSPaolo Bonzini case 0x30: /* TDR */ 9227702e47cSPaolo Bonzini write_IRQreg_idr(opp, opp->irq_tim0 + idx, val); 9237702e47cSPaolo Bonzini break; 9247702e47cSPaolo Bonzini } 9257702e47cSPaolo Bonzini } 9267702e47cSPaolo Bonzini 9277702e47cSPaolo Bonzini static uint64_t openpic_tmr_read(void *opaque, hwaddr addr, unsigned len) 9287702e47cSPaolo Bonzini { 9297702e47cSPaolo Bonzini OpenPICState *opp = opaque; 9307702e47cSPaolo Bonzini uint32_t retval = -1; 9317702e47cSPaolo Bonzini int idx; 9327702e47cSPaolo Bonzini 933a09f7443SAaron Larson DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr + 0x10f0); 9347702e47cSPaolo Bonzini if (addr & 0xF) { 9357702e47cSPaolo Bonzini goto out; 9367702e47cSPaolo Bonzini } 937a09f7443SAaron Larson if (addr == 0) { 9387702e47cSPaolo Bonzini /* TFRR */ 9397702e47cSPaolo Bonzini retval = opp->tfrr; 9407702e47cSPaolo Bonzini goto out; 9417702e47cSPaolo Bonzini } 942a09f7443SAaron Larson addr -= 0x10; /* correct for TFRR */ 943a09f7443SAaron Larson idx = (addr >> 6) & 0x3; 9447702e47cSPaolo Bonzini switch (addr & 0x30) { 9457702e47cSPaolo Bonzini case 0x00: /* TCCR */ 946*ddd5140bSAaron Larson retval = openpic_tmr_get_timer(&opp->timers[idx]); 9477702e47cSPaolo Bonzini break; 9487702e47cSPaolo Bonzini case 0x10: /* TBCR */ 9497702e47cSPaolo Bonzini retval = opp->timers[idx].tbcr; 9507702e47cSPaolo Bonzini break; 951a09f7443SAaron Larson case 0x20: /* TVPR */ 9527702e47cSPaolo Bonzini retval = read_IRQreg_ivpr(opp, opp->irq_tim0 + idx); 9537702e47cSPaolo Bonzini break; 954a09f7443SAaron Larson case 0x30: /* TDR */ 9557702e47cSPaolo Bonzini retval = read_IRQreg_idr(opp, opp->irq_tim0 + idx); 9567702e47cSPaolo Bonzini break; 9577702e47cSPaolo Bonzini } 9587702e47cSPaolo Bonzini 9597702e47cSPaolo Bonzini out: 9607702e47cSPaolo Bonzini DPRINTF("%s: => 0x%08x\n", __func__, retval); 9617702e47cSPaolo Bonzini 9627702e47cSPaolo Bonzini return retval; 9637702e47cSPaolo Bonzini } 9647702e47cSPaolo Bonzini 9657702e47cSPaolo Bonzini static void openpic_src_write(void *opaque, hwaddr addr, uint64_t val, 9667702e47cSPaolo Bonzini unsigned len) 9677702e47cSPaolo Bonzini { 9687702e47cSPaolo Bonzini OpenPICState *opp = opaque; 9697702e47cSPaolo Bonzini int idx; 9707702e47cSPaolo Bonzini 9717702e47cSPaolo Bonzini DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n", 9727702e47cSPaolo Bonzini __func__, addr, val); 9737702e47cSPaolo Bonzini 9747702e47cSPaolo Bonzini addr = addr & 0xffff; 9757702e47cSPaolo Bonzini idx = addr >> 5; 9767702e47cSPaolo Bonzini 9777702e47cSPaolo Bonzini switch (addr & 0x1f) { 9787702e47cSPaolo Bonzini case 0x00: 9797702e47cSPaolo Bonzini write_IRQreg_ivpr(opp, idx, val); 9807702e47cSPaolo Bonzini break; 9817702e47cSPaolo Bonzini case 0x10: 9827702e47cSPaolo Bonzini write_IRQreg_idr(opp, idx, val); 9837702e47cSPaolo Bonzini break; 9847702e47cSPaolo Bonzini case 0x18: 9857702e47cSPaolo Bonzini write_IRQreg_ilr(opp, idx, val); 9867702e47cSPaolo Bonzini break; 9877702e47cSPaolo Bonzini } 9887702e47cSPaolo Bonzini } 9897702e47cSPaolo Bonzini 9907702e47cSPaolo Bonzini static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len) 9917702e47cSPaolo Bonzini { 9927702e47cSPaolo Bonzini OpenPICState *opp = opaque; 9937702e47cSPaolo Bonzini uint32_t retval; 9947702e47cSPaolo Bonzini int idx; 9957702e47cSPaolo Bonzini 9967702e47cSPaolo Bonzini DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); 9977702e47cSPaolo Bonzini retval = 0xFFFFFFFF; 9987702e47cSPaolo Bonzini 9997702e47cSPaolo Bonzini addr = addr & 0xffff; 10007702e47cSPaolo Bonzini idx = addr >> 5; 10017702e47cSPaolo Bonzini 10027702e47cSPaolo Bonzini switch (addr & 0x1f) { 10037702e47cSPaolo Bonzini case 0x00: 10047702e47cSPaolo Bonzini retval = read_IRQreg_ivpr(opp, idx); 10057702e47cSPaolo Bonzini break; 10067702e47cSPaolo Bonzini case 0x10: 10077702e47cSPaolo Bonzini retval = read_IRQreg_idr(opp, idx); 10087702e47cSPaolo Bonzini break; 10097702e47cSPaolo Bonzini case 0x18: 10107702e47cSPaolo Bonzini retval = read_IRQreg_ilr(opp, idx); 10117702e47cSPaolo Bonzini break; 10127702e47cSPaolo Bonzini } 10137702e47cSPaolo Bonzini 10147702e47cSPaolo Bonzini DPRINTF("%s: => 0x%08x\n", __func__, retval); 10157702e47cSPaolo Bonzini return retval; 10167702e47cSPaolo Bonzini } 10177702e47cSPaolo Bonzini 10187702e47cSPaolo Bonzini static void openpic_msi_write(void *opaque, hwaddr addr, uint64_t val, 10197702e47cSPaolo Bonzini unsigned size) 10207702e47cSPaolo Bonzini { 10217702e47cSPaolo Bonzini OpenPICState *opp = opaque; 10227702e47cSPaolo Bonzini int idx = opp->irq_msi; 10237702e47cSPaolo Bonzini int srs, ibs; 10247702e47cSPaolo Bonzini 10257702e47cSPaolo Bonzini DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64 "\n", 10267702e47cSPaolo Bonzini __func__, addr, val); 10277702e47cSPaolo Bonzini if (addr & 0xF) { 10287702e47cSPaolo Bonzini return; 10297702e47cSPaolo Bonzini } 10307702e47cSPaolo Bonzini 10317702e47cSPaolo Bonzini switch (addr) { 10327702e47cSPaolo Bonzini case MSIIR_OFFSET: 10337702e47cSPaolo Bonzini srs = val >> MSIIR_SRS_SHIFT; 10347702e47cSPaolo Bonzini idx += srs; 10357702e47cSPaolo Bonzini ibs = (val & MSIIR_IBS_MASK) >> MSIIR_IBS_SHIFT; 10367702e47cSPaolo Bonzini opp->msi[srs].msir |= 1 << ibs; 10377702e47cSPaolo Bonzini openpic_set_irq(opp, idx, 1); 10387702e47cSPaolo Bonzini break; 10397702e47cSPaolo Bonzini default: 10407702e47cSPaolo Bonzini /* most registers are read-only, thus ignored */ 10417702e47cSPaolo Bonzini break; 10427702e47cSPaolo Bonzini } 10437702e47cSPaolo Bonzini } 10447702e47cSPaolo Bonzini 10457702e47cSPaolo Bonzini static uint64_t openpic_msi_read(void *opaque, hwaddr addr, unsigned size) 10467702e47cSPaolo Bonzini { 10477702e47cSPaolo Bonzini OpenPICState *opp = opaque; 10487702e47cSPaolo Bonzini uint64_t r = 0; 10497702e47cSPaolo Bonzini int i, srs; 10507702e47cSPaolo Bonzini 10517702e47cSPaolo Bonzini DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); 10527702e47cSPaolo Bonzini if (addr & 0xF) { 10537702e47cSPaolo Bonzini return -1; 10547702e47cSPaolo Bonzini } 10557702e47cSPaolo Bonzini 10567702e47cSPaolo Bonzini srs = addr >> 4; 10577702e47cSPaolo Bonzini 10587702e47cSPaolo Bonzini switch (addr) { 10597702e47cSPaolo Bonzini case 0x00: 10607702e47cSPaolo Bonzini case 0x10: 10617702e47cSPaolo Bonzini case 0x20: 10627702e47cSPaolo Bonzini case 0x30: 10637702e47cSPaolo Bonzini case 0x40: 10647702e47cSPaolo Bonzini case 0x50: 10657702e47cSPaolo Bonzini case 0x60: 10667702e47cSPaolo Bonzini case 0x70: /* MSIRs */ 10677702e47cSPaolo Bonzini r = opp->msi[srs].msir; 10687702e47cSPaolo Bonzini /* Clear on read */ 10697702e47cSPaolo Bonzini opp->msi[srs].msir = 0; 10707702e47cSPaolo Bonzini openpic_set_irq(opp, opp->irq_msi + srs, 0); 10717702e47cSPaolo Bonzini break; 10727702e47cSPaolo Bonzini case 0x120: /* MSISR */ 10737702e47cSPaolo Bonzini for (i = 0; i < MAX_MSI; i++) { 10747702e47cSPaolo Bonzini r |= (opp->msi[i].msir ? 1 : 0) << i; 10757702e47cSPaolo Bonzini } 10767702e47cSPaolo Bonzini break; 10777702e47cSPaolo Bonzini } 10787702e47cSPaolo Bonzini 10797702e47cSPaolo Bonzini return r; 10807702e47cSPaolo Bonzini } 10817702e47cSPaolo Bonzini 10827702e47cSPaolo Bonzini static uint64_t openpic_summary_read(void *opaque, hwaddr addr, unsigned size) 10837702e47cSPaolo Bonzini { 10847702e47cSPaolo Bonzini uint64_t r = 0; 10857702e47cSPaolo Bonzini 10867702e47cSPaolo Bonzini DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); 10877702e47cSPaolo Bonzini 10887702e47cSPaolo Bonzini /* TODO: EISR/EIMR */ 10897702e47cSPaolo Bonzini 10907702e47cSPaolo Bonzini return r; 10917702e47cSPaolo Bonzini } 10927702e47cSPaolo Bonzini 10937702e47cSPaolo Bonzini static void openpic_summary_write(void *opaque, hwaddr addr, uint64_t val, 10947702e47cSPaolo Bonzini unsigned size) 10957702e47cSPaolo Bonzini { 10967702e47cSPaolo Bonzini DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64 "\n", 10977702e47cSPaolo Bonzini __func__, addr, val); 10987702e47cSPaolo Bonzini 10997702e47cSPaolo Bonzini /* TODO: EISR/EIMR */ 11007702e47cSPaolo Bonzini } 11017702e47cSPaolo Bonzini 11027702e47cSPaolo Bonzini static void openpic_cpu_write_internal(void *opaque, hwaddr addr, 11037702e47cSPaolo Bonzini uint32_t val, int idx) 11047702e47cSPaolo Bonzini { 11057702e47cSPaolo Bonzini OpenPICState *opp = opaque; 11067702e47cSPaolo Bonzini IRQSource *src; 11077702e47cSPaolo Bonzini IRQDest *dst; 11087702e47cSPaolo Bonzini int s_IRQ, n_IRQ; 11097702e47cSPaolo Bonzini 11107702e47cSPaolo Bonzini DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx " <= 0x%08x\n", __func__, idx, 11117702e47cSPaolo Bonzini addr, val); 11127702e47cSPaolo Bonzini 111304d2acbbSFabien Chouteau if (idx < 0 || idx >= opp->nb_cpus) { 11147702e47cSPaolo Bonzini return; 11157702e47cSPaolo Bonzini } 11167702e47cSPaolo Bonzini 11177702e47cSPaolo Bonzini if (addr & 0xF) { 11187702e47cSPaolo Bonzini return; 11197702e47cSPaolo Bonzini } 11207702e47cSPaolo Bonzini dst = &opp->dst[idx]; 11217702e47cSPaolo Bonzini addr &= 0xFF0; 11227702e47cSPaolo Bonzini switch (addr) { 11237702e47cSPaolo Bonzini case 0x40: /* IPIDR */ 11247702e47cSPaolo Bonzini case 0x50: 11257702e47cSPaolo Bonzini case 0x60: 11267702e47cSPaolo Bonzini case 0x70: 11277702e47cSPaolo Bonzini idx = (addr - 0x40) >> 4; 11287702e47cSPaolo Bonzini /* we use IDE as mask which CPUs to deliver the IPI to still. */ 11297702e47cSPaolo Bonzini opp->src[opp->irq_ipi0 + idx].destmask |= val; 11307702e47cSPaolo Bonzini openpic_set_irq(opp, opp->irq_ipi0 + idx, 1); 11317702e47cSPaolo Bonzini openpic_set_irq(opp, opp->irq_ipi0 + idx, 0); 11327702e47cSPaolo Bonzini break; 11337702e47cSPaolo Bonzini case 0x80: /* CTPR */ 11347702e47cSPaolo Bonzini dst->ctpr = val & 0x0000000F; 11357702e47cSPaolo Bonzini 11367702e47cSPaolo Bonzini DPRINTF("%s: set CPU %d ctpr to %d, raised %d servicing %d\n", 11377702e47cSPaolo Bonzini __func__, idx, dst->ctpr, dst->raised.priority, 11387702e47cSPaolo Bonzini dst->servicing.priority); 11397702e47cSPaolo Bonzini 11407702e47cSPaolo Bonzini if (dst->raised.priority <= dst->ctpr) { 11417702e47cSPaolo Bonzini DPRINTF("%s: Lower OpenPIC INT output cpu %d due to ctpr\n", 11427702e47cSPaolo Bonzini __func__, idx); 11437702e47cSPaolo Bonzini qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]); 11447702e47cSPaolo Bonzini } else if (dst->raised.priority > dst->servicing.priority) { 11457702e47cSPaolo Bonzini DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d\n", 11467702e47cSPaolo Bonzini __func__, idx, dst->raised.next); 11477702e47cSPaolo Bonzini qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]); 11487702e47cSPaolo Bonzini } 11497702e47cSPaolo Bonzini 11507702e47cSPaolo Bonzini break; 11517702e47cSPaolo Bonzini case 0x90: /* WHOAMI */ 11527702e47cSPaolo Bonzini /* Read-only register */ 11537702e47cSPaolo Bonzini break; 11547702e47cSPaolo Bonzini case 0xA0: /* IACK */ 11557702e47cSPaolo Bonzini /* Read-only register */ 11567702e47cSPaolo Bonzini break; 11577702e47cSPaolo Bonzini case 0xB0: /* EOI */ 11587702e47cSPaolo Bonzini DPRINTF("EOI\n"); 11597702e47cSPaolo Bonzini s_IRQ = IRQ_get_next(opp, &dst->servicing); 11607702e47cSPaolo Bonzini 11617702e47cSPaolo Bonzini if (s_IRQ < 0) { 11627702e47cSPaolo Bonzini DPRINTF("%s: EOI with no interrupt in service\n", __func__); 11637702e47cSPaolo Bonzini break; 11647702e47cSPaolo Bonzini } 11657702e47cSPaolo Bonzini 11667702e47cSPaolo Bonzini IRQ_resetbit(&dst->servicing, s_IRQ); 11677702e47cSPaolo Bonzini /* Set up next servicing IRQ */ 11687702e47cSPaolo Bonzini s_IRQ = IRQ_get_next(opp, &dst->servicing); 11697702e47cSPaolo Bonzini /* Check queued interrupts. */ 11707702e47cSPaolo Bonzini n_IRQ = IRQ_get_next(opp, &dst->raised); 11717702e47cSPaolo Bonzini src = &opp->src[n_IRQ]; 11727702e47cSPaolo Bonzini if (n_IRQ != -1 && 11737702e47cSPaolo Bonzini (s_IRQ == -1 || 11747702e47cSPaolo Bonzini IVPR_PRIORITY(src->ivpr) > dst->servicing.priority)) { 11757702e47cSPaolo Bonzini DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", 11767702e47cSPaolo Bonzini idx, n_IRQ); 11777702e47cSPaolo Bonzini qemu_irq_raise(opp->dst[idx].irqs[OPENPIC_OUTPUT_INT]); 11787702e47cSPaolo Bonzini } 11797702e47cSPaolo Bonzini break; 11807702e47cSPaolo Bonzini default: 11817702e47cSPaolo Bonzini break; 11827702e47cSPaolo Bonzini } 11837702e47cSPaolo Bonzini } 11847702e47cSPaolo Bonzini 11857702e47cSPaolo Bonzini static void openpic_cpu_write(void *opaque, hwaddr addr, uint64_t val, 11867702e47cSPaolo Bonzini unsigned len) 11877702e47cSPaolo Bonzini { 11887702e47cSPaolo Bonzini openpic_cpu_write_internal(opaque, addr, val, (addr & 0x1f000) >> 12); 11897702e47cSPaolo Bonzini } 11907702e47cSPaolo Bonzini 11917702e47cSPaolo Bonzini 11927702e47cSPaolo Bonzini static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu) 11937702e47cSPaolo Bonzini { 11947702e47cSPaolo Bonzini IRQSource *src; 11957702e47cSPaolo Bonzini int retval, irq; 11967702e47cSPaolo Bonzini 11977702e47cSPaolo Bonzini DPRINTF("Lower OpenPIC INT output\n"); 11987702e47cSPaolo Bonzini qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]); 11997702e47cSPaolo Bonzini 12007702e47cSPaolo Bonzini irq = IRQ_get_next(opp, &dst->raised); 12017702e47cSPaolo Bonzini DPRINTF("IACK: irq=%d\n", irq); 12027702e47cSPaolo Bonzini 12037702e47cSPaolo Bonzini if (irq == -1) { 12047702e47cSPaolo Bonzini /* No more interrupt pending */ 12057702e47cSPaolo Bonzini return opp->spve; 12067702e47cSPaolo Bonzini } 12077702e47cSPaolo Bonzini 12087702e47cSPaolo Bonzini src = &opp->src[irq]; 12097702e47cSPaolo Bonzini if (!(src->ivpr & IVPR_ACTIVITY_MASK) || 12107702e47cSPaolo Bonzini !(IVPR_PRIORITY(src->ivpr) > dst->ctpr)) { 12117702e47cSPaolo Bonzini fprintf(stderr, "%s: bad raised IRQ %d ctpr %d ivpr 0x%08x\n", 12127702e47cSPaolo Bonzini __func__, irq, dst->ctpr, src->ivpr); 12137702e47cSPaolo Bonzini openpic_update_irq(opp, irq); 12147702e47cSPaolo Bonzini retval = opp->spve; 12157702e47cSPaolo Bonzini } else { 12167702e47cSPaolo Bonzini /* IRQ enter servicing state */ 12177702e47cSPaolo Bonzini IRQ_setbit(&dst->servicing, irq); 12187702e47cSPaolo Bonzini retval = IVPR_VECTOR(opp, src->ivpr); 12197702e47cSPaolo Bonzini } 12207702e47cSPaolo Bonzini 12217702e47cSPaolo Bonzini if (!src->level) { 12227702e47cSPaolo Bonzini /* edge-sensitive IRQ */ 12237702e47cSPaolo Bonzini src->ivpr &= ~IVPR_ACTIVITY_MASK; 12247702e47cSPaolo Bonzini src->pending = 0; 12257702e47cSPaolo Bonzini IRQ_resetbit(&dst->raised, irq); 12267702e47cSPaolo Bonzini } 12277702e47cSPaolo Bonzini 1228*ddd5140bSAaron Larson /* Timers and IPIs support multicast. */ 1229*ddd5140bSAaron Larson if (((irq >= opp->irq_ipi0) && (irq < (opp->irq_ipi0 + OPENPIC_MAX_IPI))) || 1230*ddd5140bSAaron Larson ((irq >= opp->irq_tim0) && (irq < (opp->irq_tim0 + OPENPIC_MAX_TMR)))) { 1231*ddd5140bSAaron Larson DPRINTF("irq is IPI or TMR\n"); 12327702e47cSPaolo Bonzini src->destmask &= ~(1 << cpu); 12337702e47cSPaolo Bonzini if (src->destmask && !src->level) { 12347702e47cSPaolo Bonzini /* trigger on CPUs that didn't know about it yet */ 12357702e47cSPaolo Bonzini openpic_set_irq(opp, irq, 1); 12367702e47cSPaolo Bonzini openpic_set_irq(opp, irq, 0); 12377702e47cSPaolo Bonzini /* if all CPUs knew about it, set active bit again */ 12387702e47cSPaolo Bonzini src->ivpr |= IVPR_ACTIVITY_MASK; 12397702e47cSPaolo Bonzini } 12407702e47cSPaolo Bonzini } 12417702e47cSPaolo Bonzini 12427702e47cSPaolo Bonzini return retval; 12437702e47cSPaolo Bonzini } 12447702e47cSPaolo Bonzini 12457702e47cSPaolo Bonzini static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, 12467702e47cSPaolo Bonzini int idx) 12477702e47cSPaolo Bonzini { 12487702e47cSPaolo Bonzini OpenPICState *opp = opaque; 12497702e47cSPaolo Bonzini IRQDest *dst; 12507702e47cSPaolo Bonzini uint32_t retval; 12517702e47cSPaolo Bonzini 12527702e47cSPaolo Bonzini DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx "\n", __func__, idx, addr); 12537702e47cSPaolo Bonzini retval = 0xFFFFFFFF; 12547702e47cSPaolo Bonzini 125504d2acbbSFabien Chouteau if (idx < 0 || idx >= opp->nb_cpus) { 12567702e47cSPaolo Bonzini return retval; 12577702e47cSPaolo Bonzini } 12587702e47cSPaolo Bonzini 12597702e47cSPaolo Bonzini if (addr & 0xF) { 12607702e47cSPaolo Bonzini return retval; 12617702e47cSPaolo Bonzini } 12627702e47cSPaolo Bonzini dst = &opp->dst[idx]; 12637702e47cSPaolo Bonzini addr &= 0xFF0; 12647702e47cSPaolo Bonzini switch (addr) { 12657702e47cSPaolo Bonzini case 0x80: /* CTPR */ 12667702e47cSPaolo Bonzini retval = dst->ctpr; 12677702e47cSPaolo Bonzini break; 12687702e47cSPaolo Bonzini case 0x90: /* WHOAMI */ 12697702e47cSPaolo Bonzini retval = idx; 12707702e47cSPaolo Bonzini break; 12717702e47cSPaolo Bonzini case 0xA0: /* IACK */ 12727702e47cSPaolo Bonzini retval = openpic_iack(opp, dst, idx); 12737702e47cSPaolo Bonzini break; 12747702e47cSPaolo Bonzini case 0xB0: /* EOI */ 12757702e47cSPaolo Bonzini retval = 0; 12767702e47cSPaolo Bonzini break; 12777702e47cSPaolo Bonzini default: 12787702e47cSPaolo Bonzini break; 12797702e47cSPaolo Bonzini } 12807702e47cSPaolo Bonzini DPRINTF("%s: => 0x%08x\n", __func__, retval); 12817702e47cSPaolo Bonzini 12827702e47cSPaolo Bonzini return retval; 12837702e47cSPaolo Bonzini } 12847702e47cSPaolo Bonzini 12857702e47cSPaolo Bonzini static uint64_t openpic_cpu_read(void *opaque, hwaddr addr, unsigned len) 12867702e47cSPaolo Bonzini { 12877702e47cSPaolo Bonzini return openpic_cpu_read_internal(opaque, addr, (addr & 0x1f000) >> 12); 12887702e47cSPaolo Bonzini } 12897702e47cSPaolo Bonzini 12907702e47cSPaolo Bonzini static const MemoryRegionOps openpic_glb_ops_le = { 12917702e47cSPaolo Bonzini .write = openpic_gbl_write, 12927702e47cSPaolo Bonzini .read = openpic_gbl_read, 12937702e47cSPaolo Bonzini .endianness = DEVICE_LITTLE_ENDIAN, 12947702e47cSPaolo Bonzini .impl = { 12957702e47cSPaolo Bonzini .min_access_size = 4, 12967702e47cSPaolo Bonzini .max_access_size = 4, 12977702e47cSPaolo Bonzini }, 12987702e47cSPaolo Bonzini }; 12997702e47cSPaolo Bonzini 13007702e47cSPaolo Bonzini static const MemoryRegionOps openpic_glb_ops_be = { 13017702e47cSPaolo Bonzini .write = openpic_gbl_write, 13027702e47cSPaolo Bonzini .read = openpic_gbl_read, 13037702e47cSPaolo Bonzini .endianness = DEVICE_BIG_ENDIAN, 13047702e47cSPaolo Bonzini .impl = { 13057702e47cSPaolo Bonzini .min_access_size = 4, 13067702e47cSPaolo Bonzini .max_access_size = 4, 13077702e47cSPaolo Bonzini }, 13087702e47cSPaolo Bonzini }; 13097702e47cSPaolo Bonzini 13107702e47cSPaolo Bonzini static const MemoryRegionOps openpic_tmr_ops_le = { 13117702e47cSPaolo Bonzini .write = openpic_tmr_write, 13127702e47cSPaolo Bonzini .read = openpic_tmr_read, 13137702e47cSPaolo Bonzini .endianness = DEVICE_LITTLE_ENDIAN, 13147702e47cSPaolo Bonzini .impl = { 13157702e47cSPaolo Bonzini .min_access_size = 4, 13167702e47cSPaolo Bonzini .max_access_size = 4, 13177702e47cSPaolo Bonzini }, 13187702e47cSPaolo Bonzini }; 13197702e47cSPaolo Bonzini 13207702e47cSPaolo Bonzini static const MemoryRegionOps openpic_tmr_ops_be = { 13217702e47cSPaolo Bonzini .write = openpic_tmr_write, 13227702e47cSPaolo Bonzini .read = openpic_tmr_read, 13237702e47cSPaolo Bonzini .endianness = DEVICE_BIG_ENDIAN, 13247702e47cSPaolo Bonzini .impl = { 13257702e47cSPaolo Bonzini .min_access_size = 4, 13267702e47cSPaolo Bonzini .max_access_size = 4, 13277702e47cSPaolo Bonzini }, 13287702e47cSPaolo Bonzini }; 13297702e47cSPaolo Bonzini 13307702e47cSPaolo Bonzini static const MemoryRegionOps openpic_cpu_ops_le = { 13317702e47cSPaolo Bonzini .write = openpic_cpu_write, 13327702e47cSPaolo Bonzini .read = openpic_cpu_read, 13337702e47cSPaolo Bonzini .endianness = DEVICE_LITTLE_ENDIAN, 13347702e47cSPaolo Bonzini .impl = { 13357702e47cSPaolo Bonzini .min_access_size = 4, 13367702e47cSPaolo Bonzini .max_access_size = 4, 13377702e47cSPaolo Bonzini }, 13387702e47cSPaolo Bonzini }; 13397702e47cSPaolo Bonzini 13407702e47cSPaolo Bonzini static const MemoryRegionOps openpic_cpu_ops_be = { 13417702e47cSPaolo Bonzini .write = openpic_cpu_write, 13427702e47cSPaolo Bonzini .read = openpic_cpu_read, 13437702e47cSPaolo Bonzini .endianness = DEVICE_BIG_ENDIAN, 13447702e47cSPaolo Bonzini .impl = { 13457702e47cSPaolo Bonzini .min_access_size = 4, 13467702e47cSPaolo Bonzini .max_access_size = 4, 13477702e47cSPaolo Bonzini }, 13487702e47cSPaolo Bonzini }; 13497702e47cSPaolo Bonzini 13507702e47cSPaolo Bonzini static const MemoryRegionOps openpic_src_ops_le = { 13517702e47cSPaolo Bonzini .write = openpic_src_write, 13527702e47cSPaolo Bonzini .read = openpic_src_read, 13537702e47cSPaolo Bonzini .endianness = DEVICE_LITTLE_ENDIAN, 13547702e47cSPaolo Bonzini .impl = { 13557702e47cSPaolo Bonzini .min_access_size = 4, 13567702e47cSPaolo Bonzini .max_access_size = 4, 13577702e47cSPaolo Bonzini }, 13587702e47cSPaolo Bonzini }; 13597702e47cSPaolo Bonzini 13607702e47cSPaolo Bonzini static const MemoryRegionOps openpic_src_ops_be = { 13617702e47cSPaolo Bonzini .write = openpic_src_write, 13627702e47cSPaolo Bonzini .read = openpic_src_read, 13637702e47cSPaolo Bonzini .endianness = DEVICE_BIG_ENDIAN, 13647702e47cSPaolo Bonzini .impl = { 13657702e47cSPaolo Bonzini .min_access_size = 4, 13667702e47cSPaolo Bonzini .max_access_size = 4, 13677702e47cSPaolo Bonzini }, 13687702e47cSPaolo Bonzini }; 13697702e47cSPaolo Bonzini 13707702e47cSPaolo Bonzini static const MemoryRegionOps openpic_msi_ops_be = { 13717702e47cSPaolo Bonzini .read = openpic_msi_read, 13727702e47cSPaolo Bonzini .write = openpic_msi_write, 13737702e47cSPaolo Bonzini .endianness = DEVICE_BIG_ENDIAN, 13747702e47cSPaolo Bonzini .impl = { 13757702e47cSPaolo Bonzini .min_access_size = 4, 13767702e47cSPaolo Bonzini .max_access_size = 4, 13777702e47cSPaolo Bonzini }, 13787702e47cSPaolo Bonzini }; 13797702e47cSPaolo Bonzini 13807702e47cSPaolo Bonzini static const MemoryRegionOps openpic_summary_ops_be = { 13817702e47cSPaolo Bonzini .read = openpic_summary_read, 13827702e47cSPaolo Bonzini .write = openpic_summary_write, 13837702e47cSPaolo Bonzini .endianness = DEVICE_BIG_ENDIAN, 13847702e47cSPaolo Bonzini .impl = { 13857702e47cSPaolo Bonzini .min_access_size = 4, 13867702e47cSPaolo Bonzini .max_access_size = 4, 13877702e47cSPaolo Bonzini }, 13887702e47cSPaolo Bonzini }; 13897702e47cSPaolo Bonzini 13908ebe65f3SPaul Janzen static void openpic_reset(DeviceState *d) 13918ebe65f3SPaul Janzen { 13928ebe65f3SPaul Janzen OpenPICState *opp = OPENPIC(d); 13938ebe65f3SPaul Janzen int i; 13948ebe65f3SPaul Janzen 13958ebe65f3SPaul Janzen opp->gcr = GCR_RESET; 13968ebe65f3SPaul Janzen /* Initialise controller registers */ 13978ebe65f3SPaul Janzen opp->frr = ((opp->nb_irqs - 1) << FRR_NIRQ_SHIFT) | 13988ebe65f3SPaul Janzen ((opp->nb_cpus - 1) << FRR_NCPU_SHIFT) | 13998ebe65f3SPaul Janzen (opp->vid << FRR_VID_SHIFT); 14008ebe65f3SPaul Janzen 14018ebe65f3SPaul Janzen opp->pir = 0; 14028ebe65f3SPaul Janzen opp->spve = -1 & opp->vector_mask; 14038ebe65f3SPaul Janzen opp->tfrr = opp->tfrr_reset; 14048ebe65f3SPaul Janzen /* Initialise IRQ sources */ 14058ebe65f3SPaul Janzen for (i = 0; i < opp->max_irq; i++) { 14068ebe65f3SPaul Janzen opp->src[i].ivpr = opp->ivpr_reset; 14078ebe65f3SPaul Janzen switch (opp->src[i].type) { 14088ebe65f3SPaul Janzen case IRQ_TYPE_NORMAL: 14098ebe65f3SPaul Janzen opp->src[i].level = !!(opp->ivpr_reset & IVPR_SENSE_MASK); 14108ebe65f3SPaul Janzen break; 14118ebe65f3SPaul Janzen 14128ebe65f3SPaul Janzen case IRQ_TYPE_FSLINT: 14138ebe65f3SPaul Janzen opp->src[i].ivpr |= IVPR_POLARITY_MASK; 14148ebe65f3SPaul Janzen break; 14158ebe65f3SPaul Janzen 14168ebe65f3SPaul Janzen case IRQ_TYPE_FSLSPECIAL: 14178ebe65f3SPaul Janzen break; 14188ebe65f3SPaul Janzen } 1419ffd5e9feSPaul Janzen 1420ffd5e9feSPaul Janzen write_IRQreg_idr(opp, i, opp->idr_reset); 14218ebe65f3SPaul Janzen } 14228ebe65f3SPaul Janzen /* Initialise IRQ destinations */ 14232ada66f9SMark Cave-Ayland for (i = 0; i < opp->nb_cpus; i++) { 14248ebe65f3SPaul Janzen opp->dst[i].ctpr = 15; 14258ebe65f3SPaul Janzen opp->dst[i].raised.next = -1; 14262ada66f9SMark Cave-Ayland opp->dst[i].raised.priority = 0; 14272ada66f9SMark Cave-Ayland bitmap_clear(opp->dst[i].raised.queue, 0, IRQQUEUE_SIZE_BITS); 14288ebe65f3SPaul Janzen opp->dst[i].servicing.next = -1; 14292ada66f9SMark Cave-Ayland opp->dst[i].servicing.priority = 0; 14302ada66f9SMark Cave-Ayland bitmap_clear(opp->dst[i].servicing.queue, 0, IRQQUEUE_SIZE_BITS); 14318ebe65f3SPaul Janzen } 14328ebe65f3SPaul Janzen /* Initialise timers */ 14338ebe65f3SPaul Janzen for (i = 0; i < OPENPIC_MAX_TMR; i++) { 14348ebe65f3SPaul Janzen opp->timers[i].tccr = 0; 14358ebe65f3SPaul Janzen opp->timers[i].tbcr = TBCR_CI; 1436*ddd5140bSAaron Larson if (opp->timers[i].qemu_timer_active) { 1437*ddd5140bSAaron Larson timer_del(opp->timers[i].qemu_timer); /* Inhibit timer */ 1438*ddd5140bSAaron Larson opp->timers[i].qemu_timer_active = false; 1439*ddd5140bSAaron Larson } 14408ebe65f3SPaul Janzen } 14418ebe65f3SPaul Janzen /* Go out of RESET state */ 14428ebe65f3SPaul Janzen opp->gcr = 0; 14438ebe65f3SPaul Janzen } 14448ebe65f3SPaul Janzen 14457702e47cSPaolo Bonzini typedef struct MemReg { 14467702e47cSPaolo Bonzini const char *name; 14477702e47cSPaolo Bonzini MemoryRegionOps const *ops; 14487702e47cSPaolo Bonzini hwaddr start_addr; 14497702e47cSPaolo Bonzini ram_addr_t size; 14507702e47cSPaolo Bonzini } MemReg; 14517702e47cSPaolo Bonzini 14527702e47cSPaolo Bonzini static void fsl_common_init(OpenPICState *opp) 14537702e47cSPaolo Bonzini { 14547702e47cSPaolo Bonzini int i; 14558935a442SScott Wood int virq = OPENPIC_MAX_SRC; 14567702e47cSPaolo Bonzini 14577702e47cSPaolo Bonzini opp->vid = VID_REVISION_1_2; 14587702e47cSPaolo Bonzini opp->vir = VIR_GENERIC; 14597702e47cSPaolo Bonzini opp->vector_mask = 0xFFFF; 14607702e47cSPaolo Bonzini opp->tfrr_reset = 0; 14617702e47cSPaolo Bonzini opp->ivpr_reset = IVPR_MASK_MASK; 14627702e47cSPaolo Bonzini opp->idr_reset = 1 << 0; 14638935a442SScott Wood opp->max_irq = OPENPIC_MAX_IRQ; 14647702e47cSPaolo Bonzini 14657702e47cSPaolo Bonzini opp->irq_ipi0 = virq; 14668935a442SScott Wood virq += OPENPIC_MAX_IPI; 14677702e47cSPaolo Bonzini opp->irq_tim0 = virq; 14688935a442SScott Wood virq += OPENPIC_MAX_TMR; 14697702e47cSPaolo Bonzini 14708935a442SScott Wood assert(virq <= OPENPIC_MAX_IRQ); 14717702e47cSPaolo Bonzini 14727702e47cSPaolo Bonzini opp->irq_msi = 224; 14737702e47cSPaolo Bonzini 1474226419d6SMichael S. Tsirkin msi_nonbroken = true; 14757702e47cSPaolo Bonzini for (i = 0; i < opp->fsl->max_ext; i++) { 14767702e47cSPaolo Bonzini opp->src[i].level = false; 14777702e47cSPaolo Bonzini } 14787702e47cSPaolo Bonzini 14797702e47cSPaolo Bonzini /* Internal interrupts, including message and MSI */ 14808935a442SScott Wood for (i = 16; i < OPENPIC_MAX_SRC; i++) { 14817702e47cSPaolo Bonzini opp->src[i].type = IRQ_TYPE_FSLINT; 14827702e47cSPaolo Bonzini opp->src[i].level = true; 14837702e47cSPaolo Bonzini } 14847702e47cSPaolo Bonzini 14857702e47cSPaolo Bonzini /* timers and IPIs */ 14868935a442SScott Wood for (i = OPENPIC_MAX_SRC; i < virq; i++) { 14877702e47cSPaolo Bonzini opp->src[i].type = IRQ_TYPE_FSLSPECIAL; 14887702e47cSPaolo Bonzini opp->src[i].level = false; 14897702e47cSPaolo Bonzini } 1490*ddd5140bSAaron Larson 1491*ddd5140bSAaron Larson for (i = 0; i < OPENPIC_MAX_TMR; i++) { 1492*ddd5140bSAaron Larson opp->timers[i].n_IRQ = opp->irq_tim0 + i; 1493*ddd5140bSAaron Larson opp->timers[i].qemu_timer_active = false; 1494*ddd5140bSAaron Larson opp->timers[i].qemu_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, 1495*ddd5140bSAaron Larson &qemu_timer_cb, 1496*ddd5140bSAaron Larson &opp->timers[i]); 1497*ddd5140bSAaron Larson opp->timers[i].opp = opp; 1498*ddd5140bSAaron Larson } 14997702e47cSPaolo Bonzini } 15007702e47cSPaolo Bonzini 15017702e47cSPaolo Bonzini static void map_list(OpenPICState *opp, const MemReg *list, int *count) 15027702e47cSPaolo Bonzini { 15037702e47cSPaolo Bonzini while (list->name) { 15047702e47cSPaolo Bonzini assert(*count < ARRAY_SIZE(opp->sub_io_mem)); 15057702e47cSPaolo Bonzini 15061437c94bSPaolo Bonzini memory_region_init_io(&opp->sub_io_mem[*count], OBJECT(opp), list->ops, 15071437c94bSPaolo Bonzini opp, list->name, list->size); 15087702e47cSPaolo Bonzini 15097702e47cSPaolo Bonzini memory_region_add_subregion(&opp->mem, list->start_addr, 15107702e47cSPaolo Bonzini &opp->sub_io_mem[*count]); 15117702e47cSPaolo Bonzini 15127702e47cSPaolo Bonzini (*count)++; 15137702e47cSPaolo Bonzini list++; 15147702e47cSPaolo Bonzini } 15157702e47cSPaolo Bonzini } 15167702e47cSPaolo Bonzini 1517e5f6e732SMark Cave-Ayland static const VMStateDescription vmstate_openpic_irq_queue = { 1518e5f6e732SMark Cave-Ayland .name = "openpic_irq_queue", 1519e5f6e732SMark Cave-Ayland .version_id = 0, 1520e5f6e732SMark Cave-Ayland .minimum_version_id = 0, 1521e5f6e732SMark Cave-Ayland .fields = (VMStateField[]) { 1522e5f6e732SMark Cave-Ayland VMSTATE_BITMAP(queue, IRQQueue, 0, queue_size), 1523e5f6e732SMark Cave-Ayland VMSTATE_INT32(next, IRQQueue), 1524e5f6e732SMark Cave-Ayland VMSTATE_INT32(priority, IRQQueue), 1525e5f6e732SMark Cave-Ayland VMSTATE_END_OF_LIST() 1526e5f6e732SMark Cave-Ayland } 1527e5f6e732SMark Cave-Ayland }; 1528e5f6e732SMark Cave-Ayland 1529e5f6e732SMark Cave-Ayland static const VMStateDescription vmstate_openpic_irqdest = { 1530e5f6e732SMark Cave-Ayland .name = "openpic_irqdest", 1531e5f6e732SMark Cave-Ayland .version_id = 0, 1532e5f6e732SMark Cave-Ayland .minimum_version_id = 0, 1533e5f6e732SMark Cave-Ayland .fields = (VMStateField[]) { 1534e5f6e732SMark Cave-Ayland VMSTATE_INT32(ctpr, IRQDest), 1535e5f6e732SMark Cave-Ayland VMSTATE_STRUCT(raised, IRQDest, 0, vmstate_openpic_irq_queue, 1536e5f6e732SMark Cave-Ayland IRQQueue), 1537e5f6e732SMark Cave-Ayland VMSTATE_STRUCT(servicing, IRQDest, 0, vmstate_openpic_irq_queue, 1538e5f6e732SMark Cave-Ayland IRQQueue), 1539e5f6e732SMark Cave-Ayland VMSTATE_UINT32_ARRAY(outputs_active, IRQDest, OPENPIC_OUTPUT_NB), 1540e5f6e732SMark Cave-Ayland VMSTATE_END_OF_LIST() 1541e5f6e732SMark Cave-Ayland } 1542e5f6e732SMark Cave-Ayland }; 1543e5f6e732SMark Cave-Ayland 1544e5f6e732SMark Cave-Ayland static const VMStateDescription vmstate_openpic_irqsource = { 1545e5f6e732SMark Cave-Ayland .name = "openpic_irqsource", 1546e5f6e732SMark Cave-Ayland .version_id = 0, 1547e5f6e732SMark Cave-Ayland .minimum_version_id = 0, 1548e5f6e732SMark Cave-Ayland .fields = (VMStateField[]) { 1549e5f6e732SMark Cave-Ayland VMSTATE_UINT32(ivpr, IRQSource), 1550e5f6e732SMark Cave-Ayland VMSTATE_UINT32(idr, IRQSource), 1551e5f6e732SMark Cave-Ayland VMSTATE_UINT32(destmask, IRQSource), 1552e5f6e732SMark Cave-Ayland VMSTATE_INT32(last_cpu, IRQSource), 1553e5f6e732SMark Cave-Ayland VMSTATE_INT32(pending, IRQSource), 1554e5f6e732SMark Cave-Ayland VMSTATE_END_OF_LIST() 1555e5f6e732SMark Cave-Ayland } 1556e5f6e732SMark Cave-Ayland }; 1557e5f6e732SMark Cave-Ayland 1558e5f6e732SMark Cave-Ayland static const VMStateDescription vmstate_openpic_timer = { 1559e5f6e732SMark Cave-Ayland .name = "openpic_timer", 1560e5f6e732SMark Cave-Ayland .version_id = 0, 1561e5f6e732SMark Cave-Ayland .minimum_version_id = 0, 1562e5f6e732SMark Cave-Ayland .fields = (VMStateField[]) { 1563e5f6e732SMark Cave-Ayland VMSTATE_UINT32(tccr, OpenPICTimer), 1564e5f6e732SMark Cave-Ayland VMSTATE_UINT32(tbcr, OpenPICTimer), 1565e5f6e732SMark Cave-Ayland VMSTATE_END_OF_LIST() 1566e5f6e732SMark Cave-Ayland } 1567e5f6e732SMark Cave-Ayland }; 1568e5f6e732SMark Cave-Ayland 1569e5f6e732SMark Cave-Ayland static const VMStateDescription vmstate_openpic_msi = { 1570e5f6e732SMark Cave-Ayland .name = "openpic_msi", 1571e5f6e732SMark Cave-Ayland .version_id = 0, 1572e5f6e732SMark Cave-Ayland .minimum_version_id = 0, 1573e5f6e732SMark Cave-Ayland .fields = (VMStateField[]) { 1574e5f6e732SMark Cave-Ayland VMSTATE_UINT32(msir, OpenPICMSI), 1575e5f6e732SMark Cave-Ayland VMSTATE_END_OF_LIST() 1576e5f6e732SMark Cave-Ayland } 1577e5f6e732SMark Cave-Ayland }; 1578e5f6e732SMark Cave-Ayland 1579e5f6e732SMark Cave-Ayland static int openpic_post_load(void *opaque, int version_id) 1580e5f6e732SMark Cave-Ayland { 1581e5f6e732SMark Cave-Ayland OpenPICState *opp = (OpenPICState *)opaque; 1582e5f6e732SMark Cave-Ayland int i; 1583e5f6e732SMark Cave-Ayland 1584e5f6e732SMark Cave-Ayland /* Update internal ivpr and idr variables */ 1585e5f6e732SMark Cave-Ayland for (i = 0; i < opp->max_irq; i++) { 1586e5f6e732SMark Cave-Ayland write_IRQreg_idr(opp, i, opp->src[i].idr); 1587e5f6e732SMark Cave-Ayland write_IRQreg_ivpr(opp, i, opp->src[i].ivpr); 1588e5f6e732SMark Cave-Ayland } 1589e5f6e732SMark Cave-Ayland 1590e5f6e732SMark Cave-Ayland return 0; 1591e5f6e732SMark Cave-Ayland } 1592e5f6e732SMark Cave-Ayland 1593e5f6e732SMark Cave-Ayland static const VMStateDescription vmstate_openpic = { 1594e5f6e732SMark Cave-Ayland .name = "openpic", 1595e5f6e732SMark Cave-Ayland .version_id = 3, 1596e5f6e732SMark Cave-Ayland .minimum_version_id = 3, 1597e5f6e732SMark Cave-Ayland .post_load = openpic_post_load, 1598e5f6e732SMark Cave-Ayland .fields = (VMStateField[]) { 1599e5f6e732SMark Cave-Ayland VMSTATE_UINT32(gcr, OpenPICState), 1600e5f6e732SMark Cave-Ayland VMSTATE_UINT32(vir, OpenPICState), 1601e5f6e732SMark Cave-Ayland VMSTATE_UINT32(pir, OpenPICState), 1602e5f6e732SMark Cave-Ayland VMSTATE_UINT32(spve, OpenPICState), 1603e5f6e732SMark Cave-Ayland VMSTATE_UINT32(tfrr, OpenPICState), 1604e5f6e732SMark Cave-Ayland VMSTATE_UINT32(max_irq, OpenPICState), 1605e5f6e732SMark Cave-Ayland VMSTATE_STRUCT_VARRAY_UINT32(src, OpenPICState, max_irq, 0, 1606e5f6e732SMark Cave-Ayland vmstate_openpic_irqsource, IRQSource), 1607d2164ad3SHalil Pasic VMSTATE_UINT32_EQUAL(nb_cpus, OpenPICState, NULL), 1608e5f6e732SMark Cave-Ayland VMSTATE_STRUCT_VARRAY_UINT32(dst, OpenPICState, nb_cpus, 0, 1609e5f6e732SMark Cave-Ayland vmstate_openpic_irqdest, IRQDest), 1610e5f6e732SMark Cave-Ayland VMSTATE_STRUCT_ARRAY(timers, OpenPICState, OPENPIC_MAX_TMR, 0, 1611e5f6e732SMark Cave-Ayland vmstate_openpic_timer, OpenPICTimer), 1612e5f6e732SMark Cave-Ayland VMSTATE_STRUCT_ARRAY(msi, OpenPICState, MAX_MSI, 0, 1613e5f6e732SMark Cave-Ayland vmstate_openpic_msi, OpenPICMSI), 1614e5f6e732SMark Cave-Ayland VMSTATE_UINT32(irq_ipi0, OpenPICState), 1615e5f6e732SMark Cave-Ayland VMSTATE_UINT32(irq_tim0, OpenPICState), 1616e5f6e732SMark Cave-Ayland VMSTATE_UINT32(irq_msi, OpenPICState), 1617e5f6e732SMark Cave-Ayland VMSTATE_END_OF_LIST() 1618e5f6e732SMark Cave-Ayland } 1619e5f6e732SMark Cave-Ayland }; 1620e5f6e732SMark Cave-Ayland 1621cbe72019SAndreas Färber static void openpic_init(Object *obj) 16227702e47cSPaolo Bonzini { 1623cbe72019SAndreas Färber OpenPICState *opp = OPENPIC(obj); 1624cbe72019SAndreas Färber 16251437c94bSPaolo Bonzini memory_region_init(&opp->mem, obj, "openpic", 0x40000); 1626cbe72019SAndreas Färber } 1627cbe72019SAndreas Färber 1628cbe72019SAndreas Färber static void openpic_realize(DeviceState *dev, Error **errp) 1629cbe72019SAndreas Färber { 1630cbe72019SAndreas Färber SysBusDevice *d = SYS_BUS_DEVICE(dev); 1631e1766344SAndreas Färber OpenPICState *opp = OPENPIC(dev); 16327702e47cSPaolo Bonzini int i, j; 16337702e47cSPaolo Bonzini int list_count = 0; 16347702e47cSPaolo Bonzini static const MemReg list_le[] = { 16357702e47cSPaolo Bonzini {"glb", &openpic_glb_ops_le, 16367702e47cSPaolo Bonzini OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE}, 16377702e47cSPaolo Bonzini {"tmr", &openpic_tmr_ops_le, 16387702e47cSPaolo Bonzini OPENPIC_TMR_REG_START, OPENPIC_TMR_REG_SIZE}, 16397702e47cSPaolo Bonzini {"src", &openpic_src_ops_le, 16407702e47cSPaolo Bonzini OPENPIC_SRC_REG_START, OPENPIC_SRC_REG_SIZE}, 16417702e47cSPaolo Bonzini {"cpu", &openpic_cpu_ops_le, 16427702e47cSPaolo Bonzini OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE}, 16437702e47cSPaolo Bonzini {NULL} 16447702e47cSPaolo Bonzini }; 16457702e47cSPaolo Bonzini static const MemReg list_be[] = { 16467702e47cSPaolo Bonzini {"glb", &openpic_glb_ops_be, 16477702e47cSPaolo Bonzini OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE}, 16487702e47cSPaolo Bonzini {"tmr", &openpic_tmr_ops_be, 16497702e47cSPaolo Bonzini OPENPIC_TMR_REG_START, OPENPIC_TMR_REG_SIZE}, 16507702e47cSPaolo Bonzini {"src", &openpic_src_ops_be, 16517702e47cSPaolo Bonzini OPENPIC_SRC_REG_START, OPENPIC_SRC_REG_SIZE}, 16527702e47cSPaolo Bonzini {"cpu", &openpic_cpu_ops_be, 16537702e47cSPaolo Bonzini OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE}, 16547702e47cSPaolo Bonzini {NULL} 16557702e47cSPaolo Bonzini }; 16567702e47cSPaolo Bonzini static const MemReg list_fsl[] = { 16577702e47cSPaolo Bonzini {"msi", &openpic_msi_ops_be, 16587702e47cSPaolo Bonzini OPENPIC_MSI_REG_START, OPENPIC_MSI_REG_SIZE}, 16597702e47cSPaolo Bonzini {"summary", &openpic_summary_ops_be, 16607702e47cSPaolo Bonzini OPENPIC_SUMMARY_REG_START, OPENPIC_SUMMARY_REG_SIZE}, 16617702e47cSPaolo Bonzini {NULL} 16627702e47cSPaolo Bonzini }; 16637702e47cSPaolo Bonzini 166473d963c0SMichael Roth if (opp->nb_cpus > MAX_CPU) { 1665c6bd8c70SMarkus Armbruster error_setg(errp, QERR_PROPERTY_VALUE_OUT_OF_RANGE, 166673d963c0SMichael Roth TYPE_OPENPIC, "nb_cpus", (uint64_t)opp->nb_cpus, 166773d963c0SMichael Roth (uint64_t)0, (uint64_t)MAX_CPU); 166873d963c0SMichael Roth return; 166973d963c0SMichael Roth } 167073d963c0SMichael Roth 16717702e47cSPaolo Bonzini switch (opp->model) { 16727702e47cSPaolo Bonzini case OPENPIC_MODEL_FSL_MPIC_20: 16737702e47cSPaolo Bonzini default: 16747702e47cSPaolo Bonzini opp->fsl = &fsl_mpic_20; 16757702e47cSPaolo Bonzini opp->brr1 = 0x00400200; 16767702e47cSPaolo Bonzini opp->flags |= OPENPIC_FLAG_IDR_CRIT; 16777702e47cSPaolo Bonzini opp->nb_irqs = 80; 16787702e47cSPaolo Bonzini opp->mpic_mode_mask = GCR_MODE_MIXED; 16797702e47cSPaolo Bonzini 16807702e47cSPaolo Bonzini fsl_common_init(opp); 16817702e47cSPaolo Bonzini map_list(opp, list_be, &list_count); 16827702e47cSPaolo Bonzini map_list(opp, list_fsl, &list_count); 16837702e47cSPaolo Bonzini 16847702e47cSPaolo Bonzini break; 16857702e47cSPaolo Bonzini 16867702e47cSPaolo Bonzini case OPENPIC_MODEL_FSL_MPIC_42: 16877702e47cSPaolo Bonzini opp->fsl = &fsl_mpic_42; 16887702e47cSPaolo Bonzini opp->brr1 = 0x00400402; 16897702e47cSPaolo Bonzini opp->flags |= OPENPIC_FLAG_ILR; 16907702e47cSPaolo Bonzini opp->nb_irqs = 196; 16917702e47cSPaolo Bonzini opp->mpic_mode_mask = GCR_MODE_PROXY; 16927702e47cSPaolo Bonzini 16937702e47cSPaolo Bonzini fsl_common_init(opp); 16947702e47cSPaolo Bonzini map_list(opp, list_be, &list_count); 16957702e47cSPaolo Bonzini map_list(opp, list_fsl, &list_count); 16967702e47cSPaolo Bonzini 16977702e47cSPaolo Bonzini break; 16987702e47cSPaolo Bonzini 16997702e47cSPaolo Bonzini case OPENPIC_MODEL_RAVEN: 17007702e47cSPaolo Bonzini opp->nb_irqs = RAVEN_MAX_EXT; 17017702e47cSPaolo Bonzini opp->vid = VID_REVISION_1_3; 17027702e47cSPaolo Bonzini opp->vir = VIR_GENERIC; 17037702e47cSPaolo Bonzini opp->vector_mask = 0xFF; 17047702e47cSPaolo Bonzini opp->tfrr_reset = 4160000; 17057702e47cSPaolo Bonzini opp->ivpr_reset = IVPR_MASK_MASK | IVPR_MODE_MASK; 17067702e47cSPaolo Bonzini opp->idr_reset = 0; 17077702e47cSPaolo Bonzini opp->max_irq = RAVEN_MAX_IRQ; 17087702e47cSPaolo Bonzini opp->irq_ipi0 = RAVEN_IPI_IRQ; 17097702e47cSPaolo Bonzini opp->irq_tim0 = RAVEN_TMR_IRQ; 17107702e47cSPaolo Bonzini opp->brr1 = -1; 17117702e47cSPaolo Bonzini opp->mpic_mode_mask = GCR_MODE_MIXED; 17127702e47cSPaolo Bonzini 17137702e47cSPaolo Bonzini if (opp->nb_cpus != 1) { 1714cbe72019SAndreas Färber error_setg(errp, "Only UP supported today"); 1715cbe72019SAndreas Färber return; 17167702e47cSPaolo Bonzini } 17177702e47cSPaolo Bonzini 17187702e47cSPaolo Bonzini map_list(opp, list_le, &list_count); 17197702e47cSPaolo Bonzini break; 17207702e47cSPaolo Bonzini } 17217702e47cSPaolo Bonzini 17227702e47cSPaolo Bonzini for (i = 0; i < opp->nb_cpus; i++) { 1723aa2ac1daSPeter Crosthwaite opp->dst[i].irqs = g_new0(qemu_irq, OPENPIC_OUTPUT_NB); 17247702e47cSPaolo Bonzini for (j = 0; j < OPENPIC_OUTPUT_NB; j++) { 1725cbe72019SAndreas Färber sysbus_init_irq(d, &opp->dst[i].irqs[j]); 17267702e47cSPaolo Bonzini } 17272ada66f9SMark Cave-Ayland 1728e5f6e732SMark Cave-Ayland opp->dst[i].raised.queue_size = IRQQUEUE_SIZE_BITS; 17292ada66f9SMark Cave-Ayland opp->dst[i].raised.queue = bitmap_new(IRQQUEUE_SIZE_BITS); 1730e5f6e732SMark Cave-Ayland opp->dst[i].servicing.queue_size = IRQQUEUE_SIZE_BITS; 17312ada66f9SMark Cave-Ayland opp->dst[i].servicing.queue = bitmap_new(IRQQUEUE_SIZE_BITS); 17327702e47cSPaolo Bonzini } 17337702e47cSPaolo Bonzini 1734cbe72019SAndreas Färber sysbus_init_mmio(d, &opp->mem); 1735cbe72019SAndreas Färber qdev_init_gpio_in(dev, openpic_set_irq, opp->max_irq); 17367702e47cSPaolo Bonzini } 17377702e47cSPaolo Bonzini 17387702e47cSPaolo Bonzini static Property openpic_properties[] = { 17397702e47cSPaolo Bonzini DEFINE_PROP_UINT32("model", OpenPICState, model, OPENPIC_MODEL_FSL_MPIC_20), 17407702e47cSPaolo Bonzini DEFINE_PROP_UINT32("nb_cpus", OpenPICState, nb_cpus, 1), 17417702e47cSPaolo Bonzini DEFINE_PROP_END_OF_LIST(), 17427702e47cSPaolo Bonzini }; 17437702e47cSPaolo Bonzini 1744cbe72019SAndreas Färber static void openpic_class_init(ObjectClass *oc, void *data) 17457702e47cSPaolo Bonzini { 1746cbe72019SAndreas Färber DeviceClass *dc = DEVICE_CLASS(oc); 17477702e47cSPaolo Bonzini 1748cbe72019SAndreas Färber dc->realize = openpic_realize; 17497702e47cSPaolo Bonzini dc->props = openpic_properties; 17507702e47cSPaolo Bonzini dc->reset = openpic_reset; 1751e5f6e732SMark Cave-Ayland dc->vmsd = &vmstate_openpic; 175229f8dd66SLaurent Vivier set_bit(DEVICE_CATEGORY_MISC, dc->categories); 17537702e47cSPaolo Bonzini } 17547702e47cSPaolo Bonzini 17557702e47cSPaolo Bonzini static const TypeInfo openpic_info = { 1756e1766344SAndreas Färber .name = TYPE_OPENPIC, 17577702e47cSPaolo Bonzini .parent = TYPE_SYS_BUS_DEVICE, 17587702e47cSPaolo Bonzini .instance_size = sizeof(OpenPICState), 1759cbe72019SAndreas Färber .instance_init = openpic_init, 17607702e47cSPaolo Bonzini .class_init = openpic_class_init, 17617702e47cSPaolo Bonzini }; 17627702e47cSPaolo Bonzini 17637702e47cSPaolo Bonzini static void openpic_register_types(void) 17647702e47cSPaolo Bonzini { 17657702e47cSPaolo Bonzini type_register_static(&openpic_info); 17667702e47cSPaolo Bonzini } 17677702e47cSPaolo Bonzini 17687702e47cSPaolo Bonzini type_init(openpic_register_types) 1769