xref: /openbmc/qemu/hw/rx/rx62n.c (revision da96ad4a6a2ef26c83b15fa95e7fceef5147269c)
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  
register_icu(RX62NState * s)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  
register_tmr(RX62NState * s,int unit)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  
register_cmt(RX62NState * s,int unit)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  
register_sci(RX62NState * s,int unit)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  
rx62n_realize(DeviceState * dev,Error ** errp)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  
rx62n_class_init(ObjectClass * klass,void * data)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  
r5f562n7_class_init(ObjectClass * oc,void * data)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  
r5f562n8_class_init(ObjectClass * oc,void * data)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