qemu/hw/riscv/shakti_c.c
<<
>>
Prefs
   1/*
   2 * Shakti C-class SoC emulation
   3 *
   4 * Copyright (c) 2021 Vijai Kumar K <vijai@behindbytes.com>
   5 *
   6 * This program is free software; you can redistribute it and/or modify it
   7 * under the terms and conditions of the GNU General Public License,
   8 * version 2 or later, as published by the Free Software Foundation.
   9 *
  10 * This program is distributed in the hope it will be useful, but WITHOUT
  11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  13 * more details.
  14 *
  15 * You should have received a copy of the GNU General Public License along with
  16 * this program.  If not, see <http://www.gnu.org/licenses/>.
  17 */
  18
  19#include "qemu/osdep.h"
  20#include "hw/boards.h"
  21#include "hw/riscv/shakti_c.h"
  22#include "qapi/error.h"
  23#include "hw/intc/sifive_plic.h"
  24#include "hw/intc/riscv_aclint.h"
  25#include "sysemu/sysemu.h"
  26#include "hw/qdev-properties.h"
  27#include "exec/address-spaces.h"
  28#include "hw/riscv/boot.h"
  29
  30
  31static const struct MemmapEntry {
  32    hwaddr base;
  33    hwaddr size;
  34} shakti_c_memmap[] = {
  35    [SHAKTI_C_ROM]   =  {  0x00001000,  0x2000   },
  36    [SHAKTI_C_RAM]   =  {  0x80000000,  0x0      },
  37    [SHAKTI_C_UART]  =  {  0x00011300,  0x00040  },
  38    [SHAKTI_C_GPIO]  =  {  0x020d0000,  0x00100  },
  39    [SHAKTI_C_PLIC]  =  {  0x0c000000,  0x20000  },
  40    [SHAKTI_C_CLINT] =  {  0x02000000,  0xc0000  },
  41    [SHAKTI_C_I2C]   =  {  0x20c00000,  0x00100  },
  42};
  43
  44static void shakti_c_machine_state_init(MachineState *mstate)
  45{
  46    ShaktiCMachineState *sms = RISCV_SHAKTI_MACHINE(mstate);
  47    MemoryRegion *system_memory = get_system_memory();
  48
  49    /* Allow only Shakti C CPU for this platform */
  50    if (strcmp(mstate->cpu_type, TYPE_RISCV_CPU_SHAKTI_C) != 0) {
  51        error_report("This board can only be used with Shakti C CPU");
  52        exit(1);
  53    }
  54
  55    /* Initialize SoC */
  56    object_initialize_child(OBJECT(mstate), "soc", &sms->soc,
  57                            TYPE_RISCV_SHAKTI_SOC);
  58    qdev_realize(DEVICE(&sms->soc), NULL, &error_abort);
  59
  60    /* register RAM */
  61    memory_region_add_subregion(system_memory,
  62                                shakti_c_memmap[SHAKTI_C_RAM].base,
  63                                mstate->ram);
  64
  65    /* ROM reset vector */
  66    riscv_setup_rom_reset_vec(mstate, &sms->soc.cpus,
  67                              shakti_c_memmap[SHAKTI_C_RAM].base,
  68                              shakti_c_memmap[SHAKTI_C_ROM].base,
  69                              shakti_c_memmap[SHAKTI_C_ROM].size, 0, 0,
  70                              NULL);
  71    if (mstate->firmware) {
  72        riscv_load_firmware(mstate->firmware,
  73                            shakti_c_memmap[SHAKTI_C_RAM].base,
  74                            NULL);
  75    }
  76}
  77
  78static void shakti_c_machine_instance_init(Object *obj)
  79{
  80}
  81
  82static void shakti_c_machine_class_init(ObjectClass *klass, void *data)
  83{
  84    MachineClass *mc = MACHINE_CLASS(klass);
  85    mc->desc = "RISC-V Board compatible with Shakti SDK";
  86    mc->init = shakti_c_machine_state_init;
  87    mc->default_cpu_type = TYPE_RISCV_CPU_SHAKTI_C;
  88    mc->default_ram_id = "riscv.shakti.c.ram";
  89}
  90
  91static const TypeInfo shakti_c_machine_type_info = {
  92    .name = TYPE_RISCV_SHAKTI_MACHINE,
  93    .parent = TYPE_MACHINE,
  94    .class_init = shakti_c_machine_class_init,
  95    .instance_init = shakti_c_machine_instance_init,
  96    .instance_size = sizeof(ShaktiCMachineState),
  97};
  98
  99static void shakti_c_machine_type_info_register(void)
 100{
 101    type_register_static(&shakti_c_machine_type_info);
 102}
 103type_init(shakti_c_machine_type_info_register)
 104
 105static void shakti_c_soc_state_realize(DeviceState *dev, Error **errp)
 106{
 107    MachineState *ms = MACHINE(qdev_get_machine());
 108    ShaktiCSoCState *sss = RISCV_SHAKTI_SOC(dev);
 109    MemoryRegion *system_memory = get_system_memory();
 110
 111    sysbus_realize(SYS_BUS_DEVICE(&sss->cpus), &error_abort);
 112
 113    sss->plic = sifive_plic_create(shakti_c_memmap[SHAKTI_C_PLIC].base,
 114        (char *)SHAKTI_C_PLIC_HART_CONFIG, ms->smp.cpus, 0,
 115        SHAKTI_C_PLIC_NUM_SOURCES,
 116        SHAKTI_C_PLIC_NUM_PRIORITIES,
 117        SHAKTI_C_PLIC_PRIORITY_BASE,
 118        SHAKTI_C_PLIC_PENDING_BASE,
 119        SHAKTI_C_PLIC_ENABLE_BASE,
 120        SHAKTI_C_PLIC_ENABLE_STRIDE,
 121        SHAKTI_C_PLIC_CONTEXT_BASE,
 122        SHAKTI_C_PLIC_CONTEXT_STRIDE,
 123        shakti_c_memmap[SHAKTI_C_PLIC].size);
 124
 125    riscv_aclint_swi_create(shakti_c_memmap[SHAKTI_C_CLINT].base,
 126        0, 1, false);
 127    riscv_aclint_mtimer_create(shakti_c_memmap[SHAKTI_C_CLINT].base +
 128            RISCV_ACLINT_SWI_SIZE,
 129        RISCV_ACLINT_DEFAULT_MTIMER_SIZE, 0, 1,
 130        RISCV_ACLINT_DEFAULT_MTIMECMP, RISCV_ACLINT_DEFAULT_MTIME,
 131        RISCV_ACLINT_DEFAULT_TIMEBASE_FREQ, false);
 132
 133    qdev_prop_set_chr(DEVICE(&(sss->uart)), "chardev", serial_hd(0));
 134    if (!sysbus_realize(SYS_BUS_DEVICE(&sss->uart), errp)) {
 135        return;
 136    }
 137    sysbus_mmio_map(SYS_BUS_DEVICE(&sss->uart), 0,
 138                    shakti_c_memmap[SHAKTI_C_UART].base);
 139
 140    /* ROM */
 141    memory_region_init_rom(&sss->rom, OBJECT(dev), "riscv.shakti.c.rom",
 142                           shakti_c_memmap[SHAKTI_C_ROM].size, &error_fatal);
 143    memory_region_add_subregion(system_memory,
 144        shakti_c_memmap[SHAKTI_C_ROM].base, &sss->rom);
 145}
 146
 147static void shakti_c_soc_class_init(ObjectClass *klass, void *data)
 148{
 149    DeviceClass *dc = DEVICE_CLASS(klass);
 150    dc->realize = shakti_c_soc_state_realize;
 151    /*
 152     * Reasons:
 153     *     - Creates CPUS in riscv_hart_realize(), and can create unintended
 154     *       CPUs
 155     *     - Uses serial_hds in realize function, thus can't be used twice
 156     */
 157    dc->user_creatable = false;
 158}
 159
 160static void shakti_c_soc_instance_init(Object *obj)
 161{
 162    ShaktiCSoCState *sss = RISCV_SHAKTI_SOC(obj);
 163
 164    object_initialize_child(obj, "cpus", &sss->cpus, TYPE_RISCV_HART_ARRAY);
 165    object_initialize_child(obj, "uart", &sss->uart, TYPE_SHAKTI_UART);
 166
 167    /*
 168     * CPU type is fixed and we are not supporting passing from commandline yet.
 169     * So let it be in instance_init. When supported should use ms->cpu_type
 170     * instead of TYPE_RISCV_CPU_SHAKTI_C
 171     */
 172    object_property_set_str(OBJECT(&sss->cpus), "cpu-type",
 173                            TYPE_RISCV_CPU_SHAKTI_C, &error_abort);
 174    object_property_set_int(OBJECT(&sss->cpus), "num-harts", 1,
 175                            &error_abort);
 176}
 177
 178static const TypeInfo shakti_c_type_info = {
 179    .name = TYPE_RISCV_SHAKTI_SOC,
 180    .parent = TYPE_DEVICE,
 181    .class_init = shakti_c_soc_class_init,
 182    .instance_init = shakti_c_soc_instance_init,
 183    .instance_size = sizeof(ShaktiCSoCState),
 184};
 185
 186static void shakti_c_type_info_register(void)
 187{
 188    type_register_static(&shakti_c_type_info);
 189}
 190type_init(shakti_c_type_info_register)
 191