10f4fcf18SXiaojuan Yang /* SPDX-License-Identifier: GPL-2.0-or-later */ 20f4fcf18SXiaojuan Yang /* 30f4fcf18SXiaojuan Yang * QEMU Loongson 7A1000 I/O interrupt controller. 40f4fcf18SXiaojuan Yang * 50f4fcf18SXiaojuan Yang * Copyright (C) 2021 Loongson Technology Corporation Limited 60f4fcf18SXiaojuan Yang */ 70f4fcf18SXiaojuan Yang 80f4fcf18SXiaojuan Yang #include "qemu/osdep.h" 9270950b4STianrui Zhao #include "qemu/bitops.h" 100f4fcf18SXiaojuan Yang #include "hw/sysbus.h" 110f4fcf18SXiaojuan Yang #include "hw/loongarch/virt.h" 12f4d10ce8STianrui Zhao #include "hw/pci-host/ls7a.h" 130f4fcf18SXiaojuan Yang #include "hw/irq.h" 140f4fcf18SXiaojuan Yang #include "hw/intc/loongarch_pch_pic.h" 15270950b4STianrui Zhao #include "hw/qdev-properties.h" 160f4fcf18SXiaojuan Yang #include "migration/vmstate.h" 170f4fcf18SXiaojuan Yang #include "trace.h" 18270950b4STianrui Zhao #include "qapi/error.h" 190f4fcf18SXiaojuan Yang 200f4fcf18SXiaojuan Yang static void pch_pic_update_irq(LoongArchPCHPIC *s, uint64_t mask, int level) 210f4fcf18SXiaojuan Yang { 22056dac53SXiaojuan Yang uint64_t val; 230f4fcf18SXiaojuan Yang int irq; 240f4fcf18SXiaojuan Yang 250f4fcf18SXiaojuan Yang if (level) { 260f4fcf18SXiaojuan Yang val = mask & s->intirr & ~s->int_mask; 270f4fcf18SXiaojuan Yang if (val) { 28056dac53SXiaojuan Yang irq = ctz64(val); 29056dac53SXiaojuan Yang s->intisr |= MAKE_64BIT_MASK(irq, 1); 300f4fcf18SXiaojuan Yang qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 1); 310f4fcf18SXiaojuan Yang } 320f4fcf18SXiaojuan Yang } else { 332948c1fbSBibo Mao /* 342948c1fbSBibo Mao * intirr means requested pending irq 352948c1fbSBibo Mao * do not clear pending irq for edge-triggered on lowering edge 362948c1fbSBibo Mao */ 372948c1fbSBibo Mao val = mask & s->intisr & ~s->intirr; 380f4fcf18SXiaojuan Yang if (val) { 39056dac53SXiaojuan Yang irq = ctz64(val); 40056dac53SXiaojuan Yang s->intisr &= ~MAKE_64BIT_MASK(irq, 1); 410f4fcf18SXiaojuan Yang qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 0); 420f4fcf18SXiaojuan Yang } 430f4fcf18SXiaojuan Yang } 440f4fcf18SXiaojuan Yang } 450f4fcf18SXiaojuan Yang 460f4fcf18SXiaojuan Yang static void pch_pic_irq_handler(void *opaque, int irq, int level) 470f4fcf18SXiaojuan Yang { 480f4fcf18SXiaojuan Yang LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque); 490f4fcf18SXiaojuan Yang uint64_t mask = 1ULL << irq; 500f4fcf18SXiaojuan Yang 51270950b4STianrui Zhao assert(irq < s->irq_num); 520f4fcf18SXiaojuan Yang trace_loongarch_pch_pic_irq_handler(irq, level); 530f4fcf18SXiaojuan Yang 540f4fcf18SXiaojuan Yang if (s->intedge & mask) { 550f4fcf18SXiaojuan Yang /* Edge triggered */ 560f4fcf18SXiaojuan Yang if (level) { 570f4fcf18SXiaojuan Yang if ((s->last_intirr & mask) == 0) { 582948c1fbSBibo Mao /* marked pending on a rising edge */ 590f4fcf18SXiaojuan Yang s->intirr |= mask; 600f4fcf18SXiaojuan Yang } 610f4fcf18SXiaojuan Yang s->last_intirr |= mask; 620f4fcf18SXiaojuan Yang } else { 630f4fcf18SXiaojuan Yang s->last_intirr &= ~mask; 640f4fcf18SXiaojuan Yang } 650f4fcf18SXiaojuan Yang } else { 660f4fcf18SXiaojuan Yang /* Level triggered */ 670f4fcf18SXiaojuan Yang if (level) { 680f4fcf18SXiaojuan Yang s->intirr |= mask; 690f4fcf18SXiaojuan Yang s->last_intirr |= mask; 700f4fcf18SXiaojuan Yang } else { 710f4fcf18SXiaojuan Yang s->intirr &= ~mask; 720f4fcf18SXiaojuan Yang s->last_intirr &= ~mask; 730f4fcf18SXiaojuan Yang } 740f4fcf18SXiaojuan Yang } 750f4fcf18SXiaojuan Yang pch_pic_update_irq(s, mask, level); 760f4fcf18SXiaojuan Yang } 770f4fcf18SXiaojuan Yang 780f4fcf18SXiaojuan Yang static uint64_t loongarch_pch_pic_low_readw(void *opaque, hwaddr addr, 790f4fcf18SXiaojuan Yang unsigned size) 800f4fcf18SXiaojuan Yang { 810f4fcf18SXiaojuan Yang LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque); 820f4fcf18SXiaojuan Yang uint64_t val = 0; 830f4fcf18SXiaojuan Yang uint32_t offset = addr & 0xfff; 840f4fcf18SXiaojuan Yang 850f4fcf18SXiaojuan Yang switch (offset) { 860f4fcf18SXiaojuan Yang case PCH_PIC_INT_ID_LO: 870f4fcf18SXiaojuan Yang val = PCH_PIC_INT_ID_VAL; 880f4fcf18SXiaojuan Yang break; 890f4fcf18SXiaojuan Yang case PCH_PIC_INT_ID_HI: 90270950b4STianrui Zhao /* 91270950b4STianrui Zhao * With 7A1000 manual 92270950b4STianrui Zhao * bit 0-15 pch irqchip version 93270950b4STianrui Zhao * bit 16-31 irq number supported with pch irqchip 94270950b4STianrui Zhao */ 95270950b4STianrui Zhao val = deposit32(PCH_PIC_INT_ID_VER, 16, 16, s->irq_num - 1); 960f4fcf18SXiaojuan Yang break; 970f4fcf18SXiaojuan Yang case PCH_PIC_INT_MASK_LO: 980f4fcf18SXiaojuan Yang val = (uint32_t)s->int_mask; 990f4fcf18SXiaojuan Yang break; 1000f4fcf18SXiaojuan Yang case PCH_PIC_INT_MASK_HI: 1010f4fcf18SXiaojuan Yang val = s->int_mask >> 32; 1020f4fcf18SXiaojuan Yang break; 1030f4fcf18SXiaojuan Yang case PCH_PIC_INT_EDGE_LO: 1040f4fcf18SXiaojuan Yang val = (uint32_t)s->intedge; 1050f4fcf18SXiaojuan Yang break; 1060f4fcf18SXiaojuan Yang case PCH_PIC_INT_EDGE_HI: 1070f4fcf18SXiaojuan Yang val = s->intedge >> 32; 1080f4fcf18SXiaojuan Yang break; 1090f4fcf18SXiaojuan Yang case PCH_PIC_HTMSI_EN_LO: 1100f4fcf18SXiaojuan Yang val = (uint32_t)s->htmsi_en; 1110f4fcf18SXiaojuan Yang break; 1120f4fcf18SXiaojuan Yang case PCH_PIC_HTMSI_EN_HI: 1130f4fcf18SXiaojuan Yang val = s->htmsi_en >> 32; 1140f4fcf18SXiaojuan Yang break; 1150f4fcf18SXiaojuan Yang case PCH_PIC_AUTO_CTRL0_LO: 1160f4fcf18SXiaojuan Yang case PCH_PIC_AUTO_CTRL0_HI: 1170f4fcf18SXiaojuan Yang case PCH_PIC_AUTO_CTRL1_LO: 1180f4fcf18SXiaojuan Yang case PCH_PIC_AUTO_CTRL1_HI: 1190f4fcf18SXiaojuan Yang break; 1200f4fcf18SXiaojuan Yang default: 1210f4fcf18SXiaojuan Yang break; 1220f4fcf18SXiaojuan Yang } 1230f4fcf18SXiaojuan Yang 1240f4fcf18SXiaojuan Yang trace_loongarch_pch_pic_low_readw(size, addr, val); 1250f4fcf18SXiaojuan Yang return val; 1260f4fcf18SXiaojuan Yang } 1270f4fcf18SXiaojuan Yang 1280f4fcf18SXiaojuan Yang static uint64_t get_writew_val(uint64_t value, uint32_t target, bool hi) 1290f4fcf18SXiaojuan Yang { 1300f4fcf18SXiaojuan Yang uint64_t mask = 0xffffffff00000000; 1310f4fcf18SXiaojuan Yang uint64_t data = target; 1320f4fcf18SXiaojuan Yang 1330f4fcf18SXiaojuan Yang return hi ? (value & ~mask) | (data << 32) : (value & mask) | data; 1340f4fcf18SXiaojuan Yang } 1350f4fcf18SXiaojuan Yang 1360f4fcf18SXiaojuan Yang static void loongarch_pch_pic_low_writew(void *opaque, hwaddr addr, 1370f4fcf18SXiaojuan Yang uint64_t value, unsigned size) 1380f4fcf18SXiaojuan Yang { 1390f4fcf18SXiaojuan Yang LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque); 1400f4fcf18SXiaojuan Yang uint32_t offset, old_valid, data = (uint32_t)value; 1410f4fcf18SXiaojuan Yang uint64_t old, int_mask; 1420f4fcf18SXiaojuan Yang offset = addr & 0xfff; 1430f4fcf18SXiaojuan Yang 1440f4fcf18SXiaojuan Yang trace_loongarch_pch_pic_low_writew(size, addr, data); 1450f4fcf18SXiaojuan Yang 1460f4fcf18SXiaojuan Yang switch (offset) { 1470f4fcf18SXiaojuan Yang case PCH_PIC_INT_MASK_LO: 1480f4fcf18SXiaojuan Yang old = s->int_mask; 1490f4fcf18SXiaojuan Yang s->int_mask = get_writew_val(old, data, 0); 1500f4fcf18SXiaojuan Yang old_valid = (uint32_t)old; 1510f4fcf18SXiaojuan Yang if (old_valid & ~data) { 1520f4fcf18SXiaojuan Yang pch_pic_update_irq(s, (old_valid & ~data), 1); 1530f4fcf18SXiaojuan Yang } 1540f4fcf18SXiaojuan Yang if (~old_valid & data) { 1550f4fcf18SXiaojuan Yang pch_pic_update_irq(s, (~old_valid & data), 0); 1560f4fcf18SXiaojuan Yang } 1570f4fcf18SXiaojuan Yang break; 1580f4fcf18SXiaojuan Yang case PCH_PIC_INT_MASK_HI: 1590f4fcf18SXiaojuan Yang old = s->int_mask; 1600f4fcf18SXiaojuan Yang s->int_mask = get_writew_val(old, data, 1); 1610f4fcf18SXiaojuan Yang old_valid = (uint32_t)(old >> 32); 1620f4fcf18SXiaojuan Yang int_mask = old_valid & ~data; 1630f4fcf18SXiaojuan Yang if (int_mask) { 1640f4fcf18SXiaojuan Yang pch_pic_update_irq(s, int_mask << 32, 1); 1650f4fcf18SXiaojuan Yang } 1660f4fcf18SXiaojuan Yang int_mask = ~old_valid & data; 1670f4fcf18SXiaojuan Yang if (int_mask) { 1680f4fcf18SXiaojuan Yang pch_pic_update_irq(s, int_mask << 32, 0); 1690f4fcf18SXiaojuan Yang } 1700f4fcf18SXiaojuan Yang break; 1710f4fcf18SXiaojuan Yang case PCH_PIC_INT_EDGE_LO: 1720f4fcf18SXiaojuan Yang s->intedge = get_writew_val(s->intedge, data, 0); 1730f4fcf18SXiaojuan Yang break; 1740f4fcf18SXiaojuan Yang case PCH_PIC_INT_EDGE_HI: 1750f4fcf18SXiaojuan Yang s->intedge = get_writew_val(s->intedge, data, 1); 1760f4fcf18SXiaojuan Yang break; 1770f4fcf18SXiaojuan Yang case PCH_PIC_INT_CLEAR_LO: 1780f4fcf18SXiaojuan Yang if (s->intedge & data) { 1790f4fcf18SXiaojuan Yang s->intirr &= (~data); 1800f4fcf18SXiaojuan Yang pch_pic_update_irq(s, data, 0); 1810f4fcf18SXiaojuan Yang s->intisr &= (~data); 1820f4fcf18SXiaojuan Yang } 1830f4fcf18SXiaojuan Yang break; 1840f4fcf18SXiaojuan Yang case PCH_PIC_INT_CLEAR_HI: 1850f4fcf18SXiaojuan Yang value <<= 32; 1860f4fcf18SXiaojuan Yang if (s->intedge & value) { 1870f4fcf18SXiaojuan Yang s->intirr &= (~value); 1880f4fcf18SXiaojuan Yang pch_pic_update_irq(s, value, 0); 1890f4fcf18SXiaojuan Yang s->intisr &= (~value); 1900f4fcf18SXiaojuan Yang } 1910f4fcf18SXiaojuan Yang break; 1920f4fcf18SXiaojuan Yang case PCH_PIC_HTMSI_EN_LO: 1930f4fcf18SXiaojuan Yang s->htmsi_en = get_writew_val(s->htmsi_en, data, 0); 1940f4fcf18SXiaojuan Yang break; 1950f4fcf18SXiaojuan Yang case PCH_PIC_HTMSI_EN_HI: 1960f4fcf18SXiaojuan Yang s->htmsi_en = get_writew_val(s->htmsi_en, data, 1); 1970f4fcf18SXiaojuan Yang break; 1980f4fcf18SXiaojuan Yang case PCH_PIC_AUTO_CTRL0_LO: 1990f4fcf18SXiaojuan Yang case PCH_PIC_AUTO_CTRL0_HI: 2000f4fcf18SXiaojuan Yang case PCH_PIC_AUTO_CTRL1_LO: 2010f4fcf18SXiaojuan Yang case PCH_PIC_AUTO_CTRL1_HI: 2020f4fcf18SXiaojuan Yang break; 2030f4fcf18SXiaojuan Yang default: 2040f4fcf18SXiaojuan Yang break; 2050f4fcf18SXiaojuan Yang } 2060f4fcf18SXiaojuan Yang } 2070f4fcf18SXiaojuan Yang 2080f4fcf18SXiaojuan Yang static uint64_t loongarch_pch_pic_high_readw(void *opaque, hwaddr addr, 2090f4fcf18SXiaojuan Yang unsigned size) 2100f4fcf18SXiaojuan Yang { 2110f4fcf18SXiaojuan Yang LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque); 2120f4fcf18SXiaojuan Yang uint64_t val = 0; 2130f4fcf18SXiaojuan Yang uint32_t offset = addr & 0xfff; 2140f4fcf18SXiaojuan Yang 2150f4fcf18SXiaojuan Yang switch (offset) { 2160f4fcf18SXiaojuan Yang case STATUS_LO_START: 2170f4fcf18SXiaojuan Yang val = (uint32_t)(s->intisr & (~s->int_mask)); 2180f4fcf18SXiaojuan Yang break; 2190f4fcf18SXiaojuan Yang case STATUS_HI_START: 2200f4fcf18SXiaojuan Yang val = (s->intisr & (~s->int_mask)) >> 32; 2210f4fcf18SXiaojuan Yang break; 2220f4fcf18SXiaojuan Yang case POL_LO_START: 2230f4fcf18SXiaojuan Yang val = (uint32_t)s->int_polarity; 2240f4fcf18SXiaojuan Yang break; 2250f4fcf18SXiaojuan Yang case POL_HI_START: 2260f4fcf18SXiaojuan Yang val = s->int_polarity >> 32; 2270f4fcf18SXiaojuan Yang break; 2280f4fcf18SXiaojuan Yang default: 2290f4fcf18SXiaojuan Yang break; 2300f4fcf18SXiaojuan Yang } 2310f4fcf18SXiaojuan Yang 2320f4fcf18SXiaojuan Yang trace_loongarch_pch_pic_high_readw(size, addr, val); 2330f4fcf18SXiaojuan Yang return val; 2340f4fcf18SXiaojuan Yang } 2350f4fcf18SXiaojuan Yang 2360f4fcf18SXiaojuan Yang static void loongarch_pch_pic_high_writew(void *opaque, hwaddr addr, 2370f4fcf18SXiaojuan Yang uint64_t value, unsigned size) 2380f4fcf18SXiaojuan Yang { 2390f4fcf18SXiaojuan Yang LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque); 2400f4fcf18SXiaojuan Yang uint32_t offset, data = (uint32_t)value; 2410f4fcf18SXiaojuan Yang offset = addr & 0xfff; 2420f4fcf18SXiaojuan Yang 2430f4fcf18SXiaojuan Yang trace_loongarch_pch_pic_high_writew(size, addr, data); 2440f4fcf18SXiaojuan Yang 2450f4fcf18SXiaojuan Yang switch (offset) { 2460f4fcf18SXiaojuan Yang case STATUS_LO_START: 2470f4fcf18SXiaojuan Yang s->intisr = get_writew_val(s->intisr, data, 0); 2480f4fcf18SXiaojuan Yang break; 2490f4fcf18SXiaojuan Yang case STATUS_HI_START: 2500f4fcf18SXiaojuan Yang s->intisr = get_writew_val(s->intisr, data, 1); 2510f4fcf18SXiaojuan Yang break; 2520f4fcf18SXiaojuan Yang case POL_LO_START: 2530f4fcf18SXiaojuan Yang s->int_polarity = get_writew_val(s->int_polarity, data, 0); 2540f4fcf18SXiaojuan Yang break; 2550f4fcf18SXiaojuan Yang case POL_HI_START: 2560f4fcf18SXiaojuan Yang s->int_polarity = get_writew_val(s->int_polarity, data, 1); 2570f4fcf18SXiaojuan Yang break; 2580f4fcf18SXiaojuan Yang default: 2590f4fcf18SXiaojuan Yang break; 2600f4fcf18SXiaojuan Yang } 2610f4fcf18SXiaojuan Yang } 2620f4fcf18SXiaojuan Yang 2630f4fcf18SXiaojuan Yang static uint64_t loongarch_pch_pic_readb(void *opaque, hwaddr addr, 2640f4fcf18SXiaojuan Yang unsigned size) 2650f4fcf18SXiaojuan Yang { 2660f4fcf18SXiaojuan Yang LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque); 2670f4fcf18SXiaojuan Yang uint64_t val = 0; 2680f4fcf18SXiaojuan Yang uint32_t offset = (addr & 0xfff) + PCH_PIC_ROUTE_ENTRY_OFFSET; 2690f4fcf18SXiaojuan Yang int64_t offset_tmp; 2700f4fcf18SXiaojuan Yang 2710f4fcf18SXiaojuan Yang switch (offset) { 2720f4fcf18SXiaojuan Yang case PCH_PIC_HTMSI_VEC_OFFSET ... PCH_PIC_HTMSI_VEC_END: 2730f4fcf18SXiaojuan Yang offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET; 2740f4fcf18SXiaojuan Yang if (offset_tmp >= 0 && offset_tmp < 64) { 2750f4fcf18SXiaojuan Yang val = s->htmsi_vector[offset_tmp]; 2760f4fcf18SXiaojuan Yang } 2770f4fcf18SXiaojuan Yang break; 2780f4fcf18SXiaojuan Yang case PCH_PIC_ROUTE_ENTRY_OFFSET ... PCH_PIC_ROUTE_ENTRY_END: 2790f4fcf18SXiaojuan Yang offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET; 2800f4fcf18SXiaojuan Yang if (offset_tmp >= 0 && offset_tmp < 64) { 2810f4fcf18SXiaojuan Yang val = s->route_entry[offset_tmp]; 2820f4fcf18SXiaojuan Yang } 2830f4fcf18SXiaojuan Yang break; 2840f4fcf18SXiaojuan Yang default: 2850f4fcf18SXiaojuan Yang break; 2860f4fcf18SXiaojuan Yang } 2870f4fcf18SXiaojuan Yang 2880f4fcf18SXiaojuan Yang trace_loongarch_pch_pic_readb(size, addr, val); 2890f4fcf18SXiaojuan Yang return val; 2900f4fcf18SXiaojuan Yang } 2910f4fcf18SXiaojuan Yang 2920f4fcf18SXiaojuan Yang static void loongarch_pch_pic_writeb(void *opaque, hwaddr addr, 2930f4fcf18SXiaojuan Yang uint64_t data, unsigned size) 2940f4fcf18SXiaojuan Yang { 2950f4fcf18SXiaojuan Yang LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque); 2960f4fcf18SXiaojuan Yang int32_t offset_tmp; 2970f4fcf18SXiaojuan Yang uint32_t offset = (addr & 0xfff) + PCH_PIC_ROUTE_ENTRY_OFFSET; 2980f4fcf18SXiaojuan Yang 2990f4fcf18SXiaojuan Yang trace_loongarch_pch_pic_writeb(size, addr, data); 3000f4fcf18SXiaojuan Yang 3010f4fcf18SXiaojuan Yang switch (offset) { 3020f4fcf18SXiaojuan Yang case PCH_PIC_HTMSI_VEC_OFFSET ... PCH_PIC_HTMSI_VEC_END: 3030f4fcf18SXiaojuan Yang offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET; 3040f4fcf18SXiaojuan Yang if (offset_tmp >= 0 && offset_tmp < 64) { 3050f4fcf18SXiaojuan Yang s->htmsi_vector[offset_tmp] = (uint8_t)(data & 0xff); 3060f4fcf18SXiaojuan Yang } 3070f4fcf18SXiaojuan Yang break; 3080f4fcf18SXiaojuan Yang case PCH_PIC_ROUTE_ENTRY_OFFSET ... PCH_PIC_ROUTE_ENTRY_END: 3090f4fcf18SXiaojuan Yang offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET; 3100f4fcf18SXiaojuan Yang if (offset_tmp >= 0 && offset_tmp < 64) { 3110f4fcf18SXiaojuan Yang s->route_entry[offset_tmp] = (uint8_t)(data & 0xff); 3120f4fcf18SXiaojuan Yang } 3130f4fcf18SXiaojuan Yang break; 3140f4fcf18SXiaojuan Yang default: 3150f4fcf18SXiaojuan Yang break; 3160f4fcf18SXiaojuan Yang } 3170f4fcf18SXiaojuan Yang } 3180f4fcf18SXiaojuan Yang 3190f4fcf18SXiaojuan Yang static const MemoryRegionOps loongarch_pch_pic_reg32_low_ops = { 3200f4fcf18SXiaojuan Yang .read = loongarch_pch_pic_low_readw, 3210f4fcf18SXiaojuan Yang .write = loongarch_pch_pic_low_writew, 3220f4fcf18SXiaojuan Yang .valid = { 3230f4fcf18SXiaojuan Yang .min_access_size = 4, 3240f4fcf18SXiaojuan Yang .max_access_size = 8, 3250f4fcf18SXiaojuan Yang }, 3260f4fcf18SXiaojuan Yang .impl = { 3270f4fcf18SXiaojuan Yang .min_access_size = 4, 3280f4fcf18SXiaojuan Yang .max_access_size = 4, 3290f4fcf18SXiaojuan Yang }, 3300f4fcf18SXiaojuan Yang .endianness = DEVICE_LITTLE_ENDIAN, 3310f4fcf18SXiaojuan Yang }; 3320f4fcf18SXiaojuan Yang 3330f4fcf18SXiaojuan Yang static const MemoryRegionOps loongarch_pch_pic_reg32_high_ops = { 3340f4fcf18SXiaojuan Yang .read = loongarch_pch_pic_high_readw, 3350f4fcf18SXiaojuan Yang .write = loongarch_pch_pic_high_writew, 3360f4fcf18SXiaojuan Yang .valid = { 3370f4fcf18SXiaojuan Yang .min_access_size = 4, 3380f4fcf18SXiaojuan Yang .max_access_size = 8, 3390f4fcf18SXiaojuan Yang }, 3400f4fcf18SXiaojuan Yang .impl = { 3410f4fcf18SXiaojuan Yang .min_access_size = 4, 3420f4fcf18SXiaojuan Yang .max_access_size = 4, 3430f4fcf18SXiaojuan Yang }, 3440f4fcf18SXiaojuan Yang .endianness = DEVICE_LITTLE_ENDIAN, 3450f4fcf18SXiaojuan Yang }; 3460f4fcf18SXiaojuan Yang 3470f4fcf18SXiaojuan Yang static const MemoryRegionOps loongarch_pch_pic_reg8_ops = { 3480f4fcf18SXiaojuan Yang .read = loongarch_pch_pic_readb, 3490f4fcf18SXiaojuan Yang .write = loongarch_pch_pic_writeb, 3500f4fcf18SXiaojuan Yang .valid = { 3510f4fcf18SXiaojuan Yang .min_access_size = 1, 3520f4fcf18SXiaojuan Yang .max_access_size = 1, 3530f4fcf18SXiaojuan Yang }, 3540f4fcf18SXiaojuan Yang .impl = { 3550f4fcf18SXiaojuan Yang .min_access_size = 1, 3560f4fcf18SXiaojuan Yang .max_access_size = 1, 3570f4fcf18SXiaojuan Yang }, 3580f4fcf18SXiaojuan Yang .endianness = DEVICE_LITTLE_ENDIAN, 3590f4fcf18SXiaojuan Yang }; 3600f4fcf18SXiaojuan Yang 3610f4fcf18SXiaojuan Yang static void loongarch_pch_pic_reset(DeviceState *d) 3620f4fcf18SXiaojuan Yang { 3630f4fcf18SXiaojuan Yang LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(d); 3640f4fcf18SXiaojuan Yang int i; 3650f4fcf18SXiaojuan Yang 3660f4fcf18SXiaojuan Yang s->int_mask = -1; 3670f4fcf18SXiaojuan Yang s->htmsi_en = 0x0; 3680f4fcf18SXiaojuan Yang s->intedge = 0x0; 3690f4fcf18SXiaojuan Yang s->intclr = 0x0; 3700f4fcf18SXiaojuan Yang s->auto_crtl0 = 0x0; 3710f4fcf18SXiaojuan Yang s->auto_crtl1 = 0x0; 3720f4fcf18SXiaojuan Yang for (i = 0; i < 64; i++) { 3730f4fcf18SXiaojuan Yang s->route_entry[i] = 0x1; 3740f4fcf18SXiaojuan Yang s->htmsi_vector[i] = 0x0; 3750f4fcf18SXiaojuan Yang } 3760f4fcf18SXiaojuan Yang s->intirr = 0x0; 3770f4fcf18SXiaojuan Yang s->intisr = 0x0; 3780f4fcf18SXiaojuan Yang s->last_intirr = 0x0; 3790f4fcf18SXiaojuan Yang s->int_polarity = 0x0; 3800f4fcf18SXiaojuan Yang } 3810f4fcf18SXiaojuan Yang 382270950b4STianrui Zhao static void loongarch_pch_pic_realize(DeviceState *dev, Error **errp) 383270950b4STianrui Zhao { 384270950b4STianrui Zhao LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(dev); 385270950b4STianrui Zhao 386f4d10ce8STianrui Zhao if (!s->irq_num || s->irq_num > VIRT_PCH_PIC_IRQ_NUM) { 387270950b4STianrui Zhao error_setg(errp, "Invalid 'pic_irq_num'"); 388270950b4STianrui Zhao return; 389270950b4STianrui Zhao } 390270950b4STianrui Zhao 391270950b4STianrui Zhao qdev_init_gpio_out(dev, s->parent_irq, s->irq_num); 392270950b4STianrui Zhao qdev_init_gpio_in(dev, pch_pic_irq_handler, s->irq_num); 393270950b4STianrui Zhao } 394270950b4STianrui Zhao 3950f4fcf18SXiaojuan Yang static void loongarch_pch_pic_init(Object *obj) 3960f4fcf18SXiaojuan Yang { 3970f4fcf18SXiaojuan Yang LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(obj); 3980f4fcf18SXiaojuan Yang SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 3990f4fcf18SXiaojuan Yang 4000f4fcf18SXiaojuan Yang memory_region_init_io(&s->iomem32_low, obj, 4010f4fcf18SXiaojuan Yang &loongarch_pch_pic_reg32_low_ops, 4020f4fcf18SXiaojuan Yang s, PCH_PIC_NAME(.reg32_part1), 0x100); 4030f4fcf18SXiaojuan Yang memory_region_init_io(&s->iomem8, obj, &loongarch_pch_pic_reg8_ops, 4040f4fcf18SXiaojuan Yang s, PCH_PIC_NAME(.reg8), 0x2a0); 4050f4fcf18SXiaojuan Yang memory_region_init_io(&s->iomem32_high, obj, 4060f4fcf18SXiaojuan Yang &loongarch_pch_pic_reg32_high_ops, 4070f4fcf18SXiaojuan Yang s, PCH_PIC_NAME(.reg32_part2), 0xc60); 4080f4fcf18SXiaojuan Yang sysbus_init_mmio(sbd, &s->iomem32_low); 4090f4fcf18SXiaojuan Yang sysbus_init_mmio(sbd, &s->iomem8); 4100f4fcf18SXiaojuan Yang sysbus_init_mmio(sbd, &s->iomem32_high); 4110f4fcf18SXiaojuan Yang 4120f4fcf18SXiaojuan Yang } 4130f4fcf18SXiaojuan Yang 414270950b4STianrui Zhao static Property loongarch_pch_pic_properties[] = { 415270950b4STianrui Zhao DEFINE_PROP_UINT32("pch_pic_irq_num", LoongArchPCHPIC, irq_num, 0), 416270950b4STianrui Zhao DEFINE_PROP_END_OF_LIST(), 417270950b4STianrui Zhao }; 418270950b4STianrui Zhao 4190f4fcf18SXiaojuan Yang static const VMStateDescription vmstate_loongarch_pch_pic = { 4200f4fcf18SXiaojuan Yang .name = TYPE_LOONGARCH_PCH_PIC, 4210f4fcf18SXiaojuan Yang .version_id = 1, 4220f4fcf18SXiaojuan Yang .minimum_version_id = 1, 423*45b1f81dSRichard Henderson .fields = (const VMStateField[]) { 4240f4fcf18SXiaojuan Yang VMSTATE_UINT64(int_mask, LoongArchPCHPIC), 4250f4fcf18SXiaojuan Yang VMSTATE_UINT64(htmsi_en, LoongArchPCHPIC), 4260f4fcf18SXiaojuan Yang VMSTATE_UINT64(intedge, LoongArchPCHPIC), 4270f4fcf18SXiaojuan Yang VMSTATE_UINT64(intclr, LoongArchPCHPIC), 4280f4fcf18SXiaojuan Yang VMSTATE_UINT64(auto_crtl0, LoongArchPCHPIC), 4290f4fcf18SXiaojuan Yang VMSTATE_UINT64(auto_crtl1, LoongArchPCHPIC), 4300f4fcf18SXiaojuan Yang VMSTATE_UINT8_ARRAY(route_entry, LoongArchPCHPIC, 64), 4310f4fcf18SXiaojuan Yang VMSTATE_UINT8_ARRAY(htmsi_vector, LoongArchPCHPIC, 64), 4320f4fcf18SXiaojuan Yang VMSTATE_UINT64(last_intirr, LoongArchPCHPIC), 4330f4fcf18SXiaojuan Yang VMSTATE_UINT64(intirr, LoongArchPCHPIC), 4340f4fcf18SXiaojuan Yang VMSTATE_UINT64(intisr, LoongArchPCHPIC), 4350f4fcf18SXiaojuan Yang VMSTATE_UINT64(int_polarity, LoongArchPCHPIC), 4360f4fcf18SXiaojuan Yang VMSTATE_END_OF_LIST() 4370f4fcf18SXiaojuan Yang } 4380f4fcf18SXiaojuan Yang }; 4390f4fcf18SXiaojuan Yang 4400f4fcf18SXiaojuan Yang static void loongarch_pch_pic_class_init(ObjectClass *klass, void *data) 4410f4fcf18SXiaojuan Yang { 4420f4fcf18SXiaojuan Yang DeviceClass *dc = DEVICE_CLASS(klass); 4430f4fcf18SXiaojuan Yang 444270950b4STianrui Zhao dc->realize = loongarch_pch_pic_realize; 4450f4fcf18SXiaojuan Yang dc->reset = loongarch_pch_pic_reset; 4460f4fcf18SXiaojuan Yang dc->vmsd = &vmstate_loongarch_pch_pic; 447270950b4STianrui Zhao device_class_set_props(dc, loongarch_pch_pic_properties); 4480f4fcf18SXiaojuan Yang } 4490f4fcf18SXiaojuan Yang 4500f4fcf18SXiaojuan Yang static const TypeInfo loongarch_pch_pic_info = { 4510f4fcf18SXiaojuan Yang .name = TYPE_LOONGARCH_PCH_PIC, 4520f4fcf18SXiaojuan Yang .parent = TYPE_SYS_BUS_DEVICE, 4530f4fcf18SXiaojuan Yang .instance_size = sizeof(LoongArchPCHPIC), 4540f4fcf18SXiaojuan Yang .instance_init = loongarch_pch_pic_init, 4550f4fcf18SXiaojuan Yang .class_init = loongarch_pch_pic_class_init, 4560f4fcf18SXiaojuan Yang }; 4570f4fcf18SXiaojuan Yang 4580f4fcf18SXiaojuan Yang static void loongarch_pch_pic_register_types(void) 4590f4fcf18SXiaojuan Yang { 4600f4fcf18SXiaojuan Yang type_register_static(&loongarch_pch_pic_info); 4610f4fcf18SXiaojuan Yang } 4620f4fcf18SXiaojuan Yang 4630f4fcf18SXiaojuan Yang type_init(loongarch_pch_pic_register_types) 464