• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

Commit MetaInfo

Revision6357a94b92691c2b6b262201c99d7c7b319768cb (tree)
Time2019-06-07 18:00:27
AuthorYoshinori Sato <ysato@user...>
CommiterYoshinori Sato

Log Message

hw/intc: RX62N interrupt controller (ICUa)

This implementation supported only ICUa.
Hardware manual.
https://www.renesas.com/us/en/doc/products/mpumcu/doc/rx_family/r01uh0033ej0140_rx62n.pdf

Signed-off-by: Yoshinori Sato <ysato@users.sourceforge.jp>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Message-Id: <20190516055244.95559-6-ysato@users.sourceforge.jp>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

Change Summary

Incremental Difference

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