1 /* 2 * Xilinx Zynq MPSoC PMU (Power Management Unit) emulation 3 * 4 * Copyright (C) 2017 Xilinx Inc 5 * Written by Alistair Francis <alistair.francis@xilinx.com> 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the 9 * Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 * for more details. 16 */ 17 18 #include "qemu/osdep.h" 19 #include "qapi/error.h" 20 #include "qemu-common.h" 21 #include "exec/address-spaces.h" 22 #include "hw/boards.h" 23 #include "hw/qdev-properties.h" 24 #include "cpu.h" 25 #include "boot.h" 26 27 /* Define the PMU device */ 28 29 #define TYPE_XLNX_ZYNQMP_PMU_SOC "xlnx,zynqmp-pmu-soc" 30 #define XLNX_ZYNQMP_PMU_SOC(obj) OBJECT_CHECK(XlnxZynqMPPMUSoCState, (obj), \ 31 TYPE_XLNX_ZYNQMP_PMU_SOC) 32 33 #define XLNX_ZYNQMP_PMU_ROM_SIZE 0x8000 34 #define XLNX_ZYNQMP_PMU_ROM_ADDR 0xFFD00000 35 #define XLNX_ZYNQMP_PMU_RAM_ADDR 0xFFDC0000 36 37 typedef struct XlnxZynqMPPMUSoCState { 38 /*< private >*/ 39 DeviceState parent_obj; 40 41 /*< public >*/ 42 MicroBlazeCPU cpu; 43 } XlnxZynqMPPMUSoCState; 44 45 static void xlnx_zynqmp_pmu_soc_init(Object *obj) 46 { 47 XlnxZynqMPPMUSoCState *s = XLNX_ZYNQMP_PMU_SOC(obj); 48 49 object_initialize(&s->cpu, sizeof(s->cpu), 50 TYPE_MICROBLAZE_CPU); 51 object_property_add_child(obj, "pmu-cpu", OBJECT(&s->cpu), 52 &error_abort); 53 } 54 55 static void xlnx_zynqmp_pmu_soc_realize(DeviceState *dev, Error **errp) 56 { 57 XlnxZynqMPPMUSoCState *s = XLNX_ZYNQMP_PMU_SOC(dev); 58 Error *err = NULL; 59 60 object_property_set_uint(OBJECT(&s->cpu), XLNX_ZYNQMP_PMU_ROM_ADDR, 61 "base-vectors", &error_abort); 62 object_property_set_bool(OBJECT(&s->cpu), true, "use-stack-protection", 63 &error_abort); 64 object_property_set_uint(OBJECT(&s->cpu), 0, "use-fpu", &error_abort); 65 object_property_set_uint(OBJECT(&s->cpu), 0, "use-hw-mul", &error_abort); 66 object_property_set_bool(OBJECT(&s->cpu), true, "use-barrel", 67 &error_abort); 68 object_property_set_bool(OBJECT(&s->cpu), true, "use-msr-instr", 69 &error_abort); 70 object_property_set_bool(OBJECT(&s->cpu), true, "use-pcmp-instr", 71 &error_abort); 72 object_property_set_bool(OBJECT(&s->cpu), false, "use-mmu", &error_abort); 73 object_property_set_bool(OBJECT(&s->cpu), true, "endianness", 74 &error_abort); 75 object_property_set_str(OBJECT(&s->cpu), "8.40.b", "version", 76 &error_abort); 77 object_property_set_uint(OBJECT(&s->cpu), 0, "pvr", &error_abort); 78 object_property_set_bool(OBJECT(&s->cpu), true, "realized", &err); 79 if (err) { 80 error_propagate(errp, err); 81 return; 82 } 83 } 84 85 static void xlnx_zynqmp_pmu_soc_class_init(ObjectClass *oc, void *data) 86 { 87 DeviceClass *dc = DEVICE_CLASS(oc); 88 89 dc->realize = xlnx_zynqmp_pmu_soc_realize; 90 } 91 92 static const TypeInfo xlnx_zynqmp_pmu_soc_type_info = { 93 .name = TYPE_XLNX_ZYNQMP_PMU_SOC, 94 .parent = TYPE_DEVICE, 95 .instance_size = sizeof(XlnxZynqMPPMUSoCState), 96 .instance_init = xlnx_zynqmp_pmu_soc_init, 97 .class_init = xlnx_zynqmp_pmu_soc_class_init, 98 }; 99 100 static void xlnx_zynqmp_pmu_soc_register_types(void) 101 { 102 type_register_static(&xlnx_zynqmp_pmu_soc_type_info); 103 } 104 105 type_init(xlnx_zynqmp_pmu_soc_register_types) 106 107 /* Define the PMU Machine */ 108 109 static void xlnx_zynqmp_pmu_init(MachineState *machine) 110 { 111 XlnxZynqMPPMUSoCState *pmu = g_new0(XlnxZynqMPPMUSoCState, 1); 112 MemoryRegion *address_space_mem = get_system_memory(); 113 MemoryRegion *pmu_rom = g_new(MemoryRegion, 1); 114 MemoryRegion *pmu_ram = g_new(MemoryRegion, 1); 115 116 /* Create the ROM */ 117 memory_region_init_rom(pmu_rom, NULL, "xlnx-zynqmp-pmu.rom", 118 XLNX_ZYNQMP_PMU_ROM_SIZE, &error_fatal); 119 memory_region_add_subregion(address_space_mem, XLNX_ZYNQMP_PMU_ROM_ADDR, 120 pmu_rom); 121 122 /* Create the RAM */ 123 memory_region_init_ram(pmu_ram, NULL, "xlnx-zynqmp-pmu.ram", 124 machine->ram_size, &error_fatal); 125 memory_region_add_subregion(address_space_mem, XLNX_ZYNQMP_PMU_RAM_ADDR, 126 pmu_ram); 127 128 /* Create the PMU device */ 129 object_initialize(pmu, sizeof(XlnxZynqMPPMUSoCState), TYPE_XLNX_ZYNQMP_PMU_SOC); 130 object_property_add_child(OBJECT(machine), "pmu", OBJECT(pmu), 131 &error_abort); 132 object_property_set_bool(OBJECT(pmu), true, "realized", &error_fatal); 133 134 /* Load the kernel */ 135 microblaze_load_kernel(&pmu->cpu, XLNX_ZYNQMP_PMU_RAM_ADDR, 136 machine->ram_size, 137 machine->initrd_filename, 138 machine->dtb, 139 NULL); 140 } 141 142 static void xlnx_zynqmp_pmu_machine_init(MachineClass *mc) 143 { 144 mc->desc = "Xilinx ZynqMP PMU machine"; 145 mc->init = xlnx_zynqmp_pmu_init; 146 } 147 148 DEFINE_MACHINE("xlnx-zynqmp-pmu", xlnx_zynqmp_pmu_machine_init) 149 150