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