1 /*
2 * ASPEED SoC 2700 family
3 *
4 * Copyright (C) 2025 ASPEED Technology Inc.
5 *
6 * This code is licensed under the GPL version 2 or later. See
7 * the COPYING file in the top-level directory.
8 *
9 * SPDX-License-Identifier: GPL-2.0-or-later
10 */
11
12 #include "qemu/osdep.h"
13 #include "qemu/units.h"
14 #include "qemu/datadir.h"
15 #include "qapi/error.h"
16 #include "system/block-backend.h"
17 #include "system/system.h"
18 #include "hw/arm/aspeed.h"
19 #include "hw/boards.h"
20 #include "hw/qdev-clock.h"
21 #include "hw/arm/aspeed_soc.h"
22 #include "hw/loader.h"
23 #include "hw/arm/boot.h"
24 #include "hw/block/flash.h"
25
26
27 #define TYPE_AST2700A1FC MACHINE_TYPE_NAME("ast2700fc")
28 OBJECT_DECLARE_SIMPLE_TYPE(Ast2700FCState, AST2700A1FC);
29
30 static struct arm_boot_info ast2700fc_board_info = {
31 .board_id = -1, /* device-tree-only board */
32 };
33
34 struct Ast2700FCState {
35 MachineState parent_obj;
36
37 MemoryRegion ca35_memory;
38 MemoryRegion ca35_dram;
39 MemoryRegion ca35_boot_rom;
40
41 Aspeed27x0SoCState ca35;
42
43 bool mmio_exec;
44 };
45
46 #define AST2700FC_BMC_RAM_SIZE (1 * GiB)
47
48 #define AST2700FC_HW_STRAP1 0x000000C0
49 #define AST2700FC_HW_STRAP2 0x00000003
50 #define AST2700FC_FMC_MODEL "w25q01jvq"
51 #define AST2700FC_SPI_MODEL "w25q512jv"
52 #define VBOOTROM_FILE_NAME "ast27x0_bootrom.bin"
53
ast2700fc_ca35_load_vbootrom(AspeedSoCState * soc,const char * bios_name,Error ** errp)54 static void ast2700fc_ca35_load_vbootrom(AspeedSoCState *soc,
55 const char *bios_name, Error **errp)
56 {
57 g_autofree char *filename = NULL;
58 int ret;
59
60 filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
61 if (!filename) {
62 error_setg(errp, "Could not find vbootrom image '%s'", bios_name);
63 return;
64 }
65
66 ret = load_image_mr(filename, &soc->vbootrom);
67 if (ret < 0) {
68 error_setg(errp, "Failed to load vbootrom image '%s'", bios_name);
69 return;
70 }
71 }
72
ast2700fc_ca35_write_boot_rom(DriveInfo * dinfo,hwaddr addr,size_t rom_size,Error ** errp)73 static void ast2700fc_ca35_write_boot_rom(DriveInfo *dinfo, hwaddr addr,
74 size_t rom_size, Error **errp)
75 {
76 BlockBackend *blk = blk_by_legacy_dinfo(dinfo);
77 g_autofree void *storage = NULL;
78 int64_t size;
79
80 /*
81 * The block backend size should have already been 'validated' by
82 * the creation of the m25p80 object.
83 */
84 size = blk_getlength(blk);
85 if (size <= 0) {
86 error_setg(errp, "failed to get flash size");
87 return;
88 }
89
90 if (rom_size > size) {
91 rom_size = size;
92 }
93
94 storage = g_malloc0(rom_size);
95 if (blk_pread(blk, 0, rom_size, storage, 0) < 0) {
96 error_setg(errp, "failed to read the initial flash content");
97 return;
98 }
99
100 rom_add_blob_fixed("aspeed.boot_rom", storage, rom_size, addr);
101 }
102
ast2700fc_ca35_init(MachineState * machine)103 static void ast2700fc_ca35_init(MachineState *machine)
104 {
105 Ast2700FCState *s = AST2700A1FC(machine);
106 const char *bios_name = NULL;
107 AspeedSoCState *soc;
108 AspeedSoCClass *sc;
109 uint64_t rom_size;
110 DriveInfo *mtd0;
111
112 object_initialize_child(OBJECT(s), "ca35", &s->ca35, "ast2700-a1");
113 soc = ASPEED_SOC(&s->ca35);
114 sc = ASPEED_SOC_GET_CLASS(soc);
115
116 memory_region_init(&s->ca35_memory, OBJECT(&s->ca35), "ca35-memory",
117 UINT64_MAX);
118 memory_region_add_subregion(get_system_memory(), 0, &s->ca35_memory);
119
120 if (!memory_region_init_ram(&s->ca35_dram, OBJECT(&s->ca35), "ca35-dram",
121 AST2700FC_BMC_RAM_SIZE, &error_abort)) {
122 return;
123 }
124 if (!object_property_set_link(OBJECT(&s->ca35), "memory",
125 OBJECT(&s->ca35_memory),
126 &error_abort)) {
127 return;
128 };
129 if (!object_property_set_link(OBJECT(&s->ca35), "dram",
130 OBJECT(&s->ca35_dram), &error_abort)) {
131 return;
132 }
133 if (!object_property_set_int(OBJECT(&s->ca35), "ram-size",
134 AST2700FC_BMC_RAM_SIZE, &error_abort)) {
135 return;
136 }
137
138 for (int i = 0; i < sc->macs_num; i++) {
139 if (!qemu_configure_nic_device(DEVICE(&soc->ftgmac100[i]),
140 true, NULL)) {
141 break;
142 }
143 }
144 if (!object_property_set_int(OBJECT(&s->ca35), "hw-strap1",
145 AST2700FC_HW_STRAP1, &error_abort)) {
146 return;
147 }
148 if (!object_property_set_int(OBJECT(&s->ca35), "hw-strap2",
149 AST2700FC_HW_STRAP2, &error_abort)) {
150 return;
151 }
152 aspeed_soc_uart_set_chr(soc, ASPEED_DEV_UART12, serial_hd(0));
153 aspeed_soc_uart_set_chr(ASPEED_SOC(&s->ca35.ssp), ASPEED_DEV_UART4,
154 serial_hd(1));
155 aspeed_soc_uart_set_chr(ASPEED_SOC(&s->ca35.tsp), ASPEED_DEV_UART7,
156 serial_hd(2));
157 if (!qdev_realize(DEVICE(&s->ca35), NULL, &error_abort)) {
158 return;
159 }
160
161 /*
162 * AST2700 EVB has a LM75 temperature sensor on I2C bus 0 at address 0x4d.
163 */
164 i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 0), "tmp105", 0x4d);
165
166 aspeed_board_init_flashes(&soc->fmc, AST2700FC_FMC_MODEL, 2, 0);
167 aspeed_board_init_flashes(&soc->spi[0], AST2700FC_SPI_MODEL, 1, 2);
168
169 ast2700fc_board_info.ram_size = machine->ram_size;
170 ast2700fc_board_info.loader_start = sc->memmap[ASPEED_DEV_SDRAM];
171
172 /* Install first FMC flash content as a boot rom. */
173 if (!s->mmio_exec) {
174 mtd0 = drive_get(IF_MTD, 0, 0);
175
176 if (mtd0) {
177 rom_size = memory_region_size(&soc->spi_boot);
178 memory_region_init_rom(&s->ca35_boot_rom, NULL, "aspeed.boot_rom",
179 rom_size, &error_abort);
180 memory_region_add_subregion_overlap(&soc->spi_boot_container, 0,
181 &s->ca35_boot_rom, 1);
182 ast2700fc_ca35_write_boot_rom(mtd0,
183 sc->memmap[ASPEED_DEV_SPI_BOOT],
184 rom_size, &error_abort);
185 }
186 }
187
188 /* VBOOTROM */
189 bios_name = machine->firmware ?: VBOOTROM_FILE_NAME;
190 ast2700fc_ca35_load_vbootrom(soc, bios_name, &error_abort);
191
192 arm_load_kernel(ARM_CPU(first_cpu), machine, &ast2700fc_board_info);
193 }
194
ast2700fc_init(MachineState * machine)195 static void ast2700fc_init(MachineState *machine)
196 {
197 ast2700fc_ca35_init(machine);
198 }
199
ast2700fc_class_init(ObjectClass * oc,const void * data)200 static void ast2700fc_class_init(ObjectClass *oc, const void *data)
201 {
202 MachineClass *mc = MACHINE_CLASS(oc);
203
204 mc->alias = "ast2700fc";
205 mc->desc = "ast2700 full core support";
206 mc->init = ast2700fc_init;
207 mc->no_floppy = 1;
208 mc->no_cdrom = 1;
209 mc->min_cpus = mc->max_cpus = mc->default_cpus = 6;
210 }
211
212 static const TypeInfo ast2700fc_types[] = {
213 {
214 .name = MACHINE_TYPE_NAME("ast2700fc"),
215 .parent = TYPE_MACHINE,
216 .class_init = ast2700fc_class_init,
217 .instance_size = sizeof(Ast2700FCState),
218 },
219 };
220
221 DEFINE_TYPES(ast2700fc_types)
222