xref: /openbmc/qemu/hw/rx/rx62n.c (revision 041c2a31)
1 /*
2  * RX62N Microcontroller
3  *
4  * Datasheet: RX62N Group, RX621 Group User's Manual: Hardware
5  * (Rev.1.40 R01UH0033EJ0140)
6  *
7  * Copyright (c) 2019 Yoshinori Sato
8  * Copyright (c) 2020 Philippe Mathieu-Daudé
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms and conditions of the GNU General Public License,
12  * version 2 or later, as published by the Free Software Foundation.
13  *
14  * This program is distributed in the hope it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
17  * more details.
18  *
19  * You should have received a copy of the GNU General Public License along with
20  * this program.  If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #include "qemu/osdep.h"
24 #include "qapi/error.h"
25 #include "qemu/error-report.h"
26 #include "hw/hw.h"
27 #include "hw/rx/rx62n.h"
28 #include "hw/loader.h"
29 #include "hw/sysbus.h"
30 #include "hw/qdev-properties.h"
31 #include "sysemu/sysemu.h"
32 #include "sysemu/qtest.h"
33 #include "cpu.h"
34 #include "qom/object.h"
35 
36 /*
37  * RX62N Internal Memory
38  */
39 #define RX62N_IRAM_BASE     0x00000000
40 #define RX62N_DFLASH_BASE   0x00100000
41 #define RX62N_CFLASH_BASE   0xfff80000
42 
43 /*
44  * RX62N Peripheral Address
45  * See users manual section 5
46  */
47 #define RX62N_ICU_BASE  0x00087000
48 #define RX62N_TMR_BASE  0x00088200
49 #define RX62N_CMT_BASE  0x00088000
50 #define RX62N_SCI_BASE  0x00088240
51 
52 /*
53  * RX62N Peripheral IRQ
54  * See users manual section 11
55  */
56 #define RX62N_TMR_IRQ   174
57 #define RX62N_CMT_IRQ   28
58 #define RX62N_SCI_IRQ   214
59 
60 #define RX62N_XTAL_MIN_HZ  (8 * 1000 * 1000)
61 #define RX62N_XTAL_MAX_HZ (14 * 1000 * 1000)
62 #define RX62N_PCLK_MAX_HZ (50 * 1000 * 1000)
63 
64 struct RX62NClass {
65     /*< private >*/
66     DeviceClass parent_class;
67     /*< public >*/
68     const char *name;
69     uint64_t ram_size;
70     uint64_t rom_flash_size;
71     uint64_t data_flash_size;
72 };
73 typedef struct RX62NClass RX62NClass;
74 
75 DECLARE_CLASS_CHECKERS(RX62NClass, RX62N_MCU,
76                        TYPE_RX62N_MCU)
77 
78 /*
79  * IRQ -> IPR mapping table
80  * 0x00 - 0x91: IPR no (IPR00 to IPR91)
81  * 0xff: IPR not assigned
82  * See "11.3.1 Interrupt Vector Table" in hardware manual.
83  */
84 static const uint8_t ipr_table[NR_IRQS] = {
85     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
86     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 15 */
87     0x00, 0xff, 0xff, 0xff, 0xff, 0x01, 0xff, 0x02,
88     0xff, 0xff, 0xff, 0x03, 0x04, 0x05, 0x06, 0x07, /* 31 */
89     0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
90     0x10, 0x11, 0x12, 0x13, 0x14, 0x14, 0x14, 0x14, /* 47 */
91     0x15, 0x15, 0x15, 0x15, 0xff, 0xff, 0xff, 0xff,
92     0x18, 0x18, 0x18, 0x18, 0x18, 0x1d, 0x1e, 0x1f, /* 63 */
93     0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
94     0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, /* 79 */
95     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
96     0xff, 0xff, 0x3a, 0x3b, 0x3c, 0xff, 0xff, 0xff, /* 95 */
97     0x40, 0xff, 0x44, 0x45, 0xff, 0xff, 0x48, 0xff,
98     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 111 */
99     0xff, 0xff, 0x51, 0x51, 0x51, 0x51, 0x52, 0x52,
100     0x52, 0x53, 0x53, 0x54, 0x54, 0x55, 0x55, 0x56, /* 127 */
101     0x56, 0x57, 0x57, 0x57, 0x57, 0x58, 0x59, 0x59,
102     0x59, 0x59, 0x5a, 0x5b, 0x5b, 0x5b, 0x5c, 0x5c, /* 143 */
103     0x5c, 0x5c, 0x5d, 0x5d, 0x5d, 0x5e, 0x5e, 0x5f,
104     0x5f, 0x60, 0x60, 0x61, 0x61, 0x62, 0x62, 0x62, /* 159 */
105     0x62, 0x63, 0x64, 0x64, 0x64, 0x64, 0x65, 0x66,
106     0x66, 0x66, 0x67, 0x67, 0x67, 0x67, 0x68, 0x68, /* 175 */
107     0x68, 0x69, 0x69, 0x69, 0x6a, 0x6a, 0x6a, 0x6b,
108     0x6b, 0x6b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 191 */
109     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x70, 0x71,
110     0x72, 0x73, 0x74, 0x75, 0xff, 0xff, 0xff, 0xff, /* 207 */
111     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x80,
112     0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x82, 0x82, /* 223 */
113     0x82, 0x82, 0x83, 0x83, 0x83, 0x83, 0xff, 0xff,
114     0xff, 0xff, 0x85, 0x85, 0x85, 0x85, 0x86, 0x86, /* 239 */
115     0x86, 0x86, 0xff, 0xff, 0xff, 0xff, 0x88, 0x89,
116     0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, /* 255 */
117 };
118 
119 /*
120  * Level triggerd IRQ list
121  * Not listed IRQ is Edge trigger.
122  * See "11.3.1 Interrupt Vector Table" in hardware manual.
123  */
124 static const uint8_t levelirq[] = {
125      16,  21,  32,  44,  47,  48,  51,  64,  65,  66,
126      67,  68,  69,  70,  71,  72,  73,  74,  75,  76,
127      77,  78,  79,  90,  91, 170, 171, 172, 173, 214,
128     217, 218, 221, 222, 225, 226, 229, 234, 237, 238,
129     241, 246, 249, 250, 253,
130 };
131 
132 static void register_icu(RX62NState *s)
133 {
134     int i;
135     SysBusDevice *icu;
136 
137     object_initialize_child(OBJECT(s), "icu", &s->icu, TYPE_RX_ICU);
138     icu = SYS_BUS_DEVICE(&s->icu);
139     qdev_prop_set_uint32(DEVICE(icu), "len-ipr-map", NR_IRQS);
140     for (i = 0; i < NR_IRQS; i++) {
141         char propname[32];
142         snprintf(propname, sizeof(propname), "ipr-map[%d]", i);
143         qdev_prop_set_uint32(DEVICE(icu), propname, ipr_table[i]);
144     }
145     qdev_prop_set_uint32(DEVICE(icu), "len-trigger-level",
146                          ARRAY_SIZE(levelirq));
147     for (i = 0; i < ARRAY_SIZE(levelirq); i++) {
148         char propname[32];
149         snprintf(propname, sizeof(propname), "trigger-level[%d]", i);
150         qdev_prop_set_uint32(DEVICE(icu), propname, levelirq[i]);
151     }
152 
153     for (i = 0; i < NR_IRQS; i++) {
154         s->irq[i] = qdev_get_gpio_in(DEVICE(icu), i);
155     }
156     sysbus_realize(icu, &error_abort);
157     sysbus_connect_irq(icu, 0, qdev_get_gpio_in(DEVICE(&s->cpu), RX_CPU_IRQ));
158     sysbus_connect_irq(icu, 1, qdev_get_gpio_in(DEVICE(&s->cpu), RX_CPU_FIR));
159     sysbus_connect_irq(icu, 2, s->irq[SWI]);
160     sysbus_mmio_map(SYS_BUS_DEVICE(icu), 0, RX62N_ICU_BASE);
161 }
162 
163 static void register_tmr(RX62NState *s, int unit)
164 {
165     SysBusDevice *tmr;
166     int i, irqbase;
167 
168     object_initialize_child(OBJECT(s), "tmr[*]",
169                             &s->tmr[unit], TYPE_RENESAS_TMR);
170     tmr = SYS_BUS_DEVICE(&s->tmr[unit]);
171     qdev_prop_set_uint64(DEVICE(tmr), "input-freq", s->pclk_freq_hz);
172     sysbus_realize(tmr, &error_abort);
173 
174     irqbase = RX62N_TMR_IRQ + TMR_NR_IRQ * unit;
175     for (i = 0; i < TMR_NR_IRQ; i++) {
176         sysbus_connect_irq(tmr, i, s->irq[irqbase + i]);
177     }
178     sysbus_mmio_map(tmr, 0, RX62N_TMR_BASE + unit * 0x10);
179 }
180 
181 static void register_cmt(RX62NState *s, int unit)
182 {
183     SysBusDevice *cmt;
184     int i, irqbase;
185 
186     object_initialize_child(OBJECT(s), "cmt[*]",
187                             &s->cmt[unit], TYPE_RENESAS_CMT);
188     cmt = SYS_BUS_DEVICE(&s->cmt[unit]);
189     qdev_prop_set_uint64(DEVICE(cmt), "input-freq", s->pclk_freq_hz);
190     sysbus_realize(cmt, &error_abort);
191 
192     irqbase = RX62N_CMT_IRQ + CMT_NR_IRQ * unit;
193     for (i = 0; i < CMT_NR_IRQ; i++) {
194         sysbus_connect_irq(cmt, i, s->irq[irqbase + i]);
195     }
196     sysbus_mmio_map(cmt, 0, RX62N_CMT_BASE + unit * 0x10);
197 }
198 
199 static void register_sci(RX62NState *s, int unit)
200 {
201     SysBusDevice *sci;
202     int i, irqbase;
203 
204     object_initialize_child(OBJECT(s), "sci[*]",
205                             &s->sci[unit], TYPE_RENESAS_SCI);
206     sci = SYS_BUS_DEVICE(&s->sci[unit]);
207     qdev_prop_set_chr(DEVICE(sci), "chardev", serial_hd(unit));
208     qdev_prop_set_uint64(DEVICE(sci), "input-freq", s->pclk_freq_hz);
209     sysbus_realize(sci, &error_abort);
210 
211     irqbase = RX62N_SCI_IRQ + SCI_NR_IRQ * unit;
212     for (i = 0; i < SCI_NR_IRQ; i++) {
213         sysbus_connect_irq(sci, i, s->irq[irqbase + i]);
214     }
215     sysbus_mmio_map(sci, 0, RX62N_SCI_BASE + unit * 0x08);
216 }
217 
218 static void rx62n_realize(DeviceState *dev, Error **errp)
219 {
220     RX62NState *s = RX62N_MCU(dev);
221     RX62NClass *rxc = RX62N_MCU_GET_CLASS(dev);
222 
223     if (s->xtal_freq_hz == 0) {
224         error_setg(errp, "\"xtal-frequency-hz\" property must be provided.");
225         return;
226     }
227     /* XTAL range: 8-14 MHz */
228     if (s->xtal_freq_hz < RX62N_XTAL_MIN_HZ
229             || s->xtal_freq_hz > RX62N_XTAL_MAX_HZ) {
230         error_setg(errp, "\"xtal-frequency-hz\" property in incorrect range.");
231         return;
232     }
233     /* Use a 4x fixed multiplier */
234     s->pclk_freq_hz = 4 * s->xtal_freq_hz;
235     /* PCLK range: 8-50 MHz */
236     assert(s->pclk_freq_hz <= RX62N_PCLK_MAX_HZ);
237 
238     memory_region_init_ram(&s->iram, OBJECT(dev), "iram",
239                            rxc->ram_size, &error_abort);
240     memory_region_add_subregion(s->sysmem, RX62N_IRAM_BASE, &s->iram);
241     memory_region_init_rom(&s->d_flash, OBJECT(dev), "flash-data",
242                            rxc->data_flash_size, &error_abort);
243     memory_region_add_subregion(s->sysmem, RX62N_DFLASH_BASE, &s->d_flash);
244     memory_region_init_rom(&s->c_flash, OBJECT(dev), "flash-code",
245                            rxc->rom_flash_size, &error_abort);
246     memory_region_add_subregion(s->sysmem, RX62N_CFLASH_BASE, &s->c_flash);
247 
248     /* Initialize CPU */
249     object_initialize_child(OBJECT(s), "cpu", &s->cpu, TYPE_RX62N_CPU);
250     qdev_realize(DEVICE(&s->cpu), NULL, &error_abort);
251 
252     register_icu(s);
253     s->cpu.env.ack = qdev_get_gpio_in_named(DEVICE(&s->icu), "ack", 0);
254     register_tmr(s, 0);
255     register_tmr(s, 1);
256     register_cmt(s, 0);
257     register_cmt(s, 1);
258     register_sci(s, 0);
259 }
260 
261 static Property rx62n_properties[] = {
262     DEFINE_PROP_LINK("main-bus", RX62NState, sysmem, TYPE_MEMORY_REGION,
263                      MemoryRegion *),
264     DEFINE_PROP_BOOL("load-kernel", RX62NState, kernel, false),
265     DEFINE_PROP_UINT32("xtal-frequency-hz", RX62NState, xtal_freq_hz, 0),
266     DEFINE_PROP_END_OF_LIST(),
267 };
268 
269 static void rx62n_class_init(ObjectClass *klass, void *data)
270 {
271     DeviceClass *dc = DEVICE_CLASS(klass);
272 
273     dc->realize = rx62n_realize;
274     device_class_set_props(dc, rx62n_properties);
275 }
276 
277 static void r5f562n7_class_init(ObjectClass *oc, void *data)
278 {
279     RX62NClass *rxc = RX62N_MCU_CLASS(oc);
280 
281     rxc->ram_size = 64 * KiB;
282     rxc->rom_flash_size = 384 * KiB;
283     rxc->data_flash_size = 32 * KiB;
284 };
285 
286 static void r5f562n8_class_init(ObjectClass *oc, void *data)
287 {
288     RX62NClass *rxc = RX62N_MCU_CLASS(oc);
289 
290     rxc->ram_size = 96 * KiB;
291     rxc->rom_flash_size = 512 * KiB;
292     rxc->data_flash_size = 32 * KiB;
293 };
294 
295 static const TypeInfo rx62n_types[] = {
296     {
297         .name           = TYPE_R5F562N7_MCU,
298         .parent         = TYPE_RX62N_MCU,
299         .class_init     = r5f562n7_class_init,
300     }, {
301         .name           = TYPE_R5F562N8_MCU,
302         .parent         = TYPE_RX62N_MCU,
303         .class_init     = r5f562n8_class_init,
304     }, {
305         .name           = TYPE_RX62N_MCU,
306         .parent         = TYPE_DEVICE,
307         .instance_size  = sizeof(RX62NState),
308         .class_size     = sizeof(RX62NClass),
309         .class_init     = rx62n_class_init,
310         .abstract       = true,
311      }
312 };
313 
314 DEFINE_TYPES(rx62n_types)
315