1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include "qemu/osdep.h"
19#include "qapi/error.h"
20#include "cpu.h"
21#include "hw/arm/xlnx-zynqmp.h"
22#include "hw/boards.h"
23#include "qemu/error-report.h"
24#include "qemu/log.h"
25#include "sysemu/qtest.h"
26#include "sysemu/device_tree.h"
27
28typedef struct XlnxZCU102 {
29 MachineState parent_obj;
30
31 XlnxZynqMPState soc;
32
33 bool secure;
34 bool virt;
35
36 struct arm_boot_info binfo;
37} XlnxZCU102;
38
39#define TYPE_ZCU102_MACHINE MACHINE_TYPE_NAME("xlnx-zcu102")
40#define ZCU102_MACHINE(obj) \
41 OBJECT_CHECK(XlnxZCU102, (obj), TYPE_ZCU102_MACHINE)
42
43
44static bool zcu102_get_secure(Object *obj, Error **errp)
45{
46 XlnxZCU102 *s = ZCU102_MACHINE(obj);
47
48 return s->secure;
49}
50
51static void zcu102_set_secure(Object *obj, bool value, Error **errp)
52{
53 XlnxZCU102 *s = ZCU102_MACHINE(obj);
54
55 s->secure = value;
56}
57
58static bool zcu102_get_virt(Object *obj, Error **errp)
59{
60 XlnxZCU102 *s = ZCU102_MACHINE(obj);
61
62 return s->virt;
63}
64
65static void zcu102_set_virt(Object *obj, bool value, Error **errp)
66{
67 XlnxZCU102 *s = ZCU102_MACHINE(obj);
68
69 s->virt = value;
70}
71
72static void zcu102_modify_dtb(const struct arm_boot_info *binfo, void *fdt)
73{
74 XlnxZCU102 *s = container_of(binfo, XlnxZCU102, binfo);
75 bool method_is_hvc;
76 char **node_path;
77 const char *r;
78 int prop_len;
79 int i;
80
81
82 if (!s->secure) {
83 node_path = qemu_fdt_node_path(fdt, NULL, "xlnx,zynqmp-firmware",
84 &error_fatal);
85
86 for (i = 0; node_path && node_path[i]; i++) {
87 r = qemu_fdt_getprop(fdt, node_path[i], "method", &prop_len,
88 false, NULL);
89 method_is_hvc = r && !strcmp("hvc", r);
90
91
92 if (method_is_hvc && s->virt) {
93 continue;
94 }
95 qemu_fdt_setprop_string(fdt, node_path[i], "status", "disabled");
96 }
97 g_strfreev(node_path);
98 }
99}
100
101static void xlnx_zcu102_init(MachineState *machine)
102{
103 XlnxZCU102 *s = ZCU102_MACHINE(machine);
104 int i;
105 uint64_t ram_size = machine->ram_size;
106
107
108 if (ram_size > XLNX_ZYNQMP_MAX_RAM_SIZE) {
109 error_report("ERROR: RAM size 0x%" PRIx64 " above max supported of "
110 "0x%llx", ram_size,
111 XLNX_ZYNQMP_MAX_RAM_SIZE);
112 exit(1);
113 }
114
115 if (ram_size < 0x08000000) {
116 qemu_log("WARNING: RAM size 0x%" PRIx64 " is small for ZCU102",
117 ram_size);
118 }
119
120 object_initialize_child(OBJECT(machine), "soc", &s->soc, sizeof(s->soc),
121 TYPE_XLNX_ZYNQMP, &error_abort, NULL);
122
123 object_property_set_link(OBJECT(&s->soc), OBJECT(machine->ram),
124 "ddr-ram", &error_abort);
125 object_property_set_bool(OBJECT(&s->soc), s->secure, "secure",
126 &error_fatal);
127 object_property_set_bool(OBJECT(&s->soc), s->virt, "virtualization",
128 &error_fatal);
129
130 object_property_set_bool(OBJECT(&s->soc), true, "realized", &error_fatal);
131
132
133 for (i = 0; i < XLNX_ZYNQMP_NUM_SDHCI; i++) {
134 BusState *bus;
135 DriveInfo *di = drive_get_next(IF_SD);
136 BlockBackend *blk = di ? blk_by_legacy_dinfo(di) : NULL;
137 DeviceState *carddev;
138 char *bus_name;
139
140 bus_name = g_strdup_printf("sd-bus%d", i);
141 bus = qdev_get_child_bus(DEVICE(&s->soc), bus_name);
142 g_free(bus_name);
143 if (!bus) {
144 error_report("No SD bus found for SD card %d", i);
145 exit(1);
146 }
147 carddev = qdev_create(bus, TYPE_SD_CARD);
148 qdev_prop_set_drive(carddev, "drive", blk, &error_fatal);
149 object_property_set_bool(OBJECT(carddev), true, "realized",
150 &error_fatal);
151 }
152
153 for (i = 0; i < XLNX_ZYNQMP_NUM_SPIS; i++) {
154 SSIBus *spi_bus;
155 DeviceState *flash_dev;
156 qemu_irq cs_line;
157 DriveInfo *dinfo = drive_get_next(IF_MTD);
158 gchar *bus_name = g_strdup_printf("spi%d", i);
159
160 spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(&s->soc), bus_name);
161 g_free(bus_name);
162
163 flash_dev = ssi_create_slave_no_init(spi_bus, "sst25wf080");
164 if (dinfo) {
165 qdev_prop_set_drive(flash_dev, "drive", blk_by_legacy_dinfo(dinfo),
166 &error_fatal);
167 }
168 qdev_init_nofail(flash_dev);
169
170 cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0);
171
172 sysbus_connect_irq(SYS_BUS_DEVICE(&s->soc.spi[i]), 1, cs_line);
173 }
174
175 for (i = 0; i < XLNX_ZYNQMP_NUM_QSPI_FLASH; i++) {
176 SSIBus *spi_bus;
177 DeviceState *flash_dev;
178 qemu_irq cs_line;
179 DriveInfo *dinfo = drive_get_next(IF_MTD);
180 int bus = i / XLNX_ZYNQMP_NUM_QSPI_BUS_CS;
181 gchar *bus_name = g_strdup_printf("qspi%d", bus);
182
183 spi_bus = (SSIBus *)qdev_get_child_bus(DEVICE(&s->soc), bus_name);
184 g_free(bus_name);
185
186 flash_dev = ssi_create_slave_no_init(spi_bus, "n25q512a11");
187 if (dinfo) {
188 qdev_prop_set_drive(flash_dev, "drive", blk_by_legacy_dinfo(dinfo),
189 &error_fatal);
190 }
191 qdev_init_nofail(flash_dev);
192
193 cs_line = qdev_get_gpio_in_named(flash_dev, SSI_GPIO_CS, 0);
194
195 sysbus_connect_irq(SYS_BUS_DEVICE(&s->soc.qspi), i + 1, cs_line);
196 }
197
198
199
200 s->binfo.ram_size = ram_size;
201 s->binfo.loader_start = 0;
202 s->binfo.modify_dtb = zcu102_modify_dtb;
203 arm_load_kernel(s->soc.boot_cpu_ptr, machine, &s->binfo);
204}
205
206static void xlnx_zcu102_machine_instance_init(Object *obj)
207{
208 XlnxZCU102 *s = ZCU102_MACHINE(obj);
209
210
211 s->secure = false;
212 object_property_add_bool(obj, "secure", zcu102_get_secure,
213 zcu102_set_secure);
214 object_property_set_description(obj, "secure",
215 "Set on/off to enable/disable the ARM "
216 "Security Extensions (TrustZone)");
217
218
219 s->virt = false;
220 object_property_add_bool(obj, "virtualization", zcu102_get_virt,
221 zcu102_set_virt);
222 object_property_set_description(obj, "virtualization",
223 "Set on/off to enable/disable emulating a "
224 "guest CPU which implements the ARM "
225 "Virtualization Extensions");
226}
227
228static void xlnx_zcu102_machine_class_init(ObjectClass *oc, void *data)
229{
230 MachineClass *mc = MACHINE_CLASS(oc);
231
232 mc->desc = "Xilinx ZynqMP ZCU102 board with 4xA53s and 2xR5Fs based on " \
233 "the value of smp";
234 mc->init = xlnx_zcu102_init;
235 mc->block_default_type = IF_IDE;
236 mc->units_per_default_bus = 1;
237 mc->ignore_memory_transaction_failures = true;
238 mc->max_cpus = XLNX_ZYNQMP_NUM_APU_CPUS + XLNX_ZYNQMP_NUM_RPU_CPUS;
239 mc->default_cpus = XLNX_ZYNQMP_NUM_APU_CPUS;
240 mc->default_ram_id = "ddr-ram";
241}
242
243static const TypeInfo xlnx_zcu102_machine_init_typeinfo = {
244 .name = MACHINE_TYPE_NAME("xlnx-zcu102"),
245 .parent = TYPE_MACHINE,
246 .class_init = xlnx_zcu102_machine_class_init,
247 .instance_init = xlnx_zcu102_machine_instance_init,
248 .instance_size = sizeof(XlnxZCU102),
249};
250
251static void xlnx_zcu102_machine_init_register_types(void)
252{
253 type_register_static(&xlnx_zcu102_machine_init_typeinfo);
254}
255
256type_init(xlnx_zcu102_machine_init_register_types)
257