xref: /openbmc/qemu/hw/intc/loongarch_pch_pic.c (revision 28ae3179fc52d2e4d870b635c4a412aab99759e7)
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 
pch_pic_update_irq(LoongArchPCHPIC * s,uint64_t mask,int level)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 
pch_pic_irq_handler(void * opaque,int irq,int level)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 
loongarch_pch_pic_low_readw(void * opaque,hwaddr addr,unsigned size)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 
get_writew_val(uint64_t value,uint32_t target,bool hi)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 
loongarch_pch_pic_low_writew(void * opaque,hwaddr addr,uint64_t value,unsigned size)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 
loongarch_pch_pic_high_readw(void * opaque,hwaddr addr,unsigned size)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 
loongarch_pch_pic_high_writew(void * opaque,hwaddr addr,uint64_t value,unsigned size)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 
loongarch_pch_pic_readb(void * opaque,hwaddr addr,unsigned size)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 
loongarch_pch_pic_writeb(void * opaque,hwaddr addr,uint64_t data,unsigned size)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 
loongarch_pch_pic_reset(DeviceState * d)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 
loongarch_pch_pic_realize(DeviceState * dev,Error ** errp)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 
loongarch_pch_pic_init(Object * obj)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,
42345b1f81dSRichard 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 
loongarch_pch_pic_class_init(ObjectClass * klass,void * data)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;
445*e3d08143SPeter Maydell     device_class_set_legacy_reset(dc, 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 
loongarch_pch_pic_register_types(void)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