blob: 755b9ecd4074cec3a90bee406a212393cd343043 [file] [log] [blame]
Tom Rinidec7ea02024-05-20 13:35:03 -06001// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) 2024 PHYTEC Messtechnik GmbH
4 * Author: Wadim Egorov <w.egorov@phytec.de>
5 */
6
Wadim Egorov648d2852024-11-27 13:17:35 +01007#include <efi_loader.h>
Tom Rinidec7ea02024-05-20 13:35:03 -06008#include <env_internal.h>
Wadim Egorov4baf2a62024-06-10 15:33:42 +02009#include <fdt_support.h>
Wadim Egorov94d92522024-10-30 17:48:15 +010010#include <dm/ofnode.h>
Wadim Egorov648d2852024-11-27 13:17:35 +010011#include <mtd.h>
Tom Rinidec7ea02024-05-20 13:35:03 -060012#include <spl.h>
Wadim Egorov94d92522024-10-30 17:48:15 +010013#include <malloc.h>
Tom Rinidec7ea02024-05-20 13:35:03 -060014#include <asm/arch/hardware.h>
15
Daniel Schultz80677cb2024-05-21 23:18:26 -070016#include "../am6_som_detection.h"
17
Wadim Egorov648d2852024-11-27 13:17:35 +010018#if IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT)
19struct efi_fw_image fw_images[] = {
20 {
21 .fw_name = PHYCORE_AM6XX_FW_NAME_TIBOOT3,
22 .image_index = 1,
23 },
24 {
25 .fw_name = PHYCORE_AM6XX_FW_NAME_SPL,
26 .image_index = 2,
27 },
28 {
29 .fw_name = PHYCORE_AM6XX_FW_NAME_UBOOT,
30 .image_index = 3,
31 }
32};
33
34struct efi_capsule_update_info update_info = {
35 .dfu_string = NULL,
36 .num_images = ARRAY_SIZE(fw_images),
37 .images = fw_images,
38};
39
40/**
41 * configure_capsule_updates() - Set up the DFU string for capsule updates
42 *
43 * Configures all three bootloader binaries for updates on the current
44 * booted flash device, which may be eMMC, OSPI NOR, or a uSD card. If
45 * booting from USB or Serial, capsule updates will be performed on the
46 * eMMC device.
47 *
48 * Note: Currently, eMMC hardware partitions are not differentiated; Updates
49 * are always applied to the first boot partition.
50 */
Wadim Egorov58ec1832025-03-05 05:58:35 +010051static void configure_capsule_updates(void)
Wadim Egorov648d2852024-11-27 13:17:35 +010052{
53 static char dfu_string[128] = { 0 };
54 const char *dfu_raw = "tiboot3.bin raw 0x0 0x400 mmcpart 1;"
55 "tispl.bin raw 0x400 0x1000 mmcpart 1;"
56 "u-boot.img.raw raw 0x1400 0x2000 mmcpart 1";
57 const char *dfu_fat = "tiboot3.bin fat 1 1;"
58 "tispl.bin fat 1 1;"
59 "u-boot.img fat 1 1";
60 const char *dfu_spi = "tiboot3.bin part 1;"
61 "tispl.bin part 2;"
62 "u-boot.img part 3";
63 u32 boot_device = get_boot_device();
64
65 switch (boot_device) {
66 case BOOT_DEVICE_MMC1:
67 snprintf(dfu_string, 128, "mmc 0=%s", dfu_raw);
68 break;
69 case BOOT_DEVICE_MMC2:
70 snprintf(dfu_string, 128, "mmc 1=%s", dfu_fat);
71 break;
72 case BOOT_DEVICE_SPI:
73 mtd_probe_devices();
74 snprintf(dfu_string, 128, "mtd nor0=%s", dfu_spi);
75 break;
76 default:
77 snprintf(dfu_string, 128, "mmc 0=%s", dfu_raw);
78 break;
79 };
80
81 update_info.dfu_string = dfu_string;
82}
83#endif
84
Tom Rinidec7ea02024-05-20 13:35:03 -060085#if IS_ENABLED(CONFIG_ENV_IS_IN_FAT) || IS_ENABLED(CONFIG_ENV_IS_IN_MMC)
86int mmc_get_env_dev(void)
87{
88 u32 boot_device = get_boot_device();
89
90 switch (boot_device) {
91 case BOOT_DEVICE_MMC1:
92 return 0;
93 case BOOT_DEVICE_MMC2:
94 return 1;
95 };
96
97 return CONFIG_SYS_MMC_ENV_DEV;
98}
99#endif
100
101enum env_location env_get_location(enum env_operation op, int prio)
102{
103 u32 boot_device = get_boot_device();
104
105 if (prio)
106 return ENVL_UNKNOWN;
107
108 switch (boot_device) {
109 case BOOT_DEVICE_MMC1:
110 case BOOT_DEVICE_MMC2:
111 if (CONFIG_IS_ENABLED(ENV_IS_IN_FAT))
112 return ENVL_FAT;
113 if (CONFIG_IS_ENABLED(ENV_IS_IN_MMC))
114 return ENVL_MMC;
115 case BOOT_DEVICE_SPI:
116 if (CONFIG_IS_ENABLED(ENV_IS_IN_SPI_FLASH))
117 return ENVL_SPI_FLASH;
118 default:
119 return ENVL_NOWHERE;
120 };
121}
122
123#if IS_ENABLED(CONFIG_BOARD_LATE_INIT)
Wadim Egorov127f1202025-05-08 17:15:46 +0200124/**
125 * Ensure the boot order favors the device we just booted from.
126 * If boot_targets is still at its default value, move the current
127 * boot device to the front of the list. Otherwise, leave any customized
128 * order untouched.
129 */
130static void boot_targets_setup(void)
Tom Rinidec7ea02024-05-20 13:35:03 -0600131{
132 u32 boot_device = get_boot_device();
Wadim Egorov127f1202025-05-08 17:15:46 +0200133 const char *boot_targets = NULL;
134 char boot_targets_default[100];
135 int ret;
Tom Rinidec7ea02024-05-20 13:35:03 -0600136
137 switch (boot_device) {
138 case BOOT_DEVICE_MMC1:
139 env_set_ulong("mmcdev", 0);
140 env_set("boot", "mmc");
Wadim Egorov127f1202025-05-08 17:15:46 +0200141 boot_targets = "mmc0 mmc1 spi_flash dhcp";
Tom Rinidec7ea02024-05-20 13:35:03 -0600142 break;
143 case BOOT_DEVICE_MMC2:
144 env_set_ulong("mmcdev", 1);
145 env_set("boot", "mmc");
Wadim Egorov127f1202025-05-08 17:15:46 +0200146 boot_targets = "mmc1 mmc0 spi_flash dhcp";
Tom Rinidec7ea02024-05-20 13:35:03 -0600147 break;
148 case BOOT_DEVICE_SPI:
149 env_set("boot", "spi");
Wadim Egorov127f1202025-05-08 17:15:46 +0200150 boot_targets = "spi_flash mmc0 mmc1 dhcp";
Tom Rinidec7ea02024-05-20 13:35:03 -0600151 break;
152 case BOOT_DEVICE_ETHERNET:
153 env_set("boot", "net");
Wadim Egorov127f1202025-05-08 17:15:46 +0200154 boot_targets = "dhcp mmc0 mmc1 spi_flash";
Tom Rinidec7ea02024-05-20 13:35:03 -0600155 break;
Daniel Schultz8592bbb2025-01-16 03:29:29 -0800156 case BOOT_DEVICE_UART:
157 env_set("boot", "uart");
158 break;
159 case BOOT_DEVICE_DFU:
160 env_set("boot", "usbdfu");
161 break;
Tom Rinidec7ea02024-05-20 13:35:03 -0600162 };
163
Wadim Egorov127f1202025-05-08 17:15:46 +0200164 if (!boot_targets)
165 return;
166
167 ret = env_get_default_into("boot_targets", boot_targets_default, sizeof(boot_targets_default));
168 if (ret < 0)
169 boot_targets_default[0] = '\0';
170
171 if (strcmp(boot_targets_default, env_get("boot_targets"))) {
172 debug("boot_targets not default, don't change it\n");
173 return;
174 }
175
176 env_set("boot_targets", boot_targets);
177}
178
179int board_late_init(void)
180{
181 boot_targets_setup();
182
Daniel Schultz80677cb2024-05-21 23:18:26 -0700183 if (IS_ENABLED(CONFIG_PHYTEC_SOM_DETECTION_BLOCKS)) {
184 struct phytec_api3_element *block_element;
185 struct phytec_eeprom_data data;
186 int ret;
187
188 ret = phytec_eeprom_data_setup(&data, 0, EEPROM_ADDR);
189 if (ret || !data.valid)
190 return 0;
191
192 PHYTEC_API3_FOREACH_BLOCK(block_element, &data) {
193 switch (block_element->block_type) {
194 case PHYTEC_API3_BLOCK_MAC:
195 phytec_blocks_add_mac_to_env(block_element);
196 break;
197 default:
198 debug("%s: Unknown block type %i\n", __func__,
199 block_element->block_type);
200 }
201 }
202 }
203
Tom Rinie20fe8c2024-12-13 17:30:27 -0600204#if IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT)
205 configure_capsule_updates();
206#endif
Wadim Egorov648d2852024-11-27 13:17:35 +0100207
Tom Rinidec7ea02024-05-20 13:35:03 -0600208 return 0;
209}
210#endif
Wadim Egorov4baf2a62024-06-10 15:33:42 +0200211
212#if IS_ENABLED(CONFIG_OF_LIBFDT) && IS_ENABLED(CONFIG_OF_BOARD_SETUP)
Wadim Egorov94d92522024-10-30 17:48:15 +0100213static int fdt_apply_overlay_from_fit(const char *overlay_path, void *fdt)
214{
215 u64 loadaddr;
216 ofnode node;
217 int ret;
218
219 node = ofnode_path(overlay_path);
220 if (!ofnode_valid(node))
221 return -FDT_ERR_NOTFOUND;
222
223 ret = ofnode_read_u64(node, "load", &loadaddr);
224 if (ret)
225 return ret;
226
227 return fdt_overlay_apply_verbose(fdt, (void *)loadaddr);
228}
229
230static void fdt_apply_som_overlays(void *blob)
231{
232 void *fdt_copy;
233 u32 fdt_size;
234 struct phytec_eeprom_data data;
235 int err;
236
237 fdt_size = fdt_totalsize(blob);
238 fdt_copy = malloc(fdt_size);
239 if (!fdt_copy)
240 goto fixup_error;
241
242 memcpy(fdt_copy, blob, fdt_size);
243
244 err = phytec_eeprom_data_setup(&data, 0, EEPROM_ADDR);
245 if (err)
246 goto fixup_error;
247
248 if (phytec_get_am6_rtc(&data) == 0) {
249 err = fdt_apply_overlay_from_fit("/fit-images/som-no-rtc", fdt_copy);
250 if (err)
251 goto fixup_error;
252 }
253
254 if (phytec_get_am6_spi(&data) == PHYTEC_EEPROM_VALUE_X) {
255 err = fdt_apply_overlay_from_fit("/fit-images/som-no-spi", fdt_copy);
256 if (err)
257 goto fixup_error;
258 }
259
260 if (phytec_get_am6_eth(&data) == 0) {
261 err = fdt_apply_overlay_from_fit("/fit-images/som-no-eth", fdt_copy);
262 if (err)
263 goto fixup_error;
264 }
265
266 if (phytec_am6_is_qspi(&data)) {
267 err = fdt_apply_overlay_from_fit("/fit-images/som-qspi-nor", fdt_copy);
268 if (err)
269 goto fixup_error;
270 }
271
272 memcpy(blob, fdt_copy, fdt_size);
273
274cleanup:
275 free(fdt_copy);
276 return;
277
278fixup_error:
279 pr_err("Failed to apply SoM overlays\n");
280 goto cleanup;
281}
282
Wadim Egorov4baf2a62024-06-10 15:33:42 +0200283int ft_board_setup(void *blob, struct bd_info *bd)
284{
Daniel Schultz0b65a382025-01-23 06:43:50 -0800285 struct phytec_eeprom_data data;
286 int ret;
287
Wadim Egorov94d92522024-10-30 17:48:15 +0100288 fdt_apply_som_overlays(blob);
Wadim Egorov4baf2a62024-06-10 15:33:42 +0200289 fdt_copy_fixed_partitions(blob);
290
Daniel Schultz0b65a382025-01-23 06:43:50 -0800291 ret = phytec_eeprom_data_setup(&data, 0, EEPROM_ADDR);
292 if (ret || !data.valid)
293 return 0;
294
295 ret = phytec_ft_board_fixup(&data, blob);
296 if (ret)
297 pr_err("%s: Failed to add PHYTEC information to fdt.\n",
298 __func__);
299
Wadim Egorov4baf2a62024-06-10 15:33:42 +0200300 return 0;
301}
302#endif