master
c 139 lines 4.36 KB
Raw
1 /*
2 * NXP i.MX 8MM Evaluation Kit System Emulation
3 *
4 * Copyright (c) 2025, NXP Semiconductors
5 * Author: Gaurav Sharma <gaurav.sharma_7@nxp.com>
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
10 #include "qemu/osdep.h"
11 #include "system/address-spaces.h"
12 #include "hw/arm/boot.h"
13 #include "hw/arm/fsl-imx8mm.h"
14 #include "hw/arm/machines-qom.h"
15 #include "hw/core/boards.h"
16 #include "hw/core/qdev-properties.h"
17 #include "system/kvm.h"
18 #include "system/qtest.h"
19 #include "qemu/error-report.h"
20 #include "qapi/error.h"
21 #include <libfdt.h>
22
23 #define TYPE_IMX8MM_EVK_MACHINE MACHINE_TYPE_NAME("imx8mm-evk")
24 OBJECT_DECLARE_SIMPLE_TYPE(Imx8mmEvkMachineState, IMX8MM_EVK_MACHINE)
25
26 struct Imx8mmEvkMachineState {
27 MachineState parent;
28
29 struct arm_boot_info bootinfo;
30 };
31
32 static void imx8mm_evk_modify_dtb(const struct arm_boot_info *info, void *fdt)
33 {
34 int i, offset;
35
36 /* Temporarily disable following nodes until they are implemented */
37 const char *nodes_to_remove[] = {
38 "nxp,imx8mm-fspi",
39 "fsl,imx8mm-mipi-csi",
40 "fsl,imx8mm-mipi-dsim"
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 imx8mm_evk_init(MachineState *machine)
71 {
72 Imx8mmEvkMachineState *ims = IMX8MM_EVK_MACHINE(machine);
73 FslImx8mmState *s;
74
75 if (machine->ram_size > FSL_IMX8MM_RAM_SIZE_MAX) {
76 error_report("RAM size " RAM_ADDR_FMT " above max supported (%08" PRIx64 ")",
77 machine->ram_size, FSL_IMX8MM_RAM_SIZE_MAX);
78 exit(1);
79 }
80
81 ims->bootinfo.loader_start = FSL_IMX8MM_RAM_START;
82 ims->bootinfo.board_id = -1;
83 ims->bootinfo.ram_size = machine->ram_size;
84 ims->bootinfo.psci_conduit = QEMU_PSCI_CONDUIT_SMC;
85 ims->bootinfo.modify_dtb = imx8mm_evk_modify_dtb;
86
87 s = FSL_IMX8MM(object_new_with_props(TYPE_FSL_IMX8MM, OBJECT(machine),
88 "soc", &error_fatal, NULL));
89 object_property_set_uint(OBJECT(s), "fec1-phy-num", 1, &error_fatal);
90 sysbus_realize_and_unref(SYS_BUS_DEVICE(s), &error_fatal);
91
92 memory_region_add_subregion(get_system_memory(), FSL_IMX8MM_RAM_START,
93 machine->ram);
94
95 for (int i = 0; i < FSL_IMX8MM_NUM_USDHCS; i++) {
96 BusState *bus;
97 DeviceState *carddev;
98 BlockBackend *blk;
99 DriveInfo *di = drive_get(IF_SD, i, 0);
100
101 if (!di) {
102 continue;
103 }
104
105 blk = blk_by_legacy_dinfo(di);
106 bus = qdev_get_child_bus(DEVICE(&s->usdhc[i]), "sd-bus");
107 carddev = qdev_new(TYPE_SD_CARD);
108 qdev_prop_set_drive_err(carddev, "drive", blk, &error_fatal);
109 qdev_realize_and_unref(carddev, bus, &error_fatal);
110 }
111
112 if (!qtest_enabled()) {
113 arm_load_kernel(&s->cpu[0], machine, &ims->bootinfo);
114 }
115 }
116
117 static const char *imx8mm_evk_get_default_cpu_type(const MachineState *ms)
118 {
119 if (kvm_enabled()) {
120 return ARM_CPU_TYPE_NAME("host");
121 }
122
123 return ARM_CPU_TYPE_NAME("cortex-a53");
124 }
125
126 static void imx8mm_evk_machine_init(MachineClass *mc)
127 {
128 mc->desc = "NXP i.MX 8MM EVK Board";
129 mc->init = imx8mm_evk_init;
130 mc->max_cpus = FSL_IMX8MM_NUM_CPUS;
131 mc->default_cpus = FSL_IMX8MM_NUM_CPUS;
132 mc->default_ram_size = 2 * GiB;
133 mc->default_ram_id = "imx8mm-evk.ram";
134 mc->get_default_cpu_type = imx8mm_evk_get_default_cpu_type;
135 }
136
137 DEFINE_MACHINE_EXTENDED("imx8mm-evk", MACHINE, Imx8mmEvkMachineState,
138 imx8mm_evk_machine_init, false,
139 aarch64_machine_interfaces)