xref: /openbmc/qemu/hw/arm/aspeed_ast27x0-fc.c (revision 19777184e8e8a0336da853eef8e55ba7cc974787)
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     MemoryRegion tsp_memory;
41 
42     Clock *tsp_sysclk;
43 
44     Aspeed27x0SoCState ca35;
45     Aspeed27x0TSPSoCState tsp;
46 
47     bool mmio_exec;
48 };
49 
50 #define AST2700FC_BMC_RAM_SIZE (1 * GiB)
51 #define AST2700FC_CM4_DRAM_SIZE (32 * MiB)
52 
53 #define AST2700FC_HW_STRAP1 0x000000C0
54 #define AST2700FC_HW_STRAP2 0x00000003
55 #define AST2700FC_FMC_MODEL "w25q01jvq"
56 #define AST2700FC_SPI_MODEL "w25q512jv"
57 #define VBOOTROM_FILE_NAME  "ast27x0_bootrom.bin"
58 
59 static void ast2700fc_ca35_load_vbootrom(AspeedSoCState *soc,
60                                          const char *bios_name, Error **errp)
61 {
62     g_autofree char *filename = NULL;
63     int ret;
64 
65     filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name);
66     if (!filename) {
67         error_setg(errp, "Could not find vbootrom image '%s'", bios_name);
68         return;
69     }
70 
71     ret = load_image_mr(filename, &soc->vbootrom);
72     if (ret < 0) {
73         error_setg(errp, "Failed to load vbootrom image '%s'", bios_name);
74         return;
75     }
76 }
77 
78 static void ast2700fc_ca35_write_boot_rom(DriveInfo *dinfo, hwaddr addr,
79                                          size_t rom_size, Error **errp)
80 {
81     BlockBackend *blk = blk_by_legacy_dinfo(dinfo);
82     g_autofree void *storage = NULL;
83     int64_t size;
84 
85     /*
86      * The block backend size should have already been 'validated' by
87      * the creation of the m25p80 object.
88      */
89     size = blk_getlength(blk);
90     if (size <= 0) {
91         error_setg(errp, "failed to get flash size");
92         return;
93     }
94 
95     if (rom_size > size) {
96         rom_size = size;
97     }
98 
99     storage = g_malloc0(rom_size);
100     if (blk_pread(blk, 0, rom_size, storage, 0) < 0) {
101         error_setg(errp, "failed to read the initial flash content");
102         return;
103     }
104 
105     rom_add_blob_fixed("aspeed.boot_rom", storage, rom_size, addr);
106 }
107 
108 static void ast2700fc_ca35_init(MachineState *machine)
109 {
110     Ast2700FCState *s = AST2700A1FC(machine);
111     const char *bios_name = NULL;
112     AspeedSoCState *soc;
113     AspeedSoCClass *sc;
114     uint64_t rom_size;
115     DriveInfo *mtd0;
116 
117     object_initialize_child(OBJECT(s), "ca35", &s->ca35, "ast2700-a1");
118     soc = ASPEED_SOC(&s->ca35);
119     sc = ASPEED_SOC_GET_CLASS(soc);
120 
121     memory_region_init(&s->ca35_memory, OBJECT(&s->ca35), "ca35-memory",
122                        UINT64_MAX);
123     memory_region_add_subregion(get_system_memory(), 0, &s->ca35_memory);
124 
125     if (!memory_region_init_ram(&s->ca35_dram, OBJECT(&s->ca35), "ca35-dram",
126                                 AST2700FC_BMC_RAM_SIZE, &error_abort)) {
127         return;
128     }
129     if (!object_property_set_link(OBJECT(&s->ca35), "memory",
130                                   OBJECT(&s->ca35_memory),
131                                   &error_abort)) {
132         return;
133     };
134     if (!object_property_set_link(OBJECT(&s->ca35), "dram",
135                                   OBJECT(&s->ca35_dram), &error_abort)) {
136         return;
137     }
138     if (!object_property_set_int(OBJECT(&s->ca35), "ram-size",
139                                  AST2700FC_BMC_RAM_SIZE, &error_abort)) {
140         return;
141     }
142 
143     for (int i = 0; i < sc->macs_num; i++) {
144         if (!qemu_configure_nic_device(DEVICE(&soc->ftgmac100[i]),
145                                        true, NULL)) {
146             break;
147         }
148     }
149     if (!object_property_set_int(OBJECT(&s->ca35), "hw-strap1",
150                                  AST2700FC_HW_STRAP1, &error_abort)) {
151         return;
152     }
153     if (!object_property_set_int(OBJECT(&s->ca35), "hw-strap2",
154                                  AST2700FC_HW_STRAP2, &error_abort)) {
155         return;
156     }
157     aspeed_soc_uart_set_chr(soc, ASPEED_DEV_UART12, serial_hd(0));
158     aspeed_soc_uart_set_chr(ASPEED_SOC(&s->ca35.ssp), ASPEED_DEV_UART4,
159                             serial_hd(1));
160     if (!qdev_realize(DEVICE(&s->ca35), NULL, &error_abort)) {
161         return;
162     }
163 
164     /*
165      * AST2700 EVB has a LM75 temperature sensor on I2C bus 0 at address 0x4d.
166      */
167     i2c_slave_create_simple(aspeed_i2c_get_bus(&soc->i2c, 0), "tmp105", 0x4d);
168 
169     aspeed_board_init_flashes(&soc->fmc, AST2700FC_FMC_MODEL, 2, 0);
170     aspeed_board_init_flashes(&soc->spi[0], AST2700FC_SPI_MODEL, 1, 2);
171 
172     ast2700fc_board_info.ram_size = machine->ram_size;
173     ast2700fc_board_info.loader_start = sc->memmap[ASPEED_DEV_SDRAM];
174 
175     /* Install first FMC flash content as a boot rom. */
176     if (!s->mmio_exec) {
177         mtd0 = drive_get(IF_MTD, 0, 0);
178 
179         if (mtd0) {
180             rom_size = memory_region_size(&soc->spi_boot);
181             memory_region_init_rom(&s->ca35_boot_rom, NULL, "aspeed.boot_rom",
182                                    rom_size, &error_abort);
183             memory_region_add_subregion_overlap(&soc->spi_boot_container, 0,
184                                                 &s->ca35_boot_rom, 1);
185             ast2700fc_ca35_write_boot_rom(mtd0,
186                                           sc->memmap[ASPEED_DEV_SPI_BOOT],
187                                           rom_size, &error_abort);
188         }
189     }
190 
191     /* VBOOTROM */
192     bios_name = machine->firmware ?: VBOOTROM_FILE_NAME;
193     ast2700fc_ca35_load_vbootrom(soc, bios_name, &error_abort);
194 
195     arm_load_kernel(ARM_CPU(first_cpu), machine, &ast2700fc_board_info);
196 }
197 
198 static void ast2700fc_tsp_init(MachineState *machine)
199 {
200     AspeedSoCState *soc;
201     Ast2700FCState *s = AST2700A1FC(machine);
202     s->tsp_sysclk = clock_new(OBJECT(s), "TSP_SYSCLK");
203     clock_set_hz(s->tsp_sysclk, 200000000ULL);
204 
205     object_initialize_child(OBJECT(s), "tsp", &s->tsp, TYPE_ASPEED27X0TSP_SOC);
206     memory_region_init(&s->tsp_memory, OBJECT(&s->tsp), "tsp-memory",
207                        UINT64_MAX);
208 
209     qdev_connect_clock_in(DEVICE(&s->tsp), "sysclk", s->tsp_sysclk);
210     if (!object_property_set_link(OBJECT(&s->tsp), "memory",
211                                   OBJECT(&s->tsp_memory), &error_abort)) {
212         return;
213     }
214 
215     soc = ASPEED_SOC(&s->tsp);
216     aspeed_soc_uart_set_chr(soc, ASPEED_DEV_UART7, serial_hd(2));
217     if (!qdev_realize(DEVICE(&s->tsp), NULL, &error_abort)) {
218         return;
219     }
220 }
221 
222 static void ast2700fc_init(MachineState *machine)
223 {
224     ast2700fc_ca35_init(machine);
225     ast2700fc_tsp_init(machine);
226 }
227 
228 static void ast2700fc_class_init(ObjectClass *oc, const void *data)
229 {
230     MachineClass *mc = MACHINE_CLASS(oc);
231 
232     mc->alias = "ast2700fc";
233     mc->desc = "ast2700 full core support";
234     mc->init = ast2700fc_init;
235     mc->no_floppy = 1;
236     mc->no_cdrom = 1;
237     mc->min_cpus = mc->max_cpus = mc->default_cpus = 6;
238 }
239 
240 static const TypeInfo ast2700fc_types[] = {
241     {
242         .name           = MACHINE_TYPE_NAME("ast2700fc"),
243         .parent         = TYPE_MACHINE,
244         .class_init     = ast2700fc_class_init,
245         .instance_size  = sizeof(Ast2700FCState),
246     },
247 };
248 
249 DEFINE_TYPES(ast2700fc_types)
250