xref: /qemu/hw/intc/rx_icu.c (revision e78597cc457ff76119bfc8f78aa21b2e5092da92)
1*e78597ccSYoshinori Sato /*
2*e78597ccSYoshinori Sato  * RX Interrupt Control Unit
3*e78597ccSYoshinori Sato  *
4*e78597ccSYoshinori Sato  * Warning: Only ICUa is supported.
5*e78597ccSYoshinori Sato  *
6*e78597ccSYoshinori Sato  * Datasheet: RX62N Group, RX621 Group User's Manual: Hardware
7*e78597ccSYoshinori Sato  *            (Rev.1.40 R01UH0033EJ0140)
8*e78597ccSYoshinori Sato  *
9*e78597ccSYoshinori Sato  * Copyright (c) 2019 Yoshinori Sato
10*e78597ccSYoshinori Sato  *
11*e78597ccSYoshinori Sato  * SPDX-License-Identifier: GPL-2.0-or-later
12*e78597ccSYoshinori Sato  *
13*e78597ccSYoshinori Sato  * This program is free software; you can redistribute it and/or modify it
14*e78597ccSYoshinori Sato  * under the terms and conditions of the GNU General Public License,
15*e78597ccSYoshinori Sato  * version 2 or later, as published by the Free Software Foundation.
16*e78597ccSYoshinori Sato  *
17*e78597ccSYoshinori Sato  * This program is distributed in the hope it will be useful, but WITHOUT
18*e78597ccSYoshinori Sato  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19*e78597ccSYoshinori Sato  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
20*e78597ccSYoshinori Sato  * more details.
21*e78597ccSYoshinori Sato  *
22*e78597ccSYoshinori Sato  * You should have received a copy of the GNU General Public License along with
23*e78597ccSYoshinori Sato  * this program.  If not, see <http://www.gnu.org/licenses/>.
24*e78597ccSYoshinori Sato  */
25*e78597ccSYoshinori Sato 
26*e78597ccSYoshinori Sato #include "qemu/osdep.h"
27*e78597ccSYoshinori Sato #include "qemu/log.h"
28*e78597ccSYoshinori Sato #include "qemu/error-report.h"
29*e78597ccSYoshinori Sato #include "hw/irq.h"
30*e78597ccSYoshinori Sato #include "hw/registerfields.h"
31*e78597ccSYoshinori Sato #include "hw/qdev-properties.h"
32*e78597ccSYoshinori Sato #include "hw/intc/rx_icu.h"
33*e78597ccSYoshinori Sato #include "migration/vmstate.h"
34*e78597ccSYoshinori Sato 
35*e78597ccSYoshinori Sato REG8(IR, 0)
36*e78597ccSYoshinori Sato   FIELD(IR, IR,  0, 1)
37*e78597ccSYoshinori Sato REG8(DTCER, 0x100)
38*e78597ccSYoshinori Sato   FIELD(DTCER, DTCE,  0, 1)
39*e78597ccSYoshinori Sato REG8(IER, 0x200)
40*e78597ccSYoshinori Sato REG8(SWINTR, 0x2e0)
41*e78597ccSYoshinori Sato   FIELD(SWINTR, SWINT, 0, 1)
42*e78597ccSYoshinori Sato REG16(FIR, 0x2f0)
43*e78597ccSYoshinori Sato   FIELD(FIR, FVCT, 0,  8)
44*e78597ccSYoshinori Sato   FIELD(FIR, FIEN, 15, 1)
45*e78597ccSYoshinori Sato REG8(IPR, 0x300)
46*e78597ccSYoshinori Sato   FIELD(IPR, IPR, 0, 4)
47*e78597ccSYoshinori Sato REG8(DMRSR, 0x400)
48*e78597ccSYoshinori Sato REG8(IRQCR, 0x500)
49*e78597ccSYoshinori Sato   FIELD(IRQCR, IRQMD, 2, 2)
50*e78597ccSYoshinori Sato REG8(NMISR, 0x580)
51*e78597ccSYoshinori Sato   FIELD(NMISR, NMIST, 0, 1)
52*e78597ccSYoshinori Sato   FIELD(NMISR, LVDST, 1, 1)
53*e78597ccSYoshinori Sato   FIELD(NMISR, OSTST, 2, 1)
54*e78597ccSYoshinori Sato REG8(NMIER, 0x581)
55*e78597ccSYoshinori Sato   FIELD(NMIER, NMIEN, 0, 1)
56*e78597ccSYoshinori Sato   FIELD(NMIER, LVDEN, 1, 1)
57*e78597ccSYoshinori Sato   FIELD(NMIER, OSTEN, 2, 1)
58*e78597ccSYoshinori Sato REG8(NMICLR, 0x582)
59*e78597ccSYoshinori Sato   FIELD(NMICLR, NMICLR, 0, 1)
60*e78597ccSYoshinori Sato   FIELD(NMICLR, OSTCLR, 2, 1)
61*e78597ccSYoshinori Sato REG8(NMICR, 0x583)
62*e78597ccSYoshinori Sato   FIELD(NMICR, NMIMD, 3, 1)
63*e78597ccSYoshinori Sato 
64*e78597ccSYoshinori Sato static void set_irq(RXICUState *icu, int n_IRQ, int req)
65*e78597ccSYoshinori Sato {
66*e78597ccSYoshinori Sato     if ((icu->fir & R_FIR_FIEN_MASK) &&
67*e78597ccSYoshinori Sato         (icu->fir & R_FIR_FVCT_MASK) == n_IRQ) {
68*e78597ccSYoshinori Sato         qemu_set_irq(icu->_fir, req);
69*e78597ccSYoshinori Sato     } else {
70*e78597ccSYoshinori Sato         qemu_set_irq(icu->_irq, req);
71*e78597ccSYoshinori Sato     }
72*e78597ccSYoshinori Sato }
73*e78597ccSYoshinori Sato 
74*e78597ccSYoshinori Sato static uint16_t rxicu_level(RXICUState *icu, unsigned n)
75*e78597ccSYoshinori Sato {
76*e78597ccSYoshinori Sato     return (icu->ipr[icu->map[n]] << 8) | n;
77*e78597ccSYoshinori Sato }
78*e78597ccSYoshinori Sato 
79*e78597ccSYoshinori Sato static void rxicu_request(RXICUState *icu, int n_IRQ)
80*e78597ccSYoshinori Sato {
81*e78597ccSYoshinori Sato     int enable;
82*e78597ccSYoshinori Sato 
83*e78597ccSYoshinori Sato     enable = icu->ier[n_IRQ / 8] & (1 << (n_IRQ & 7));
84*e78597ccSYoshinori Sato     if (n_IRQ > 0 && enable != 0 && atomic_read(&icu->req_irq) < 0) {
85*e78597ccSYoshinori Sato         atomic_set(&icu->req_irq, n_IRQ);
86*e78597ccSYoshinori Sato         set_irq(icu, n_IRQ, rxicu_level(icu, n_IRQ));
87*e78597ccSYoshinori Sato     }
88*e78597ccSYoshinori Sato }
89*e78597ccSYoshinori Sato 
90*e78597ccSYoshinori Sato static void rxicu_set_irq(void *opaque, int n_IRQ, int level)
91*e78597ccSYoshinori Sato {
92*e78597ccSYoshinori Sato     RXICUState *icu = opaque;
93*e78597ccSYoshinori Sato     struct IRQSource *src;
94*e78597ccSYoshinori Sato     int issue;
95*e78597ccSYoshinori Sato 
96*e78597ccSYoshinori Sato     if (n_IRQ >= NR_IRQS) {
97*e78597ccSYoshinori Sato         error_report("%s: IRQ %d out of range", __func__, n_IRQ);
98*e78597ccSYoshinori Sato         return;
99*e78597ccSYoshinori Sato     }
100*e78597ccSYoshinori Sato 
101*e78597ccSYoshinori Sato     src = &icu->src[n_IRQ];
102*e78597ccSYoshinori Sato 
103*e78597ccSYoshinori Sato     level = (level != 0);
104*e78597ccSYoshinori Sato     switch (src->sense) {
105*e78597ccSYoshinori Sato     case TRG_LEVEL:
106*e78597ccSYoshinori Sato         /* level-sensitive irq */
107*e78597ccSYoshinori Sato         issue = level;
108*e78597ccSYoshinori Sato         src->level = level;
109*e78597ccSYoshinori Sato         break;
110*e78597ccSYoshinori Sato     case TRG_NEDGE:
111*e78597ccSYoshinori Sato         issue = (level == 0 && src->level == 1);
112*e78597ccSYoshinori Sato         src->level = level;
113*e78597ccSYoshinori Sato         break;
114*e78597ccSYoshinori Sato     case TRG_PEDGE:
115*e78597ccSYoshinori Sato         issue = (level == 1 && src->level == 0);
116*e78597ccSYoshinori Sato         src->level = level;
117*e78597ccSYoshinori Sato         break;
118*e78597ccSYoshinori Sato     case TRG_BEDGE:
119*e78597ccSYoshinori Sato         issue = ((level ^ src->level) & 1);
120*e78597ccSYoshinori Sato         src->level = level;
121*e78597ccSYoshinori Sato         break;
122*e78597ccSYoshinori Sato     default:
123*e78597ccSYoshinori Sato         g_assert_not_reached();
124*e78597ccSYoshinori Sato     }
125*e78597ccSYoshinori Sato     if (issue == 0 && src->sense == TRG_LEVEL) {
126*e78597ccSYoshinori Sato         icu->ir[n_IRQ] = 0;
127*e78597ccSYoshinori Sato         if (atomic_read(&icu->req_irq) == n_IRQ) {
128*e78597ccSYoshinori Sato             /* clear request */
129*e78597ccSYoshinori Sato             set_irq(icu, n_IRQ, 0);
130*e78597ccSYoshinori Sato             atomic_set(&icu->req_irq, -1);
131*e78597ccSYoshinori Sato         }
132*e78597ccSYoshinori Sato         return;
133*e78597ccSYoshinori Sato     }
134*e78597ccSYoshinori Sato     if (issue) {
135*e78597ccSYoshinori Sato         icu->ir[n_IRQ] = 1;
136*e78597ccSYoshinori Sato         rxicu_request(icu, n_IRQ);
137*e78597ccSYoshinori Sato     }
138*e78597ccSYoshinori Sato }
139*e78597ccSYoshinori Sato 
140*e78597ccSYoshinori Sato static void rxicu_ack_irq(void *opaque, int no, int level)
141*e78597ccSYoshinori Sato {
142*e78597ccSYoshinori Sato     RXICUState *icu = opaque;
143*e78597ccSYoshinori Sato     int i;
144*e78597ccSYoshinori Sato     int n_IRQ;
145*e78597ccSYoshinori Sato     int max_pri;
146*e78597ccSYoshinori Sato 
147*e78597ccSYoshinori Sato     n_IRQ = atomic_read(&icu->req_irq);
148*e78597ccSYoshinori Sato     if (n_IRQ < 0) {
149*e78597ccSYoshinori Sato         return;
150*e78597ccSYoshinori Sato     }
151*e78597ccSYoshinori Sato     atomic_set(&icu->req_irq, -1);
152*e78597ccSYoshinori Sato     if (icu->src[n_IRQ].sense != TRG_LEVEL) {
153*e78597ccSYoshinori Sato         icu->ir[n_IRQ] = 0;
154*e78597ccSYoshinori Sato     }
155*e78597ccSYoshinori Sato 
156*e78597ccSYoshinori Sato     max_pri = 0;
157*e78597ccSYoshinori Sato     n_IRQ = -1;
158*e78597ccSYoshinori Sato     for (i = 0; i < NR_IRQS; i++) {
159*e78597ccSYoshinori Sato         if (icu->ir[i]) {
160*e78597ccSYoshinori Sato             if (max_pri < icu->ipr[icu->map[i]]) {
161*e78597ccSYoshinori Sato                 n_IRQ = i;
162*e78597ccSYoshinori Sato                 max_pri = icu->ipr[icu->map[i]];
163*e78597ccSYoshinori Sato             }
164*e78597ccSYoshinori Sato         }
165*e78597ccSYoshinori Sato     }
166*e78597ccSYoshinori Sato 
167*e78597ccSYoshinori Sato     if (n_IRQ >= 0) {
168*e78597ccSYoshinori Sato         rxicu_request(icu, n_IRQ);
169*e78597ccSYoshinori Sato     }
170*e78597ccSYoshinori Sato }
171*e78597ccSYoshinori Sato 
172*e78597ccSYoshinori Sato static uint64_t icu_read(void *opaque, hwaddr addr, unsigned size)
173*e78597ccSYoshinori Sato {
174*e78597ccSYoshinori Sato     RXICUState *icu = opaque;
175*e78597ccSYoshinori Sato     int reg = addr & 0xff;
176*e78597ccSYoshinori Sato 
177*e78597ccSYoshinori Sato     if ((addr != A_FIR && size != 1) ||
178*e78597ccSYoshinori Sato         (addr == A_FIR && size != 2)) {
179*e78597ccSYoshinori Sato         qemu_log_mask(LOG_GUEST_ERROR, "rx_icu: Invalid read size 0x%"
180*e78597ccSYoshinori Sato                                        HWADDR_PRIX "\n",
181*e78597ccSYoshinori Sato                       addr);
182*e78597ccSYoshinori Sato         return UINT64_MAX;
183*e78597ccSYoshinori Sato     }
184*e78597ccSYoshinori Sato     switch (addr) {
185*e78597ccSYoshinori Sato     case A_IR ... A_IR + 0xff:
186*e78597ccSYoshinori Sato         return icu->ir[reg] & R_IR_IR_MASK;
187*e78597ccSYoshinori Sato     case A_DTCER ... A_DTCER + 0xff:
188*e78597ccSYoshinori Sato         return icu->dtcer[reg] & R_DTCER_DTCE_MASK;
189*e78597ccSYoshinori Sato     case A_IER ... A_IER + 0x1f:
190*e78597ccSYoshinori Sato         return icu->ier[reg];
191*e78597ccSYoshinori Sato     case A_SWINTR:
192*e78597ccSYoshinori Sato         return 0;
193*e78597ccSYoshinori Sato     case A_FIR:
194*e78597ccSYoshinori Sato         return icu->fir & (R_FIR_FIEN_MASK | R_FIR_FVCT_MASK);
195*e78597ccSYoshinori Sato     case A_IPR ... A_IPR + 0x8f:
196*e78597ccSYoshinori Sato         return icu->ipr[reg] & R_IPR_IPR_MASK;
197*e78597ccSYoshinori Sato     case A_DMRSR:
198*e78597ccSYoshinori Sato     case A_DMRSR + 4:
199*e78597ccSYoshinori Sato     case A_DMRSR + 8:
200*e78597ccSYoshinori Sato     case A_DMRSR + 12:
201*e78597ccSYoshinori Sato         return icu->dmasr[reg >> 2];
202*e78597ccSYoshinori Sato     case A_IRQCR ... A_IRQCR + 0x1f:
203*e78597ccSYoshinori Sato         return icu->src[64 + reg].sense << R_IRQCR_IRQMD_SHIFT;
204*e78597ccSYoshinori Sato     case A_NMISR:
205*e78597ccSYoshinori Sato     case A_NMICLR:
206*e78597ccSYoshinori Sato         return 0;
207*e78597ccSYoshinori Sato     case A_NMIER:
208*e78597ccSYoshinori Sato         return icu->nmier;
209*e78597ccSYoshinori Sato     case A_NMICR:
210*e78597ccSYoshinori Sato         return icu->nmicr;
211*e78597ccSYoshinori Sato     default:
212*e78597ccSYoshinori Sato         qemu_log_mask(LOG_UNIMP, "rx_icu: Register 0x%" HWADDR_PRIX " "
213*e78597ccSYoshinori Sato                                  "not implemented.\n",
214*e78597ccSYoshinori Sato                       addr);
215*e78597ccSYoshinori Sato         break;
216*e78597ccSYoshinori Sato     }
217*e78597ccSYoshinori Sato     return UINT64_MAX;
218*e78597ccSYoshinori Sato }
219*e78597ccSYoshinori Sato 
220*e78597ccSYoshinori Sato static void icu_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)
221*e78597ccSYoshinori Sato {
222*e78597ccSYoshinori Sato     RXICUState *icu = opaque;
223*e78597ccSYoshinori Sato     int reg = addr & 0xff;
224*e78597ccSYoshinori Sato 
225*e78597ccSYoshinori Sato     if ((addr != A_FIR && size != 1) ||
226*e78597ccSYoshinori Sato         (addr == A_FIR && size != 2)) {
227*e78597ccSYoshinori Sato         qemu_log_mask(LOG_GUEST_ERROR, "rx_icu: Invalid write size at "
228*e78597ccSYoshinori Sato                                        "0x%" HWADDR_PRIX "\n",
229*e78597ccSYoshinori Sato                       addr);
230*e78597ccSYoshinori Sato         return;
231*e78597ccSYoshinori Sato     }
232*e78597ccSYoshinori Sato     switch (addr) {
233*e78597ccSYoshinori Sato     case A_IR ... A_IR + 0xff:
234*e78597ccSYoshinori Sato         if (icu->src[reg].sense != TRG_LEVEL && val == 0) {
235*e78597ccSYoshinori Sato             icu->ir[reg] = 0;
236*e78597ccSYoshinori Sato         }
237*e78597ccSYoshinori Sato         break;
238*e78597ccSYoshinori Sato     case A_DTCER ... A_DTCER + 0xff:
239*e78597ccSYoshinori Sato         icu->dtcer[reg] = val & R_DTCER_DTCE_MASK;
240*e78597ccSYoshinori Sato         qemu_log_mask(LOG_UNIMP, "rx_icu: DTC not implemented\n");
241*e78597ccSYoshinori Sato         break;
242*e78597ccSYoshinori Sato     case A_IER ... A_IER + 0x1f:
243*e78597ccSYoshinori Sato         icu->ier[reg] = val;
244*e78597ccSYoshinori Sato         break;
245*e78597ccSYoshinori Sato     case A_SWINTR:
246*e78597ccSYoshinori Sato         if (val & R_SWINTR_SWINT_MASK) {
247*e78597ccSYoshinori Sato             qemu_irq_pulse(icu->_swi);
248*e78597ccSYoshinori Sato         }
249*e78597ccSYoshinori Sato         break;
250*e78597ccSYoshinori Sato     case A_FIR:
251*e78597ccSYoshinori Sato         icu->fir = val & (R_FIR_FIEN_MASK | R_FIR_FVCT_MASK);
252*e78597ccSYoshinori Sato         break;
253*e78597ccSYoshinori Sato     case A_IPR ... A_IPR + 0x8f:
254*e78597ccSYoshinori Sato         icu->ipr[reg] = val & R_IPR_IPR_MASK;
255*e78597ccSYoshinori Sato         break;
256*e78597ccSYoshinori Sato     case A_DMRSR:
257*e78597ccSYoshinori Sato     case A_DMRSR + 4:
258*e78597ccSYoshinori Sato     case A_DMRSR + 8:
259*e78597ccSYoshinori Sato     case A_DMRSR + 12:
260*e78597ccSYoshinori Sato         icu->dmasr[reg >> 2] = val;
261*e78597ccSYoshinori Sato         qemu_log_mask(LOG_UNIMP, "rx_icu: DMAC not implemented\n");
262*e78597ccSYoshinori Sato         break;
263*e78597ccSYoshinori Sato     case A_IRQCR ... A_IRQCR + 0x1f:
264*e78597ccSYoshinori Sato         icu->src[64 + reg].sense = val >> R_IRQCR_IRQMD_SHIFT;
265*e78597ccSYoshinori Sato         break;
266*e78597ccSYoshinori Sato     case A_NMICLR:
267*e78597ccSYoshinori Sato         break;
268*e78597ccSYoshinori Sato     case A_NMIER:
269*e78597ccSYoshinori Sato         icu->nmier |= val & (R_NMIER_NMIEN_MASK |
270*e78597ccSYoshinori Sato                              R_NMIER_LVDEN_MASK |
271*e78597ccSYoshinori Sato                              R_NMIER_OSTEN_MASK);
272*e78597ccSYoshinori Sato         break;
273*e78597ccSYoshinori Sato     case A_NMICR:
274*e78597ccSYoshinori Sato         if ((icu->nmier & R_NMIER_NMIEN_MASK) == 0) {
275*e78597ccSYoshinori Sato             icu->nmicr = val & R_NMICR_NMIMD_MASK;
276*e78597ccSYoshinori Sato         }
277*e78597ccSYoshinori Sato         break;
278*e78597ccSYoshinori Sato     default:
279*e78597ccSYoshinori Sato         qemu_log_mask(LOG_UNIMP, "rx_icu: Register 0x%" HWADDR_PRIX " "
280*e78597ccSYoshinori Sato                                  "not implemented\n",
281*e78597ccSYoshinori Sato                       addr);
282*e78597ccSYoshinori Sato         break;
283*e78597ccSYoshinori Sato     }
284*e78597ccSYoshinori Sato }
285*e78597ccSYoshinori Sato 
286*e78597ccSYoshinori Sato static const MemoryRegionOps icu_ops = {
287*e78597ccSYoshinori Sato     .write = icu_write,
288*e78597ccSYoshinori Sato     .read  = icu_read,
289*e78597ccSYoshinori Sato     .endianness = DEVICE_LITTLE_ENDIAN,
290*e78597ccSYoshinori Sato     .impl = {
291*e78597ccSYoshinori Sato         .min_access_size = 1,
292*e78597ccSYoshinori Sato         .max_access_size = 2,
293*e78597ccSYoshinori Sato     },
294*e78597ccSYoshinori Sato     .valid = {
295*e78597ccSYoshinori Sato         .min_access_size = 1,
296*e78597ccSYoshinori Sato         .max_access_size = 2,
297*e78597ccSYoshinori Sato     },
298*e78597ccSYoshinori Sato };
299*e78597ccSYoshinori Sato 
300*e78597ccSYoshinori Sato static void rxicu_realize(DeviceState *dev, Error **errp)
301*e78597ccSYoshinori Sato {
302*e78597ccSYoshinori Sato     RXICUState *icu = RX_ICU(dev);
303*e78597ccSYoshinori Sato     int i, j;
304*e78597ccSYoshinori Sato 
305*e78597ccSYoshinori Sato     if (icu->init_sense == NULL) {
306*e78597ccSYoshinori Sato         qemu_log_mask(LOG_GUEST_ERROR,
307*e78597ccSYoshinori Sato                       "rx_icu: trigger-level property must be set.");
308*e78597ccSYoshinori Sato         return;
309*e78597ccSYoshinori Sato     }
310*e78597ccSYoshinori Sato     for (i = j = 0; i < NR_IRQS; i++) {
311*e78597ccSYoshinori Sato         if (icu->init_sense[j] == i) {
312*e78597ccSYoshinori Sato             icu->src[i].sense = TRG_LEVEL;
313*e78597ccSYoshinori Sato             if (j < icu->nr_sense) {
314*e78597ccSYoshinori Sato                 j++;
315*e78597ccSYoshinori Sato             }
316*e78597ccSYoshinori Sato         } else {
317*e78597ccSYoshinori Sato             icu->src[i].sense = TRG_PEDGE;
318*e78597ccSYoshinori Sato         }
319*e78597ccSYoshinori Sato     }
320*e78597ccSYoshinori Sato     icu->req_irq = -1;
321*e78597ccSYoshinori Sato }
322*e78597ccSYoshinori Sato 
323*e78597ccSYoshinori Sato static void rxicu_init(Object *obj)
324*e78597ccSYoshinori Sato {
325*e78597ccSYoshinori Sato     SysBusDevice *d = SYS_BUS_DEVICE(obj);
326*e78597ccSYoshinori Sato     RXICUState *icu = RX_ICU(obj);
327*e78597ccSYoshinori Sato 
328*e78597ccSYoshinori Sato     memory_region_init_io(&icu->memory, OBJECT(icu), &icu_ops,
329*e78597ccSYoshinori Sato                           icu, "rx-icu", 0x600);
330*e78597ccSYoshinori Sato     sysbus_init_mmio(d, &icu->memory);
331*e78597ccSYoshinori Sato 
332*e78597ccSYoshinori Sato     qdev_init_gpio_in(DEVICE(d), rxicu_set_irq, NR_IRQS);
333*e78597ccSYoshinori Sato     qdev_init_gpio_in_named(DEVICE(d), rxicu_ack_irq, "ack", 1);
334*e78597ccSYoshinori Sato     sysbus_init_irq(d, &icu->_irq);
335*e78597ccSYoshinori Sato     sysbus_init_irq(d, &icu->_fir);
336*e78597ccSYoshinori Sato     sysbus_init_irq(d, &icu->_swi);
337*e78597ccSYoshinori Sato }
338*e78597ccSYoshinori Sato 
339*e78597ccSYoshinori Sato static void rxicu_fini(Object *obj)
340*e78597ccSYoshinori Sato {
341*e78597ccSYoshinori Sato     RXICUState *icu = RX_ICU(obj);
342*e78597ccSYoshinori Sato     g_free(icu->map);
343*e78597ccSYoshinori Sato     g_free(icu->init_sense);
344*e78597ccSYoshinori Sato }
345*e78597ccSYoshinori Sato 
346*e78597ccSYoshinori Sato static const VMStateDescription vmstate_rxicu = {
347*e78597ccSYoshinori Sato     .name = "rx-icu",
348*e78597ccSYoshinori Sato     .version_id = 1,
349*e78597ccSYoshinori Sato     .minimum_version_id = 1,
350*e78597ccSYoshinori Sato     .fields = (VMStateField[]) {
351*e78597ccSYoshinori Sato         VMSTATE_UINT8_ARRAY(ir, RXICUState, NR_IRQS),
352*e78597ccSYoshinori Sato         VMSTATE_UINT8_ARRAY(dtcer, RXICUState, NR_IRQS),
353*e78597ccSYoshinori Sato         VMSTATE_UINT8_ARRAY(ier, RXICUState, NR_IRQS / 8),
354*e78597ccSYoshinori Sato         VMSTATE_UINT8_ARRAY(ipr, RXICUState, 142),
355*e78597ccSYoshinori Sato         VMSTATE_UINT8_ARRAY(dmasr, RXICUState, 4),
356*e78597ccSYoshinori Sato         VMSTATE_UINT16(fir, RXICUState),
357*e78597ccSYoshinori Sato         VMSTATE_UINT8(nmisr, RXICUState),
358*e78597ccSYoshinori Sato         VMSTATE_UINT8(nmier, RXICUState),
359*e78597ccSYoshinori Sato         VMSTATE_UINT8(nmiclr, RXICUState),
360*e78597ccSYoshinori Sato         VMSTATE_UINT8(nmicr, RXICUState),
361*e78597ccSYoshinori Sato         VMSTATE_INT16(req_irq, RXICUState),
362*e78597ccSYoshinori Sato         VMSTATE_END_OF_LIST()
363*e78597ccSYoshinori Sato     }
364*e78597ccSYoshinori Sato };
365*e78597ccSYoshinori Sato 
366*e78597ccSYoshinori Sato static Property rxicu_properties[] = {
367*e78597ccSYoshinori Sato     DEFINE_PROP_ARRAY("ipr-map", RXICUState, nr_irqs, map,
368*e78597ccSYoshinori Sato                       qdev_prop_uint8, uint8_t),
369*e78597ccSYoshinori Sato     DEFINE_PROP_ARRAY("trigger-level", RXICUState, nr_sense, init_sense,
370*e78597ccSYoshinori Sato                       qdev_prop_uint8, uint8_t),
371*e78597ccSYoshinori Sato     DEFINE_PROP_END_OF_LIST(),
372*e78597ccSYoshinori Sato };
373*e78597ccSYoshinori Sato 
374*e78597ccSYoshinori Sato static void rxicu_class_init(ObjectClass *klass, void *data)
375*e78597ccSYoshinori Sato {
376*e78597ccSYoshinori Sato     DeviceClass *dc = DEVICE_CLASS(klass);
377*e78597ccSYoshinori Sato 
378*e78597ccSYoshinori Sato     dc->realize = rxicu_realize;
379*e78597ccSYoshinori Sato     dc->vmsd = &vmstate_rxicu;
380*e78597ccSYoshinori Sato     device_class_set_props(dc, rxicu_properties);
381*e78597ccSYoshinori Sato }
382*e78597ccSYoshinori Sato 
383*e78597ccSYoshinori Sato static const TypeInfo rxicu_info = {
384*e78597ccSYoshinori Sato     .name = TYPE_RX_ICU,
385*e78597ccSYoshinori Sato     .parent = TYPE_SYS_BUS_DEVICE,
386*e78597ccSYoshinori Sato     .instance_size = sizeof(RXICUState),
387*e78597ccSYoshinori Sato     .instance_init = rxicu_init,
388*e78597ccSYoshinori Sato     .instance_finalize = rxicu_fini,
389*e78597ccSYoshinori Sato     .class_init = rxicu_class_init,
390*e78597ccSYoshinori Sato };
391*e78597ccSYoshinori Sato 
392*e78597ccSYoshinori Sato static void rxicu_register_types(void)
393*e78597ccSYoshinori Sato {
394*e78597ccSYoshinori Sato     type_register_static(&rxicu_info);
395*e78597ccSYoshinori Sato }
396*e78597ccSYoshinori Sato 
397*e78597ccSYoshinori Sato type_init(rxicu_register_types)
398