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/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 "cpu.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
  63struct 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};
  72typedef struct RX62NClass RX62NClass;
  73
  74DECLARE_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 */
  83static 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 triggerd IRQ list
 120 * Not listed IRQ is Edge trigger.
 121 * See "11.3.1 Interrupt Vector Table" in hardware manual.
 122 */
 123static 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
 131static void register_icu(RX62NState *s)
 132{
 133    int i;
 134    SysBusDevice *icu;
 135
 136    object_initialize_child(OBJECT(s), "icu", &s->icu, TYPE_RX_ICU);
 137    icu = SYS_BUS_DEVICE(&s->icu);
 138    qdev_prop_set_uint32(DEVICE(icu), "len-ipr-map", NR_IRQS);
 139    for (i = 0; i < NR_IRQS; i++) {
 140        char propname[32];
 141        snprintf(propname, sizeof(propname), "ipr-map[%d]", i);
 142        qdev_prop_set_uint32(DEVICE(icu), propname, ipr_table[i]);
 143    }
 144    qdev_prop_set_uint32(DEVICE(icu), "len-trigger-level",
 145                         ARRAY_SIZE(levelirq));
 146    for (i = 0; i < ARRAY_SIZE(levelirq); i++) {
 147        char propname[32];
 148        snprintf(propname, sizeof(propname), "trigger-level[%d]", i);
 149        qdev_prop_set_uint32(DEVICE(icu), propname, levelirq[i]);
 150    }
 151
 152    for (i = 0; i < NR_IRQS; i++) {
 153        s->irq[i] = qdev_get_gpio_in(DEVICE(icu), i);
 154    }
 155    sysbus_realize(icu, &error_abort);
 156    sysbus_connect_irq(icu, 0, qdev_get_gpio_in(DEVICE(&s->cpu), RX_CPU_IRQ));
 157    sysbus_connect_irq(icu, 1, qdev_get_gpio_in(DEVICE(&s->cpu), RX_CPU_FIR));
 158    sysbus_connect_irq(icu, 2, s->irq[SWI]);
 159    sysbus_mmio_map(SYS_BUS_DEVICE(icu), 0, RX62N_ICU_BASE);
 160}
 161
 162static void register_tmr(RX62NState *s, int unit)
 163{
 164    SysBusDevice *tmr;
 165    int i, irqbase;
 166
 167    object_initialize_child(OBJECT(s), "tmr[*]",
 168                            &s->tmr[unit], TYPE_RENESAS_TMR);
 169    tmr = SYS_BUS_DEVICE(&s->tmr[unit]);
 170    qdev_prop_set_uint64(DEVICE(tmr), "input-freq", s->pclk_freq_hz);
 171    sysbus_realize(tmr, &error_abort);
 172
 173    irqbase = RX62N_TMR_IRQ + TMR_NR_IRQ * unit;
 174    for (i = 0; i < TMR_NR_IRQ; i++) {
 175        sysbus_connect_irq(tmr, i, s->irq[irqbase + i]);
 176    }
 177    sysbus_mmio_map(tmr, 0, RX62N_TMR_BASE + unit * 0x10);
 178}
 179
 180static void register_cmt(RX62NState *s, int unit)
 181{
 182    SysBusDevice *cmt;
 183    int i, irqbase;
 184
 185    object_initialize_child(OBJECT(s), "cmt[*]",
 186                            &s->cmt[unit], TYPE_RENESAS_CMT);
 187    cmt = SYS_BUS_DEVICE(&s->cmt[unit]);
 188    qdev_prop_set_uint64(DEVICE(cmt), "input-freq", s->pclk_freq_hz);
 189    sysbus_realize(cmt, &error_abort);
 190
 191    irqbase = RX62N_CMT_IRQ + CMT_NR_IRQ * unit;
 192    for (i = 0; i < CMT_NR_IRQ; i++) {
 193        sysbus_connect_irq(cmt, i, s->irq[irqbase + i]);
 194    }
 195    sysbus_mmio_map(cmt, 0, RX62N_CMT_BASE + unit * 0x10);
 196}
 197
 198static void register_sci(RX62NState *s, int unit)
 199{
 200    SysBusDevice *sci;
 201    int i, irqbase;
 202
 203    object_initialize_child(OBJECT(s), "sci[*]",
 204                            &s->sci[unit], TYPE_RENESAS_SCI);
 205    sci = SYS_BUS_DEVICE(&s->sci[unit]);
 206    qdev_prop_set_chr(DEVICE(sci), "chardev", serial_hd(unit));
 207    qdev_prop_set_uint64(DEVICE(sci), "input-freq", s->pclk_freq_hz);
 208    sysbus_realize(sci, &error_abort);
 209
 210    irqbase = RX62N_SCI_IRQ + SCI_NR_IRQ * unit;
 211    for (i = 0; i < SCI_NR_IRQ; i++) {
 212        sysbus_connect_irq(sci, i, s->irq[irqbase + i]);
 213    }
 214    sysbus_mmio_map(sci, 0, RX62N_SCI_BASE + unit * 0x08);
 215}
 216
 217static 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
 260static 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
 268static 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
 276static 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
 285static 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
 294static 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
 313DEFINE_TYPES(rx62n_types)
 314