qemu/hw/rx/rx62n.c
<<
>>
Prefs
   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
  61struct 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};
  70typedef struct RX62NClass RX62NClass;
  71
  72DECLARE_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 */
  81static 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 triggerd IRQ list
 118 * Not listed IRQ is Edge trigger.
 119 * See "11.3.1 Interrupt Vector Table" in hardware manual.
 120 */
 121static 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
 129static 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
 160static 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
 178static 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
 196static 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
 215static 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
 258static 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
 266static 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
 274static 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
 283static 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
 292static 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
 311DEFINE_TYPES(rx62n_types)
 312