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