master
c 169 lines 5.22 KB
Raw
1 /*
2 * NXP i.MX 8M Plus Evaluation Kit System Emulation
3 *
4 * Copyright (c) 2024, Bernhard Beschow <shentey@gmail.com>
5 *
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
8
9 #include "qemu/osdep.h"
10 #include "system/address-spaces.h"
11 #include "hw/arm/boot.h"
12 #include "hw/arm/fsl-imx8mp.h"
13 #include "hw/arm/machines-qom.h"
14 #include "hw/core/boards.h"
15 #include "hw/core/qdev-properties.h"
16 #include "system/kvm.h"
17 #include "system/qtest.h"
18 #include "qemu/error-report.h"
19 #include "qapi/error.h"
20 #include <libfdt.h>
21
22 #define TYPE_IMX8MPEVK_MACHINE MACHINE_TYPE_NAME("imx8mp-evk")
23 OBJECT_DECLARE_SIMPLE_TYPE(FslImx8mpEvkState, IMX8MPEVK_MACHINE)
24
25 struct FslImx8mpEvkState {
26 MachineState parent_obj;
27
28 FslImx8mpState soc;
29 CanBusState *canbus[FSL_IMX8MP_NUM_CANS];
30
31 struct arm_boot_info boot_info;
32 };
33
34 static void imx8mp_evk_modify_dtb(const struct arm_boot_info *info, void *fdt)
35 {
36 int i, offset;
37
38 /* Temporarily disable following nodes until they are implemented */
39 const char *nodes_to_remove[] = {
40 "nxp,imx8mp-fspi",
41 };
42
43 for (i = 0; i < ARRAY_SIZE(nodes_to_remove); i++) {
44 const char *dev_str = nodes_to_remove[i];
45
46 offset = fdt_node_offset_by_compatible(fdt, -1, dev_str);
47 while (offset >= 0) {
48 fdt_nop_node(fdt, offset);
49 offset = fdt_node_offset_by_compatible(fdt, offset, dev_str);
50 }
51 }
52
53 /* Remove cpu-idle-states property from CPU nodes */
54 offset = fdt_node_offset_by_compatible(fdt, -1, "arm,cortex-a53");
55 while (offset >= 0) {
56 fdt_nop_property(fdt, offset, "cpu-idle-states");
57 offset = fdt_node_offset_by_compatible(fdt, offset, "arm,cortex-a53");
58 }
59
60 if (kvm_enabled()) {
61 /* Use system counter frequency from host CPU to fix time in guest */
62 offset = fdt_node_offset_by_compatible(fdt, -1, "arm,armv8-timer");
63 while (offset >= 0) {
64 fdt_nop_property(fdt, offset, "clock-frequency");
65 offset = fdt_node_offset_by_compatible(fdt, offset, "arm,armv8-timer");
66 }
67 }
68 }
69
70 static void imx8mp_evk_init(MachineState *machine)
71 {
72 FslImx8mpEvkState *s = IMX8MPEVK_MACHINE(machine);
73
74 if (machine->ram_size > FSL_IMX8MP_RAM_SIZE_MAX) {
75 error_report("RAM size " RAM_ADDR_FMT " above max supported (%08" PRIx64 ")",
76 machine->ram_size, FSL_IMX8MP_RAM_SIZE_MAX);
77 exit(1);
78 }
79
80 s->boot_info = (struct arm_boot_info) {
81 .loader_start = FSL_IMX8MP_RAM_START,
82 .board_id = -1,
83 .ram_size = machine->ram_size,
84 .psci_conduit = QEMU_PSCI_CONDUIT_SMC,
85 .modify_dtb = imx8mp_evk_modify_dtb,
86 };
87
88 object_initialize_child(OBJECT(machine), "soc", &s->soc, TYPE_FSL_IMX8MP);
89 object_property_set_uint(OBJECT(&s->soc), "fec1-phy-num", 1, &error_fatal);
90 for (int i = 0; i < FSL_IMX8MP_NUM_CANS; i++) {
91 g_autofree char *bus_name = g_strdup_printf("canbus%d", i);
92
93 object_property_set_link(OBJECT(&s->soc), bus_name,
94 OBJECT(s->canbus[i]), &error_fatal);
95 }
96 sysbus_realize_and_unref(SYS_BUS_DEVICE(&s->soc), &error_fatal);
97
98 memory_region_add_subregion(get_system_memory(), FSL_IMX8MP_RAM_START,
99 machine->ram);
100
101 for (int i = 0; i < FSL_IMX8MP_NUM_USDHCS; i++) {
102 BusState *bus;
103 DeviceState *carddev;
104 BlockBackend *blk;
105 DriveInfo *di = drive_get(IF_SD, i, 0);
106
107 if (!di) {
108 continue;
109 }
110
111 blk = blk_by_legacy_dinfo(di);
112 bus = qdev_get_child_bus(DEVICE(&s->soc.usdhc[i]), "sd-bus");
113 carddev = qdev_new(TYPE_SD_CARD);
114 qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal);
115 qdev_realize_and_unref(carddev, bus, &error_fatal);
116 }
117
118 if (!qtest_enabled()) {
119 arm_load_kernel(&s->soc.cpu[0], machine, &s->boot_info);
120 }
121 }
122
123 static const char *imx8mp_evk_get_default_cpu_type(const MachineState *ms)
124 {
125 if (kvm_enabled()) {
126 return ARM_CPU_TYPE_NAME("host");
127 }
128
129 return ARM_CPU_TYPE_NAME("cortex-a53");
130 }
131
132 static void imx8mp_evk_machine_init(Object *obj)
133 {
134 FslImx8mpEvkState *s = IMX8MPEVK_MACHINE(obj);
135
136 object_property_add_link(obj, "canbus0", TYPE_CAN_BUS,
137 (Object **)&s->canbus[0],
138 object_property_allow_set_link, 0);
139
140 object_property_add_link(obj, "canbus1", TYPE_CAN_BUS,
141 (Object **)&s->canbus[1],
142 object_property_allow_set_link, 0);
143 }
144
145 static void imx8mp_evk_machine_class_init(ObjectClass *oc, const void *data)
146 {
147 MachineClass *mc = MACHINE_CLASS(oc);
148
149 mc->desc = "NXP i.MX 8M Plus EVK Board";
150 mc->init = imx8mp_evk_init;
151 mc->default_cpus = 4;
152 mc->max_cpus = FSL_IMX8MP_NUM_CPUS;
153 mc->default_ram_id = "imx8mp-evk.ram";
154 mc->default_ram_size = 6 * GiB;
155 mc->get_default_cpu_type = imx8mp_evk_get_default_cpu_type;
156 }
157
158 static const TypeInfo imx8mp_evk_machine_types[] = {
159 {
160 .name = TYPE_IMX8MPEVK_MACHINE,
161 .parent = TYPE_MACHINE,
162 .class_init = imx8mp_evk_machine_class_init,
163 .instance_init = imx8mp_evk_machine_init,
164 .instance_size = sizeof(FslImx8mpEvkState),
165 .interfaces = aarch64_machine_interfaces,
166 },
167 };
168
169 DEFINE_TYPES(imx8mp_evk_machine_types)