1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16#include "qemu/osdep.h"
17#include "cpu.h"
18#include "hw/boards.h"
19#include "hw/loader.h"
20#include "qapi/error.h"
21#include "hw/block/flash.h"
22#include "qemu/error-report.h"
23#include "qemu/log.h"
24#include "sysemu/qtest.h"
25#include "hw/arm/xlnx-zynqmp.h"
26
27#include <libfdt.h>
28#include "hw/fdt_generic_util.h"
29#include "hw/fdt_generic_devices.h"
30
31#ifndef ARM_GENERIC_FDT_DEBUG
32#define ARM_GENERIC_FDT_DEBUG 3
33#endif
34#define DB_PRINT(lvl, ...) do { \
35 if (ARM_GENERIC_FDT_DEBUG > (lvl)) { \
36 qemu_log_mask(LOG_FDT, ": %s: ", __func__); \
37 qemu_log_mask(LOG_FDT, ## __VA_ARGS__); \
38 } \
39} while (0);
40
41#define DB_PRINT_RAW(lvl, ...) do { \
42 if (ARM_GENERIC_FDT_DEBUG > (lvl)) { \
43 qemu_log_mask(LOG_FDT, ## __VA_ARGS__); \
44 } \
45} while (0);
46
47#define GENERAL_MACHINE_NAME "arm-generic-fdt"
48#define ZYNQ7000_MACHINE_NAME "arm-generic-fdt-7series"
49#define DEP_GENERAL_MACHINE_NAME "arm-generic-fdt-plnx"
50
51#define QTEST_RUNNING (qtest_enabled() && qtest_driver())
52
53#define MAX_CPUS 4
54
55#define ZYNQ7000_MPCORE_PERIPHBASE 0xF8F00000
56
57#define SMP_BOOT_ADDR 0xfffffff0
58
59#define SMP_BOOTREG_ADDR 0xfffffffc
60
61static struct arm_boot_info arm_generic_fdt_binfo = {};
62
63
64static uint32_t zynq_smpboot[] = {
65 0xe320f003,
66 0xeafffffd,
67};
68
69typedef struct {
70 ram_addr_t ram_kernel_base;
71 ram_addr_t ram_kernel_size;
72} memory_info;
73
74static void arm_write_secondary_boot(ARMCPU *cpu,
75 const struct arm_boot_info *info)
76{
77 int n;
78
79 for (n = 0; n < ARRAY_SIZE(zynq_smpboot); n++) {
80 zynq_smpboot[n] = tswap32(zynq_smpboot[n]);
81 }
82 rom_add_blob_fixed("smpboot", zynq_smpboot, sizeof(zynq_smpboot),
83 SMP_BOOT_ADDR);
84}
85
86static void zynq7000_usb_nuke_phy(void *fdt)
87{
88 char usb_node_path[DT_PATH_LENGTH];
89
90 int ret = qemu_devtree_node_by_compatible(fdt, usb_node_path,
91 "xlnx,ps7-usb-1.00.a");
92 if (!ret) {
93 qemu_fdt_setprop_string(fdt, usb_node_path, "dr_mode", "host");
94 }
95}
96
97static int zynq7000_mdio_phy_connect(char *node_path, FDTMachineInfo *fdti,
98 void *Opaque)
99{
100 Object *parent;
101 char parent_node_path[DT_PATH_LENGTH];
102
103
104 fdt_init_set_opaque(fdti, node_path, Opaque);
105 if (qemu_devtree_getparent(fdti->fdt, parent_node_path, node_path)) {
106 abort();
107 }
108
109
110 while (!fdt_init_has_opaque(fdti, parent_node_path)) {
111 fdt_init_yield(fdti);
112 }
113
114
115 parent = fdt_init_get_opaque(fdti, parent_node_path);
116
117
118 object_property_add_child(OBJECT(parent), "mdio_child", OBJECT(Opaque),
119 NULL);
120
121
122 object_property_set_link(OBJECT(parent), OBJECT(Opaque), "mdio", NULL);
123 return 0;
124}
125
126static int zynq7000_mdio_phy_create(char *node_path, FDTMachineInfo *fdti,
127 void *Opaque)
128{
129 bool has_mdio = false;
130 char parent_node_path[DT_PATH_LENGTH];
131 DeviceState *dev;
132 uint32_t reg;
133
134 if (qemu_devtree_getparent(fdti->fdt, parent_node_path, node_path)) {
135 abort();
136 }
137
138 if (!strcmp(qemu_devtree_get_node_name(fdti->fdt, parent_node_path),
139 "mdio")) {
140
141
142
143
144
145
146
147
148
149
150
151 has_mdio = true;
152 }
153
154 if (!has_mdio) {
155 zynq7000_mdio_phy_connect(node_path, fdti, Opaque);
156 }
157
158
159 while (!fdt_init_has_opaque(fdti, parent_node_path)) {
160 fdt_init_yield(fdti);
161 }
162
163 dev = DEVICE(object_new("88e1116r"));
164 qdev_set_parent_bus(dev, qdev_get_child_bus(Opaque, "mdio-bus"));
165 reg = qemu_fdt_getprop_cell(fdti->fdt, node_path, "reg", 0, false,
166 NULL);
167 object_property_set_int(OBJECT(dev), reg, "reg", NULL);
168 return 0;
169}
170
171static char *zynq7000_qspi_flash_node_clone(void *fdt)
172{
173 char qspi_node_path[DT_PATH_LENGTH];
174 char qspi_new_node_path[DT_PATH_LENGTH];
175 char *qspi_clone_name = NULL;
176 uint32_t val[2];
177
178
179 memset(qspi_node_path, 0, sizeof(qspi_node_path));
180 memset(qspi_new_node_path, 0, sizeof(qspi_new_node_path));
181
182
183 int ret = qemu_devtree_node_by_compatible(fdt, qspi_node_path,
184 "xlnx,zynq-qspi-1.0");
185 if (ret == 0) {
186 int qspi_is_dual = qemu_fdt_getprop_cell(fdt, qspi_node_path,
187 "is-dual", 0, false, NULL);
188
189 val[0] = cpu_to_be32(1);
190 val[1] = 0;
191 fdt_setprop(fdt, fdt_path_offset(fdt, qspi_node_path),
192 "#bus-cells", val, 4);
193
194
195 snprintf(qspi_new_node_path, DT_PATH_LENGTH, "%s/ps7-qspi-dummy@0",
196 qspi_node_path);
197
198
199 int child_num = qemu_devtree_get_num_children(fdt, qspi_node_path, 1);
200 char **child_flash = qemu_devtree_get_children(fdt, qspi_node_path, 1);
201 if (child_num > 0) {
202 char *compat_str = NULL;
203 compat_str = qemu_fdt_getprop(fdt, child_flash[0],
204 "compatible", NULL, false, NULL);
205
206 val[0] = 0;
207 val[1] = 0;
208 fdt_setprop(fdt, fdt_path_offset(fdt, child_flash[0]), "reg", val, 8);
209
210
211
212 if (compat_str != NULL) {
213 if (qspi_is_dual == 1) {
214
215 qemu_fdt_add_subnode(fdt, qspi_new_node_path);
216 qemu_fdt_setprop_string(fdt, qspi_new_node_path,
217 "compatible", compat_str);
218 qspi_clone_name = g_strdup(qspi_new_node_path);
219
220
221 val[0] = 0;
222 val[1] = cpu_to_be32(1);
223 fdt_setprop(fdt, fdt_path_offset(fdt, qspi_new_node_path),
224 "reg", val, 8);
225 }
226 g_free(compat_str);
227 }
228 }
229 g_free(child_flash);
230 }
231
232 return qspi_clone_name;
233}
234
235static memory_info init_memory(void *fdt, ram_addr_t ram_size, bool zynq_7000)
236{
237 FDTMachineInfo *fdti;
238 char node_path[DT_PATH_LENGTH];
239 MemoryRegion *mem_area;
240 memory_info kernel_info;
241 ram_addr_t start_addr;
242 int mem_offset = 0;
243
244
245 while (qemu_devtree_get_node_by_name(fdt, node_path, "memory")) {
246 qemu_fdt_add_subnode(fdt, "/memory@0");
247 qemu_fdt_setprop_cells(fdt, "/memory@0", "reg", 0, ram_size);
248 }
249
250 if (!qemu_fdt_getprop(fdt, "/memory", "compatible", NULL, 0, NULL)) {
251 qemu_fdt_setprop_string(fdt, "/memory", "compatible",
252 "qemu:memory-region");
253 qemu_fdt_setprop_cells(fdt, "/memory", "qemu,ram", 1);
254 }
255
256
257 fdti = fdt_generic_create_machine(fdt, NULL);
258
259 mem_area = MEMORY_REGION(object_resolve_path(node_path, NULL));
260 kernel_info.ram_kernel_base = object_property_get_int(OBJECT(mem_area),
261 "addr", NULL);
262 kernel_info.ram_kernel_size = object_property_get_int(OBJECT(mem_area),
263 "size", NULL);
264
265 if (zynq_7000) {
266 do {
267 mem_offset = fdt_node_offset_by_compatible(fdt, mem_offset,
268 "qemu:memory-region");
269 if (mem_offset > 0) {
270 fdt_get_path(fdt, mem_offset, node_path, DT_PATH_LENGTH);
271 mem_area = MEMORY_REGION(object_resolve_path(node_path, NULL));
272
273 if (!memory_region_is_mapped(mem_area)) {
274 start_addr = object_property_get_int(OBJECT(mem_area),
275 "addr", NULL);
276 memory_region_add_subregion(get_system_memory(),
277 start_addr, mem_area);
278 }
279 }
280 } while (mem_offset > 0);
281 } else {
282
283
284
285 uint64_t reg_value, mem_created = 0;
286 int mem_container;
287 char mem_node_path[DT_PATH_LENGTH];
288
289 do {
290 mem_offset =
291 fdt_node_offset_by_compatible(fdt, mem_offset,
292 "qemu:memory-region");
293
294
295 if (mem_offset > 0 &&
296 fdt_node_depth(fdt, mem_offset) == 1) {
297 fdt_get_path(fdt, mem_offset, mem_node_path,
298 DT_PATH_LENGTH);
299
300 mem_container = qemu_fdt_getprop_cell(fdt, mem_node_path,
301 "container",
302 0, 0, NULL);
303
304
305
306
307
308 if (mem_container != qemu_fdt_get_phandle(fdt, node_path)) {
309 continue;
310 }
311
312 DB_PRINT(0, "Found top level memory region %s\n",
313 mem_node_path);
314
315 reg_value = qemu_fdt_getprop_cell(fdt, mem_node_path,
316 "reg", 0, 0, NULL);
317 reg_value = reg_value << 32;
318 reg_value += qemu_fdt_getprop_cell(fdt, mem_node_path,
319 "reg", 1, 0, NULL);
320
321 DB_PRINT(1, " Address: 0x%" PRIx64 " ", reg_value);
322
323 reg_value += qemu_fdt_getprop_cell(fdt, mem_node_path,
324 "reg", 2, 0, NULL);
325
326 DB_PRINT_RAW(1, "Size: 0x%" PRIx64 "\n", reg_value);
327
328
329 if (mem_created < reg_value) {
330 mem_created = reg_value;
331 }
332 }
333 } while (mem_offset > 0);
334
335 DB_PRINT(0, "Highest memory address from DTS is: " \
336 "0x%" PRIx64 "/0x" RAM_ADDR_FMT "\n", mem_created, ram_size);
337
338
339 if (mem_created == 0) {
340 qemu_log_mask(LOG_GUEST_ERROR, "No memory was specified in the " \
341 "device tree, are there no memory nodes on the " \
342 "root level?\n");
343 } else if (mem_created < ram_size) {
344
345
346
347 do {
348 mem_offset =
349 fdt_node_offset_by_compatible(fdt, mem_offset,
350 "qemu:memory-region-spec");
351
352 if (mem_offset > 0) {
353 MemoryRegion *container;
354 MemoryRegion *ram_region = g_new(MemoryRegion, 1);
355 const char *region_name;
356 uint64_t region_start, region_size;
357 int container_offset, container_phandle, ram_prop;
358
359 fdt_get_path(fdt, mem_offset, mem_node_path,
360 DT_PATH_LENGTH);
361
362 DB_PRINT(0, "Connecting %s\n", mem_node_path);
363
364 region_name = fdt_get_name(fdt, mem_offset, NULL);
365
366
367 region_start = qemu_fdt_getprop_cell(fdt, mem_node_path,
368 "reg", 0, 0, NULL);
369 region_start = region_start << 32;
370 region_start += qemu_fdt_getprop_cell(fdt, mem_node_path,
371 "reg", 1, 0, NULL);
372
373 DB_PRINT(1, " Address: 0x%" PRIx64 " ", region_start);
374
375 region_size = qemu_fdt_getprop_cell(fdt, mem_node_path,
376 "reg", 2, 0, NULL);
377 region_size = region_size << 32;
378 region_size += qemu_fdt_getprop_cell(fdt, mem_node_path,
379 "reg", 3, 0, NULL);
380
381 region_size = MIN(region_size, ram_size - mem_created);
382 ram_size -= region_size;
383
384 DB_PRINT_RAW(1, "Size: 0x%" PRIx64 "\n", region_size);
385
386 container_phandle = qemu_fdt_getprop_cell(fdt,
387 mem_node_path,
388 "container", 0,
389 0, NULL);
390 container_offset =
391 fdt_node_offset_by_phandle(fdt, container_phandle);
392 fdt_get_path(fdt, container_offset,
393 node_path, DT_PATH_LENGTH);
394 container = MEMORY_REGION(
395 object_resolve_path(node_path, NULL));
396
397 ram_prop = qemu_fdt_getprop_cell(fdt, mem_node_path,
398 "qemu,ram", 0,
399 0, NULL);
400
401 memory_region_init_ram(ram_region, NULL, region_name,
402 region_size, &error_fatal);
403 object_property_set_int(OBJECT(ram_region), ram_prop,
404 "ram", &error_abort);
405 memory_region_add_subregion(container, region_start,
406 ram_region);
407 }
408 } while (mem_offset > 0 && ram_size > mem_created);
409 } else {
410
411
412
413 DB_PRINT(0, "No extra memory is required\n");
414
415 ram_size = mem_created;
416 qemu_opt_set_number(qemu_find_opts_singleton("memory"), "size",
417 mem_created, &error_fatal);
418 }
419 }
420
421 fdt_init_destroy_fdti(fdti);
422
423 return kernel_info;
424}
425
426static void arm_generic_fdt_init(MachineState *machine)
427{
428 void *fdt = NULL, *sw_fdt = NULL;
429 int fdt_size, sw_fdt_size;
430 const char *dtb_arg, *hw_dtb_arg;
431 char node_path[DT_PATH_LENGTH];
432 char *qspi_clone_spi_flash_node_name = NULL;
433 memory_info kernel_info;
434 bool zynq_7000 = false;
435
436
437 if (!strcmp(MACHINE_GET_CLASS(machine)->name, ZYNQ7000_MACHINE_NAME)) {
438 zynq_7000 = true;
439 } else if (!strcmp(MACHINE_GET_CLASS(machine)->name,
440 DEP_GENERAL_MACHINE_NAME)) {
441 if (!QTEST_RUNNING) {
442
443 fprintf(stderr, "The '" DEP_GENERAL_MACHINE_NAME "' machine has " \
444 "been deprecated and will be removed after the 2017.4 " \
445 "release.Please use '" ZYNQ7000_MACHINE_NAME \
446 "' instead.\n");
447 }
448 zynq_7000 = true;
449 }
450
451 dtb_arg = qemu_opt_get(qemu_get_machine_opts(), "dtb");
452 hw_dtb_arg = qemu_opt_get(qemu_get_machine_opts(), "hw-dtb");
453 if (!dtb_arg && !hw_dtb_arg) {
454 if (!QTEST_RUNNING) {
455
456
457
458 hw_error("DTB must be specified for %s machine model\n",
459 MACHINE_GET_CLASS(machine)->name);
460 }
461 return;
462 }
463
464
465 if (dtb_arg) {
466 sw_fdt = load_device_tree(dtb_arg, &sw_fdt_size);
467 if (!sw_fdt) {
468 error_report("Error: Unable to load Device Tree %s", dtb_arg);
469 exit(1);
470 }
471 }
472
473
474 if (hw_dtb_arg) {
475 fdt = load_device_tree(hw_dtb_arg, &fdt_size);
476 if (!fdt) {
477 error_report("Error: Unable to load Device Tree %s", hw_dtb_arg);
478 exit(1);
479 }
480 } else if (sw_fdt) {
481 fdt = sw_fdt;
482 fdt_size = sw_fdt_size;
483 }
484
485 if (zynq_7000) {
486 int node_offset = 0;
487
488
489 qspi_clone_spi_flash_node_name = zynq7000_qspi_flash_node_clone(fdt);
490
491
492 if (!qemu_devtree_get_node_by_name(fdt, node_path,
493 "interrupt-controller")) {
494 qemu_fdt_setprop_cells(fdt, node_path,
495 "disable-linux-gic-init", true);
496 }
497
498
499
500
501
502
503 do {
504 node_offset = fdt_node_offset_by_compatible(fdt, node_offset,
505 "arm,cortex-a9");
506 if (node_offset > 0) {
507 fdt_get_path(fdt, node_offset, node_path, DT_PATH_LENGTH);
508 qemu_fdt_setprop_cells(fdt, node_path, "reset-cbar",
509 ZYNQ7000_MPCORE_PERIPHBASE);
510 }
511 } while (node_offset > 0);
512 }
513
514 kernel_info = init_memory(fdt, machine->ram_size, zynq_7000);
515
516 arm_generic_fdt_binfo.fdt = sw_fdt;
517 arm_generic_fdt_binfo.fdt_size = sw_fdt_size;
518 arm_generic_fdt_binfo.ram_size = kernel_info.ram_kernel_size;
519 arm_generic_fdt_binfo.kernel_filename = machine->kernel_filename;
520 arm_generic_fdt_binfo.kernel_cmdline = machine->kernel_cmdline;
521 arm_generic_fdt_binfo.initrd_filename = machine->initrd_filename;
522 arm_generic_fdt_binfo.nb_cpus = fdt_generic_num_cpus;
523 arm_generic_fdt_binfo.write_secondary_boot = arm_write_secondary_boot;
524 arm_generic_fdt_binfo.smp_loader_start = SMP_BOOT_ADDR;
525 arm_generic_fdt_binfo.smp_bootreg_addr = SMP_BOOTREG_ADDR;
526 arm_generic_fdt_binfo.board_id = 0xd32;
527 arm_generic_fdt_binfo.loader_start = kernel_info.ram_kernel_base;
528 arm_generic_fdt_binfo.secure_boot = true;
529
530 if (qspi_clone_spi_flash_node_name != NULL) {
531
532 int offset = fdt_path_offset(fdt, qspi_clone_spi_flash_node_name);
533 fdt_del_node(fdt, offset);
534 g_free(qspi_clone_spi_flash_node_name);
535 }
536
537 if (zynq_7000) {
538 zynq7000_usb_nuke_phy(fdt);
539 }
540
541 if (machine->kernel_filename) {
542 arm_load_kernel(ARM_CPU(first_cpu), &arm_generic_fdt_binfo);
543 }
544
545 return;
546}
547
548static void arm_generic_fdt_7000_init(MachineState *machine)
549{
550 MemoryRegion *address_space_mem = get_system_memory();
551 DeviceState *dev;
552 SysBusDevice *busdev;
553 MemoryRegion *ocm_ram;
554 DriveInfo *dinfo;
555 DeviceState *att_dev;
556
557 ocm_ram = g_new(MemoryRegion, 1);
558 memory_region_init_ram(ocm_ram, NULL, "zynq.ocm_ram", 256 << 10,
559 &error_abort);
560 vmstate_register_ram_global(ocm_ram);
561 memory_region_add_subregion(address_space_mem, 0xFFFC0000, ocm_ram);
562
563 dev = qdev_create(NULL, "arm.pl35x");
564 object_property_add_child(container_get(qdev_get_machine(), "/unattached"),
565 "pl353", OBJECT(dev), NULL);
566 qdev_prop_set_uint8(dev, "x", 3);
567 dinfo = drive_get_next(IF_PFLASH);
568 att_dev = nand_init(dinfo ? blk_by_legacy_dinfo(dinfo)
569 : NULL,
570 NAND_MFR_STMICRO, 0xaa);
571 object_property_set_link(OBJECT(dev), OBJECT(att_dev), "dev1",
572 &error_abort);
573
574 qdev_init_nofail(dev);
575 busdev = SYS_BUS_DEVICE(dev);
576 sysbus_mmio_map(busdev, 0, 0xe000e000);
577 sysbus_mmio_map(busdev, 2, 0xe1000000);
578
579
580 add_to_compat_table(NULL, "compatible:simple-bus", NULL);
581
582 dev = qdev_create(NULL, "mdio");
583 qdev_init_nofail(dev);
584
585 add_to_inst_bind_table(zynq7000_mdio_phy_connect, "mdio", dev);
586 add_to_compat_table(zynq7000_mdio_phy_create, "device_type:ethernet-phy",
587 dev);
588
589 arm_generic_fdt_init(machine);
590
591 dev = qdev_create(NULL, "a9-scu");
592 busdev = SYS_BUS_DEVICE(dev);
593 qdev_prop_set_uint32(dev, "num-cpu", fdt_generic_num_cpus);
594 qdev_init_nofail(dev);
595 sysbus_mmio_map(busdev, 0, ZYNQ7000_MPCORE_PERIPHBASE);
596}
597
598static void arm_generic_fdt_machine_init(MachineClass *mc)
599{
600 mc->desc = "ARM device tree driven machine model";
601 mc->init = arm_generic_fdt_init;
602 mc->max_cpus = MAX_CPUS;
603}
604
605static void arm_generic_fdt_7000_machine_init(MachineClass *mc)
606{
607 mc->desc = "ARM device tree driven machine model for the Zynq-7000";
608 mc->init = arm_generic_fdt_7000_init;
609 mc->max_cpus = MAX_CPUS;
610}
611
612
613static void arm_generic_fdt_dep_machine_init(MachineClass *mc)
614{
615 mc->desc = "Deprecated ARM device tree driven machine for the Zynq-7000";
616 mc->init = arm_generic_fdt_7000_init;
617 mc->max_cpus = MAX_CPUS;
618}
619
620fdt_register_compatibility_opaque(pflash_cfi01_fdt_init,
621 "compatibile:cfi-flash", 0, NULL);
622
623DEFINE_MACHINE(GENERAL_MACHINE_NAME, arm_generic_fdt_machine_init)
624DEFINE_MACHINE(ZYNQ7000_MACHINE_NAME, arm_generic_fdt_7000_machine_init)
625DEFINE_MACHINE(DEP_GENERAL_MACHINE_NAME, arm_generic_fdt_dep_machine_init)
626