xref: /openbmc/qemu/hw/intc/loongarch_pch_pic.c (revision 0f4fcf1845fe188901d4ff4cc807bd78690dddd0)
1*0f4fcf18SXiaojuan Yang /* SPDX-License-Identifier: GPL-2.0-or-later */
2*0f4fcf18SXiaojuan Yang /*
3*0f4fcf18SXiaojuan Yang  * QEMU Loongson 7A1000 I/O interrupt controller.
4*0f4fcf18SXiaojuan Yang  *
5*0f4fcf18SXiaojuan Yang  * Copyright (C) 2021 Loongson Technology Corporation Limited
6*0f4fcf18SXiaojuan Yang  */
7*0f4fcf18SXiaojuan Yang 
8*0f4fcf18SXiaojuan Yang #include "qemu/osdep.h"
9*0f4fcf18SXiaojuan Yang #include "hw/sysbus.h"
10*0f4fcf18SXiaojuan Yang #include "hw/loongarch/virt.h"
11*0f4fcf18SXiaojuan Yang #include "hw/irq.h"
12*0f4fcf18SXiaojuan Yang #include "hw/intc/loongarch_pch_pic.h"
13*0f4fcf18SXiaojuan Yang #include "migration/vmstate.h"
14*0f4fcf18SXiaojuan Yang #include "trace.h"
15*0f4fcf18SXiaojuan Yang 
16*0f4fcf18SXiaojuan Yang static void pch_pic_update_irq(LoongArchPCHPIC *s, uint64_t mask, int level)
17*0f4fcf18SXiaojuan Yang {
18*0f4fcf18SXiaojuan Yang     unsigned long val;
19*0f4fcf18SXiaojuan Yang     int irq;
20*0f4fcf18SXiaojuan Yang 
21*0f4fcf18SXiaojuan Yang     if (level) {
22*0f4fcf18SXiaojuan Yang         val = mask & s->intirr & ~s->int_mask;
23*0f4fcf18SXiaojuan Yang         if (val) {
24*0f4fcf18SXiaojuan Yang             irq = find_first_bit(&val, 64);
25*0f4fcf18SXiaojuan Yang             s->intisr |= 0x1ULL << irq;
26*0f4fcf18SXiaojuan Yang             qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 1);
27*0f4fcf18SXiaojuan Yang         }
28*0f4fcf18SXiaojuan Yang     } else {
29*0f4fcf18SXiaojuan Yang         val = mask & s->intisr;
30*0f4fcf18SXiaojuan Yang         if (val) {
31*0f4fcf18SXiaojuan Yang             irq = find_first_bit(&val, 64);
32*0f4fcf18SXiaojuan Yang             s->intisr &= ~(0x1ULL << irq);
33*0f4fcf18SXiaojuan Yang             qemu_set_irq(s->parent_irq[s->htmsi_vector[irq]], 0);
34*0f4fcf18SXiaojuan Yang         }
35*0f4fcf18SXiaojuan Yang     }
36*0f4fcf18SXiaojuan Yang }
37*0f4fcf18SXiaojuan Yang 
38*0f4fcf18SXiaojuan Yang static void pch_pic_irq_handler(void *opaque, int irq, int level)
39*0f4fcf18SXiaojuan Yang {
40*0f4fcf18SXiaojuan Yang     LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
41*0f4fcf18SXiaojuan Yang     uint64_t mask = 1ULL << irq;
42*0f4fcf18SXiaojuan Yang 
43*0f4fcf18SXiaojuan Yang     assert(irq < PCH_PIC_IRQ_NUM);
44*0f4fcf18SXiaojuan Yang     trace_loongarch_pch_pic_irq_handler(irq, level);
45*0f4fcf18SXiaojuan Yang 
46*0f4fcf18SXiaojuan Yang     if (s->intedge & mask) {
47*0f4fcf18SXiaojuan Yang         /* Edge triggered */
48*0f4fcf18SXiaojuan Yang         if (level) {
49*0f4fcf18SXiaojuan Yang             if ((s->last_intirr & mask) == 0) {
50*0f4fcf18SXiaojuan Yang                 s->intirr |= mask;
51*0f4fcf18SXiaojuan Yang             }
52*0f4fcf18SXiaojuan Yang             s->last_intirr |= mask;
53*0f4fcf18SXiaojuan Yang         } else {
54*0f4fcf18SXiaojuan Yang             s->last_intirr &= ~mask;
55*0f4fcf18SXiaojuan Yang         }
56*0f4fcf18SXiaojuan Yang     } else {
57*0f4fcf18SXiaojuan Yang         /* Level triggered */
58*0f4fcf18SXiaojuan Yang         if (level) {
59*0f4fcf18SXiaojuan Yang             s->intirr |= mask;
60*0f4fcf18SXiaojuan Yang             s->last_intirr |= mask;
61*0f4fcf18SXiaojuan Yang         } else {
62*0f4fcf18SXiaojuan Yang             s->intirr &= ~mask;
63*0f4fcf18SXiaojuan Yang             s->last_intirr &= ~mask;
64*0f4fcf18SXiaojuan Yang         }
65*0f4fcf18SXiaojuan Yang     }
66*0f4fcf18SXiaojuan Yang     pch_pic_update_irq(s, mask, level);
67*0f4fcf18SXiaojuan Yang }
68*0f4fcf18SXiaojuan Yang 
69*0f4fcf18SXiaojuan Yang static uint64_t loongarch_pch_pic_low_readw(void *opaque, hwaddr addr,
70*0f4fcf18SXiaojuan Yang                                             unsigned size)
71*0f4fcf18SXiaojuan Yang {
72*0f4fcf18SXiaojuan Yang     LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
73*0f4fcf18SXiaojuan Yang     uint64_t val = 0;
74*0f4fcf18SXiaojuan Yang     uint32_t offset = addr & 0xfff;
75*0f4fcf18SXiaojuan Yang 
76*0f4fcf18SXiaojuan Yang     switch (offset) {
77*0f4fcf18SXiaojuan Yang     case PCH_PIC_INT_ID_LO:
78*0f4fcf18SXiaojuan Yang         val = PCH_PIC_INT_ID_VAL;
79*0f4fcf18SXiaojuan Yang         break;
80*0f4fcf18SXiaojuan Yang     case PCH_PIC_INT_ID_HI:
81*0f4fcf18SXiaojuan Yang         val = PCH_PIC_INT_ID_NUM;
82*0f4fcf18SXiaojuan Yang         break;
83*0f4fcf18SXiaojuan Yang     case PCH_PIC_INT_MASK_LO:
84*0f4fcf18SXiaojuan Yang         val = (uint32_t)s->int_mask;
85*0f4fcf18SXiaojuan Yang         break;
86*0f4fcf18SXiaojuan Yang     case PCH_PIC_INT_MASK_HI:
87*0f4fcf18SXiaojuan Yang         val = s->int_mask >> 32;
88*0f4fcf18SXiaojuan Yang         break;
89*0f4fcf18SXiaojuan Yang     case PCH_PIC_INT_EDGE_LO:
90*0f4fcf18SXiaojuan Yang         val = (uint32_t)s->intedge;
91*0f4fcf18SXiaojuan Yang         break;
92*0f4fcf18SXiaojuan Yang     case PCH_PIC_INT_EDGE_HI:
93*0f4fcf18SXiaojuan Yang         val = s->intedge >> 32;
94*0f4fcf18SXiaojuan Yang         break;
95*0f4fcf18SXiaojuan Yang     case PCH_PIC_HTMSI_EN_LO:
96*0f4fcf18SXiaojuan Yang         val = (uint32_t)s->htmsi_en;
97*0f4fcf18SXiaojuan Yang         break;
98*0f4fcf18SXiaojuan Yang     case PCH_PIC_HTMSI_EN_HI:
99*0f4fcf18SXiaojuan Yang         val = s->htmsi_en >> 32;
100*0f4fcf18SXiaojuan Yang         break;
101*0f4fcf18SXiaojuan Yang     case PCH_PIC_AUTO_CTRL0_LO:
102*0f4fcf18SXiaojuan Yang     case PCH_PIC_AUTO_CTRL0_HI:
103*0f4fcf18SXiaojuan Yang     case PCH_PIC_AUTO_CTRL1_LO:
104*0f4fcf18SXiaojuan Yang     case PCH_PIC_AUTO_CTRL1_HI:
105*0f4fcf18SXiaojuan Yang         break;
106*0f4fcf18SXiaojuan Yang     default:
107*0f4fcf18SXiaojuan Yang         break;
108*0f4fcf18SXiaojuan Yang     }
109*0f4fcf18SXiaojuan Yang 
110*0f4fcf18SXiaojuan Yang     trace_loongarch_pch_pic_low_readw(size, addr, val);
111*0f4fcf18SXiaojuan Yang     return val;
112*0f4fcf18SXiaojuan Yang }
113*0f4fcf18SXiaojuan Yang 
114*0f4fcf18SXiaojuan Yang static uint64_t get_writew_val(uint64_t value, uint32_t target, bool hi)
115*0f4fcf18SXiaojuan Yang {
116*0f4fcf18SXiaojuan Yang     uint64_t mask = 0xffffffff00000000;
117*0f4fcf18SXiaojuan Yang     uint64_t data = target;
118*0f4fcf18SXiaojuan Yang 
119*0f4fcf18SXiaojuan Yang     return hi ? (value & ~mask) | (data << 32) : (value & mask) | data;
120*0f4fcf18SXiaojuan Yang }
121*0f4fcf18SXiaojuan Yang 
122*0f4fcf18SXiaojuan Yang static void loongarch_pch_pic_low_writew(void *opaque, hwaddr addr,
123*0f4fcf18SXiaojuan Yang                                          uint64_t value, unsigned size)
124*0f4fcf18SXiaojuan Yang {
125*0f4fcf18SXiaojuan Yang     LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
126*0f4fcf18SXiaojuan Yang     uint32_t offset, old_valid, data = (uint32_t)value;
127*0f4fcf18SXiaojuan Yang     uint64_t old, int_mask;
128*0f4fcf18SXiaojuan Yang     offset = addr & 0xfff;
129*0f4fcf18SXiaojuan Yang 
130*0f4fcf18SXiaojuan Yang     trace_loongarch_pch_pic_low_writew(size, addr, data);
131*0f4fcf18SXiaojuan Yang 
132*0f4fcf18SXiaojuan Yang     switch (offset) {
133*0f4fcf18SXiaojuan Yang     case PCH_PIC_INT_MASK_LO:
134*0f4fcf18SXiaojuan Yang         old = s->int_mask;
135*0f4fcf18SXiaojuan Yang         s->int_mask = get_writew_val(old, data, 0);
136*0f4fcf18SXiaojuan Yang         old_valid = (uint32_t)old;
137*0f4fcf18SXiaojuan Yang         if (old_valid & ~data) {
138*0f4fcf18SXiaojuan Yang             pch_pic_update_irq(s, (old_valid & ~data), 1);
139*0f4fcf18SXiaojuan Yang         }
140*0f4fcf18SXiaojuan Yang         if (~old_valid & data) {
141*0f4fcf18SXiaojuan Yang             pch_pic_update_irq(s, (~old_valid & data), 0);
142*0f4fcf18SXiaojuan Yang         }
143*0f4fcf18SXiaojuan Yang         break;
144*0f4fcf18SXiaojuan Yang     case PCH_PIC_INT_MASK_HI:
145*0f4fcf18SXiaojuan Yang         old = s->int_mask;
146*0f4fcf18SXiaojuan Yang         s->int_mask = get_writew_val(old, data, 1);
147*0f4fcf18SXiaojuan Yang         old_valid = (uint32_t)(old >> 32);
148*0f4fcf18SXiaojuan Yang         int_mask = old_valid & ~data;
149*0f4fcf18SXiaojuan Yang         if (int_mask) {
150*0f4fcf18SXiaojuan Yang             pch_pic_update_irq(s, int_mask << 32, 1);
151*0f4fcf18SXiaojuan Yang         }
152*0f4fcf18SXiaojuan Yang         int_mask = ~old_valid & data;
153*0f4fcf18SXiaojuan Yang         if (int_mask) {
154*0f4fcf18SXiaojuan Yang             pch_pic_update_irq(s, int_mask << 32, 0);
155*0f4fcf18SXiaojuan Yang         }
156*0f4fcf18SXiaojuan Yang         break;
157*0f4fcf18SXiaojuan Yang     case PCH_PIC_INT_EDGE_LO:
158*0f4fcf18SXiaojuan Yang         s->intedge = get_writew_val(s->intedge, data, 0);
159*0f4fcf18SXiaojuan Yang         break;
160*0f4fcf18SXiaojuan Yang     case PCH_PIC_INT_EDGE_HI:
161*0f4fcf18SXiaojuan Yang         s->intedge = get_writew_val(s->intedge, data, 1);
162*0f4fcf18SXiaojuan Yang         break;
163*0f4fcf18SXiaojuan Yang     case PCH_PIC_INT_CLEAR_LO:
164*0f4fcf18SXiaojuan Yang         if (s->intedge & data) {
165*0f4fcf18SXiaojuan Yang             s->intirr &= (~data);
166*0f4fcf18SXiaojuan Yang             pch_pic_update_irq(s, data, 0);
167*0f4fcf18SXiaojuan Yang             s->intisr &= (~data);
168*0f4fcf18SXiaojuan Yang         }
169*0f4fcf18SXiaojuan Yang         break;
170*0f4fcf18SXiaojuan Yang     case PCH_PIC_INT_CLEAR_HI:
171*0f4fcf18SXiaojuan Yang         value <<= 32;
172*0f4fcf18SXiaojuan Yang         if (s->intedge & value) {
173*0f4fcf18SXiaojuan Yang             s->intirr &= (~value);
174*0f4fcf18SXiaojuan Yang             pch_pic_update_irq(s, value, 0);
175*0f4fcf18SXiaojuan Yang             s->intisr &= (~value);
176*0f4fcf18SXiaojuan Yang         }
177*0f4fcf18SXiaojuan Yang         break;
178*0f4fcf18SXiaojuan Yang     case PCH_PIC_HTMSI_EN_LO:
179*0f4fcf18SXiaojuan Yang         s->htmsi_en = get_writew_val(s->htmsi_en, data, 0);
180*0f4fcf18SXiaojuan Yang         break;
181*0f4fcf18SXiaojuan Yang     case PCH_PIC_HTMSI_EN_HI:
182*0f4fcf18SXiaojuan Yang         s->htmsi_en = get_writew_val(s->htmsi_en, data, 1);
183*0f4fcf18SXiaojuan Yang         break;
184*0f4fcf18SXiaojuan Yang     case PCH_PIC_AUTO_CTRL0_LO:
185*0f4fcf18SXiaojuan Yang     case PCH_PIC_AUTO_CTRL0_HI:
186*0f4fcf18SXiaojuan Yang     case PCH_PIC_AUTO_CTRL1_LO:
187*0f4fcf18SXiaojuan Yang     case PCH_PIC_AUTO_CTRL1_HI:
188*0f4fcf18SXiaojuan Yang         break;
189*0f4fcf18SXiaojuan Yang     default:
190*0f4fcf18SXiaojuan Yang         break;
191*0f4fcf18SXiaojuan Yang     }
192*0f4fcf18SXiaojuan Yang }
193*0f4fcf18SXiaojuan Yang 
194*0f4fcf18SXiaojuan Yang static uint64_t loongarch_pch_pic_high_readw(void *opaque, hwaddr addr,
195*0f4fcf18SXiaojuan Yang                                         unsigned size)
196*0f4fcf18SXiaojuan Yang {
197*0f4fcf18SXiaojuan Yang     LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
198*0f4fcf18SXiaojuan Yang     uint64_t val = 0;
199*0f4fcf18SXiaojuan Yang     uint32_t offset = addr & 0xfff;
200*0f4fcf18SXiaojuan Yang 
201*0f4fcf18SXiaojuan Yang     switch (offset) {
202*0f4fcf18SXiaojuan Yang     case STATUS_LO_START:
203*0f4fcf18SXiaojuan Yang         val = (uint32_t)(s->intisr & (~s->int_mask));
204*0f4fcf18SXiaojuan Yang         break;
205*0f4fcf18SXiaojuan Yang     case STATUS_HI_START:
206*0f4fcf18SXiaojuan Yang         val = (s->intisr & (~s->int_mask)) >> 32;
207*0f4fcf18SXiaojuan Yang         break;
208*0f4fcf18SXiaojuan Yang     case POL_LO_START:
209*0f4fcf18SXiaojuan Yang         val = (uint32_t)s->int_polarity;
210*0f4fcf18SXiaojuan Yang         break;
211*0f4fcf18SXiaojuan Yang     case POL_HI_START:
212*0f4fcf18SXiaojuan Yang         val = s->int_polarity >> 32;
213*0f4fcf18SXiaojuan Yang         break;
214*0f4fcf18SXiaojuan Yang     default:
215*0f4fcf18SXiaojuan Yang         break;
216*0f4fcf18SXiaojuan Yang     }
217*0f4fcf18SXiaojuan Yang 
218*0f4fcf18SXiaojuan Yang     trace_loongarch_pch_pic_high_readw(size, addr, val);
219*0f4fcf18SXiaojuan Yang     return val;
220*0f4fcf18SXiaojuan Yang }
221*0f4fcf18SXiaojuan Yang 
222*0f4fcf18SXiaojuan Yang static void loongarch_pch_pic_high_writew(void *opaque, hwaddr addr,
223*0f4fcf18SXiaojuan Yang                                      uint64_t value, unsigned size)
224*0f4fcf18SXiaojuan Yang {
225*0f4fcf18SXiaojuan Yang     LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
226*0f4fcf18SXiaojuan Yang     uint32_t offset, data = (uint32_t)value;
227*0f4fcf18SXiaojuan Yang     offset = addr & 0xfff;
228*0f4fcf18SXiaojuan Yang 
229*0f4fcf18SXiaojuan Yang     trace_loongarch_pch_pic_high_writew(size, addr, data);
230*0f4fcf18SXiaojuan Yang 
231*0f4fcf18SXiaojuan Yang     switch (offset) {
232*0f4fcf18SXiaojuan Yang     case STATUS_LO_START:
233*0f4fcf18SXiaojuan Yang         s->intisr = get_writew_val(s->intisr, data, 0);
234*0f4fcf18SXiaojuan Yang         break;
235*0f4fcf18SXiaojuan Yang     case STATUS_HI_START:
236*0f4fcf18SXiaojuan Yang         s->intisr = get_writew_val(s->intisr, data, 1);
237*0f4fcf18SXiaojuan Yang         break;
238*0f4fcf18SXiaojuan Yang     case POL_LO_START:
239*0f4fcf18SXiaojuan Yang         s->int_polarity = get_writew_val(s->int_polarity, data, 0);
240*0f4fcf18SXiaojuan Yang         break;
241*0f4fcf18SXiaojuan Yang     case POL_HI_START:
242*0f4fcf18SXiaojuan Yang         s->int_polarity = get_writew_val(s->int_polarity, data, 1);
243*0f4fcf18SXiaojuan Yang         break;
244*0f4fcf18SXiaojuan Yang     default:
245*0f4fcf18SXiaojuan Yang         break;
246*0f4fcf18SXiaojuan Yang     }
247*0f4fcf18SXiaojuan Yang }
248*0f4fcf18SXiaojuan Yang 
249*0f4fcf18SXiaojuan Yang static uint64_t loongarch_pch_pic_readb(void *opaque, hwaddr addr,
250*0f4fcf18SXiaojuan Yang                                         unsigned size)
251*0f4fcf18SXiaojuan Yang {
252*0f4fcf18SXiaojuan Yang     LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
253*0f4fcf18SXiaojuan Yang     uint64_t val = 0;
254*0f4fcf18SXiaojuan Yang     uint32_t offset = (addr & 0xfff) + PCH_PIC_ROUTE_ENTRY_OFFSET;
255*0f4fcf18SXiaojuan Yang     int64_t offset_tmp;
256*0f4fcf18SXiaojuan Yang 
257*0f4fcf18SXiaojuan Yang     switch (offset) {
258*0f4fcf18SXiaojuan Yang     case PCH_PIC_HTMSI_VEC_OFFSET ... PCH_PIC_HTMSI_VEC_END:
259*0f4fcf18SXiaojuan Yang         offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET;
260*0f4fcf18SXiaojuan Yang         if (offset_tmp >= 0 && offset_tmp < 64) {
261*0f4fcf18SXiaojuan Yang             val = s->htmsi_vector[offset_tmp];
262*0f4fcf18SXiaojuan Yang         }
263*0f4fcf18SXiaojuan Yang         break;
264*0f4fcf18SXiaojuan Yang     case PCH_PIC_ROUTE_ENTRY_OFFSET ... PCH_PIC_ROUTE_ENTRY_END:
265*0f4fcf18SXiaojuan Yang         offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET;
266*0f4fcf18SXiaojuan Yang         if (offset_tmp >= 0 && offset_tmp < 64) {
267*0f4fcf18SXiaojuan Yang             val = s->route_entry[offset_tmp];
268*0f4fcf18SXiaojuan Yang         }
269*0f4fcf18SXiaojuan Yang         break;
270*0f4fcf18SXiaojuan Yang     default:
271*0f4fcf18SXiaojuan Yang         break;
272*0f4fcf18SXiaojuan Yang     }
273*0f4fcf18SXiaojuan Yang 
274*0f4fcf18SXiaojuan Yang     trace_loongarch_pch_pic_readb(size, addr, val);
275*0f4fcf18SXiaojuan Yang     return val;
276*0f4fcf18SXiaojuan Yang }
277*0f4fcf18SXiaojuan Yang 
278*0f4fcf18SXiaojuan Yang static void loongarch_pch_pic_writeb(void *opaque, hwaddr addr,
279*0f4fcf18SXiaojuan Yang                                      uint64_t data, unsigned size)
280*0f4fcf18SXiaojuan Yang {
281*0f4fcf18SXiaojuan Yang     LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(opaque);
282*0f4fcf18SXiaojuan Yang     int32_t offset_tmp;
283*0f4fcf18SXiaojuan Yang     uint32_t offset = (addr & 0xfff) + PCH_PIC_ROUTE_ENTRY_OFFSET;
284*0f4fcf18SXiaojuan Yang 
285*0f4fcf18SXiaojuan Yang     trace_loongarch_pch_pic_writeb(size, addr, data);
286*0f4fcf18SXiaojuan Yang 
287*0f4fcf18SXiaojuan Yang     switch (offset) {
288*0f4fcf18SXiaojuan Yang     case PCH_PIC_HTMSI_VEC_OFFSET ... PCH_PIC_HTMSI_VEC_END:
289*0f4fcf18SXiaojuan Yang         offset_tmp = offset - PCH_PIC_HTMSI_VEC_OFFSET;
290*0f4fcf18SXiaojuan Yang         if (offset_tmp >= 0 && offset_tmp < 64) {
291*0f4fcf18SXiaojuan Yang             s->htmsi_vector[offset_tmp] = (uint8_t)(data & 0xff);
292*0f4fcf18SXiaojuan Yang         }
293*0f4fcf18SXiaojuan Yang         break;
294*0f4fcf18SXiaojuan Yang     case PCH_PIC_ROUTE_ENTRY_OFFSET ... PCH_PIC_ROUTE_ENTRY_END:
295*0f4fcf18SXiaojuan Yang         offset_tmp = offset - PCH_PIC_ROUTE_ENTRY_OFFSET;
296*0f4fcf18SXiaojuan Yang         if (offset_tmp >= 0 && offset_tmp < 64) {
297*0f4fcf18SXiaojuan Yang             s->route_entry[offset_tmp] = (uint8_t)(data & 0xff);
298*0f4fcf18SXiaojuan Yang         }
299*0f4fcf18SXiaojuan Yang         break;
300*0f4fcf18SXiaojuan Yang     default:
301*0f4fcf18SXiaojuan Yang         break;
302*0f4fcf18SXiaojuan Yang     }
303*0f4fcf18SXiaojuan Yang }
304*0f4fcf18SXiaojuan Yang 
305*0f4fcf18SXiaojuan Yang static const MemoryRegionOps loongarch_pch_pic_reg32_low_ops = {
306*0f4fcf18SXiaojuan Yang     .read = loongarch_pch_pic_low_readw,
307*0f4fcf18SXiaojuan Yang     .write = loongarch_pch_pic_low_writew,
308*0f4fcf18SXiaojuan Yang     .valid = {
309*0f4fcf18SXiaojuan Yang         .min_access_size = 4,
310*0f4fcf18SXiaojuan Yang         .max_access_size = 8,
311*0f4fcf18SXiaojuan Yang     },
312*0f4fcf18SXiaojuan Yang     .impl = {
313*0f4fcf18SXiaojuan Yang         .min_access_size = 4,
314*0f4fcf18SXiaojuan Yang         .max_access_size = 4,
315*0f4fcf18SXiaojuan Yang     },
316*0f4fcf18SXiaojuan Yang     .endianness = DEVICE_LITTLE_ENDIAN,
317*0f4fcf18SXiaojuan Yang };
318*0f4fcf18SXiaojuan Yang 
319*0f4fcf18SXiaojuan Yang static const MemoryRegionOps loongarch_pch_pic_reg32_high_ops = {
320*0f4fcf18SXiaojuan Yang     .read = loongarch_pch_pic_high_readw,
321*0f4fcf18SXiaojuan Yang     .write = loongarch_pch_pic_high_writew,
322*0f4fcf18SXiaojuan Yang     .valid = {
323*0f4fcf18SXiaojuan Yang         .min_access_size = 4,
324*0f4fcf18SXiaojuan Yang         .max_access_size = 8,
325*0f4fcf18SXiaojuan Yang     },
326*0f4fcf18SXiaojuan Yang     .impl = {
327*0f4fcf18SXiaojuan Yang         .min_access_size = 4,
328*0f4fcf18SXiaojuan Yang         .max_access_size = 4,
329*0f4fcf18SXiaojuan Yang     },
330*0f4fcf18SXiaojuan Yang     .endianness = DEVICE_LITTLE_ENDIAN,
331*0f4fcf18SXiaojuan Yang };
332*0f4fcf18SXiaojuan Yang 
333*0f4fcf18SXiaojuan Yang static const MemoryRegionOps loongarch_pch_pic_reg8_ops = {
334*0f4fcf18SXiaojuan Yang     .read = loongarch_pch_pic_readb,
335*0f4fcf18SXiaojuan Yang     .write = loongarch_pch_pic_writeb,
336*0f4fcf18SXiaojuan Yang     .valid = {
337*0f4fcf18SXiaojuan Yang         .min_access_size = 1,
338*0f4fcf18SXiaojuan Yang         .max_access_size = 1,
339*0f4fcf18SXiaojuan Yang     },
340*0f4fcf18SXiaojuan Yang     .impl = {
341*0f4fcf18SXiaojuan Yang         .min_access_size = 1,
342*0f4fcf18SXiaojuan Yang         .max_access_size = 1,
343*0f4fcf18SXiaojuan Yang     },
344*0f4fcf18SXiaojuan Yang     .endianness = DEVICE_LITTLE_ENDIAN,
345*0f4fcf18SXiaojuan Yang };
346*0f4fcf18SXiaojuan Yang 
347*0f4fcf18SXiaojuan Yang static void loongarch_pch_pic_reset(DeviceState *d)
348*0f4fcf18SXiaojuan Yang {
349*0f4fcf18SXiaojuan Yang     LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(d);
350*0f4fcf18SXiaojuan Yang     int i;
351*0f4fcf18SXiaojuan Yang 
352*0f4fcf18SXiaojuan Yang     s->int_mask = -1;
353*0f4fcf18SXiaojuan Yang     s->htmsi_en = 0x0;
354*0f4fcf18SXiaojuan Yang     s->intedge  = 0x0;
355*0f4fcf18SXiaojuan Yang     s->intclr   = 0x0;
356*0f4fcf18SXiaojuan Yang     s->auto_crtl0 = 0x0;
357*0f4fcf18SXiaojuan Yang     s->auto_crtl1 = 0x0;
358*0f4fcf18SXiaojuan Yang     for (i = 0; i < 64; i++) {
359*0f4fcf18SXiaojuan Yang         s->route_entry[i] = 0x1;
360*0f4fcf18SXiaojuan Yang         s->htmsi_vector[i] = 0x0;
361*0f4fcf18SXiaojuan Yang     }
362*0f4fcf18SXiaojuan Yang     s->intirr = 0x0;
363*0f4fcf18SXiaojuan Yang     s->intisr = 0x0;
364*0f4fcf18SXiaojuan Yang     s->last_intirr = 0x0;
365*0f4fcf18SXiaojuan Yang     s->int_polarity = 0x0;
366*0f4fcf18SXiaojuan Yang }
367*0f4fcf18SXiaojuan Yang 
368*0f4fcf18SXiaojuan Yang static void loongarch_pch_pic_init(Object *obj)
369*0f4fcf18SXiaojuan Yang {
370*0f4fcf18SXiaojuan Yang     LoongArchPCHPIC *s = LOONGARCH_PCH_PIC(obj);
371*0f4fcf18SXiaojuan Yang     SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
372*0f4fcf18SXiaojuan Yang 
373*0f4fcf18SXiaojuan Yang     memory_region_init_io(&s->iomem32_low, obj,
374*0f4fcf18SXiaojuan Yang                           &loongarch_pch_pic_reg32_low_ops,
375*0f4fcf18SXiaojuan Yang                           s, PCH_PIC_NAME(.reg32_part1), 0x100);
376*0f4fcf18SXiaojuan Yang     memory_region_init_io(&s->iomem8, obj, &loongarch_pch_pic_reg8_ops,
377*0f4fcf18SXiaojuan Yang                           s, PCH_PIC_NAME(.reg8), 0x2a0);
378*0f4fcf18SXiaojuan Yang     memory_region_init_io(&s->iomem32_high, obj,
379*0f4fcf18SXiaojuan Yang                           &loongarch_pch_pic_reg32_high_ops,
380*0f4fcf18SXiaojuan Yang                           s, PCH_PIC_NAME(.reg32_part2), 0xc60);
381*0f4fcf18SXiaojuan Yang     sysbus_init_mmio(sbd, &s->iomem32_low);
382*0f4fcf18SXiaojuan Yang     sysbus_init_mmio(sbd, &s->iomem8);
383*0f4fcf18SXiaojuan Yang     sysbus_init_mmio(sbd, &s->iomem32_high);
384*0f4fcf18SXiaojuan Yang 
385*0f4fcf18SXiaojuan Yang     qdev_init_gpio_out(DEVICE(obj), s->parent_irq, PCH_PIC_IRQ_NUM);
386*0f4fcf18SXiaojuan Yang     qdev_init_gpio_in(DEVICE(obj), pch_pic_irq_handler, PCH_PIC_IRQ_NUM);
387*0f4fcf18SXiaojuan Yang }
388*0f4fcf18SXiaojuan Yang 
389*0f4fcf18SXiaojuan Yang static const VMStateDescription vmstate_loongarch_pch_pic = {
390*0f4fcf18SXiaojuan Yang     .name = TYPE_LOONGARCH_PCH_PIC,
391*0f4fcf18SXiaojuan Yang     .version_id = 1,
392*0f4fcf18SXiaojuan Yang     .minimum_version_id = 1,
393*0f4fcf18SXiaojuan Yang     .fields = (VMStateField[]) {
394*0f4fcf18SXiaojuan Yang         VMSTATE_UINT64(int_mask, LoongArchPCHPIC),
395*0f4fcf18SXiaojuan Yang         VMSTATE_UINT64(htmsi_en, LoongArchPCHPIC),
396*0f4fcf18SXiaojuan Yang         VMSTATE_UINT64(intedge, LoongArchPCHPIC),
397*0f4fcf18SXiaojuan Yang         VMSTATE_UINT64(intclr, LoongArchPCHPIC),
398*0f4fcf18SXiaojuan Yang         VMSTATE_UINT64(auto_crtl0, LoongArchPCHPIC),
399*0f4fcf18SXiaojuan Yang         VMSTATE_UINT64(auto_crtl1, LoongArchPCHPIC),
400*0f4fcf18SXiaojuan Yang         VMSTATE_UINT8_ARRAY(route_entry, LoongArchPCHPIC, 64),
401*0f4fcf18SXiaojuan Yang         VMSTATE_UINT8_ARRAY(htmsi_vector, LoongArchPCHPIC, 64),
402*0f4fcf18SXiaojuan Yang         VMSTATE_UINT64(last_intirr, LoongArchPCHPIC),
403*0f4fcf18SXiaojuan Yang         VMSTATE_UINT64(intirr, LoongArchPCHPIC),
404*0f4fcf18SXiaojuan Yang         VMSTATE_UINT64(intisr, LoongArchPCHPIC),
405*0f4fcf18SXiaojuan Yang         VMSTATE_UINT64(int_polarity, LoongArchPCHPIC),
406*0f4fcf18SXiaojuan Yang         VMSTATE_END_OF_LIST()
407*0f4fcf18SXiaojuan Yang     }
408*0f4fcf18SXiaojuan Yang };
409*0f4fcf18SXiaojuan Yang 
410*0f4fcf18SXiaojuan Yang static void loongarch_pch_pic_class_init(ObjectClass *klass, void *data)
411*0f4fcf18SXiaojuan Yang {
412*0f4fcf18SXiaojuan Yang     DeviceClass *dc = DEVICE_CLASS(klass);
413*0f4fcf18SXiaojuan Yang 
414*0f4fcf18SXiaojuan Yang     dc->reset = loongarch_pch_pic_reset;
415*0f4fcf18SXiaojuan Yang     dc->vmsd = &vmstate_loongarch_pch_pic;
416*0f4fcf18SXiaojuan Yang }
417*0f4fcf18SXiaojuan Yang 
418*0f4fcf18SXiaojuan Yang static const TypeInfo loongarch_pch_pic_info = {
419*0f4fcf18SXiaojuan Yang     .name          = TYPE_LOONGARCH_PCH_PIC,
420*0f4fcf18SXiaojuan Yang     .parent        = TYPE_SYS_BUS_DEVICE,
421*0f4fcf18SXiaojuan Yang     .instance_size = sizeof(LoongArchPCHPIC),
422*0f4fcf18SXiaojuan Yang     .instance_init = loongarch_pch_pic_init,
423*0f4fcf18SXiaojuan Yang     .class_init    = loongarch_pch_pic_class_init,
424*0f4fcf18SXiaojuan Yang };
425*0f4fcf18SXiaojuan Yang 
426*0f4fcf18SXiaojuan Yang static void loongarch_pch_pic_register_types(void)
427*0f4fcf18SXiaojuan Yang {
428*0f4fcf18SXiaojuan Yang     type_register_static(&loongarch_pch_pic_info);
429*0f4fcf18SXiaojuan Yang }
430*0f4fcf18SXiaojuan Yang 
431*0f4fcf18SXiaojuan Yang type_init(loongarch_pch_pic_register_types)
432