blob: d9aec16b0903182a2eff942714a5342f2f1e29cd [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
Wadim Egorove083486a2025-05-08 17:15:47 +0200179static void setup_mac_from_eeprom(void)
Wadim Egorov127f1202025-05-08 17:15:46 +0200180{
Wadim Egorove083486a2025-05-08 17:15:47 +0200181 struct phytec_api3_element *block_element;
182 struct phytec_eeprom_data data;
183 int ret;
Wadim Egorov127f1202025-05-08 17:15:46 +0200184
Wadim Egorove083486a2025-05-08 17:15:47 +0200185 ret = phytec_eeprom_data_setup(&data, 0, EEPROM_ADDR);
186 if (ret || !data.valid)
187 return;
Daniel Schultz80677cb2024-05-21 23:18:26 -0700188
Wadim Egorove083486a2025-05-08 17:15:47 +0200189 PHYTEC_API3_FOREACH_BLOCK(block_element, &data) {
190 switch (block_element->block_type) {
191 case PHYTEC_API3_BLOCK_MAC:
192 phytec_blocks_add_mac_to_env(block_element);
193 break;
194 default:
195 debug("%s: Unknown block type %i\n", __func__,
196 block_element->block_type);
Daniel Schultz80677cb2024-05-21 23:18:26 -0700197 }
198 }
Wadim Egorove083486a2025-05-08 17:15:47 +0200199}
200
201int board_late_init(void)
202{
203 boot_targets_setup();
204
205 if (IS_ENABLED(CONFIG_PHYTEC_SOM_DETECTION_BLOCKS))
206 setup_mac_from_eeprom();
Daniel Schultz80677cb2024-05-21 23:18:26 -0700207
Tom Rinie20fe8c2024-12-13 17:30:27 -0600208#if IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT)
209 configure_capsule_updates();
210#endif
Wadim Egorov648d2852024-11-27 13:17:35 +0100211
Tom Rinidec7ea02024-05-20 13:35:03 -0600212 return 0;
213}
214#endif
Wadim Egorov4baf2a62024-06-10 15:33:42 +0200215
216#if IS_ENABLED(CONFIG_OF_LIBFDT) && IS_ENABLED(CONFIG_OF_BOARD_SETUP)
Wadim Egorov94d92522024-10-30 17:48:15 +0100217static int fdt_apply_overlay_from_fit(const char *overlay_path, void *fdt)
218{
219 u64 loadaddr;
220 ofnode node;
221 int ret;
222
223 node = ofnode_path(overlay_path);
224 if (!ofnode_valid(node))
225 return -FDT_ERR_NOTFOUND;
226
227 ret = ofnode_read_u64(node, "load", &loadaddr);
228 if (ret)
229 return ret;
230
231 return fdt_overlay_apply_verbose(fdt, (void *)loadaddr);
232}
233
234static void fdt_apply_som_overlays(void *blob)
235{
236 void *fdt_copy;
237 u32 fdt_size;
238 struct phytec_eeprom_data data;
239 int err;
240
241 fdt_size = fdt_totalsize(blob);
242 fdt_copy = malloc(fdt_size);
243 if (!fdt_copy)
244 goto fixup_error;
245
246 memcpy(fdt_copy, blob, fdt_size);
247
248 err = phytec_eeprom_data_setup(&data, 0, EEPROM_ADDR);
249 if (err)
250 goto fixup_error;
251
252 if (phytec_get_am6_rtc(&data) == 0) {
253 err = fdt_apply_overlay_from_fit("/fit-images/som-no-rtc", fdt_copy);
254 if (err)
255 goto fixup_error;
256 }
257
258 if (phytec_get_am6_spi(&data) == PHYTEC_EEPROM_VALUE_X) {
259 err = fdt_apply_overlay_from_fit("/fit-images/som-no-spi", fdt_copy);
260 if (err)
261 goto fixup_error;
262 }
263
264 if (phytec_get_am6_eth(&data) == 0) {
265 err = fdt_apply_overlay_from_fit("/fit-images/som-no-eth", fdt_copy);
266 if (err)
267 goto fixup_error;
268 }
269
270 if (phytec_am6_is_qspi(&data)) {
271 err = fdt_apply_overlay_from_fit("/fit-images/som-qspi-nor", fdt_copy);
272 if (err)
273 goto fixup_error;
274 }
275
276 memcpy(blob, fdt_copy, fdt_size);
277
278cleanup:
279 free(fdt_copy);
280 return;
281
282fixup_error:
283 pr_err("Failed to apply SoM overlays\n");
284 goto cleanup;
285}
286
Wadim Egorov4baf2a62024-06-10 15:33:42 +0200287int ft_board_setup(void *blob, struct bd_info *bd)
288{
Daniel Schultz0b65a382025-01-23 06:43:50 -0800289 struct phytec_eeprom_data data;
290 int ret;
291
Wadim Egorov94d92522024-10-30 17:48:15 +0100292 fdt_apply_som_overlays(blob);
Wadim Egorov4baf2a62024-06-10 15:33:42 +0200293 fdt_copy_fixed_partitions(blob);
294
Daniel Schultz0b65a382025-01-23 06:43:50 -0800295 ret = phytec_eeprom_data_setup(&data, 0, EEPROM_ADDR);
296 if (ret || !data.valid)
297 return 0;
298
299 ret = phytec_ft_board_fixup(&data, blob);
300 if (ret)
301 pr_err("%s: Failed to add PHYTEC information to fdt.\n",
302 __func__);
303
Wadim Egorov4baf2a62024-06-10 15:33:42 +0200304 return 0;
305}
306#endif