xref: /openbmc/qemu/hw/microblaze/xlnx-zynqmp-pmu.c (revision c859b566e8ceba48c4314e7123f7480e4eb66ff2)
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