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 */ 367702e47cSPaolo Bonzini #include "hw/hw.h" 377702e47cSPaolo Bonzini #include "hw/ppc/mac.h" 387702e47cSPaolo Bonzini #include "hw/pci/pci.h" 397702e47cSPaolo Bonzini #include "hw/ppc/openpic.h" 407702e47cSPaolo Bonzini #include "hw/sysbus.h" 417702e47cSPaolo Bonzini #include "hw/pci/msi.h" 427702e47cSPaolo Bonzini #include "qemu/bitops.h" 437702e47cSPaolo Bonzini #include "hw/ppc/ppc.h" 447702e47cSPaolo Bonzini 457702e47cSPaolo Bonzini //#define DEBUG_OPENPIC 467702e47cSPaolo Bonzini 477702e47cSPaolo Bonzini #ifdef DEBUG_OPENPIC 487702e47cSPaolo Bonzini static const int debug_openpic = 1; 497702e47cSPaolo Bonzini #else 507702e47cSPaolo Bonzini static const int debug_openpic = 0; 517702e47cSPaolo Bonzini #endif 527702e47cSPaolo Bonzini 537702e47cSPaolo Bonzini #define DPRINTF(fmt, ...) do { \ 547702e47cSPaolo Bonzini if (debug_openpic) { \ 557702e47cSPaolo Bonzini printf(fmt , ## __VA_ARGS__); \ 567702e47cSPaolo Bonzini } \ 577702e47cSPaolo Bonzini } while (0) 587702e47cSPaolo Bonzini 597702e47cSPaolo Bonzini #define MAX_CPU 32 607702e47cSPaolo Bonzini #define MAX_MSI 8 617702e47cSPaolo Bonzini #define VID 0x03 /* MPIC version ID */ 627702e47cSPaolo Bonzini 637702e47cSPaolo Bonzini /* OpenPIC capability flags */ 647702e47cSPaolo Bonzini #define OPENPIC_FLAG_IDR_CRIT (1 << 0) 657702e47cSPaolo Bonzini #define OPENPIC_FLAG_ILR (2 << 0) 667702e47cSPaolo Bonzini 677702e47cSPaolo Bonzini /* OpenPIC address map */ 687702e47cSPaolo Bonzini #define OPENPIC_GLB_REG_START 0x0 697702e47cSPaolo Bonzini #define OPENPIC_GLB_REG_SIZE 0x10F0 707702e47cSPaolo Bonzini #define OPENPIC_TMR_REG_START 0x10F0 717702e47cSPaolo Bonzini #define OPENPIC_TMR_REG_SIZE 0x220 727702e47cSPaolo Bonzini #define OPENPIC_MSI_REG_START 0x1600 737702e47cSPaolo Bonzini #define OPENPIC_MSI_REG_SIZE 0x200 747702e47cSPaolo Bonzini #define OPENPIC_SUMMARY_REG_START 0x3800 757702e47cSPaolo Bonzini #define OPENPIC_SUMMARY_REG_SIZE 0x800 767702e47cSPaolo Bonzini #define OPENPIC_SRC_REG_START 0x10000 778935a442SScott Wood #define OPENPIC_SRC_REG_SIZE (OPENPIC_MAX_SRC * 0x20) 787702e47cSPaolo Bonzini #define OPENPIC_CPU_REG_START 0x20000 797702e47cSPaolo Bonzini #define OPENPIC_CPU_REG_SIZE 0x100 + ((MAX_CPU - 1) * 0x1000) 807702e47cSPaolo Bonzini 817702e47cSPaolo Bonzini /* Raven */ 827702e47cSPaolo Bonzini #define RAVEN_MAX_CPU 2 837702e47cSPaolo Bonzini #define RAVEN_MAX_EXT 48 847702e47cSPaolo Bonzini #define RAVEN_MAX_IRQ 64 858935a442SScott Wood #define RAVEN_MAX_TMR OPENPIC_MAX_TMR 868935a442SScott Wood #define RAVEN_MAX_IPI OPENPIC_MAX_IPI 877702e47cSPaolo Bonzini 887702e47cSPaolo Bonzini /* Interrupt definitions */ 897702e47cSPaolo Bonzini #define RAVEN_FE_IRQ (RAVEN_MAX_EXT) /* Internal functional IRQ */ 907702e47cSPaolo Bonzini #define RAVEN_ERR_IRQ (RAVEN_MAX_EXT + 1) /* Error IRQ */ 917702e47cSPaolo Bonzini #define RAVEN_TMR_IRQ (RAVEN_MAX_EXT + 2) /* First timer IRQ */ 927702e47cSPaolo Bonzini #define RAVEN_IPI_IRQ (RAVEN_TMR_IRQ + RAVEN_MAX_TMR) /* First IPI IRQ */ 937702e47cSPaolo Bonzini /* First doorbell IRQ */ 947702e47cSPaolo Bonzini #define RAVEN_DBL_IRQ (RAVEN_IPI_IRQ + (RAVEN_MAX_CPU * RAVEN_MAX_IPI)) 957702e47cSPaolo Bonzini 967702e47cSPaolo Bonzini typedef struct FslMpicInfo { 977702e47cSPaolo Bonzini int max_ext; 987702e47cSPaolo Bonzini } FslMpicInfo; 997702e47cSPaolo Bonzini 1007702e47cSPaolo Bonzini static FslMpicInfo fsl_mpic_20 = { 1017702e47cSPaolo Bonzini .max_ext = 12, 1027702e47cSPaolo Bonzini }; 1037702e47cSPaolo Bonzini 1047702e47cSPaolo Bonzini static FslMpicInfo fsl_mpic_42 = { 1057702e47cSPaolo Bonzini .max_ext = 12, 1067702e47cSPaolo Bonzini }; 1077702e47cSPaolo Bonzini 1087702e47cSPaolo Bonzini #define FRR_NIRQ_SHIFT 16 1097702e47cSPaolo Bonzini #define FRR_NCPU_SHIFT 8 1107702e47cSPaolo Bonzini #define FRR_VID_SHIFT 0 1117702e47cSPaolo Bonzini 1127702e47cSPaolo Bonzini #define VID_REVISION_1_2 2 1137702e47cSPaolo Bonzini #define VID_REVISION_1_3 3 1147702e47cSPaolo Bonzini 1157702e47cSPaolo Bonzini #define VIR_GENERIC 0x00000000 /* Generic Vendor ID */ 1167702e47cSPaolo Bonzini 1177702e47cSPaolo Bonzini #define GCR_RESET 0x80000000 1187702e47cSPaolo Bonzini #define GCR_MODE_PASS 0x00000000 1197702e47cSPaolo Bonzini #define GCR_MODE_MIXED 0x20000000 1207702e47cSPaolo Bonzini #define GCR_MODE_PROXY 0x60000000 1217702e47cSPaolo Bonzini 1227702e47cSPaolo Bonzini #define TBCR_CI 0x80000000 /* count inhibit */ 1237702e47cSPaolo Bonzini #define TCCR_TOG 0x80000000 /* toggles when decrement to zero */ 1247702e47cSPaolo Bonzini 1257702e47cSPaolo Bonzini #define IDR_EP_SHIFT 31 1267702e47cSPaolo Bonzini #define IDR_EP_MASK (1 << IDR_EP_SHIFT) 1277702e47cSPaolo Bonzini #define IDR_CI0_SHIFT 30 1287702e47cSPaolo Bonzini #define IDR_CI1_SHIFT 29 1297702e47cSPaolo Bonzini #define IDR_P1_SHIFT 1 1307702e47cSPaolo Bonzini #define IDR_P0_SHIFT 0 1317702e47cSPaolo Bonzini 1327702e47cSPaolo Bonzini #define ILR_INTTGT_MASK 0x000000ff 1337702e47cSPaolo Bonzini #define ILR_INTTGT_INT 0x00 1347702e47cSPaolo Bonzini #define ILR_INTTGT_CINT 0x01 /* critical */ 1357702e47cSPaolo Bonzini #define ILR_INTTGT_MCP 0x02 /* machine check */ 1367702e47cSPaolo Bonzini 1377702e47cSPaolo Bonzini /* The currently supported INTTGT values happen to be the same as QEMU's 1387702e47cSPaolo Bonzini * openpic output codes, but don't depend on this. The output codes 1397702e47cSPaolo Bonzini * could change (unlikely, but...) or support could be added for 1407702e47cSPaolo Bonzini * more INTTGT values. 1417702e47cSPaolo Bonzini */ 1427702e47cSPaolo Bonzini static const int inttgt_output[][2] = { 1437702e47cSPaolo Bonzini { ILR_INTTGT_INT, OPENPIC_OUTPUT_INT }, 1447702e47cSPaolo Bonzini { ILR_INTTGT_CINT, OPENPIC_OUTPUT_CINT }, 1457702e47cSPaolo Bonzini { ILR_INTTGT_MCP, OPENPIC_OUTPUT_MCK }, 1467702e47cSPaolo Bonzini }; 1477702e47cSPaolo Bonzini 1487702e47cSPaolo Bonzini static int inttgt_to_output(int inttgt) 1497702e47cSPaolo Bonzini { 1507702e47cSPaolo Bonzini int i; 1517702e47cSPaolo Bonzini 1527702e47cSPaolo Bonzini for (i = 0; i < ARRAY_SIZE(inttgt_output); i++) { 1537702e47cSPaolo Bonzini if (inttgt_output[i][0] == inttgt) { 1547702e47cSPaolo Bonzini return inttgt_output[i][1]; 1557702e47cSPaolo Bonzini } 1567702e47cSPaolo Bonzini } 1577702e47cSPaolo Bonzini 1587702e47cSPaolo Bonzini fprintf(stderr, "%s: unsupported inttgt %d\n", __func__, inttgt); 1597702e47cSPaolo Bonzini return OPENPIC_OUTPUT_INT; 1607702e47cSPaolo Bonzini } 1617702e47cSPaolo Bonzini 1627702e47cSPaolo Bonzini static int output_to_inttgt(int output) 1637702e47cSPaolo Bonzini { 1647702e47cSPaolo Bonzini int i; 1657702e47cSPaolo Bonzini 1667702e47cSPaolo Bonzini for (i = 0; i < ARRAY_SIZE(inttgt_output); i++) { 1677702e47cSPaolo Bonzini if (inttgt_output[i][1] == output) { 1687702e47cSPaolo Bonzini return inttgt_output[i][0]; 1697702e47cSPaolo Bonzini } 1707702e47cSPaolo Bonzini } 1717702e47cSPaolo Bonzini 1727702e47cSPaolo Bonzini abort(); 1737702e47cSPaolo Bonzini } 1747702e47cSPaolo Bonzini 1757702e47cSPaolo Bonzini #define MSIIR_OFFSET 0x140 1767702e47cSPaolo Bonzini #define MSIIR_SRS_SHIFT 29 1777702e47cSPaolo Bonzini #define MSIIR_SRS_MASK (0x7 << MSIIR_SRS_SHIFT) 1787702e47cSPaolo Bonzini #define MSIIR_IBS_SHIFT 24 1797702e47cSPaolo Bonzini #define MSIIR_IBS_MASK (0x1f << MSIIR_IBS_SHIFT) 1807702e47cSPaolo Bonzini 1817702e47cSPaolo Bonzini static int get_current_cpu(void) 1827702e47cSPaolo Bonzini { 183*4917cf44SAndreas Färber if (!current_cpu) { 1847702e47cSPaolo Bonzini return -1; 1857702e47cSPaolo Bonzini } 1867702e47cSPaolo Bonzini 187*4917cf44SAndreas Färber return current_cpu->cpu_index; 1887702e47cSPaolo Bonzini } 1897702e47cSPaolo Bonzini 1907702e47cSPaolo Bonzini static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, 1917702e47cSPaolo Bonzini int idx); 1927702e47cSPaolo Bonzini static void openpic_cpu_write_internal(void *opaque, hwaddr addr, 1937702e47cSPaolo Bonzini uint32_t val, int idx); 1947702e47cSPaolo Bonzini 1957702e47cSPaolo Bonzini typedef enum IRQType { 1967702e47cSPaolo Bonzini IRQ_TYPE_NORMAL = 0, 1977702e47cSPaolo Bonzini IRQ_TYPE_FSLINT, /* FSL internal interrupt -- level only */ 1987702e47cSPaolo Bonzini IRQ_TYPE_FSLSPECIAL, /* FSL timer/IPI interrupt, edge, no polarity */ 1997702e47cSPaolo Bonzini } IRQType; 2007702e47cSPaolo Bonzini 2017702e47cSPaolo Bonzini typedef struct IRQQueue { 2027702e47cSPaolo Bonzini /* Round up to the nearest 64 IRQs so that the queue length 2037702e47cSPaolo Bonzini * won't change when moving between 32 and 64 bit hosts. 2047702e47cSPaolo Bonzini */ 2058935a442SScott Wood unsigned long queue[BITS_TO_LONGS((OPENPIC_MAX_IRQ + 63) & ~63)]; 2067702e47cSPaolo Bonzini int next; 2077702e47cSPaolo Bonzini int priority; 2087702e47cSPaolo Bonzini } IRQQueue; 2097702e47cSPaolo Bonzini 2107702e47cSPaolo Bonzini typedef struct IRQSource { 2117702e47cSPaolo Bonzini uint32_t ivpr; /* IRQ vector/priority register */ 2127702e47cSPaolo Bonzini uint32_t idr; /* IRQ destination register */ 2137702e47cSPaolo Bonzini uint32_t destmask; /* bitmap of CPU destinations */ 2147702e47cSPaolo Bonzini int last_cpu; 2157702e47cSPaolo Bonzini int output; /* IRQ level, e.g. OPENPIC_OUTPUT_INT */ 2167702e47cSPaolo Bonzini int pending; /* TRUE if IRQ is pending */ 2177702e47cSPaolo Bonzini IRQType type; 2187702e47cSPaolo Bonzini bool level:1; /* level-triggered */ 2197702e47cSPaolo Bonzini bool nomask:1; /* critical interrupts ignore mask on some FSL MPICs */ 2207702e47cSPaolo Bonzini } IRQSource; 2217702e47cSPaolo Bonzini 2227702e47cSPaolo Bonzini #define IVPR_MASK_SHIFT 31 2237702e47cSPaolo Bonzini #define IVPR_MASK_MASK (1 << IVPR_MASK_SHIFT) 2247702e47cSPaolo Bonzini #define IVPR_ACTIVITY_SHIFT 30 2257702e47cSPaolo Bonzini #define IVPR_ACTIVITY_MASK (1 << IVPR_ACTIVITY_SHIFT) 2267702e47cSPaolo Bonzini #define IVPR_MODE_SHIFT 29 2277702e47cSPaolo Bonzini #define IVPR_MODE_MASK (1 << IVPR_MODE_SHIFT) 2287702e47cSPaolo Bonzini #define IVPR_POLARITY_SHIFT 23 2297702e47cSPaolo Bonzini #define IVPR_POLARITY_MASK (1 << IVPR_POLARITY_SHIFT) 2307702e47cSPaolo Bonzini #define IVPR_SENSE_SHIFT 22 2317702e47cSPaolo Bonzini #define IVPR_SENSE_MASK (1 << IVPR_SENSE_SHIFT) 2327702e47cSPaolo Bonzini 2337702e47cSPaolo Bonzini #define IVPR_PRIORITY_MASK (0xF << 16) 2347702e47cSPaolo Bonzini #define IVPR_PRIORITY(_ivprr_) ((int)(((_ivprr_) & IVPR_PRIORITY_MASK) >> 16)) 2357702e47cSPaolo Bonzini #define IVPR_VECTOR(opp, _ivprr_) ((_ivprr_) & (opp)->vector_mask) 2367702e47cSPaolo Bonzini 2377702e47cSPaolo Bonzini /* IDR[EP/CI] are only for FSL MPIC prior to v4.0 */ 2387702e47cSPaolo Bonzini #define IDR_EP 0x80000000 /* external pin */ 2397702e47cSPaolo Bonzini #define IDR_CI 0x40000000 /* critical interrupt */ 2407702e47cSPaolo Bonzini 2417702e47cSPaolo Bonzini typedef struct IRQDest { 2427702e47cSPaolo Bonzini int32_t ctpr; /* CPU current task priority */ 2437702e47cSPaolo Bonzini IRQQueue raised; 2447702e47cSPaolo Bonzini IRQQueue servicing; 2457702e47cSPaolo Bonzini qemu_irq *irqs; 2467702e47cSPaolo Bonzini 2477702e47cSPaolo Bonzini /* Count of IRQ sources asserting on non-INT outputs */ 2487702e47cSPaolo Bonzini uint32_t outputs_active[OPENPIC_OUTPUT_NB]; 2497702e47cSPaolo Bonzini } IRQDest; 2507702e47cSPaolo Bonzini 251e1766344SAndreas Färber #define OPENPIC(obj) OBJECT_CHECK(OpenPICState, (obj), TYPE_OPENPIC) 252e1766344SAndreas Färber 2537702e47cSPaolo Bonzini typedef struct OpenPICState { 254e1766344SAndreas Färber /*< private >*/ 255e1766344SAndreas Färber SysBusDevice parent_obj; 256e1766344SAndreas Färber /*< public >*/ 257e1766344SAndreas Färber 2587702e47cSPaolo Bonzini MemoryRegion mem; 2597702e47cSPaolo Bonzini 2607702e47cSPaolo Bonzini /* Behavior control */ 2617702e47cSPaolo Bonzini FslMpicInfo *fsl; 2627702e47cSPaolo Bonzini uint32_t model; 2637702e47cSPaolo Bonzini uint32_t flags; 2647702e47cSPaolo Bonzini uint32_t nb_irqs; 2657702e47cSPaolo Bonzini uint32_t vid; 2667702e47cSPaolo Bonzini uint32_t vir; /* Vendor identification register */ 2677702e47cSPaolo Bonzini uint32_t vector_mask; 2687702e47cSPaolo Bonzini uint32_t tfrr_reset; 2697702e47cSPaolo Bonzini uint32_t ivpr_reset; 2707702e47cSPaolo Bonzini uint32_t idr_reset; 2717702e47cSPaolo Bonzini uint32_t brr1; 2727702e47cSPaolo Bonzini uint32_t mpic_mode_mask; 2737702e47cSPaolo Bonzini 2747702e47cSPaolo Bonzini /* Sub-regions */ 2757702e47cSPaolo Bonzini MemoryRegion sub_io_mem[6]; 2767702e47cSPaolo Bonzini 2777702e47cSPaolo Bonzini /* Global registers */ 2787702e47cSPaolo Bonzini uint32_t frr; /* Feature reporting register */ 2797702e47cSPaolo Bonzini uint32_t gcr; /* Global configuration register */ 2807702e47cSPaolo Bonzini uint32_t pir; /* Processor initialization register */ 2817702e47cSPaolo Bonzini uint32_t spve; /* Spurious vector register */ 2827702e47cSPaolo Bonzini uint32_t tfrr; /* Timer frequency reporting register */ 2837702e47cSPaolo Bonzini /* Source registers */ 2848935a442SScott Wood IRQSource src[OPENPIC_MAX_IRQ]; 2857702e47cSPaolo Bonzini /* Local registers per output pin */ 2867702e47cSPaolo Bonzini IRQDest dst[MAX_CPU]; 2877702e47cSPaolo Bonzini uint32_t nb_cpus; 2887702e47cSPaolo Bonzini /* Timer registers */ 2897702e47cSPaolo Bonzini struct { 2907702e47cSPaolo Bonzini uint32_t tccr; /* Global timer current count register */ 2917702e47cSPaolo Bonzini uint32_t tbcr; /* Global timer base count register */ 2928935a442SScott Wood } timers[OPENPIC_MAX_TMR]; 2937702e47cSPaolo Bonzini /* Shared MSI registers */ 2947702e47cSPaolo Bonzini struct { 2957702e47cSPaolo Bonzini uint32_t msir; /* Shared Message Signaled Interrupt Register */ 2967702e47cSPaolo Bonzini } msi[MAX_MSI]; 2977702e47cSPaolo Bonzini uint32_t max_irq; 2987702e47cSPaolo Bonzini uint32_t irq_ipi0; 2997702e47cSPaolo Bonzini uint32_t irq_tim0; 3007702e47cSPaolo Bonzini uint32_t irq_msi; 3017702e47cSPaolo Bonzini } OpenPICState; 3027702e47cSPaolo Bonzini 3037702e47cSPaolo Bonzini static inline void IRQ_setbit(IRQQueue *q, int n_IRQ) 3047702e47cSPaolo Bonzini { 3057702e47cSPaolo Bonzini set_bit(n_IRQ, q->queue); 3067702e47cSPaolo Bonzini } 3077702e47cSPaolo Bonzini 3087702e47cSPaolo Bonzini static inline void IRQ_resetbit(IRQQueue *q, int n_IRQ) 3097702e47cSPaolo Bonzini { 3107702e47cSPaolo Bonzini clear_bit(n_IRQ, q->queue); 3117702e47cSPaolo Bonzini } 3127702e47cSPaolo Bonzini 3137702e47cSPaolo Bonzini static inline int IRQ_testbit(IRQQueue *q, int n_IRQ) 3147702e47cSPaolo Bonzini { 3157702e47cSPaolo Bonzini return test_bit(n_IRQ, q->queue); 3167702e47cSPaolo Bonzini } 3177702e47cSPaolo Bonzini 3187702e47cSPaolo Bonzini static void IRQ_check(OpenPICState *opp, IRQQueue *q) 3197702e47cSPaolo Bonzini { 3207702e47cSPaolo Bonzini int irq = -1; 3217702e47cSPaolo Bonzini int next = -1; 3227702e47cSPaolo Bonzini int priority = -1; 3237702e47cSPaolo Bonzini 3247702e47cSPaolo Bonzini for (;;) { 3257702e47cSPaolo Bonzini irq = find_next_bit(q->queue, opp->max_irq, irq + 1); 3267702e47cSPaolo Bonzini if (irq == opp->max_irq) { 3277702e47cSPaolo Bonzini break; 3287702e47cSPaolo Bonzini } 3297702e47cSPaolo Bonzini 3307702e47cSPaolo Bonzini DPRINTF("IRQ_check: irq %d set ivpr_pr=%d pr=%d\n", 3317702e47cSPaolo Bonzini irq, IVPR_PRIORITY(opp->src[irq].ivpr), priority); 3327702e47cSPaolo Bonzini 3337702e47cSPaolo Bonzini if (IVPR_PRIORITY(opp->src[irq].ivpr) > priority) { 3347702e47cSPaolo Bonzini next = irq; 3357702e47cSPaolo Bonzini priority = IVPR_PRIORITY(opp->src[irq].ivpr); 3367702e47cSPaolo Bonzini } 3377702e47cSPaolo Bonzini } 3387702e47cSPaolo Bonzini 3397702e47cSPaolo Bonzini q->next = next; 3407702e47cSPaolo Bonzini q->priority = priority; 3417702e47cSPaolo Bonzini } 3427702e47cSPaolo Bonzini 3437702e47cSPaolo Bonzini static int IRQ_get_next(OpenPICState *opp, IRQQueue *q) 3447702e47cSPaolo Bonzini { 3457702e47cSPaolo Bonzini /* XXX: optimize */ 3467702e47cSPaolo Bonzini IRQ_check(opp, q); 3477702e47cSPaolo Bonzini 3487702e47cSPaolo Bonzini return q->next; 3497702e47cSPaolo Bonzini } 3507702e47cSPaolo Bonzini 3517702e47cSPaolo Bonzini static void IRQ_local_pipe(OpenPICState *opp, int n_CPU, int n_IRQ, 3527702e47cSPaolo Bonzini bool active, bool was_active) 3537702e47cSPaolo Bonzini { 3547702e47cSPaolo Bonzini IRQDest *dst; 3557702e47cSPaolo Bonzini IRQSource *src; 3567702e47cSPaolo Bonzini int priority; 3577702e47cSPaolo Bonzini 3587702e47cSPaolo Bonzini dst = &opp->dst[n_CPU]; 3597702e47cSPaolo Bonzini src = &opp->src[n_IRQ]; 3607702e47cSPaolo Bonzini 3617702e47cSPaolo Bonzini DPRINTF("%s: IRQ %d active %d was %d\n", 3627702e47cSPaolo Bonzini __func__, n_IRQ, active, was_active); 3637702e47cSPaolo Bonzini 3647702e47cSPaolo Bonzini if (src->output != OPENPIC_OUTPUT_INT) { 3657702e47cSPaolo Bonzini DPRINTF("%s: output %d irq %d active %d was %d count %d\n", 3667702e47cSPaolo Bonzini __func__, src->output, n_IRQ, active, was_active, 3677702e47cSPaolo Bonzini dst->outputs_active[src->output]); 3687702e47cSPaolo Bonzini 3697702e47cSPaolo Bonzini /* On Freescale MPIC, critical interrupts ignore priority, 3707702e47cSPaolo Bonzini * IACK, EOI, etc. Before MPIC v4.1 they also ignore 3717702e47cSPaolo Bonzini * masking. 3727702e47cSPaolo Bonzini */ 3737702e47cSPaolo Bonzini if (active) { 3747702e47cSPaolo Bonzini if (!was_active && dst->outputs_active[src->output]++ == 0) { 3757702e47cSPaolo Bonzini DPRINTF("%s: Raise OpenPIC output %d cpu %d irq %d\n", 3767702e47cSPaolo Bonzini __func__, src->output, n_CPU, n_IRQ); 3777702e47cSPaolo Bonzini qemu_irq_raise(dst->irqs[src->output]); 3787702e47cSPaolo Bonzini } 3797702e47cSPaolo Bonzini } else { 3807702e47cSPaolo Bonzini if (was_active && --dst->outputs_active[src->output] == 0) { 3817702e47cSPaolo Bonzini DPRINTF("%s: Lower OpenPIC output %d cpu %d irq %d\n", 3827702e47cSPaolo Bonzini __func__, src->output, n_CPU, n_IRQ); 3837702e47cSPaolo Bonzini qemu_irq_lower(dst->irqs[src->output]); 3847702e47cSPaolo Bonzini } 3857702e47cSPaolo Bonzini } 3867702e47cSPaolo Bonzini 3877702e47cSPaolo Bonzini return; 3887702e47cSPaolo Bonzini } 3897702e47cSPaolo Bonzini 3907702e47cSPaolo Bonzini priority = IVPR_PRIORITY(src->ivpr); 3917702e47cSPaolo Bonzini 3927702e47cSPaolo Bonzini /* Even if the interrupt doesn't have enough priority, 3937702e47cSPaolo Bonzini * it is still raised, in case ctpr is lowered later. 3947702e47cSPaolo Bonzini */ 3957702e47cSPaolo Bonzini if (active) { 3967702e47cSPaolo Bonzini IRQ_setbit(&dst->raised, n_IRQ); 3977702e47cSPaolo Bonzini } else { 3987702e47cSPaolo Bonzini IRQ_resetbit(&dst->raised, n_IRQ); 3997702e47cSPaolo Bonzini } 4007702e47cSPaolo Bonzini 4017702e47cSPaolo Bonzini IRQ_check(opp, &dst->raised); 4027702e47cSPaolo Bonzini 4037702e47cSPaolo Bonzini if (active && priority <= dst->ctpr) { 4047702e47cSPaolo Bonzini DPRINTF("%s: IRQ %d priority %d too low for ctpr %d on CPU %d\n", 4057702e47cSPaolo Bonzini __func__, n_IRQ, priority, dst->ctpr, n_CPU); 4067702e47cSPaolo Bonzini active = 0; 4077702e47cSPaolo Bonzini } 4087702e47cSPaolo Bonzini 4097702e47cSPaolo Bonzini if (active) { 4107702e47cSPaolo Bonzini if (IRQ_get_next(opp, &dst->servicing) >= 0 && 4117702e47cSPaolo Bonzini priority <= dst->servicing.priority) { 4127702e47cSPaolo Bonzini DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n", 4137702e47cSPaolo Bonzini __func__, n_IRQ, dst->servicing.next, n_CPU); 4147702e47cSPaolo Bonzini } else { 4157702e47cSPaolo Bonzini DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d/%d\n", 4167702e47cSPaolo Bonzini __func__, n_CPU, n_IRQ, dst->raised.next); 4177702e47cSPaolo Bonzini qemu_irq_raise(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]); 4187702e47cSPaolo Bonzini } 4197702e47cSPaolo Bonzini } else { 4207702e47cSPaolo Bonzini IRQ_get_next(opp, &dst->servicing); 4217702e47cSPaolo Bonzini if (dst->raised.priority > dst->ctpr && 4227702e47cSPaolo Bonzini dst->raised.priority > dst->servicing.priority) { 4237702e47cSPaolo Bonzini DPRINTF("%s: IRQ %d inactive, IRQ %d prio %d above %d/%d, CPU %d\n", 4247702e47cSPaolo Bonzini __func__, n_IRQ, dst->raised.next, dst->raised.priority, 4257702e47cSPaolo Bonzini dst->ctpr, dst->servicing.priority, n_CPU); 4267702e47cSPaolo Bonzini /* IRQ line stays asserted */ 4277702e47cSPaolo Bonzini } else { 4287702e47cSPaolo Bonzini DPRINTF("%s: IRQ %d inactive, current prio %d/%d, CPU %d\n", 4297702e47cSPaolo Bonzini __func__, n_IRQ, dst->ctpr, dst->servicing.priority, n_CPU); 4307702e47cSPaolo Bonzini qemu_irq_lower(opp->dst[n_CPU].irqs[OPENPIC_OUTPUT_INT]); 4317702e47cSPaolo Bonzini } 4327702e47cSPaolo Bonzini } 4337702e47cSPaolo Bonzini } 4347702e47cSPaolo Bonzini 4357702e47cSPaolo Bonzini /* update pic state because registers for n_IRQ have changed value */ 4367702e47cSPaolo Bonzini static void openpic_update_irq(OpenPICState *opp, int n_IRQ) 4377702e47cSPaolo Bonzini { 4387702e47cSPaolo Bonzini IRQSource *src; 4397702e47cSPaolo Bonzini bool active, was_active; 4407702e47cSPaolo Bonzini int i; 4417702e47cSPaolo Bonzini 4427702e47cSPaolo Bonzini src = &opp->src[n_IRQ]; 4437702e47cSPaolo Bonzini active = src->pending; 4447702e47cSPaolo Bonzini 4457702e47cSPaolo Bonzini if ((src->ivpr & IVPR_MASK_MASK) && !src->nomask) { 4467702e47cSPaolo Bonzini /* Interrupt source is disabled */ 4477702e47cSPaolo Bonzini DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ); 4487702e47cSPaolo Bonzini active = false; 4497702e47cSPaolo Bonzini } 4507702e47cSPaolo Bonzini 4517702e47cSPaolo Bonzini was_active = !!(src->ivpr & IVPR_ACTIVITY_MASK); 4527702e47cSPaolo Bonzini 4537702e47cSPaolo Bonzini /* 4547702e47cSPaolo Bonzini * We don't have a similar check for already-active because 4557702e47cSPaolo Bonzini * ctpr may have changed and we need to withdraw the interrupt. 4567702e47cSPaolo Bonzini */ 4577702e47cSPaolo Bonzini if (!active && !was_active) { 4587702e47cSPaolo Bonzini DPRINTF("%s: IRQ %d is already inactive\n", __func__, n_IRQ); 4597702e47cSPaolo Bonzini return; 4607702e47cSPaolo Bonzini } 4617702e47cSPaolo Bonzini 4627702e47cSPaolo Bonzini if (active) { 4637702e47cSPaolo Bonzini src->ivpr |= IVPR_ACTIVITY_MASK; 4647702e47cSPaolo Bonzini } else { 4657702e47cSPaolo Bonzini src->ivpr &= ~IVPR_ACTIVITY_MASK; 4667702e47cSPaolo Bonzini } 4677702e47cSPaolo Bonzini 4687702e47cSPaolo Bonzini if (src->destmask == 0) { 4697702e47cSPaolo Bonzini /* No target */ 4707702e47cSPaolo Bonzini DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ); 4717702e47cSPaolo Bonzini return; 4727702e47cSPaolo Bonzini } 4737702e47cSPaolo Bonzini 4747702e47cSPaolo Bonzini if (src->destmask == (1 << src->last_cpu)) { 4757702e47cSPaolo Bonzini /* Only one CPU is allowed to receive this IRQ */ 4767702e47cSPaolo Bonzini IRQ_local_pipe(opp, src->last_cpu, n_IRQ, active, was_active); 4777702e47cSPaolo Bonzini } else if (!(src->ivpr & IVPR_MODE_MASK)) { 4787702e47cSPaolo Bonzini /* Directed delivery mode */ 4797702e47cSPaolo Bonzini for (i = 0; i < opp->nb_cpus; i++) { 4807702e47cSPaolo Bonzini if (src->destmask & (1 << i)) { 4817702e47cSPaolo Bonzini IRQ_local_pipe(opp, i, n_IRQ, active, was_active); 4827702e47cSPaolo Bonzini } 4837702e47cSPaolo Bonzini } 4847702e47cSPaolo Bonzini } else { 4857702e47cSPaolo Bonzini /* Distributed delivery mode */ 4867702e47cSPaolo Bonzini for (i = src->last_cpu + 1; i != src->last_cpu; i++) { 4877702e47cSPaolo Bonzini if (i == opp->nb_cpus) { 4887702e47cSPaolo Bonzini i = 0; 4897702e47cSPaolo Bonzini } 4907702e47cSPaolo Bonzini if (src->destmask & (1 << i)) { 4917702e47cSPaolo Bonzini IRQ_local_pipe(opp, i, n_IRQ, active, was_active); 4927702e47cSPaolo Bonzini src->last_cpu = i; 4937702e47cSPaolo Bonzini break; 4947702e47cSPaolo Bonzini } 4957702e47cSPaolo Bonzini } 4967702e47cSPaolo Bonzini } 4977702e47cSPaolo Bonzini } 4987702e47cSPaolo Bonzini 4997702e47cSPaolo Bonzini static void openpic_set_irq(void *opaque, int n_IRQ, int level) 5007702e47cSPaolo Bonzini { 5017702e47cSPaolo Bonzini OpenPICState *opp = opaque; 5027702e47cSPaolo Bonzini IRQSource *src; 5037702e47cSPaolo Bonzini 5048935a442SScott Wood if (n_IRQ >= OPENPIC_MAX_IRQ) { 5057702e47cSPaolo Bonzini fprintf(stderr, "%s: IRQ %d out of range\n", __func__, n_IRQ); 5067702e47cSPaolo Bonzini abort(); 5077702e47cSPaolo Bonzini } 5087702e47cSPaolo Bonzini 5097702e47cSPaolo Bonzini src = &opp->src[n_IRQ]; 5107702e47cSPaolo Bonzini DPRINTF("openpic: set irq %d = %d ivpr=0x%08x\n", 5117702e47cSPaolo Bonzini n_IRQ, level, src->ivpr); 5127702e47cSPaolo Bonzini if (src->level) { 5137702e47cSPaolo Bonzini /* level-sensitive irq */ 5147702e47cSPaolo Bonzini src->pending = level; 5157702e47cSPaolo Bonzini openpic_update_irq(opp, n_IRQ); 5167702e47cSPaolo Bonzini } else { 5177702e47cSPaolo Bonzini /* edge-sensitive irq */ 5187702e47cSPaolo Bonzini if (level) { 5197702e47cSPaolo Bonzini src->pending = 1; 5207702e47cSPaolo Bonzini openpic_update_irq(opp, n_IRQ); 5217702e47cSPaolo Bonzini } 5227702e47cSPaolo Bonzini 5237702e47cSPaolo Bonzini if (src->output != OPENPIC_OUTPUT_INT) { 5247702e47cSPaolo Bonzini /* Edge-triggered interrupts shouldn't be used 5257702e47cSPaolo Bonzini * with non-INT delivery, but just in case, 5267702e47cSPaolo Bonzini * try to make it do something sane rather than 5277702e47cSPaolo Bonzini * cause an interrupt storm. This is close to 5287702e47cSPaolo Bonzini * what you'd probably see happen in real hardware. 5297702e47cSPaolo Bonzini */ 5307702e47cSPaolo Bonzini src->pending = 0; 5317702e47cSPaolo Bonzini openpic_update_irq(opp, n_IRQ); 5327702e47cSPaolo Bonzini } 5337702e47cSPaolo Bonzini } 5347702e47cSPaolo Bonzini } 5357702e47cSPaolo Bonzini 5367702e47cSPaolo Bonzini static void openpic_reset(DeviceState *d) 5377702e47cSPaolo Bonzini { 538e1766344SAndreas Färber OpenPICState *opp = OPENPIC(d); 5397702e47cSPaolo Bonzini int i; 5407702e47cSPaolo Bonzini 5417702e47cSPaolo Bonzini opp->gcr = GCR_RESET; 5427702e47cSPaolo Bonzini /* Initialise controller registers */ 5437702e47cSPaolo Bonzini opp->frr = ((opp->nb_irqs - 1) << FRR_NIRQ_SHIFT) | 5447702e47cSPaolo Bonzini ((opp->nb_cpus - 1) << FRR_NCPU_SHIFT) | 5457702e47cSPaolo Bonzini (opp->vid << FRR_VID_SHIFT); 5467702e47cSPaolo Bonzini 5477702e47cSPaolo Bonzini opp->pir = 0; 5487702e47cSPaolo Bonzini opp->spve = -1 & opp->vector_mask; 5497702e47cSPaolo Bonzini opp->tfrr = opp->tfrr_reset; 5507702e47cSPaolo Bonzini /* Initialise IRQ sources */ 5517702e47cSPaolo Bonzini for (i = 0; i < opp->max_irq; i++) { 5527702e47cSPaolo Bonzini opp->src[i].ivpr = opp->ivpr_reset; 5537702e47cSPaolo Bonzini opp->src[i].idr = opp->idr_reset; 5547702e47cSPaolo Bonzini 5557702e47cSPaolo Bonzini switch (opp->src[i].type) { 5567702e47cSPaolo Bonzini case IRQ_TYPE_NORMAL: 5577702e47cSPaolo Bonzini opp->src[i].level = !!(opp->ivpr_reset & IVPR_SENSE_MASK); 5587702e47cSPaolo Bonzini break; 5597702e47cSPaolo Bonzini 5607702e47cSPaolo Bonzini case IRQ_TYPE_FSLINT: 5617702e47cSPaolo Bonzini opp->src[i].ivpr |= IVPR_POLARITY_MASK; 5627702e47cSPaolo Bonzini break; 5637702e47cSPaolo Bonzini 5647702e47cSPaolo Bonzini case IRQ_TYPE_FSLSPECIAL: 5657702e47cSPaolo Bonzini break; 5667702e47cSPaolo Bonzini } 5677702e47cSPaolo Bonzini } 5687702e47cSPaolo Bonzini /* Initialise IRQ destinations */ 5697702e47cSPaolo Bonzini for (i = 0; i < MAX_CPU; i++) { 5707702e47cSPaolo Bonzini opp->dst[i].ctpr = 15; 5717702e47cSPaolo Bonzini memset(&opp->dst[i].raised, 0, sizeof(IRQQueue)); 5727702e47cSPaolo Bonzini opp->dst[i].raised.next = -1; 5737702e47cSPaolo Bonzini memset(&opp->dst[i].servicing, 0, sizeof(IRQQueue)); 5747702e47cSPaolo Bonzini opp->dst[i].servicing.next = -1; 5757702e47cSPaolo Bonzini } 5767702e47cSPaolo Bonzini /* Initialise timers */ 5778935a442SScott Wood for (i = 0; i < OPENPIC_MAX_TMR; i++) { 5787702e47cSPaolo Bonzini opp->timers[i].tccr = 0; 5797702e47cSPaolo Bonzini opp->timers[i].tbcr = TBCR_CI; 5807702e47cSPaolo Bonzini } 5817702e47cSPaolo Bonzini /* Go out of RESET state */ 5827702e47cSPaolo Bonzini opp->gcr = 0; 5837702e47cSPaolo Bonzini } 5847702e47cSPaolo Bonzini 5857702e47cSPaolo Bonzini static inline uint32_t read_IRQreg_idr(OpenPICState *opp, int n_IRQ) 5867702e47cSPaolo Bonzini { 5877702e47cSPaolo Bonzini return opp->src[n_IRQ].idr; 5887702e47cSPaolo Bonzini } 5897702e47cSPaolo Bonzini 5907702e47cSPaolo Bonzini static inline uint32_t read_IRQreg_ilr(OpenPICState *opp, int n_IRQ) 5917702e47cSPaolo Bonzini { 5927702e47cSPaolo Bonzini if (opp->flags & OPENPIC_FLAG_ILR) { 5937702e47cSPaolo Bonzini return output_to_inttgt(opp->src[n_IRQ].output); 5947702e47cSPaolo Bonzini } 5957702e47cSPaolo Bonzini 5967702e47cSPaolo Bonzini return 0xffffffff; 5977702e47cSPaolo Bonzini } 5987702e47cSPaolo Bonzini 5997702e47cSPaolo Bonzini static inline uint32_t read_IRQreg_ivpr(OpenPICState *opp, int n_IRQ) 6007702e47cSPaolo Bonzini { 6017702e47cSPaolo Bonzini return opp->src[n_IRQ].ivpr; 6027702e47cSPaolo Bonzini } 6037702e47cSPaolo Bonzini 6047702e47cSPaolo Bonzini static inline void write_IRQreg_idr(OpenPICState *opp, int n_IRQ, uint32_t val) 6057702e47cSPaolo Bonzini { 6067702e47cSPaolo Bonzini IRQSource *src = &opp->src[n_IRQ]; 6077702e47cSPaolo Bonzini uint32_t normal_mask = (1UL << opp->nb_cpus) - 1; 6087702e47cSPaolo Bonzini uint32_t crit_mask = 0; 6097702e47cSPaolo Bonzini uint32_t mask = normal_mask; 6107702e47cSPaolo Bonzini int crit_shift = IDR_EP_SHIFT - opp->nb_cpus; 6117702e47cSPaolo Bonzini int i; 6127702e47cSPaolo Bonzini 6137702e47cSPaolo Bonzini if (opp->flags & OPENPIC_FLAG_IDR_CRIT) { 6147702e47cSPaolo Bonzini crit_mask = mask << crit_shift; 6157702e47cSPaolo Bonzini mask |= crit_mask | IDR_EP; 6167702e47cSPaolo Bonzini } 6177702e47cSPaolo Bonzini 6187702e47cSPaolo Bonzini src->idr = val & mask; 6197702e47cSPaolo Bonzini DPRINTF("Set IDR %d to 0x%08x\n", n_IRQ, src->idr); 6207702e47cSPaolo Bonzini 6217702e47cSPaolo Bonzini if (opp->flags & OPENPIC_FLAG_IDR_CRIT) { 6227702e47cSPaolo Bonzini if (src->idr & crit_mask) { 6237702e47cSPaolo Bonzini if (src->idr & normal_mask) { 6247702e47cSPaolo Bonzini DPRINTF("%s: IRQ configured for multiple output types, using " 6257702e47cSPaolo Bonzini "critical\n", __func__); 6267702e47cSPaolo Bonzini } 6277702e47cSPaolo Bonzini 6287702e47cSPaolo Bonzini src->output = OPENPIC_OUTPUT_CINT; 6297702e47cSPaolo Bonzini src->nomask = true; 6307702e47cSPaolo Bonzini src->destmask = 0; 6317702e47cSPaolo Bonzini 6327702e47cSPaolo Bonzini for (i = 0; i < opp->nb_cpus; i++) { 6337702e47cSPaolo Bonzini int n_ci = IDR_CI0_SHIFT - i; 6347702e47cSPaolo Bonzini 6357702e47cSPaolo Bonzini if (src->idr & (1UL << n_ci)) { 6367702e47cSPaolo Bonzini src->destmask |= 1UL << i; 6377702e47cSPaolo Bonzini } 6387702e47cSPaolo Bonzini } 6397702e47cSPaolo Bonzini } else { 6407702e47cSPaolo Bonzini src->output = OPENPIC_OUTPUT_INT; 6417702e47cSPaolo Bonzini src->nomask = false; 6427702e47cSPaolo Bonzini src->destmask = src->idr & normal_mask; 6437702e47cSPaolo Bonzini } 6447702e47cSPaolo Bonzini } else { 6457702e47cSPaolo Bonzini src->destmask = src->idr; 6467702e47cSPaolo Bonzini } 6477702e47cSPaolo Bonzini } 6487702e47cSPaolo Bonzini 6497702e47cSPaolo Bonzini static inline void write_IRQreg_ilr(OpenPICState *opp, int n_IRQ, uint32_t val) 6507702e47cSPaolo Bonzini { 6517702e47cSPaolo Bonzini if (opp->flags & OPENPIC_FLAG_ILR) { 6527702e47cSPaolo Bonzini IRQSource *src = &opp->src[n_IRQ]; 6537702e47cSPaolo Bonzini 6547702e47cSPaolo Bonzini src->output = inttgt_to_output(val & ILR_INTTGT_MASK); 6557702e47cSPaolo Bonzini DPRINTF("Set ILR %d to 0x%08x, output %d\n", n_IRQ, src->idr, 6567702e47cSPaolo Bonzini src->output); 6577702e47cSPaolo Bonzini 6587702e47cSPaolo Bonzini /* TODO: on MPIC v4.0 only, set nomask for non-INT */ 6597702e47cSPaolo Bonzini } 6607702e47cSPaolo Bonzini } 6617702e47cSPaolo Bonzini 6627702e47cSPaolo Bonzini static inline void write_IRQreg_ivpr(OpenPICState *opp, int n_IRQ, uint32_t val) 6637702e47cSPaolo Bonzini { 6647702e47cSPaolo Bonzini uint32_t mask; 6657702e47cSPaolo Bonzini 6667702e47cSPaolo Bonzini /* NOTE when implementing newer FSL MPIC models: starting with v4.0, 6677702e47cSPaolo Bonzini * the polarity bit is read-only on internal interrupts. 6687702e47cSPaolo Bonzini */ 6697702e47cSPaolo Bonzini mask = IVPR_MASK_MASK | IVPR_PRIORITY_MASK | IVPR_SENSE_MASK | 6707702e47cSPaolo Bonzini IVPR_POLARITY_MASK | opp->vector_mask; 6717702e47cSPaolo Bonzini 6727702e47cSPaolo Bonzini /* ACTIVITY bit is read-only */ 6737702e47cSPaolo Bonzini opp->src[n_IRQ].ivpr = 6747702e47cSPaolo Bonzini (opp->src[n_IRQ].ivpr & IVPR_ACTIVITY_MASK) | (val & mask); 6757702e47cSPaolo Bonzini 6767702e47cSPaolo Bonzini /* For FSL internal interrupts, The sense bit is reserved and zero, 6777702e47cSPaolo Bonzini * and the interrupt is always level-triggered. Timers and IPIs 6787702e47cSPaolo Bonzini * have no sense or polarity bits, and are edge-triggered. 6797702e47cSPaolo Bonzini */ 6807702e47cSPaolo Bonzini switch (opp->src[n_IRQ].type) { 6817702e47cSPaolo Bonzini case IRQ_TYPE_NORMAL: 6827702e47cSPaolo Bonzini opp->src[n_IRQ].level = !!(opp->src[n_IRQ].ivpr & IVPR_SENSE_MASK); 6837702e47cSPaolo Bonzini break; 6847702e47cSPaolo Bonzini 6857702e47cSPaolo Bonzini case IRQ_TYPE_FSLINT: 6867702e47cSPaolo Bonzini opp->src[n_IRQ].ivpr &= ~IVPR_SENSE_MASK; 6877702e47cSPaolo Bonzini break; 6887702e47cSPaolo Bonzini 6897702e47cSPaolo Bonzini case IRQ_TYPE_FSLSPECIAL: 6907702e47cSPaolo Bonzini opp->src[n_IRQ].ivpr &= ~(IVPR_POLARITY_MASK | IVPR_SENSE_MASK); 6917702e47cSPaolo Bonzini break; 6927702e47cSPaolo Bonzini } 6937702e47cSPaolo Bonzini 6947702e47cSPaolo Bonzini openpic_update_irq(opp, n_IRQ); 6957702e47cSPaolo Bonzini DPRINTF("Set IVPR %d to 0x%08x -> 0x%08x\n", n_IRQ, val, 6967702e47cSPaolo Bonzini opp->src[n_IRQ].ivpr); 6977702e47cSPaolo Bonzini } 6987702e47cSPaolo Bonzini 6997702e47cSPaolo Bonzini static void openpic_gcr_write(OpenPICState *opp, uint64_t val) 7007702e47cSPaolo Bonzini { 7017702e47cSPaolo Bonzini bool mpic_proxy = false; 7027702e47cSPaolo Bonzini 7037702e47cSPaolo Bonzini if (val & GCR_RESET) { 704e1766344SAndreas Färber openpic_reset(DEVICE(opp)); 7057702e47cSPaolo Bonzini return; 7067702e47cSPaolo Bonzini } 7077702e47cSPaolo Bonzini 7087702e47cSPaolo Bonzini opp->gcr &= ~opp->mpic_mode_mask; 7097702e47cSPaolo Bonzini opp->gcr |= val & opp->mpic_mode_mask; 7107702e47cSPaolo Bonzini 7117702e47cSPaolo Bonzini /* Set external proxy mode */ 7127702e47cSPaolo Bonzini if ((val & opp->mpic_mode_mask) == GCR_MODE_PROXY) { 7137702e47cSPaolo Bonzini mpic_proxy = true; 7147702e47cSPaolo Bonzini } 7157702e47cSPaolo Bonzini 7167702e47cSPaolo Bonzini ppce500_set_mpic_proxy(mpic_proxy); 7177702e47cSPaolo Bonzini } 7187702e47cSPaolo Bonzini 7197702e47cSPaolo Bonzini static void openpic_gbl_write(void *opaque, hwaddr addr, uint64_t val, 7207702e47cSPaolo Bonzini unsigned len) 7217702e47cSPaolo Bonzini { 7227702e47cSPaolo Bonzini OpenPICState *opp = opaque; 7237702e47cSPaolo Bonzini IRQDest *dst; 7247702e47cSPaolo Bonzini int idx; 7257702e47cSPaolo Bonzini 7267702e47cSPaolo Bonzini DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n", 7277702e47cSPaolo Bonzini __func__, addr, val); 7287702e47cSPaolo Bonzini if (addr & 0xF) { 7297702e47cSPaolo Bonzini return; 7307702e47cSPaolo Bonzini } 7317702e47cSPaolo Bonzini switch (addr) { 7327702e47cSPaolo Bonzini case 0x00: /* Block Revision Register1 (BRR1) is Readonly */ 7337702e47cSPaolo Bonzini break; 7347702e47cSPaolo Bonzini case 0x40: 7357702e47cSPaolo Bonzini case 0x50: 7367702e47cSPaolo Bonzini case 0x60: 7377702e47cSPaolo Bonzini case 0x70: 7387702e47cSPaolo Bonzini case 0x80: 7397702e47cSPaolo Bonzini case 0x90: 7407702e47cSPaolo Bonzini case 0xA0: 7417702e47cSPaolo Bonzini case 0xB0: 7427702e47cSPaolo Bonzini openpic_cpu_write_internal(opp, addr, val, get_current_cpu()); 7437702e47cSPaolo Bonzini break; 7447702e47cSPaolo Bonzini case 0x1000: /* FRR */ 7457702e47cSPaolo Bonzini break; 7467702e47cSPaolo Bonzini case 0x1020: /* GCR */ 7477702e47cSPaolo Bonzini openpic_gcr_write(opp, val); 7487702e47cSPaolo Bonzini break; 7497702e47cSPaolo Bonzini case 0x1080: /* VIR */ 7507702e47cSPaolo Bonzini break; 7517702e47cSPaolo Bonzini case 0x1090: /* PIR */ 7527702e47cSPaolo Bonzini for (idx = 0; idx < opp->nb_cpus; idx++) { 7537702e47cSPaolo Bonzini if ((val & (1 << idx)) && !(opp->pir & (1 << idx))) { 7547702e47cSPaolo Bonzini DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx); 7557702e47cSPaolo Bonzini dst = &opp->dst[idx]; 7567702e47cSPaolo Bonzini qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_RESET]); 7577702e47cSPaolo Bonzini } else if (!(val & (1 << idx)) && (opp->pir & (1 << idx))) { 7587702e47cSPaolo Bonzini DPRINTF("Lower OpenPIC RESET output for CPU %d\n", idx); 7597702e47cSPaolo Bonzini dst = &opp->dst[idx]; 7607702e47cSPaolo Bonzini qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_RESET]); 7617702e47cSPaolo Bonzini } 7627702e47cSPaolo Bonzini } 7637702e47cSPaolo Bonzini opp->pir = val; 7647702e47cSPaolo Bonzini break; 7657702e47cSPaolo Bonzini case 0x10A0: /* IPI_IVPR */ 7667702e47cSPaolo Bonzini case 0x10B0: 7677702e47cSPaolo Bonzini case 0x10C0: 7687702e47cSPaolo Bonzini case 0x10D0: 7697702e47cSPaolo Bonzini { 7707702e47cSPaolo Bonzini int idx; 7717702e47cSPaolo Bonzini idx = (addr - 0x10A0) >> 4; 7727702e47cSPaolo Bonzini write_IRQreg_ivpr(opp, opp->irq_ipi0 + idx, val); 7737702e47cSPaolo Bonzini } 7747702e47cSPaolo Bonzini break; 7757702e47cSPaolo Bonzini case 0x10E0: /* SPVE */ 7767702e47cSPaolo Bonzini opp->spve = val & opp->vector_mask; 7777702e47cSPaolo Bonzini break; 7787702e47cSPaolo Bonzini default: 7797702e47cSPaolo Bonzini break; 7807702e47cSPaolo Bonzini } 7817702e47cSPaolo Bonzini } 7827702e47cSPaolo Bonzini 7837702e47cSPaolo Bonzini static uint64_t openpic_gbl_read(void *opaque, hwaddr addr, unsigned len) 7847702e47cSPaolo Bonzini { 7857702e47cSPaolo Bonzini OpenPICState *opp = opaque; 7867702e47cSPaolo Bonzini uint32_t retval; 7877702e47cSPaolo Bonzini 7887702e47cSPaolo Bonzini DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); 7897702e47cSPaolo Bonzini retval = 0xFFFFFFFF; 7907702e47cSPaolo Bonzini if (addr & 0xF) { 7917702e47cSPaolo Bonzini return retval; 7927702e47cSPaolo Bonzini } 7937702e47cSPaolo Bonzini switch (addr) { 7947702e47cSPaolo Bonzini case 0x1000: /* FRR */ 7957702e47cSPaolo Bonzini retval = opp->frr; 7967702e47cSPaolo Bonzini break; 7977702e47cSPaolo Bonzini case 0x1020: /* GCR */ 7987702e47cSPaolo Bonzini retval = opp->gcr; 7997702e47cSPaolo Bonzini break; 8007702e47cSPaolo Bonzini case 0x1080: /* VIR */ 8017702e47cSPaolo Bonzini retval = opp->vir; 8027702e47cSPaolo Bonzini break; 8037702e47cSPaolo Bonzini case 0x1090: /* PIR */ 8047702e47cSPaolo Bonzini retval = 0x00000000; 8057702e47cSPaolo Bonzini break; 8067702e47cSPaolo Bonzini case 0x00: /* Block Revision Register1 (BRR1) */ 8077702e47cSPaolo Bonzini retval = opp->brr1; 8087702e47cSPaolo Bonzini break; 8097702e47cSPaolo Bonzini case 0x40: 8107702e47cSPaolo Bonzini case 0x50: 8117702e47cSPaolo Bonzini case 0x60: 8127702e47cSPaolo Bonzini case 0x70: 8137702e47cSPaolo Bonzini case 0x80: 8147702e47cSPaolo Bonzini case 0x90: 8157702e47cSPaolo Bonzini case 0xA0: 8167702e47cSPaolo Bonzini case 0xB0: 8177702e47cSPaolo Bonzini retval = openpic_cpu_read_internal(opp, addr, get_current_cpu()); 8187702e47cSPaolo Bonzini break; 8197702e47cSPaolo Bonzini case 0x10A0: /* IPI_IVPR */ 8207702e47cSPaolo Bonzini case 0x10B0: 8217702e47cSPaolo Bonzini case 0x10C0: 8227702e47cSPaolo Bonzini case 0x10D0: 8237702e47cSPaolo Bonzini { 8247702e47cSPaolo Bonzini int idx; 8257702e47cSPaolo Bonzini idx = (addr - 0x10A0) >> 4; 8267702e47cSPaolo Bonzini retval = read_IRQreg_ivpr(opp, opp->irq_ipi0 + idx); 8277702e47cSPaolo Bonzini } 8287702e47cSPaolo Bonzini break; 8297702e47cSPaolo Bonzini case 0x10E0: /* SPVE */ 8307702e47cSPaolo Bonzini retval = opp->spve; 8317702e47cSPaolo Bonzini break; 8327702e47cSPaolo Bonzini default: 8337702e47cSPaolo Bonzini break; 8347702e47cSPaolo Bonzini } 8357702e47cSPaolo Bonzini DPRINTF("%s: => 0x%08x\n", __func__, retval); 8367702e47cSPaolo Bonzini 8377702e47cSPaolo Bonzini return retval; 8387702e47cSPaolo Bonzini } 8397702e47cSPaolo Bonzini 8407702e47cSPaolo Bonzini static void openpic_tmr_write(void *opaque, hwaddr addr, uint64_t val, 8417702e47cSPaolo Bonzini unsigned len) 8427702e47cSPaolo Bonzini { 8437702e47cSPaolo Bonzini OpenPICState *opp = opaque; 8447702e47cSPaolo Bonzini int idx; 8457702e47cSPaolo Bonzini 8467702e47cSPaolo Bonzini addr += 0x10f0; 8477702e47cSPaolo Bonzini 8487702e47cSPaolo Bonzini DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n", 8497702e47cSPaolo Bonzini __func__, addr, val); 8507702e47cSPaolo Bonzini if (addr & 0xF) { 8517702e47cSPaolo Bonzini return; 8527702e47cSPaolo Bonzini } 8537702e47cSPaolo Bonzini 8547702e47cSPaolo Bonzini if (addr == 0x10f0) { 8557702e47cSPaolo Bonzini /* TFRR */ 8567702e47cSPaolo Bonzini opp->tfrr = val; 8577702e47cSPaolo Bonzini return; 8587702e47cSPaolo Bonzini } 8597702e47cSPaolo Bonzini 8607702e47cSPaolo Bonzini idx = (addr >> 6) & 0x3; 8617702e47cSPaolo Bonzini addr = addr & 0x30; 8627702e47cSPaolo Bonzini 8637702e47cSPaolo Bonzini switch (addr & 0x30) { 8647702e47cSPaolo Bonzini case 0x00: /* TCCR */ 8657702e47cSPaolo Bonzini break; 8667702e47cSPaolo Bonzini case 0x10: /* TBCR */ 8677702e47cSPaolo Bonzini if ((opp->timers[idx].tccr & TCCR_TOG) != 0 && 8687702e47cSPaolo Bonzini (val & TBCR_CI) == 0 && 8697702e47cSPaolo Bonzini (opp->timers[idx].tbcr & TBCR_CI) != 0) { 8707702e47cSPaolo Bonzini opp->timers[idx].tccr &= ~TCCR_TOG; 8717702e47cSPaolo Bonzini } 8727702e47cSPaolo Bonzini opp->timers[idx].tbcr = val; 8737702e47cSPaolo Bonzini break; 8747702e47cSPaolo Bonzini case 0x20: /* TVPR */ 8757702e47cSPaolo Bonzini write_IRQreg_ivpr(opp, opp->irq_tim0 + idx, val); 8767702e47cSPaolo Bonzini break; 8777702e47cSPaolo Bonzini case 0x30: /* TDR */ 8787702e47cSPaolo Bonzini write_IRQreg_idr(opp, opp->irq_tim0 + idx, val); 8797702e47cSPaolo Bonzini break; 8807702e47cSPaolo Bonzini } 8817702e47cSPaolo Bonzini } 8827702e47cSPaolo Bonzini 8837702e47cSPaolo Bonzini static uint64_t openpic_tmr_read(void *opaque, hwaddr addr, unsigned len) 8847702e47cSPaolo Bonzini { 8857702e47cSPaolo Bonzini OpenPICState *opp = opaque; 8867702e47cSPaolo Bonzini uint32_t retval = -1; 8877702e47cSPaolo Bonzini int idx; 8887702e47cSPaolo Bonzini 8897702e47cSPaolo Bonzini DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); 8907702e47cSPaolo Bonzini if (addr & 0xF) { 8917702e47cSPaolo Bonzini goto out; 8927702e47cSPaolo Bonzini } 8937702e47cSPaolo Bonzini idx = (addr >> 6) & 0x3; 8947702e47cSPaolo Bonzini if (addr == 0x0) { 8957702e47cSPaolo Bonzini /* TFRR */ 8967702e47cSPaolo Bonzini retval = opp->tfrr; 8977702e47cSPaolo Bonzini goto out; 8987702e47cSPaolo Bonzini } 8997702e47cSPaolo Bonzini switch (addr & 0x30) { 9007702e47cSPaolo Bonzini case 0x00: /* TCCR */ 9017702e47cSPaolo Bonzini retval = opp->timers[idx].tccr; 9027702e47cSPaolo Bonzini break; 9037702e47cSPaolo Bonzini case 0x10: /* TBCR */ 9047702e47cSPaolo Bonzini retval = opp->timers[idx].tbcr; 9057702e47cSPaolo Bonzini break; 9067702e47cSPaolo Bonzini case 0x20: /* TIPV */ 9077702e47cSPaolo Bonzini retval = read_IRQreg_ivpr(opp, opp->irq_tim0 + idx); 9087702e47cSPaolo Bonzini break; 9097702e47cSPaolo Bonzini case 0x30: /* TIDE (TIDR) */ 9107702e47cSPaolo Bonzini retval = read_IRQreg_idr(opp, opp->irq_tim0 + idx); 9117702e47cSPaolo Bonzini break; 9127702e47cSPaolo Bonzini } 9137702e47cSPaolo Bonzini 9147702e47cSPaolo Bonzini out: 9157702e47cSPaolo Bonzini DPRINTF("%s: => 0x%08x\n", __func__, retval); 9167702e47cSPaolo Bonzini 9177702e47cSPaolo Bonzini return retval; 9187702e47cSPaolo Bonzini } 9197702e47cSPaolo Bonzini 9207702e47cSPaolo Bonzini static void openpic_src_write(void *opaque, hwaddr addr, uint64_t val, 9217702e47cSPaolo Bonzini unsigned len) 9227702e47cSPaolo Bonzini { 9237702e47cSPaolo Bonzini OpenPICState *opp = opaque; 9247702e47cSPaolo Bonzini int idx; 9257702e47cSPaolo Bonzini 9267702e47cSPaolo Bonzini DPRINTF("%s: addr %#" HWADDR_PRIx " <= %08" PRIx64 "\n", 9277702e47cSPaolo Bonzini __func__, addr, val); 9287702e47cSPaolo Bonzini 9297702e47cSPaolo Bonzini addr = addr & 0xffff; 9307702e47cSPaolo Bonzini idx = addr >> 5; 9317702e47cSPaolo Bonzini 9327702e47cSPaolo Bonzini switch (addr & 0x1f) { 9337702e47cSPaolo Bonzini case 0x00: 9347702e47cSPaolo Bonzini write_IRQreg_ivpr(opp, idx, val); 9357702e47cSPaolo Bonzini break; 9367702e47cSPaolo Bonzini case 0x10: 9377702e47cSPaolo Bonzini write_IRQreg_idr(opp, idx, val); 9387702e47cSPaolo Bonzini break; 9397702e47cSPaolo Bonzini case 0x18: 9407702e47cSPaolo Bonzini write_IRQreg_ilr(opp, idx, val); 9417702e47cSPaolo Bonzini break; 9427702e47cSPaolo Bonzini } 9437702e47cSPaolo Bonzini } 9447702e47cSPaolo Bonzini 9457702e47cSPaolo Bonzini static uint64_t openpic_src_read(void *opaque, uint64_t addr, unsigned len) 9467702e47cSPaolo Bonzini { 9477702e47cSPaolo Bonzini OpenPICState *opp = opaque; 9487702e47cSPaolo Bonzini uint32_t retval; 9497702e47cSPaolo Bonzini int idx; 9507702e47cSPaolo Bonzini 9517702e47cSPaolo Bonzini DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); 9527702e47cSPaolo Bonzini retval = 0xFFFFFFFF; 9537702e47cSPaolo Bonzini 9547702e47cSPaolo Bonzini addr = addr & 0xffff; 9557702e47cSPaolo Bonzini idx = addr >> 5; 9567702e47cSPaolo Bonzini 9577702e47cSPaolo Bonzini switch (addr & 0x1f) { 9587702e47cSPaolo Bonzini case 0x00: 9597702e47cSPaolo Bonzini retval = read_IRQreg_ivpr(opp, idx); 9607702e47cSPaolo Bonzini break; 9617702e47cSPaolo Bonzini case 0x10: 9627702e47cSPaolo Bonzini retval = read_IRQreg_idr(opp, idx); 9637702e47cSPaolo Bonzini break; 9647702e47cSPaolo Bonzini case 0x18: 9657702e47cSPaolo Bonzini retval = read_IRQreg_ilr(opp, idx); 9667702e47cSPaolo Bonzini break; 9677702e47cSPaolo Bonzini } 9687702e47cSPaolo Bonzini 9697702e47cSPaolo Bonzini DPRINTF("%s: => 0x%08x\n", __func__, retval); 9707702e47cSPaolo Bonzini return retval; 9717702e47cSPaolo Bonzini } 9727702e47cSPaolo Bonzini 9737702e47cSPaolo Bonzini static void openpic_msi_write(void *opaque, hwaddr addr, uint64_t val, 9747702e47cSPaolo Bonzini unsigned size) 9757702e47cSPaolo Bonzini { 9767702e47cSPaolo Bonzini OpenPICState *opp = opaque; 9777702e47cSPaolo Bonzini int idx = opp->irq_msi; 9787702e47cSPaolo Bonzini int srs, ibs; 9797702e47cSPaolo Bonzini 9807702e47cSPaolo Bonzini DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64 "\n", 9817702e47cSPaolo Bonzini __func__, addr, val); 9827702e47cSPaolo Bonzini if (addr & 0xF) { 9837702e47cSPaolo Bonzini return; 9847702e47cSPaolo Bonzini } 9857702e47cSPaolo Bonzini 9867702e47cSPaolo Bonzini switch (addr) { 9877702e47cSPaolo Bonzini case MSIIR_OFFSET: 9887702e47cSPaolo Bonzini srs = val >> MSIIR_SRS_SHIFT; 9897702e47cSPaolo Bonzini idx += srs; 9907702e47cSPaolo Bonzini ibs = (val & MSIIR_IBS_MASK) >> MSIIR_IBS_SHIFT; 9917702e47cSPaolo Bonzini opp->msi[srs].msir |= 1 << ibs; 9927702e47cSPaolo Bonzini openpic_set_irq(opp, idx, 1); 9937702e47cSPaolo Bonzini break; 9947702e47cSPaolo Bonzini default: 9957702e47cSPaolo Bonzini /* most registers are read-only, thus ignored */ 9967702e47cSPaolo Bonzini break; 9977702e47cSPaolo Bonzini } 9987702e47cSPaolo Bonzini } 9997702e47cSPaolo Bonzini 10007702e47cSPaolo Bonzini static uint64_t openpic_msi_read(void *opaque, hwaddr addr, unsigned size) 10017702e47cSPaolo Bonzini { 10027702e47cSPaolo Bonzini OpenPICState *opp = opaque; 10037702e47cSPaolo Bonzini uint64_t r = 0; 10047702e47cSPaolo Bonzini int i, srs; 10057702e47cSPaolo Bonzini 10067702e47cSPaolo Bonzini DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); 10077702e47cSPaolo Bonzini if (addr & 0xF) { 10087702e47cSPaolo Bonzini return -1; 10097702e47cSPaolo Bonzini } 10107702e47cSPaolo Bonzini 10117702e47cSPaolo Bonzini srs = addr >> 4; 10127702e47cSPaolo Bonzini 10137702e47cSPaolo Bonzini switch (addr) { 10147702e47cSPaolo Bonzini case 0x00: 10157702e47cSPaolo Bonzini case 0x10: 10167702e47cSPaolo Bonzini case 0x20: 10177702e47cSPaolo Bonzini case 0x30: 10187702e47cSPaolo Bonzini case 0x40: 10197702e47cSPaolo Bonzini case 0x50: 10207702e47cSPaolo Bonzini case 0x60: 10217702e47cSPaolo Bonzini case 0x70: /* MSIRs */ 10227702e47cSPaolo Bonzini r = opp->msi[srs].msir; 10237702e47cSPaolo Bonzini /* Clear on read */ 10247702e47cSPaolo Bonzini opp->msi[srs].msir = 0; 10257702e47cSPaolo Bonzini openpic_set_irq(opp, opp->irq_msi + srs, 0); 10267702e47cSPaolo Bonzini break; 10277702e47cSPaolo Bonzini case 0x120: /* MSISR */ 10287702e47cSPaolo Bonzini for (i = 0; i < MAX_MSI; i++) { 10297702e47cSPaolo Bonzini r |= (opp->msi[i].msir ? 1 : 0) << i; 10307702e47cSPaolo Bonzini } 10317702e47cSPaolo Bonzini break; 10327702e47cSPaolo Bonzini } 10337702e47cSPaolo Bonzini 10347702e47cSPaolo Bonzini return r; 10357702e47cSPaolo Bonzini } 10367702e47cSPaolo Bonzini 10377702e47cSPaolo Bonzini static uint64_t openpic_summary_read(void *opaque, hwaddr addr, unsigned size) 10387702e47cSPaolo Bonzini { 10397702e47cSPaolo Bonzini uint64_t r = 0; 10407702e47cSPaolo Bonzini 10417702e47cSPaolo Bonzini DPRINTF("%s: addr %#" HWADDR_PRIx "\n", __func__, addr); 10427702e47cSPaolo Bonzini 10437702e47cSPaolo Bonzini /* TODO: EISR/EIMR */ 10447702e47cSPaolo Bonzini 10457702e47cSPaolo Bonzini return r; 10467702e47cSPaolo Bonzini } 10477702e47cSPaolo Bonzini 10487702e47cSPaolo Bonzini static void openpic_summary_write(void *opaque, hwaddr addr, uint64_t val, 10497702e47cSPaolo Bonzini unsigned size) 10507702e47cSPaolo Bonzini { 10517702e47cSPaolo Bonzini DPRINTF("%s: addr %#" HWADDR_PRIx " <= 0x%08" PRIx64 "\n", 10527702e47cSPaolo Bonzini __func__, addr, val); 10537702e47cSPaolo Bonzini 10547702e47cSPaolo Bonzini /* TODO: EISR/EIMR */ 10557702e47cSPaolo Bonzini } 10567702e47cSPaolo Bonzini 10577702e47cSPaolo Bonzini static void openpic_cpu_write_internal(void *opaque, hwaddr addr, 10587702e47cSPaolo Bonzini uint32_t val, int idx) 10597702e47cSPaolo Bonzini { 10607702e47cSPaolo Bonzini OpenPICState *opp = opaque; 10617702e47cSPaolo Bonzini IRQSource *src; 10627702e47cSPaolo Bonzini IRQDest *dst; 10637702e47cSPaolo Bonzini int s_IRQ, n_IRQ; 10647702e47cSPaolo Bonzini 10657702e47cSPaolo Bonzini DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx " <= 0x%08x\n", __func__, idx, 10667702e47cSPaolo Bonzini addr, val); 10677702e47cSPaolo Bonzini 10687702e47cSPaolo Bonzini if (idx < 0) { 10697702e47cSPaolo Bonzini return; 10707702e47cSPaolo Bonzini } 10717702e47cSPaolo Bonzini 10727702e47cSPaolo Bonzini if (addr & 0xF) { 10737702e47cSPaolo Bonzini return; 10747702e47cSPaolo Bonzini } 10757702e47cSPaolo Bonzini dst = &opp->dst[idx]; 10767702e47cSPaolo Bonzini addr &= 0xFF0; 10777702e47cSPaolo Bonzini switch (addr) { 10787702e47cSPaolo Bonzini case 0x40: /* IPIDR */ 10797702e47cSPaolo Bonzini case 0x50: 10807702e47cSPaolo Bonzini case 0x60: 10817702e47cSPaolo Bonzini case 0x70: 10827702e47cSPaolo Bonzini idx = (addr - 0x40) >> 4; 10837702e47cSPaolo Bonzini /* we use IDE as mask which CPUs to deliver the IPI to still. */ 10847702e47cSPaolo Bonzini opp->src[opp->irq_ipi0 + idx].destmask |= val; 10857702e47cSPaolo Bonzini openpic_set_irq(opp, opp->irq_ipi0 + idx, 1); 10867702e47cSPaolo Bonzini openpic_set_irq(opp, opp->irq_ipi0 + idx, 0); 10877702e47cSPaolo Bonzini break; 10887702e47cSPaolo Bonzini case 0x80: /* CTPR */ 10897702e47cSPaolo Bonzini dst->ctpr = val & 0x0000000F; 10907702e47cSPaolo Bonzini 10917702e47cSPaolo Bonzini DPRINTF("%s: set CPU %d ctpr to %d, raised %d servicing %d\n", 10927702e47cSPaolo Bonzini __func__, idx, dst->ctpr, dst->raised.priority, 10937702e47cSPaolo Bonzini dst->servicing.priority); 10947702e47cSPaolo Bonzini 10957702e47cSPaolo Bonzini if (dst->raised.priority <= dst->ctpr) { 10967702e47cSPaolo Bonzini DPRINTF("%s: Lower OpenPIC INT output cpu %d due to ctpr\n", 10977702e47cSPaolo Bonzini __func__, idx); 10987702e47cSPaolo Bonzini qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]); 10997702e47cSPaolo Bonzini } else if (dst->raised.priority > dst->servicing.priority) { 11007702e47cSPaolo Bonzini DPRINTF("%s: Raise OpenPIC INT output cpu %d irq %d\n", 11017702e47cSPaolo Bonzini __func__, idx, dst->raised.next); 11027702e47cSPaolo Bonzini qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]); 11037702e47cSPaolo Bonzini } 11047702e47cSPaolo Bonzini 11057702e47cSPaolo Bonzini break; 11067702e47cSPaolo Bonzini case 0x90: /* WHOAMI */ 11077702e47cSPaolo Bonzini /* Read-only register */ 11087702e47cSPaolo Bonzini break; 11097702e47cSPaolo Bonzini case 0xA0: /* IACK */ 11107702e47cSPaolo Bonzini /* Read-only register */ 11117702e47cSPaolo Bonzini break; 11127702e47cSPaolo Bonzini case 0xB0: /* EOI */ 11137702e47cSPaolo Bonzini DPRINTF("EOI\n"); 11147702e47cSPaolo Bonzini s_IRQ = IRQ_get_next(opp, &dst->servicing); 11157702e47cSPaolo Bonzini 11167702e47cSPaolo Bonzini if (s_IRQ < 0) { 11177702e47cSPaolo Bonzini DPRINTF("%s: EOI with no interrupt in service\n", __func__); 11187702e47cSPaolo Bonzini break; 11197702e47cSPaolo Bonzini } 11207702e47cSPaolo Bonzini 11217702e47cSPaolo Bonzini IRQ_resetbit(&dst->servicing, s_IRQ); 11227702e47cSPaolo Bonzini /* Set up next servicing IRQ */ 11237702e47cSPaolo Bonzini s_IRQ = IRQ_get_next(opp, &dst->servicing); 11247702e47cSPaolo Bonzini /* Check queued interrupts. */ 11257702e47cSPaolo Bonzini n_IRQ = IRQ_get_next(opp, &dst->raised); 11267702e47cSPaolo Bonzini src = &opp->src[n_IRQ]; 11277702e47cSPaolo Bonzini if (n_IRQ != -1 && 11287702e47cSPaolo Bonzini (s_IRQ == -1 || 11297702e47cSPaolo Bonzini IVPR_PRIORITY(src->ivpr) > dst->servicing.priority)) { 11307702e47cSPaolo Bonzini DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", 11317702e47cSPaolo Bonzini idx, n_IRQ); 11327702e47cSPaolo Bonzini qemu_irq_raise(opp->dst[idx].irqs[OPENPIC_OUTPUT_INT]); 11337702e47cSPaolo Bonzini } 11347702e47cSPaolo Bonzini break; 11357702e47cSPaolo Bonzini default: 11367702e47cSPaolo Bonzini break; 11377702e47cSPaolo Bonzini } 11387702e47cSPaolo Bonzini } 11397702e47cSPaolo Bonzini 11407702e47cSPaolo Bonzini static void openpic_cpu_write(void *opaque, hwaddr addr, uint64_t val, 11417702e47cSPaolo Bonzini unsigned len) 11427702e47cSPaolo Bonzini { 11437702e47cSPaolo Bonzini openpic_cpu_write_internal(opaque, addr, val, (addr & 0x1f000) >> 12); 11447702e47cSPaolo Bonzini } 11457702e47cSPaolo Bonzini 11467702e47cSPaolo Bonzini 11477702e47cSPaolo Bonzini static uint32_t openpic_iack(OpenPICState *opp, IRQDest *dst, int cpu) 11487702e47cSPaolo Bonzini { 11497702e47cSPaolo Bonzini IRQSource *src; 11507702e47cSPaolo Bonzini int retval, irq; 11517702e47cSPaolo Bonzini 11527702e47cSPaolo Bonzini DPRINTF("Lower OpenPIC INT output\n"); 11537702e47cSPaolo Bonzini qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]); 11547702e47cSPaolo Bonzini 11557702e47cSPaolo Bonzini irq = IRQ_get_next(opp, &dst->raised); 11567702e47cSPaolo Bonzini DPRINTF("IACK: irq=%d\n", irq); 11577702e47cSPaolo Bonzini 11587702e47cSPaolo Bonzini if (irq == -1) { 11597702e47cSPaolo Bonzini /* No more interrupt pending */ 11607702e47cSPaolo Bonzini return opp->spve; 11617702e47cSPaolo Bonzini } 11627702e47cSPaolo Bonzini 11637702e47cSPaolo Bonzini src = &opp->src[irq]; 11647702e47cSPaolo Bonzini if (!(src->ivpr & IVPR_ACTIVITY_MASK) || 11657702e47cSPaolo Bonzini !(IVPR_PRIORITY(src->ivpr) > dst->ctpr)) { 11667702e47cSPaolo Bonzini fprintf(stderr, "%s: bad raised IRQ %d ctpr %d ivpr 0x%08x\n", 11677702e47cSPaolo Bonzini __func__, irq, dst->ctpr, src->ivpr); 11687702e47cSPaolo Bonzini openpic_update_irq(opp, irq); 11697702e47cSPaolo Bonzini retval = opp->spve; 11707702e47cSPaolo Bonzini } else { 11717702e47cSPaolo Bonzini /* IRQ enter servicing state */ 11727702e47cSPaolo Bonzini IRQ_setbit(&dst->servicing, irq); 11737702e47cSPaolo Bonzini retval = IVPR_VECTOR(opp, src->ivpr); 11747702e47cSPaolo Bonzini } 11757702e47cSPaolo Bonzini 11767702e47cSPaolo Bonzini if (!src->level) { 11777702e47cSPaolo Bonzini /* edge-sensitive IRQ */ 11787702e47cSPaolo Bonzini src->ivpr &= ~IVPR_ACTIVITY_MASK; 11797702e47cSPaolo Bonzini src->pending = 0; 11807702e47cSPaolo Bonzini IRQ_resetbit(&dst->raised, irq); 11817702e47cSPaolo Bonzini } 11827702e47cSPaolo Bonzini 11838935a442SScott Wood if ((irq >= opp->irq_ipi0) && (irq < (opp->irq_ipi0 + OPENPIC_MAX_IPI))) { 11847702e47cSPaolo Bonzini src->destmask &= ~(1 << cpu); 11857702e47cSPaolo Bonzini if (src->destmask && !src->level) { 11867702e47cSPaolo Bonzini /* trigger on CPUs that didn't know about it yet */ 11877702e47cSPaolo Bonzini openpic_set_irq(opp, irq, 1); 11887702e47cSPaolo Bonzini openpic_set_irq(opp, irq, 0); 11897702e47cSPaolo Bonzini /* if all CPUs knew about it, set active bit again */ 11907702e47cSPaolo Bonzini src->ivpr |= IVPR_ACTIVITY_MASK; 11917702e47cSPaolo Bonzini } 11927702e47cSPaolo Bonzini } 11937702e47cSPaolo Bonzini 11947702e47cSPaolo Bonzini return retval; 11957702e47cSPaolo Bonzini } 11967702e47cSPaolo Bonzini 11977702e47cSPaolo Bonzini static uint32_t openpic_cpu_read_internal(void *opaque, hwaddr addr, 11987702e47cSPaolo Bonzini int idx) 11997702e47cSPaolo Bonzini { 12007702e47cSPaolo Bonzini OpenPICState *opp = opaque; 12017702e47cSPaolo Bonzini IRQDest *dst; 12027702e47cSPaolo Bonzini uint32_t retval; 12037702e47cSPaolo Bonzini 12047702e47cSPaolo Bonzini DPRINTF("%s: cpu %d addr %#" HWADDR_PRIx "\n", __func__, idx, addr); 12057702e47cSPaolo Bonzini retval = 0xFFFFFFFF; 12067702e47cSPaolo Bonzini 12077702e47cSPaolo Bonzini if (idx < 0) { 12087702e47cSPaolo Bonzini return retval; 12097702e47cSPaolo Bonzini } 12107702e47cSPaolo Bonzini 12117702e47cSPaolo Bonzini if (addr & 0xF) { 12127702e47cSPaolo Bonzini return retval; 12137702e47cSPaolo Bonzini } 12147702e47cSPaolo Bonzini dst = &opp->dst[idx]; 12157702e47cSPaolo Bonzini addr &= 0xFF0; 12167702e47cSPaolo Bonzini switch (addr) { 12177702e47cSPaolo Bonzini case 0x80: /* CTPR */ 12187702e47cSPaolo Bonzini retval = dst->ctpr; 12197702e47cSPaolo Bonzini break; 12207702e47cSPaolo Bonzini case 0x90: /* WHOAMI */ 12217702e47cSPaolo Bonzini retval = idx; 12227702e47cSPaolo Bonzini break; 12237702e47cSPaolo Bonzini case 0xA0: /* IACK */ 12247702e47cSPaolo Bonzini retval = openpic_iack(opp, dst, idx); 12257702e47cSPaolo Bonzini break; 12267702e47cSPaolo Bonzini case 0xB0: /* EOI */ 12277702e47cSPaolo Bonzini retval = 0; 12287702e47cSPaolo Bonzini break; 12297702e47cSPaolo Bonzini default: 12307702e47cSPaolo Bonzini break; 12317702e47cSPaolo Bonzini } 12327702e47cSPaolo Bonzini DPRINTF("%s: => 0x%08x\n", __func__, retval); 12337702e47cSPaolo Bonzini 12347702e47cSPaolo Bonzini return retval; 12357702e47cSPaolo Bonzini } 12367702e47cSPaolo Bonzini 12377702e47cSPaolo Bonzini static uint64_t openpic_cpu_read(void *opaque, hwaddr addr, unsigned len) 12387702e47cSPaolo Bonzini { 12397702e47cSPaolo Bonzini return openpic_cpu_read_internal(opaque, addr, (addr & 0x1f000) >> 12); 12407702e47cSPaolo Bonzini } 12417702e47cSPaolo Bonzini 12427702e47cSPaolo Bonzini static const MemoryRegionOps openpic_glb_ops_le = { 12437702e47cSPaolo Bonzini .write = openpic_gbl_write, 12447702e47cSPaolo Bonzini .read = openpic_gbl_read, 12457702e47cSPaolo Bonzini .endianness = DEVICE_LITTLE_ENDIAN, 12467702e47cSPaolo Bonzini .impl = { 12477702e47cSPaolo Bonzini .min_access_size = 4, 12487702e47cSPaolo Bonzini .max_access_size = 4, 12497702e47cSPaolo Bonzini }, 12507702e47cSPaolo Bonzini }; 12517702e47cSPaolo Bonzini 12527702e47cSPaolo Bonzini static const MemoryRegionOps openpic_glb_ops_be = { 12537702e47cSPaolo Bonzini .write = openpic_gbl_write, 12547702e47cSPaolo Bonzini .read = openpic_gbl_read, 12557702e47cSPaolo Bonzini .endianness = DEVICE_BIG_ENDIAN, 12567702e47cSPaolo Bonzini .impl = { 12577702e47cSPaolo Bonzini .min_access_size = 4, 12587702e47cSPaolo Bonzini .max_access_size = 4, 12597702e47cSPaolo Bonzini }, 12607702e47cSPaolo Bonzini }; 12617702e47cSPaolo Bonzini 12627702e47cSPaolo Bonzini static const MemoryRegionOps openpic_tmr_ops_le = { 12637702e47cSPaolo Bonzini .write = openpic_tmr_write, 12647702e47cSPaolo Bonzini .read = openpic_tmr_read, 12657702e47cSPaolo Bonzini .endianness = DEVICE_LITTLE_ENDIAN, 12667702e47cSPaolo Bonzini .impl = { 12677702e47cSPaolo Bonzini .min_access_size = 4, 12687702e47cSPaolo Bonzini .max_access_size = 4, 12697702e47cSPaolo Bonzini }, 12707702e47cSPaolo Bonzini }; 12717702e47cSPaolo Bonzini 12727702e47cSPaolo Bonzini static const MemoryRegionOps openpic_tmr_ops_be = { 12737702e47cSPaolo Bonzini .write = openpic_tmr_write, 12747702e47cSPaolo Bonzini .read = openpic_tmr_read, 12757702e47cSPaolo Bonzini .endianness = DEVICE_BIG_ENDIAN, 12767702e47cSPaolo Bonzini .impl = { 12777702e47cSPaolo Bonzini .min_access_size = 4, 12787702e47cSPaolo Bonzini .max_access_size = 4, 12797702e47cSPaolo Bonzini }, 12807702e47cSPaolo Bonzini }; 12817702e47cSPaolo Bonzini 12827702e47cSPaolo Bonzini static const MemoryRegionOps openpic_cpu_ops_le = { 12837702e47cSPaolo Bonzini .write = openpic_cpu_write, 12847702e47cSPaolo Bonzini .read = openpic_cpu_read, 12857702e47cSPaolo Bonzini .endianness = DEVICE_LITTLE_ENDIAN, 12867702e47cSPaolo Bonzini .impl = { 12877702e47cSPaolo Bonzini .min_access_size = 4, 12887702e47cSPaolo Bonzini .max_access_size = 4, 12897702e47cSPaolo Bonzini }, 12907702e47cSPaolo Bonzini }; 12917702e47cSPaolo Bonzini 12927702e47cSPaolo Bonzini static const MemoryRegionOps openpic_cpu_ops_be = { 12937702e47cSPaolo Bonzini .write = openpic_cpu_write, 12947702e47cSPaolo Bonzini .read = openpic_cpu_read, 12957702e47cSPaolo Bonzini .endianness = DEVICE_BIG_ENDIAN, 12967702e47cSPaolo Bonzini .impl = { 12977702e47cSPaolo Bonzini .min_access_size = 4, 12987702e47cSPaolo Bonzini .max_access_size = 4, 12997702e47cSPaolo Bonzini }, 13007702e47cSPaolo Bonzini }; 13017702e47cSPaolo Bonzini 13027702e47cSPaolo Bonzini static const MemoryRegionOps openpic_src_ops_le = { 13037702e47cSPaolo Bonzini .write = openpic_src_write, 13047702e47cSPaolo Bonzini .read = openpic_src_read, 13057702e47cSPaolo Bonzini .endianness = DEVICE_LITTLE_ENDIAN, 13067702e47cSPaolo Bonzini .impl = { 13077702e47cSPaolo Bonzini .min_access_size = 4, 13087702e47cSPaolo Bonzini .max_access_size = 4, 13097702e47cSPaolo Bonzini }, 13107702e47cSPaolo Bonzini }; 13117702e47cSPaolo Bonzini 13127702e47cSPaolo Bonzini static const MemoryRegionOps openpic_src_ops_be = { 13137702e47cSPaolo Bonzini .write = openpic_src_write, 13147702e47cSPaolo Bonzini .read = openpic_src_read, 13157702e47cSPaolo Bonzini .endianness = DEVICE_BIG_ENDIAN, 13167702e47cSPaolo Bonzini .impl = { 13177702e47cSPaolo Bonzini .min_access_size = 4, 13187702e47cSPaolo Bonzini .max_access_size = 4, 13197702e47cSPaolo Bonzini }, 13207702e47cSPaolo Bonzini }; 13217702e47cSPaolo Bonzini 13227702e47cSPaolo Bonzini static const MemoryRegionOps openpic_msi_ops_be = { 13237702e47cSPaolo Bonzini .read = openpic_msi_read, 13247702e47cSPaolo Bonzini .write = openpic_msi_write, 13257702e47cSPaolo Bonzini .endianness = DEVICE_BIG_ENDIAN, 13267702e47cSPaolo Bonzini .impl = { 13277702e47cSPaolo Bonzini .min_access_size = 4, 13287702e47cSPaolo Bonzini .max_access_size = 4, 13297702e47cSPaolo Bonzini }, 13307702e47cSPaolo Bonzini }; 13317702e47cSPaolo Bonzini 13327702e47cSPaolo Bonzini static const MemoryRegionOps openpic_summary_ops_be = { 13337702e47cSPaolo Bonzini .read = openpic_summary_read, 13347702e47cSPaolo Bonzini .write = openpic_summary_write, 13357702e47cSPaolo Bonzini .endianness = DEVICE_BIG_ENDIAN, 13367702e47cSPaolo Bonzini .impl = { 13377702e47cSPaolo Bonzini .min_access_size = 4, 13387702e47cSPaolo Bonzini .max_access_size = 4, 13397702e47cSPaolo Bonzini }, 13407702e47cSPaolo Bonzini }; 13417702e47cSPaolo Bonzini 13427702e47cSPaolo Bonzini static void openpic_save_IRQ_queue(QEMUFile* f, IRQQueue *q) 13437702e47cSPaolo Bonzini { 13447702e47cSPaolo Bonzini unsigned int i; 13457702e47cSPaolo Bonzini 13467702e47cSPaolo Bonzini for (i = 0; i < ARRAY_SIZE(q->queue); i++) { 13477702e47cSPaolo Bonzini /* Always put the lower half of a 64-bit long first, in case we 13487702e47cSPaolo Bonzini * restore on a 32-bit host. The least significant bits correspond 13497702e47cSPaolo Bonzini * to lower IRQ numbers in the bitmap. 13507702e47cSPaolo Bonzini */ 13517702e47cSPaolo Bonzini qemu_put_be32(f, (uint32_t)q->queue[i]); 13527702e47cSPaolo Bonzini #if LONG_MAX > 0x7FFFFFFF 13537702e47cSPaolo Bonzini qemu_put_be32(f, (uint32_t)(q->queue[i] >> 32)); 13547702e47cSPaolo Bonzini #endif 13557702e47cSPaolo Bonzini } 13567702e47cSPaolo Bonzini 13577702e47cSPaolo Bonzini qemu_put_sbe32s(f, &q->next); 13587702e47cSPaolo Bonzini qemu_put_sbe32s(f, &q->priority); 13597702e47cSPaolo Bonzini } 13607702e47cSPaolo Bonzini 13617702e47cSPaolo Bonzini static void openpic_save(QEMUFile* f, void *opaque) 13627702e47cSPaolo Bonzini { 13637702e47cSPaolo Bonzini OpenPICState *opp = (OpenPICState *)opaque; 13647702e47cSPaolo Bonzini unsigned int i; 13657702e47cSPaolo Bonzini 13667702e47cSPaolo Bonzini qemu_put_be32s(f, &opp->gcr); 13677702e47cSPaolo Bonzini qemu_put_be32s(f, &opp->vir); 13687702e47cSPaolo Bonzini qemu_put_be32s(f, &opp->pir); 13697702e47cSPaolo Bonzini qemu_put_be32s(f, &opp->spve); 13707702e47cSPaolo Bonzini qemu_put_be32s(f, &opp->tfrr); 13717702e47cSPaolo Bonzini 13727702e47cSPaolo Bonzini qemu_put_be32s(f, &opp->nb_cpus); 13737702e47cSPaolo Bonzini 13747702e47cSPaolo Bonzini for (i = 0; i < opp->nb_cpus; i++) { 13757702e47cSPaolo Bonzini qemu_put_sbe32s(f, &opp->dst[i].ctpr); 13767702e47cSPaolo Bonzini openpic_save_IRQ_queue(f, &opp->dst[i].raised); 13777702e47cSPaolo Bonzini openpic_save_IRQ_queue(f, &opp->dst[i].servicing); 13787702e47cSPaolo Bonzini qemu_put_buffer(f, (uint8_t *)&opp->dst[i].outputs_active, 13797702e47cSPaolo Bonzini sizeof(opp->dst[i].outputs_active)); 13807702e47cSPaolo Bonzini } 13817702e47cSPaolo Bonzini 13828935a442SScott Wood for (i = 0; i < OPENPIC_MAX_TMR; i++) { 13837702e47cSPaolo Bonzini qemu_put_be32s(f, &opp->timers[i].tccr); 13847702e47cSPaolo Bonzini qemu_put_be32s(f, &opp->timers[i].tbcr); 13857702e47cSPaolo Bonzini } 13867702e47cSPaolo Bonzini 13877702e47cSPaolo Bonzini for (i = 0; i < opp->max_irq; i++) { 13887702e47cSPaolo Bonzini qemu_put_be32s(f, &opp->src[i].ivpr); 13897702e47cSPaolo Bonzini qemu_put_be32s(f, &opp->src[i].idr); 13907702e47cSPaolo Bonzini qemu_get_be32s(f, &opp->src[i].destmask); 13917702e47cSPaolo Bonzini qemu_put_sbe32s(f, &opp->src[i].last_cpu); 13927702e47cSPaolo Bonzini qemu_put_sbe32s(f, &opp->src[i].pending); 13937702e47cSPaolo Bonzini } 13947702e47cSPaolo Bonzini } 13957702e47cSPaolo Bonzini 13967702e47cSPaolo Bonzini static void openpic_load_IRQ_queue(QEMUFile* f, IRQQueue *q) 13977702e47cSPaolo Bonzini { 13987702e47cSPaolo Bonzini unsigned int i; 13997702e47cSPaolo Bonzini 14007702e47cSPaolo Bonzini for (i = 0; i < ARRAY_SIZE(q->queue); i++) { 14017702e47cSPaolo Bonzini unsigned long val; 14027702e47cSPaolo Bonzini 14037702e47cSPaolo Bonzini val = qemu_get_be32(f); 14047702e47cSPaolo Bonzini #if LONG_MAX > 0x7FFFFFFF 14057702e47cSPaolo Bonzini val <<= 32; 14067702e47cSPaolo Bonzini val |= qemu_get_be32(f); 14077702e47cSPaolo Bonzini #endif 14087702e47cSPaolo Bonzini 14097702e47cSPaolo Bonzini q->queue[i] = val; 14107702e47cSPaolo Bonzini } 14117702e47cSPaolo Bonzini 14127702e47cSPaolo Bonzini qemu_get_sbe32s(f, &q->next); 14137702e47cSPaolo Bonzini qemu_get_sbe32s(f, &q->priority); 14147702e47cSPaolo Bonzini } 14157702e47cSPaolo Bonzini 14167702e47cSPaolo Bonzini static int openpic_load(QEMUFile* f, void *opaque, int version_id) 14177702e47cSPaolo Bonzini { 14187702e47cSPaolo Bonzini OpenPICState *opp = (OpenPICState *)opaque; 14197702e47cSPaolo Bonzini unsigned int i; 14207702e47cSPaolo Bonzini 14217702e47cSPaolo Bonzini if (version_id != 1) { 14227702e47cSPaolo Bonzini return -EINVAL; 14237702e47cSPaolo Bonzini } 14247702e47cSPaolo Bonzini 14257702e47cSPaolo Bonzini qemu_get_be32s(f, &opp->gcr); 14267702e47cSPaolo Bonzini qemu_get_be32s(f, &opp->vir); 14277702e47cSPaolo Bonzini qemu_get_be32s(f, &opp->pir); 14287702e47cSPaolo Bonzini qemu_get_be32s(f, &opp->spve); 14297702e47cSPaolo Bonzini qemu_get_be32s(f, &opp->tfrr); 14307702e47cSPaolo Bonzini 14317702e47cSPaolo Bonzini qemu_get_be32s(f, &opp->nb_cpus); 14327702e47cSPaolo Bonzini 14337702e47cSPaolo Bonzini for (i = 0; i < opp->nb_cpus; i++) { 14347702e47cSPaolo Bonzini qemu_get_sbe32s(f, &opp->dst[i].ctpr); 14357702e47cSPaolo Bonzini openpic_load_IRQ_queue(f, &opp->dst[i].raised); 14367702e47cSPaolo Bonzini openpic_load_IRQ_queue(f, &opp->dst[i].servicing); 14377702e47cSPaolo Bonzini qemu_get_buffer(f, (uint8_t *)&opp->dst[i].outputs_active, 14387702e47cSPaolo Bonzini sizeof(opp->dst[i].outputs_active)); 14397702e47cSPaolo Bonzini } 14407702e47cSPaolo Bonzini 14418935a442SScott Wood for (i = 0; i < OPENPIC_MAX_TMR; i++) { 14427702e47cSPaolo Bonzini qemu_get_be32s(f, &opp->timers[i].tccr); 14437702e47cSPaolo Bonzini qemu_get_be32s(f, &opp->timers[i].tbcr); 14447702e47cSPaolo Bonzini } 14457702e47cSPaolo Bonzini 14467702e47cSPaolo Bonzini for (i = 0; i < opp->max_irq; i++) { 14477702e47cSPaolo Bonzini uint32_t val; 14487702e47cSPaolo Bonzini 14497702e47cSPaolo Bonzini val = qemu_get_be32(f); 14507702e47cSPaolo Bonzini write_IRQreg_idr(opp, i, val); 14517702e47cSPaolo Bonzini val = qemu_get_be32(f); 14527702e47cSPaolo Bonzini write_IRQreg_ivpr(opp, i, val); 14537702e47cSPaolo Bonzini 14547702e47cSPaolo Bonzini qemu_get_be32s(f, &opp->src[i].ivpr); 14557702e47cSPaolo Bonzini qemu_get_be32s(f, &opp->src[i].idr); 14567702e47cSPaolo Bonzini qemu_get_be32s(f, &opp->src[i].destmask); 14577702e47cSPaolo Bonzini qemu_get_sbe32s(f, &opp->src[i].last_cpu); 14587702e47cSPaolo Bonzini qemu_get_sbe32s(f, &opp->src[i].pending); 14597702e47cSPaolo Bonzini } 14607702e47cSPaolo Bonzini 14617702e47cSPaolo Bonzini return 0; 14627702e47cSPaolo Bonzini } 14637702e47cSPaolo Bonzini 14647702e47cSPaolo Bonzini typedef struct MemReg { 14657702e47cSPaolo Bonzini const char *name; 14667702e47cSPaolo Bonzini MemoryRegionOps const *ops; 14677702e47cSPaolo Bonzini hwaddr start_addr; 14687702e47cSPaolo Bonzini ram_addr_t size; 14697702e47cSPaolo Bonzini } MemReg; 14707702e47cSPaolo Bonzini 14717702e47cSPaolo Bonzini static void fsl_common_init(OpenPICState *opp) 14727702e47cSPaolo Bonzini { 14737702e47cSPaolo Bonzini int i; 14748935a442SScott Wood int virq = OPENPIC_MAX_SRC; 14757702e47cSPaolo Bonzini 14767702e47cSPaolo Bonzini opp->vid = VID_REVISION_1_2; 14777702e47cSPaolo Bonzini opp->vir = VIR_GENERIC; 14787702e47cSPaolo Bonzini opp->vector_mask = 0xFFFF; 14797702e47cSPaolo Bonzini opp->tfrr_reset = 0; 14807702e47cSPaolo Bonzini opp->ivpr_reset = IVPR_MASK_MASK; 14817702e47cSPaolo Bonzini opp->idr_reset = 1 << 0; 14828935a442SScott Wood opp->max_irq = OPENPIC_MAX_IRQ; 14837702e47cSPaolo Bonzini 14847702e47cSPaolo Bonzini opp->irq_ipi0 = virq; 14858935a442SScott Wood virq += OPENPIC_MAX_IPI; 14867702e47cSPaolo Bonzini opp->irq_tim0 = virq; 14878935a442SScott Wood virq += OPENPIC_MAX_TMR; 14887702e47cSPaolo Bonzini 14898935a442SScott Wood assert(virq <= OPENPIC_MAX_IRQ); 14907702e47cSPaolo Bonzini 14917702e47cSPaolo Bonzini opp->irq_msi = 224; 14927702e47cSPaolo Bonzini 14937702e47cSPaolo Bonzini msi_supported = true; 14947702e47cSPaolo Bonzini for (i = 0; i < opp->fsl->max_ext; i++) { 14957702e47cSPaolo Bonzini opp->src[i].level = false; 14967702e47cSPaolo Bonzini } 14977702e47cSPaolo Bonzini 14987702e47cSPaolo Bonzini /* Internal interrupts, including message and MSI */ 14998935a442SScott Wood for (i = 16; i < OPENPIC_MAX_SRC; i++) { 15007702e47cSPaolo Bonzini opp->src[i].type = IRQ_TYPE_FSLINT; 15017702e47cSPaolo Bonzini opp->src[i].level = true; 15027702e47cSPaolo Bonzini } 15037702e47cSPaolo Bonzini 15047702e47cSPaolo Bonzini /* timers and IPIs */ 15058935a442SScott Wood for (i = OPENPIC_MAX_SRC; i < virq; i++) { 15067702e47cSPaolo Bonzini opp->src[i].type = IRQ_TYPE_FSLSPECIAL; 15077702e47cSPaolo Bonzini opp->src[i].level = false; 15087702e47cSPaolo Bonzini } 15097702e47cSPaolo Bonzini } 15107702e47cSPaolo Bonzini 15117702e47cSPaolo Bonzini static void map_list(OpenPICState *opp, const MemReg *list, int *count) 15127702e47cSPaolo Bonzini { 15137702e47cSPaolo Bonzini while (list->name) { 15147702e47cSPaolo Bonzini assert(*count < ARRAY_SIZE(opp->sub_io_mem)); 15157702e47cSPaolo Bonzini 15161437c94bSPaolo Bonzini memory_region_init_io(&opp->sub_io_mem[*count], OBJECT(opp), list->ops, 15171437c94bSPaolo Bonzini opp, list->name, list->size); 15187702e47cSPaolo Bonzini 15197702e47cSPaolo Bonzini memory_region_add_subregion(&opp->mem, list->start_addr, 15207702e47cSPaolo Bonzini &opp->sub_io_mem[*count]); 15217702e47cSPaolo Bonzini 15227702e47cSPaolo Bonzini (*count)++; 15237702e47cSPaolo Bonzini list++; 15247702e47cSPaolo Bonzini } 15257702e47cSPaolo Bonzini } 15267702e47cSPaolo Bonzini 1527cbe72019SAndreas Färber static void openpic_init(Object *obj) 15287702e47cSPaolo Bonzini { 1529cbe72019SAndreas Färber OpenPICState *opp = OPENPIC(obj); 1530cbe72019SAndreas Färber 15311437c94bSPaolo Bonzini memory_region_init(&opp->mem, obj, "openpic", 0x40000); 1532cbe72019SAndreas Färber } 1533cbe72019SAndreas Färber 1534cbe72019SAndreas Färber static void openpic_realize(DeviceState *dev, Error **errp) 1535cbe72019SAndreas Färber { 1536cbe72019SAndreas Färber SysBusDevice *d = SYS_BUS_DEVICE(dev); 1537e1766344SAndreas Färber OpenPICState *opp = OPENPIC(dev); 15387702e47cSPaolo Bonzini int i, j; 15397702e47cSPaolo Bonzini int list_count = 0; 15407702e47cSPaolo Bonzini static const MemReg list_le[] = { 15417702e47cSPaolo Bonzini {"glb", &openpic_glb_ops_le, 15427702e47cSPaolo Bonzini OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE}, 15437702e47cSPaolo Bonzini {"tmr", &openpic_tmr_ops_le, 15447702e47cSPaolo Bonzini OPENPIC_TMR_REG_START, OPENPIC_TMR_REG_SIZE}, 15457702e47cSPaolo Bonzini {"src", &openpic_src_ops_le, 15467702e47cSPaolo Bonzini OPENPIC_SRC_REG_START, OPENPIC_SRC_REG_SIZE}, 15477702e47cSPaolo Bonzini {"cpu", &openpic_cpu_ops_le, 15487702e47cSPaolo Bonzini OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE}, 15497702e47cSPaolo Bonzini {NULL} 15507702e47cSPaolo Bonzini }; 15517702e47cSPaolo Bonzini static const MemReg list_be[] = { 15527702e47cSPaolo Bonzini {"glb", &openpic_glb_ops_be, 15537702e47cSPaolo Bonzini OPENPIC_GLB_REG_START, OPENPIC_GLB_REG_SIZE}, 15547702e47cSPaolo Bonzini {"tmr", &openpic_tmr_ops_be, 15557702e47cSPaolo Bonzini OPENPIC_TMR_REG_START, OPENPIC_TMR_REG_SIZE}, 15567702e47cSPaolo Bonzini {"src", &openpic_src_ops_be, 15577702e47cSPaolo Bonzini OPENPIC_SRC_REG_START, OPENPIC_SRC_REG_SIZE}, 15587702e47cSPaolo Bonzini {"cpu", &openpic_cpu_ops_be, 15597702e47cSPaolo Bonzini OPENPIC_CPU_REG_START, OPENPIC_CPU_REG_SIZE}, 15607702e47cSPaolo Bonzini {NULL} 15617702e47cSPaolo Bonzini }; 15627702e47cSPaolo Bonzini static const MemReg list_fsl[] = { 15637702e47cSPaolo Bonzini {"msi", &openpic_msi_ops_be, 15647702e47cSPaolo Bonzini OPENPIC_MSI_REG_START, OPENPIC_MSI_REG_SIZE}, 15657702e47cSPaolo Bonzini {"summary", &openpic_summary_ops_be, 15667702e47cSPaolo Bonzini OPENPIC_SUMMARY_REG_START, OPENPIC_SUMMARY_REG_SIZE}, 15677702e47cSPaolo Bonzini {NULL} 15687702e47cSPaolo Bonzini }; 15697702e47cSPaolo Bonzini 15707702e47cSPaolo Bonzini switch (opp->model) { 15717702e47cSPaolo Bonzini case OPENPIC_MODEL_FSL_MPIC_20: 15727702e47cSPaolo Bonzini default: 15737702e47cSPaolo Bonzini opp->fsl = &fsl_mpic_20; 15747702e47cSPaolo Bonzini opp->brr1 = 0x00400200; 15757702e47cSPaolo Bonzini opp->flags |= OPENPIC_FLAG_IDR_CRIT; 15767702e47cSPaolo Bonzini opp->nb_irqs = 80; 15777702e47cSPaolo Bonzini opp->mpic_mode_mask = GCR_MODE_MIXED; 15787702e47cSPaolo Bonzini 15797702e47cSPaolo Bonzini fsl_common_init(opp); 15807702e47cSPaolo Bonzini map_list(opp, list_be, &list_count); 15817702e47cSPaolo Bonzini map_list(opp, list_fsl, &list_count); 15827702e47cSPaolo Bonzini 15837702e47cSPaolo Bonzini break; 15847702e47cSPaolo Bonzini 15857702e47cSPaolo Bonzini case OPENPIC_MODEL_FSL_MPIC_42: 15867702e47cSPaolo Bonzini opp->fsl = &fsl_mpic_42; 15877702e47cSPaolo Bonzini opp->brr1 = 0x00400402; 15887702e47cSPaolo Bonzini opp->flags |= OPENPIC_FLAG_ILR; 15897702e47cSPaolo Bonzini opp->nb_irqs = 196; 15907702e47cSPaolo Bonzini opp->mpic_mode_mask = GCR_MODE_PROXY; 15917702e47cSPaolo Bonzini 15927702e47cSPaolo Bonzini fsl_common_init(opp); 15937702e47cSPaolo Bonzini map_list(opp, list_be, &list_count); 15947702e47cSPaolo Bonzini map_list(opp, list_fsl, &list_count); 15957702e47cSPaolo Bonzini 15967702e47cSPaolo Bonzini break; 15977702e47cSPaolo Bonzini 15987702e47cSPaolo Bonzini case OPENPIC_MODEL_RAVEN: 15997702e47cSPaolo Bonzini opp->nb_irqs = RAVEN_MAX_EXT; 16007702e47cSPaolo Bonzini opp->vid = VID_REVISION_1_3; 16017702e47cSPaolo Bonzini opp->vir = VIR_GENERIC; 16027702e47cSPaolo Bonzini opp->vector_mask = 0xFF; 16037702e47cSPaolo Bonzini opp->tfrr_reset = 4160000; 16047702e47cSPaolo Bonzini opp->ivpr_reset = IVPR_MASK_MASK | IVPR_MODE_MASK; 16057702e47cSPaolo Bonzini opp->idr_reset = 0; 16067702e47cSPaolo Bonzini opp->max_irq = RAVEN_MAX_IRQ; 16077702e47cSPaolo Bonzini opp->irq_ipi0 = RAVEN_IPI_IRQ; 16087702e47cSPaolo Bonzini opp->irq_tim0 = RAVEN_TMR_IRQ; 16097702e47cSPaolo Bonzini opp->brr1 = -1; 16107702e47cSPaolo Bonzini opp->mpic_mode_mask = GCR_MODE_MIXED; 16117702e47cSPaolo Bonzini 16127702e47cSPaolo Bonzini if (opp->nb_cpus != 1) { 1613cbe72019SAndreas Färber error_setg(errp, "Only UP supported today"); 1614cbe72019SAndreas Färber return; 16157702e47cSPaolo Bonzini } 16167702e47cSPaolo Bonzini 16177702e47cSPaolo Bonzini map_list(opp, list_le, &list_count); 16187702e47cSPaolo Bonzini break; 16197702e47cSPaolo Bonzini } 16207702e47cSPaolo Bonzini 16217702e47cSPaolo Bonzini for (i = 0; i < opp->nb_cpus; i++) { 16227702e47cSPaolo Bonzini opp->dst[i].irqs = g_new(qemu_irq, OPENPIC_OUTPUT_NB); 16237702e47cSPaolo Bonzini for (j = 0; j < OPENPIC_OUTPUT_NB; j++) { 1624cbe72019SAndreas Färber sysbus_init_irq(d, &opp->dst[i].irqs[j]); 16257702e47cSPaolo Bonzini } 16267702e47cSPaolo Bonzini } 16277702e47cSPaolo Bonzini 1628cbe72019SAndreas Färber register_savevm(dev, "openpic", 0, 2, 16297702e47cSPaolo Bonzini openpic_save, openpic_load, opp); 16307702e47cSPaolo Bonzini 1631cbe72019SAndreas Färber sysbus_init_mmio(d, &opp->mem); 1632cbe72019SAndreas Färber qdev_init_gpio_in(dev, openpic_set_irq, opp->max_irq); 16337702e47cSPaolo Bonzini } 16347702e47cSPaolo Bonzini 16357702e47cSPaolo Bonzini static Property openpic_properties[] = { 16367702e47cSPaolo Bonzini DEFINE_PROP_UINT32("model", OpenPICState, model, OPENPIC_MODEL_FSL_MPIC_20), 16377702e47cSPaolo Bonzini DEFINE_PROP_UINT32("nb_cpus", OpenPICState, nb_cpus, 1), 16387702e47cSPaolo Bonzini DEFINE_PROP_END_OF_LIST(), 16397702e47cSPaolo Bonzini }; 16407702e47cSPaolo Bonzini 1641cbe72019SAndreas Färber static void openpic_class_init(ObjectClass *oc, void *data) 16427702e47cSPaolo Bonzini { 1643cbe72019SAndreas Färber DeviceClass *dc = DEVICE_CLASS(oc); 16447702e47cSPaolo Bonzini 1645cbe72019SAndreas Färber dc->realize = openpic_realize; 16467702e47cSPaolo Bonzini dc->props = openpic_properties; 16477702e47cSPaolo Bonzini dc->reset = openpic_reset; 16487702e47cSPaolo Bonzini } 16497702e47cSPaolo Bonzini 16507702e47cSPaolo Bonzini static const TypeInfo openpic_info = { 1651e1766344SAndreas Färber .name = TYPE_OPENPIC, 16527702e47cSPaolo Bonzini .parent = TYPE_SYS_BUS_DEVICE, 16537702e47cSPaolo Bonzini .instance_size = sizeof(OpenPICState), 1654cbe72019SAndreas Färber .instance_init = openpic_init, 16557702e47cSPaolo Bonzini .class_init = openpic_class_init, 16567702e47cSPaolo Bonzini }; 16577702e47cSPaolo Bonzini 16587702e47cSPaolo Bonzini static void openpic_register_types(void) 16597702e47cSPaolo Bonzini { 16607702e47cSPaolo Bonzini type_register_static(&openpic_info); 16617702e47cSPaolo Bonzini } 16627702e47cSPaolo Bonzini 16637702e47cSPaolo Bonzini type_init(openpic_register_types) 1664