xref: /openbmc/qemu/hw/arm/aspeed_ast27x0-fc.c (revision e87b80531afbbfcfc91c9a531f821d76a0c6d096)
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