]>
Commit | Line | Data |
---|---|---|
83d290c5 | 1 | // SPDX-License-Identifier: GPL-2.0+ |
a2777ecb | 2 | /* |
842ddf8e | 3 | * Copyright (c) 2016-2020 Toradex |
a2777ecb MZ |
4 | */ |
5 | ||
d678a59d | 6 | #include <common.h> |
401d1c4f | 7 | #include <asm/global_data.h> |
a2777ecb | 8 | #include "tdx-cfg-block.h" |
0c6b5588 IO |
9 | #include "tdx-eeprom.h" |
10 | ||
09140113 | 11 | #include <command.h> |
90526e9f | 12 | #include <asm/cache.h> |
a2777ecb | 13 | |
a2777ecb MZ |
14 | #include <cli.h> |
15 | #include <console.h> | |
7b51b576 | 16 | #include <env.h> |
17ead040 | 17 | #ifdef CONFIG_TDX_CFG_BLOCK_IS_IN_NOR |
a2777ecb | 18 | #include <flash.h> |
17ead040 | 19 | #endif |
a2777ecb MZ |
20 | #include <malloc.h> |
21 | #include <mmc.h> | |
22 | #include <nand.h> | |
c62db35d | 23 | #include <asm/mach-types.h> |
a2777ecb MZ |
24 | |
25 | DECLARE_GLOBAL_DATA_PTR; | |
26 | ||
27 | #define TAG_VALID 0xcf01 | |
28 | #define TAG_MAC 0x0000 | |
0c6b5588 | 29 | #define TAG_CAR_SERIAL 0x0021 |
a2777ecb MZ |
30 | #define TAG_HW 0x0008 |
31 | #define TAG_INVALID 0xffff | |
32 | ||
33 | #define TAG_FLAG_VALID 0x1 | |
34 | ||
0c6b5588 IO |
35 | #define TDX_EEPROM_ID_MODULE 0 |
36 | #define TDX_EEPROM_ID_CARRIER 1 | |
37 | ||
a2777ecb MZ |
38 | #if defined(CONFIG_TDX_CFG_BLOCK_IS_IN_MMC) |
39 | #define TDX_CFG_BLOCK_MAX_SIZE 512 | |
40 | #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NAND) | |
41 | #define TDX_CFG_BLOCK_MAX_SIZE 64 | |
42 | #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NOR) | |
43 | #define TDX_CFG_BLOCK_MAX_SIZE 64 | |
0c6b5588 IO |
44 | #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_EEPROM) |
45 | #define TDX_CFG_BLOCK_MAX_SIZE 64 | |
a2777ecb MZ |
46 | #else |
47 | #error Toradex config block location not set | |
48 | #endif | |
49 | ||
0c6b5588 IO |
50 | #ifdef CONFIG_TDX_CFG_BLOCK_EXTRA |
51 | #define TDX_CFG_BLOCK_EXTRA_MAX_SIZE 64 | |
52 | #endif | |
53 | ||
a2777ecb MZ |
54 | struct toradex_tag { |
55 | u32 len:14; | |
56 | u32 flags:2; | |
57 | u32 id:16; | |
58 | }; | |
59 | ||
60 | bool valid_cfgblock; | |
61 | struct toradex_hw tdx_hw_tag; | |
62 | struct toradex_eth_addr tdx_eth_addr; | |
63 | u32 tdx_serial; | |
0c6b5588 IO |
64 | #ifdef CONFIG_TDX_CFG_BLOCK_EXTRA |
65 | u32 tdx_car_serial; | |
66 | bool valid_cfgblock_carrier; | |
67 | struct toradex_hw tdx_car_hw_tag; | |
68 | #endif | |
a2777ecb | 69 | |
8b6dc5d3 FD |
70 | #define TARGET_IS_ENABLED(x) IS_ENABLED(CONFIG_TARGET_ ## x) |
71 | ||
72 | const struct toradex_som toradex_modules[] = { | |
4f0c33c4 FD |
73 | [0] = { "UNKNOWN MODULE", 0 }, |
74 | [1] = { "Colibri PXA270 312MHz", 0 }, | |
75 | [2] = { "Colibri PXA270 520MHz", 0 }, | |
76 | [3] = { "Colibri PXA320 806MHz", 0 }, | |
77 | [4] = { "Colibri PXA300 208MHz", 0 }, | |
78 | [5] = { "Colibri PXA310 624MHz", 0 }, | |
79 | [6] = { "Colibri PXA320IT 806MHz", 0 }, | |
80 | [7] = { "Colibri PXA300 208MHz XT", 0 }, | |
81 | [8] = { "Colibri PXA270 312MHz", 0 }, | |
82 | [9] = { "Colibri PXA270 520MHz", 0 }, | |
83 | [10] = { "Colibri VF50 128MB", TARGET_IS_ENABLED(COLIBRI_VF) }, | |
84 | [11] = { "Colibri VF61 256MB", TARGET_IS_ENABLED(COLIBRI_VF) }, | |
85 | [12] = { "Colibri VF61 256MB IT", TARGET_IS_ENABLED(COLIBRI_VF) }, | |
86 | [13] = { "Colibri VF50 128MB IT", TARGET_IS_ENABLED(COLIBRI_VF) }, | |
87 | [14] = { "Colibri iMX6S 256MB", TARGET_IS_ENABLED(COLIBRI_IMX6) }, | |
88 | [15] = { "Colibri iMX6DL 512MB", TARGET_IS_ENABLED(COLIBRI_IMX6) }, | |
89 | [16] = { "Colibri iMX6S 256MB IT", TARGET_IS_ENABLED(COLIBRI_IMX6) }, | |
90 | [17] = { "Colibri iMX6DL 512MB IT", TARGET_IS_ENABLED(COLIBRI_IMX6) }, | |
91 | [18] = { "UNKNOWN MODULE", 0 }, | |
92 | [19] = { "UNKNOWN MODULE", 0 }, | |
93 | [20] = { "Colibri T20 256MB", TARGET_IS_ENABLED(COLIBRI_T20) }, | |
94 | [21] = { "Colibri T20 512MB", TARGET_IS_ENABLED(COLIBRI_T20) }, | |
95 | [22] = { "Colibri T20 512MB IT", TARGET_IS_ENABLED(COLIBRI_T20) }, | |
96 | [23] = { "Colibri T30 1GB", TARGET_IS_ENABLED(COLIBRI_T30) }, | |
97 | [24] = { "Colibri T20 256MB IT", TARGET_IS_ENABLED(COLIBRI_T20) }, | |
98 | [25] = { "Apalis T30 2GB", TARGET_IS_ENABLED(APALIS_T30) }, | |
99 | [26] = { "Apalis T30 1GB", TARGET_IS_ENABLED(APALIS_T30) }, | |
100 | [27] = { "Apalis iMX6Q 1GB", TARGET_IS_ENABLED(APALIS_IMX6) }, | |
101 | [28] = { "Apalis iMX6Q 2GB IT", TARGET_IS_ENABLED(APALIS_IMX6) }, | |
102 | [29] = { "Apalis iMX6D 512MB", TARGET_IS_ENABLED(APALIS_IMX6) }, | |
103 | [30] = { "Colibri T30 1GB IT", TARGET_IS_ENABLED(COLIBRI_T30) }, | |
104 | [31] = { "Apalis T30 1GB IT", TARGET_IS_ENABLED(APALIS_T30) }, | |
105 | [32] = { "Colibri iMX7S 256MB", TARGET_IS_ENABLED(COLIBRI_IMX7) }, | |
106 | [33] = { "Colibri iMX7D 512MB", TARGET_IS_ENABLED(COLIBRI_IMX7) }, | |
107 | [34] = { "Apalis TK1 2GB", TARGET_IS_ENABLED(APALIS_TK1) }, | |
108 | [35] = { "Apalis iMX6D 1GB IT", TARGET_IS_ENABLED(APALIS_IMX6) }, | |
109 | [36] = { "Colibri iMX6ULL 256MB", TARGET_IS_ENABLED(COLIBRI_IMX6ULL) }, | |
110 | [37] = { "Apalis iMX8QM 4GB WB IT", TARGET_IS_ENABLED(APALIS_IMX8) }, | |
111 | [38] = { "Colibri iMX8QXP 2GB WB IT", TARGET_IS_ENABLED(COLIBRI_IMX8X) }, | |
112 | [39] = { "Colibri iMX7D 1GB", TARGET_IS_ENABLED(COLIBRI_IMX7) }, | |
113 | [40] = { "Colibri iMX6ULL 512MB WB IT", TARGET_IS_ENABLED(COLIBRI_IMX6ULL) }, | |
114 | [41] = { "Colibri iMX7D 512MB EPDC", TARGET_IS_ENABLED(COLIBRI_IMX7) }, | |
115 | [42] = { "Apalis TK1 4GB", TARGET_IS_ENABLED(APALIS_TK1) }, | |
116 | [43] = { "Colibri T20 512MB IT SETEK", TARGET_IS_ENABLED(COLIBRI_T20) }, | |
117 | [44] = { "Colibri iMX6ULL 512MB IT", TARGET_IS_ENABLED(COLIBRI_IMX6ULL) }, | |
118 | [45] = { "Colibri iMX6ULL 512MB WB", TARGET_IS_ENABLED(COLIBRI_IMX6ULL) }, | |
119 | [46] = { "Apalis iMX8QXP 2GB WB IT", 0 }, | |
120 | [47] = { "Apalis iMX8QM 4GB IT", TARGET_IS_ENABLED(APALIS_IMX8) }, | |
121 | [48] = { "Apalis iMX8QP 2GB WB", TARGET_IS_ENABLED(APALIS_IMX8) }, | |
122 | [49] = { "Apalis iMX8QP 2GB", TARGET_IS_ENABLED(APALIS_IMX8) }, | |
123 | [50] = { "Colibri iMX8QXP 2GB IT", TARGET_IS_ENABLED(COLIBRI_IMX8X) }, | |
124 | [51] = { "Colibri iMX8DX 1GB WB", TARGET_IS_ENABLED(COLIBRI_IMX8X) }, | |
125 | [52] = { "Colibri iMX8DX 1GB", TARGET_IS_ENABLED(COLIBRI_IMX8X) }, | |
126 | [53] = { "Apalis iMX8QXP 2GB ECC IT", 0 }, | |
127 | [54] = { "Apalis iMX8DXP 1GB", TARGET_IS_ENABLED(APALIS_IMX8) }, | |
128 | [55] = { "Verdin iMX8M Mini Quad 2GB WB IT", TARGET_IS_ENABLED(VERDIN_IMX8MM) }, | |
129 | [56] = { "Verdin iMX8M Nano Quad 1GB WB", 0 }, | |
130 | [57] = { "Verdin iMX8M Mini DualLite 1GB", TARGET_IS_ENABLED(VERDIN_IMX8MM) }, | |
131 | [58] = { "Verdin iMX8M Plus Quad 4GB WB IT", TARGET_IS_ENABLED(VERDIN_IMX8MP) }, | |
132 | [59] = { "Verdin iMX8M Mini Quad 2GB IT", TARGET_IS_ENABLED(VERDIN_IMX8MM) }, | |
133 | [60] = { "Verdin iMX8M Mini DualLite 1GB WB IT", TARGET_IS_ENABLED(VERDIN_IMX8MM) }, | |
134 | [61] = { "Verdin iMX8M Plus Quad 2GB", TARGET_IS_ENABLED(VERDIN_IMX8MP) }, | |
135 | [62] = { "Colibri iMX6ULL 1GB IT", TARGET_IS_ENABLED(COLIBRI_IMX6ULL) }, | |
136 | [63] = { "Verdin iMX8M Plus Quad 4GB IT", TARGET_IS_ENABLED(VERDIN_IMX8MP) }, | |
137 | [64] = { "Verdin iMX8M Plus Quad 2GB WB IT", TARGET_IS_ENABLED(VERDIN_IMX8MP) }, | |
138 | [65] = { "Verdin iMX8M Plus QuadLite 1GB IT", TARGET_IS_ENABLED(VERDIN_IMX8MP) }, | |
139 | [66] = { "Verdin iMX8M Plus Quad 8GB WB", TARGET_IS_ENABLED(VERDIN_IMX8MP) }, | |
140 | [67] = { "Apalis iMX8QM 8GB WB IT", TARGET_IS_ENABLED(APALIS_IMX8) }, | |
141 | [68] = { "Verdin iMX8M Mini Quad 2GB WB IT", TARGET_IS_ENABLED(VERDIN_IMX8MM) }, | |
0bcfda1b | 142 | [69] = { "Verdin AM62 Quad 1GB WB IT", TARGET_IS_ENABLED(VERDIN_AM62_A53) }, |
611b94bf | 143 | [70] = { "Verdin iMX8M Plus Quad 8GB WB IT", TARGET_IS_ENABLED(VERDIN_IMX8MP) }, |
0bcfda1b MZ |
144 | [71] = { "Verdin AM62 Solo 512MB", TARGET_IS_ENABLED(VERDIN_AM62_A53) }, |
145 | [72] = { "Verdin AM62 Solo 512MB WB IT", TARGET_IS_ENABLED(VERDIN_AM62_A53) }, | |
146 | [73] = { "Verdin AM62 Dual 1GB ET", TARGET_IS_ENABLED(VERDIN_AM62_A53) }, | |
147 | [74] = { "Verdin AM62 Dual 1GB IT", TARGET_IS_ENABLED(VERDIN_AM62_A53) }, | |
148 | [75] = { "Verdin AM62 Dual 1GB WB IT", TARGET_IS_ENABLED(VERDIN_AM62_A53) }, | |
149 | [76] = { "Verdin AM62 Quad 2GB WB IT", TARGET_IS_ENABLED(VERDIN_AM62_A53) }, | |
216ead4d JPG |
150 | [77] = { "Colibri iMX6S 256MB", TARGET_IS_ENABLED(COLIBRI_IMX6) }, |
151 | [78] = { "Colibri iMX6S 256MB IT", TARGET_IS_ENABLED(COLIBRI_IMX6) }, | |
152 | [79] = { "Colibri iMX6DL 512MB", TARGET_IS_ENABLED(COLIBRI_IMX6) }, | |
153 | [80] = { "Colibri iMX6DL 512MB IT", TARGET_IS_ENABLED(COLIBRI_IMX6) }, | |
154 | [81] = { "Colibri iMX7D 512MB", TARGET_IS_ENABLED(COLIBRI_IMX7) }, | |
155 | [82] = { "Apalis iMX6D 512MB", TARGET_IS_ENABLED(APALIS_IMX6) }, | |
156 | [83] = { "Apalis iMX6Q 1GB", TARGET_IS_ENABLED(APALIS_IMX6) }, | |
157 | [84] = { "Apalis iMX6D 1GB IT", TARGET_IS_ENABLED(APALIS_IMX6) }, | |
158 | [85] = { "Apalis iMX6Q 2GB IT", TARGET_IS_ENABLED(APALIS_IMX6) }, | |
00653867 | 159 | [86] = { "Verdin iMX8M Mini DualLite 2GB IT", TARGET_IS_ENABLED(VERDIN_IMX8MM) }, |
12d3257f | 160 | [87] = { "Verdin iMX8M Mini Quad 2GB IT", TARGET_IS_ENABLED(VERDIN_IMX8MM) }, |
a2777ecb MZ |
161 | }; |
162 | ||
39e521f7 MK |
163 | struct pid4list { |
164 | int pid4; | |
165 | char * const name; | |
166 | }; | |
167 | ||
168 | const struct pid4list toradex_carrier_boards[] = { | |
169 | /* the code assumes unknown at index 0 */ | |
170 | {0, "UNKNOWN CARRIER BOARD"}, | |
171 | {DAHLIA, "Dahlia"}, | |
172 | {VERDIN_DEVELOPMENT_BOARD, "Verdin Development Board"}, | |
173 | {YAVIA, "Yavia"}, | |
26921f58 IO |
174 | }; |
175 | ||
a0383427 MK |
176 | const struct pid4list toradex_display_adapters[] = { |
177 | /* the code assumes unknown at index 0 */ | |
178 | {0, "UNKNOWN DISPLAY ADAPTER"}, | |
179 | {VERDIN_DSI_TO_HDMI_ADAPTER, "Verdin DSI to HDMI Adapter"}, | |
180 | {VERDIN_DSI_TO_LVDS_ADAPTER, "Verdin DSI to LVDS Adapter"}, | |
26921f58 IO |
181 | }; |
182 | ||
1cf4e79f PS |
183 | const u32 toradex_ouis[] = { |
184 | [0] = 0x00142dUL, | |
185 | [1] = 0x8c06cbUL, | |
186 | }; | |
187 | ||
39e521f7 MK |
188 | const char * const get_toradex_carrier_boards(int pid4) |
189 | { | |
190 | int i, index = 0; | |
191 | ||
192 | for (i = 1; i < ARRAY_SIZE(toradex_carrier_boards); i++) { | |
193 | if (pid4 == toradex_carrier_boards[i].pid4) { | |
194 | index = i; | |
195 | break; | |
196 | } | |
197 | } | |
198 | return toradex_carrier_boards[index].name; | |
199 | } | |
200 | ||
a0383427 MK |
201 | const char * const get_toradex_display_adapters(int pid4) |
202 | { | |
203 | int i, index = 0; | |
204 | ||
205 | for (i = 1; i < ARRAY_SIZE(toradex_display_adapters); i++) { | |
206 | if (pid4 == toradex_display_adapters[i].pid4) { | |
207 | index = i; | |
208 | break; | |
209 | } | |
210 | } | |
211 | return toradex_display_adapters[index].name; | |
212 | } | |
213 | ||
1cf4e79f PS |
214 | static u32 get_serial_from_mac(struct toradex_eth_addr *eth_addr) |
215 | { | |
216 | int i; | |
217 | u32 oui = ntohl(eth_addr->oui) >> 8; | |
218 | u32 nic = ntohl(eth_addr->nic) >> 8; | |
219 | ||
220 | for (i = 0; i < ARRAY_SIZE(toradex_ouis); i++) { | |
221 | if (toradex_ouis[i] == oui) | |
222 | break; | |
223 | } | |
224 | ||
225 | return (u32)((i << 24) + nic); | |
226 | } | |
227 | ||
228 | void get_mac_from_serial(u32 tdx_serial, struct toradex_eth_addr *eth_addr) | |
229 | { | |
230 | u8 oui_index = tdx_serial >> 24; | |
231 | u32 nic = tdx_serial & GENMASK(23, 0); | |
232 | u32 oui; | |
233 | ||
234 | if (oui_index >= ARRAY_SIZE(toradex_ouis)) { | |
235 | puts("Can't find OUI for this serial#\n"); | |
236 | oui_index = 0; | |
237 | } | |
238 | ||
239 | oui = toradex_ouis[oui_index]; | |
240 | ||
241 | eth_addr->oui = htonl(oui << 8); | |
242 | eth_addr->nic = htonl(nic << 8); | |
243 | } | |
244 | ||
a2777ecb MZ |
245 | #ifdef CONFIG_TDX_CFG_BLOCK_IS_IN_MMC |
246 | static int tdx_cfg_block_mmc_storage(u8 *config_block, int write) | |
247 | { | |
248 | struct mmc *mmc; | |
249 | int dev = CONFIG_TDX_CFG_BLOCK_DEV; | |
250 | int offset = CONFIG_TDX_CFG_BLOCK_OFFSET; | |
251 | uint part = CONFIG_TDX_CFG_BLOCK_PART; | |
252 | uint blk_start; | |
253 | int ret = 0; | |
254 | ||
255 | /* Read production parameter config block from eMMC */ | |
256 | mmc = find_mmc_device(dev); | |
257 | if (!mmc) { | |
258 | puts("No MMC card found\n"); | |
259 | ret = -ENODEV; | |
260 | goto out; | |
261 | } | |
42a4f182 SA |
262 | if (mmc_init(mmc)) { |
263 | puts("MMC init failed\n"); | |
264 | return -EINVAL; | |
265 | } | |
0e513e78 | 266 | if (part != mmc_get_blk_desc(mmc)->hwpart) { |
e33a5c6b | 267 | if (blk_select_hwpart_devnum(UCLASS_MMC, dev, part)) { |
a2777ecb MZ |
268 | puts("MMC partition switch failed\n"); |
269 | ret = -ENODEV; | |
270 | goto out; | |
271 | } | |
272 | } | |
273 | if (offset < 0) | |
274 | offset += mmc->capacity; | |
275 | blk_start = ALIGN(offset, mmc->write_bl_len) / mmc->write_bl_len; | |
276 | ||
277 | if (!write) { | |
278 | /* Careful reads a whole block of 512 bytes into config_block */ | |
279 | if (blk_dread(mmc_get_blk_desc(mmc), blk_start, 1, | |
280 | (unsigned char *)config_block) != 1) { | |
281 | ret = -EIO; | |
282 | goto out; | |
283 | } | |
a2777ecb MZ |
284 | } else { |
285 | /* Just writing one 512 byte block */ | |
286 | if (blk_dwrite(mmc_get_blk_desc(mmc), blk_start, 1, | |
287 | (unsigned char *)config_block) != 1) { | |
288 | ret = -EIO; | |
289 | goto out; | |
290 | } | |
291 | } | |
292 | ||
293 | out: | |
294 | /* Switch back to regular eMMC user partition */ | |
e33a5c6b | 295 | blk_select_hwpart_devnum(UCLASS_MMC, 0, 0); |
a2777ecb MZ |
296 | |
297 | return ret; | |
298 | } | |
299 | #endif | |
300 | ||
301 | #ifdef CONFIG_TDX_CFG_BLOCK_IS_IN_NAND | |
302 | static int read_tdx_cfg_block_from_nand(unsigned char *config_block) | |
303 | { | |
304 | size_t size = TDX_CFG_BLOCK_MAX_SIZE; | |
bc53fb19 SA |
305 | struct mtd_info *mtd = get_nand_dev_by_index(0); |
306 | ||
307 | if (!mtd) | |
308 | return -ENODEV; | |
a2777ecb MZ |
309 | |
310 | /* Read production parameter config block from NAND page */ | |
bc53fb19 | 311 | return nand_read_skip_bad(mtd, CONFIG_TDX_CFG_BLOCK_OFFSET, |
bf264cd0 GS |
312 | &size, NULL, TDX_CFG_BLOCK_MAX_SIZE, |
313 | config_block); | |
a2777ecb MZ |
314 | } |
315 | ||
316 | static int write_tdx_cfg_block_to_nand(unsigned char *config_block) | |
317 | { | |
318 | size_t size = TDX_CFG_BLOCK_MAX_SIZE; | |
319 | ||
320 | /* Write production parameter config block to NAND page */ | |
bf264cd0 GS |
321 | return nand_write_skip_bad(get_nand_dev_by_index(0), |
322 | CONFIG_TDX_CFG_BLOCK_OFFSET, | |
a2777ecb MZ |
323 | &size, NULL, TDX_CFG_BLOCK_MAX_SIZE, |
324 | config_block, WITH_WR_VERIFY); | |
325 | } | |
326 | #endif | |
327 | ||
328 | #ifdef CONFIG_TDX_CFG_BLOCK_IS_IN_NOR | |
329 | static int read_tdx_cfg_block_from_nor(unsigned char *config_block) | |
330 | { | |
331 | /* Read production parameter config block from NOR flash */ | |
332 | memcpy(config_block, (void *)CONFIG_TDX_CFG_BLOCK_OFFSET, | |
333 | TDX_CFG_BLOCK_MAX_SIZE); | |
334 | return 0; | |
335 | } | |
336 | ||
337 | static int write_tdx_cfg_block_to_nor(unsigned char *config_block) | |
338 | { | |
339 | /* Write production parameter config block to NOR flash */ | |
340 | return flash_write((void *)config_block, CONFIG_TDX_CFG_BLOCK_OFFSET, | |
341 | TDX_CFG_BLOCK_MAX_SIZE); | |
342 | } | |
343 | #endif | |
344 | ||
0c6b5588 IO |
345 | #ifdef CONFIG_TDX_CFG_BLOCK_IS_IN_EEPROM |
346 | static int read_tdx_cfg_block_from_eeprom(unsigned char *config_block) | |
347 | { | |
348 | return read_tdx_eeprom_data(TDX_EEPROM_ID_MODULE, 0x0, config_block, | |
349 | TDX_CFG_BLOCK_MAX_SIZE); | |
350 | } | |
351 | ||
352 | static int write_tdx_cfg_block_to_eeprom(unsigned char *config_block) | |
353 | { | |
354 | return write_tdx_eeprom_data(TDX_EEPROM_ID_MODULE, 0x0, config_block, | |
355 | TDX_CFG_BLOCK_MAX_SIZE); | |
356 | } | |
357 | #endif | |
358 | ||
a2777ecb MZ |
359 | int read_tdx_cfg_block(void) |
360 | { | |
361 | int ret = 0; | |
362 | u8 *config_block = NULL; | |
363 | struct toradex_tag *tag; | |
364 | size_t size = TDX_CFG_BLOCK_MAX_SIZE; | |
365 | int offset; | |
366 | ||
367 | /* Allocate RAM area for config block */ | |
368 | config_block = memalign(ARCH_DMA_MINALIGN, size); | |
369 | if (!config_block) { | |
370 | printf("Not enough malloc space available!\n"); | |
371 | return -ENOMEM; | |
372 | } | |
373 | ||
374 | memset(config_block, 0, size); | |
375 | ||
376 | #if defined(CONFIG_TDX_CFG_BLOCK_IS_IN_MMC) | |
377 | ret = tdx_cfg_block_mmc_storage(config_block, 0); | |
378 | #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NAND) | |
379 | ret = read_tdx_cfg_block_from_nand(config_block); | |
380 | #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NOR) | |
381 | ret = read_tdx_cfg_block_from_nor(config_block); | |
0c6b5588 IO |
382 | #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_EEPROM) |
383 | ret = read_tdx_cfg_block_from_eeprom(config_block); | |
a2777ecb MZ |
384 | #else |
385 | ret = -EINVAL; | |
386 | #endif | |
387 | if (ret) | |
388 | goto out; | |
389 | ||
390 | /* Expect a valid tag first */ | |
391 | tag = (struct toradex_tag *)config_block; | |
392 | if (tag->flags != TAG_FLAG_VALID || tag->id != TAG_VALID) { | |
393 | valid_cfgblock = false; | |
394 | ret = -EINVAL; | |
395 | goto out; | |
396 | } | |
397 | valid_cfgblock = true; | |
398 | offset = 4; | |
399 | ||
0c6b5588 IO |
400 | /* |
401 | * check if there is enough space for storing tag and value of the | |
402 | * biggest element | |
403 | */ | |
404 | while (offset + sizeof(struct toradex_tag) + | |
405 | sizeof(struct toradex_hw) < TDX_CFG_BLOCK_MAX_SIZE) { | |
a2777ecb MZ |
406 | tag = (struct toradex_tag *)(config_block + offset); |
407 | offset += 4; | |
408 | if (tag->id == TAG_INVALID) | |
409 | break; | |
410 | ||
411 | if (tag->flags == TAG_FLAG_VALID) { | |
412 | switch (tag->id) { | |
413 | case TAG_MAC: | |
414 | memcpy(&tdx_eth_addr, config_block + offset, | |
415 | 6); | |
416 | ||
1cf4e79f | 417 | tdx_serial = get_serial_from_mac(&tdx_eth_addr); |
a2777ecb MZ |
418 | break; |
419 | case TAG_HW: | |
420 | memcpy(&tdx_hw_tag, config_block + offset, 8); | |
421 | break; | |
422 | } | |
423 | } | |
424 | ||
425 | /* Get to next tag according to current tags length */ | |
426 | offset += tag->len * 4; | |
427 | } | |
428 | ||
429 | /* Cap product id to avoid issues with a yet unknown one */ | |
cdc39c6a | 430 | if (tdx_hw_tag.prodid >= ARRAY_SIZE(toradex_modules)) |
a2777ecb MZ |
431 | tdx_hw_tag.prodid = 0; |
432 | ||
433 | out: | |
434 | free(config_block); | |
435 | return ret; | |
436 | } | |
437 | ||
7e27ce16 PS |
438 | static int parse_assembly_string(char *string_to_parse, u16 *assembly) |
439 | { | |
440 | if (string_to_parse[3] >= 'A' && string_to_parse[3] <= 'Z') | |
441 | *assembly = string_to_parse[3] - 'A'; | |
442 | else if (string_to_parse[3] == '#') | |
443 | *assembly = dectoul(&string_to_parse[4], NULL); | |
444 | else | |
445 | return -EINVAL; | |
446 | ||
447 | return 0; | |
448 | } | |
449 | ||
a2777ecb MZ |
450 | static int get_cfgblock_interactive(void) |
451 | { | |
452 | char message[CONFIG_SYS_CBSIZE]; | |
c0c3978c | 453 | int len = 0; |
7e27ce16 | 454 | int ret = 0; |
8b6dc5d3 FD |
455 | unsigned int prodid; |
456 | int i; | |
a2777ecb | 457 | |
8b6dc5d3 FD |
458 | printf("Enabled modules:\n"); |
459 | for (i = 0; i < ARRAY_SIZE(toradex_modules); i++) { | |
460 | if (toradex_modules[i].is_enabled) | |
461 | printf(" %04d %s\n", i, toradex_modules[i].name); | |
49410351 | 462 | } |
d1aa1444 | 463 | |
8b6dc5d3 FD |
464 | sprintf(message, "Enter the module ID: "); |
465 | len = cli_readline(message); | |
89315f31 | 466 | |
8b6dc5d3 FD |
467 | prodid = dectoul(console_buffer, NULL); |
468 | if (prodid >= ARRAY_SIZE(toradex_modules) || !toradex_modules[prodid].is_enabled) { | |
469 | printf("Parsing module id failed\n"); | |
a2777ecb MZ |
470 | return -1; |
471 | } | |
8b6dc5d3 | 472 | tdx_hw_tag.prodid = prodid; |
a2777ecb | 473 | |
8b6dc5d3 | 474 | len = 0; |
a2777ecb | 475 | while (len < 4) { |
7e27ce16 | 476 | sprintf(message, "Enter the module version (e.g. V1.1B or V1.1#26): V"); |
a2777ecb MZ |
477 | len = cli_readline(message); |
478 | } | |
479 | ||
480 | tdx_hw_tag.ver_major = console_buffer[0] - '0'; | |
481 | tdx_hw_tag.ver_minor = console_buffer[2] - '0'; | |
7e27ce16 PS |
482 | |
483 | ret = parse_assembly_string(console_buffer, &tdx_hw_tag.ver_assembly); | |
484 | if (ret) { | |
485 | printf("Parsing module version failed\n"); | |
486 | return ret; | |
487 | } | |
a2777ecb | 488 | |
a2777ecb MZ |
489 | while (len < 8) { |
490 | sprintf(message, "Enter module serial number: "); | |
491 | len = cli_readline(message); | |
492 | } | |
493 | ||
0b1284eb | 494 | tdx_serial = dectoul(console_buffer, NULL); |
a2777ecb MZ |
495 | |
496 | return 0; | |
497 | } | |
498 | ||
0c6b5588 IO |
499 | static int get_cfgblock_barcode(char *barcode, struct toradex_hw *tag, |
500 | u32 *serial) | |
a2777ecb | 501 | { |
fd90aca3 DD |
502 | char revision[3] = {barcode[6], barcode[7], '\0'}; |
503 | ||
a2777ecb MZ |
504 | if (strlen(barcode) < 16) { |
505 | printf("Argument too short, barcode is 16 chars long\n"); | |
506 | return -1; | |
507 | } | |
508 | ||
509 | /* Get hardware information from the first 8 digits */ | |
0c6b5588 IO |
510 | tag->ver_major = barcode[4] - '0'; |
511 | tag->ver_minor = barcode[5] - '0'; | |
0b1284eb | 512 | tag->ver_assembly = dectoul(revision, NULL); |
a2777ecb MZ |
513 | |
514 | barcode[4] = '\0'; | |
0b1284eb | 515 | tag->prodid = dectoul(barcode, NULL); |
a2777ecb MZ |
516 | |
517 | /* Parse second part of the barcode (serial number */ | |
518 | barcode += 8; | |
0b1284eb | 519 | *serial = dectoul(barcode, NULL); |
a2777ecb MZ |
520 | |
521 | return 0; | |
522 | } | |
523 | ||
0c6b5588 IO |
524 | static int write_tag(u8 *config_block, int *offset, int tag_id, |
525 | u8 *tag_data, size_t tag_data_size) | |
a2777ecb | 526 | { |
a2777ecb | 527 | struct toradex_tag *tag; |
0c6b5588 IO |
528 | |
529 | if (!offset || !config_block) | |
530 | return -EINVAL; | |
531 | ||
532 | tag = (struct toradex_tag *)(config_block + *offset); | |
533 | tag->id = tag_id; | |
534 | tag->flags = TAG_FLAG_VALID; | |
535 | /* len is provided as number of 32bit values after the tag */ | |
536 | tag->len = (tag_data_size + sizeof(u32) - 1) / sizeof(u32); | |
537 | *offset += sizeof(struct toradex_tag); | |
538 | if (tag_data && tag_data_size) { | |
539 | memcpy(config_block + *offset, tag_data, | |
540 | tag_data_size); | |
541 | *offset += tag_data_size; | |
542 | } | |
543 | ||
544 | return 0; | |
545 | } | |
546 | ||
547 | #ifdef CONFIG_TDX_CFG_BLOCK_EXTRA | |
548 | int read_tdx_cfg_block_carrier(void) | |
549 | { | |
550 | int ret = 0; | |
551 | u8 *config_block = NULL; | |
552 | struct toradex_tag *tag; | |
553 | size_t size = TDX_CFG_BLOCK_EXTRA_MAX_SIZE; | |
554 | int offset; | |
555 | ||
556 | /* Allocate RAM area for carrier config block */ | |
557 | config_block = memalign(ARCH_DMA_MINALIGN, size); | |
558 | if (!config_block) { | |
559 | printf("Not enough malloc space available!\n"); | |
560 | return -ENOMEM; | |
561 | } | |
562 | ||
563 | memset(config_block, 0, size); | |
564 | ||
565 | ret = read_tdx_eeprom_data(TDX_EEPROM_ID_CARRIER, 0x0, config_block, | |
566 | size); | |
567 | if (ret) | |
568 | return ret; | |
569 | ||
570 | /* Expect a valid tag first */ | |
571 | tag = (struct toradex_tag *)config_block; | |
572 | if (tag->flags != TAG_FLAG_VALID || tag->id != TAG_VALID) { | |
573 | valid_cfgblock_carrier = false; | |
574 | ret = -EINVAL; | |
575 | goto out; | |
576 | } | |
577 | valid_cfgblock_carrier = true; | |
578 | offset = 4; | |
579 | ||
580 | while (offset + sizeof(struct toradex_tag) + | |
581 | sizeof(struct toradex_hw) < TDX_CFG_BLOCK_MAX_SIZE) { | |
582 | tag = (struct toradex_tag *)(config_block + offset); | |
583 | offset += 4; | |
584 | if (tag->id == TAG_INVALID) | |
585 | break; | |
586 | ||
587 | if (tag->flags == TAG_FLAG_VALID) { | |
588 | switch (tag->id) { | |
589 | case TAG_CAR_SERIAL: | |
590 | memcpy(&tdx_car_serial, config_block + offset, | |
591 | sizeof(tdx_car_serial)); | |
592 | break; | |
593 | case TAG_HW: | |
594 | memcpy(&tdx_car_hw_tag, config_block + | |
595 | offset, 8); | |
596 | break; | |
597 | } | |
598 | } | |
599 | ||
600 | /* Get to next tag according to current tags length */ | |
601 | offset += tag->len * 4; | |
602 | } | |
603 | out: | |
604 | free(config_block); | |
605 | return ret; | |
606 | } | |
607 | ||
db4ab6d4 IO |
608 | int check_pid8_sanity(char *pid8) |
609 | { | |
610 | char s_carrierid_verdin_dev[5]; | |
611 | char s_carrierid_dahlia[5]; | |
612 | ||
613 | sprintf(s_carrierid_verdin_dev, "0%d", VERDIN_DEVELOPMENT_BOARD); | |
614 | sprintf(s_carrierid_dahlia, "0%d", DAHLIA); | |
615 | ||
616 | /* sane value check, first 4 chars which represent carrier id */ | |
617 | if (!strncmp(pid8, s_carrierid_verdin_dev, 4)) | |
618 | return 0; | |
619 | ||
620 | if (!strncmp(pid8, s_carrierid_dahlia, 4)) | |
621 | return 0; | |
622 | ||
623 | return -EINVAL; | |
624 | } | |
625 | ||
626 | int try_migrate_tdx_cfg_block_carrier(void) | |
627 | { | |
628 | char pid8[8]; | |
629 | int offset = 0; | |
630 | int ret = CMD_RET_SUCCESS; | |
631 | size_t size = TDX_CFG_BLOCK_EXTRA_MAX_SIZE; | |
632 | u8 *config_block; | |
633 | ||
634 | memset(pid8, 0x0, 8); | |
635 | ret = read_tdx_eeprom_data(TDX_EEPROM_ID_CARRIER, 0x0, (u8 *)pid8, 8); | |
636 | if (ret) | |
637 | return ret; | |
638 | ||
639 | if (check_pid8_sanity(pid8)) | |
640 | return -EINVAL; | |
641 | ||
642 | /* Allocate RAM area for config block */ | |
643 | config_block = memalign(ARCH_DMA_MINALIGN, size); | |
644 | if (!config_block) { | |
645 | printf("Not enough malloc space available!\n"); | |
646 | return CMD_RET_FAILURE; | |
647 | } | |
648 | ||
649 | memset(config_block, 0xff, size); | |
650 | /* we try parse PID8 concatenating zeroed serial number */ | |
651 | tdx_car_hw_tag.ver_major = pid8[4] - '0'; | |
652 | tdx_car_hw_tag.ver_minor = pid8[5] - '0'; | |
653 | tdx_car_hw_tag.ver_assembly = pid8[7] - '0'; | |
654 | ||
655 | pid8[4] = '\0'; | |
0b1284eb | 656 | tdx_car_hw_tag.prodid = dectoul(pid8, NULL); |
db4ab6d4 IO |
657 | |
658 | /* Valid Tag */ | |
659 | write_tag(config_block, &offset, TAG_VALID, NULL, 0); | |
660 | ||
661 | /* Product Tag */ | |
662 | write_tag(config_block, &offset, TAG_HW, (u8 *)&tdx_car_hw_tag, | |
663 | sizeof(tdx_car_hw_tag)); | |
664 | ||
665 | /* Serial Tag */ | |
666 | write_tag(config_block, &offset, TAG_CAR_SERIAL, (u8 *)&tdx_car_serial, | |
667 | sizeof(tdx_car_serial)); | |
668 | ||
669 | memset(config_block + offset, 0, 32 - offset); | |
670 | ret = write_tdx_eeprom_data(TDX_EEPROM_ID_CARRIER, 0x0, config_block, | |
671 | size); | |
672 | if (ret) { | |
673 | printf("Failed to write Toradex Extra config block: %d\n", | |
674 | ret); | |
675 | ret = CMD_RET_FAILURE; | |
676 | goto out; | |
677 | } | |
678 | ||
679 | printf("Successfully migrated to Toradex Config Block from PID8\n"); | |
680 | ||
681 | out: | |
682 | free(config_block); | |
683 | return ret; | |
684 | } | |
685 | ||
0c6b5588 IO |
686 | static int get_cfgblock_carrier_interactive(void) |
687 | { | |
688 | char message[CONFIG_SYS_CBSIZE]; | |
689 | int len; | |
7e27ce16 | 690 | int ret = 0; |
0c6b5588 IO |
691 | |
692 | printf("Supported carrier boards:\n"); | |
39e521f7 | 693 | printf("%30s\t[ID]\n", "CARRIER BOARD NAME"); |
cdc39c6a | 694 | for (int i = 0; i < ARRAY_SIZE(toradex_carrier_boards); i++) |
39e521f7 MK |
695 | printf("%30s\t[%d]\n", |
696 | toradex_carrier_boards[i].name, | |
697 | toradex_carrier_boards[i].pid4); | |
0c6b5588 IO |
698 | |
699 | sprintf(message, "Choose your carrier board (provide ID): "); | |
700 | len = cli_readline(message); | |
0b1284eb | 701 | tdx_car_hw_tag.prodid = dectoul(console_buffer, NULL); |
0c6b5588 IO |
702 | |
703 | do { | |
7e27ce16 | 704 | sprintf(message, "Enter carrier board version (e.g. V1.1B or V1.1#26): V"); |
0c6b5588 IO |
705 | len = cli_readline(message); |
706 | } while (len < 4); | |
707 | ||
708 | tdx_car_hw_tag.ver_major = console_buffer[0] - '0'; | |
709 | tdx_car_hw_tag.ver_minor = console_buffer[2] - '0'; | |
7e27ce16 PS |
710 | |
711 | ret = parse_assembly_string(console_buffer, &tdx_car_hw_tag.ver_assembly); | |
712 | if (ret) { | |
713 | printf("Parsing module version failed\n"); | |
714 | return ret; | |
715 | } | |
0c6b5588 IO |
716 | |
717 | while (len < 8) { | |
718 | sprintf(message, "Enter carrier board serial number: "); | |
719 | len = cli_readline(message); | |
720 | } | |
721 | ||
0b1284eb | 722 | tdx_car_serial = dectoul(console_buffer, NULL); |
0c6b5588 IO |
723 | |
724 | return 0; | |
725 | } | |
726 | ||
727 | static int do_cfgblock_carrier_create(struct cmd_tbl *cmdtp, int flag, int argc, | |
728 | char * const argv[]) | |
729 | { | |
730 | u8 *config_block; | |
731 | size_t size = TDX_CFG_BLOCK_EXTRA_MAX_SIZE; | |
a2777ecb MZ |
732 | int offset = 0; |
733 | int ret = CMD_RET_SUCCESS; | |
734 | int err; | |
587b13c6 | 735 | int force_overwrite = 0; |
a2777ecb | 736 | |
0c6b5588 IO |
737 | if (argc >= 3) { |
738 | if (argv[2][0] == '-' && argv[2][1] == 'y') | |
739 | force_overwrite = 1; | |
740 | } | |
741 | ||
a2777ecb MZ |
742 | /* Allocate RAM area for config block */ |
743 | config_block = memalign(ARCH_DMA_MINALIGN, size); | |
744 | if (!config_block) { | |
745 | printf("Not enough malloc space available!\n"); | |
746 | return CMD_RET_FAILURE; | |
747 | } | |
748 | ||
749 | memset(config_block, 0xff, size); | |
0c6b5588 IO |
750 | read_tdx_cfg_block_carrier(); |
751 | if (valid_cfgblock_carrier && !force_overwrite) { | |
752 | char message[CONFIG_SYS_CBSIZE]; | |
753 | ||
754 | sprintf(message, "A valid Toradex Carrier config block is present, still recreate? [y/N] "); | |
755 | ||
756 | if (!cli_readline(message)) | |
757 | goto out; | |
758 | ||
759 | if (console_buffer[0] != 'y' && | |
760 | console_buffer[0] != 'Y') | |
761 | goto out; | |
762 | } | |
763 | ||
764 | if (argc < 3 || (force_overwrite && argc < 4)) { | |
765 | err = get_cfgblock_carrier_interactive(); | |
766 | } else { | |
767 | if (force_overwrite) | |
768 | err = get_cfgblock_barcode(argv[3], &tdx_car_hw_tag, | |
769 | &tdx_car_serial); | |
770 | else | |
771 | err = get_cfgblock_barcode(argv[2], &tdx_car_hw_tag, | |
772 | &tdx_car_serial); | |
773 | } | |
774 | ||
775 | if (err) { | |
776 | ret = CMD_RET_FAILURE; | |
777 | goto out; | |
778 | } | |
779 | ||
780 | /* Valid Tag */ | |
781 | write_tag(config_block, &offset, TAG_VALID, NULL, 0); | |
782 | ||
783 | /* Product Tag */ | |
784 | write_tag(config_block, &offset, TAG_HW, (u8 *)&tdx_car_hw_tag, | |
785 | sizeof(tdx_car_hw_tag)); | |
786 | ||
787 | /* Serial Tag */ | |
788 | write_tag(config_block, &offset, TAG_CAR_SERIAL, (u8 *)&tdx_car_serial, | |
789 | sizeof(tdx_car_serial)); | |
790 | ||
791 | memset(config_block + offset, 0, 32 - offset); | |
792 | err = write_tdx_eeprom_data(TDX_EEPROM_ID_CARRIER, 0x0, config_block, | |
793 | size); | |
794 | if (err) { | |
795 | printf("Failed to write Toradex Extra config block: %d\n", | |
796 | ret); | |
797 | ret = CMD_RET_FAILURE; | |
798 | goto out; | |
799 | } | |
800 | ||
801 | printf("Toradex Extra config block successfully written\n"); | |
802 | ||
803 | out: | |
804 | free(config_block); | |
805 | return ret; | |
806 | } | |
807 | ||
808 | #endif /* CONFIG_TDX_CFG_BLOCK_EXTRA */ | |
809 | ||
810 | static int do_cfgblock_create(struct cmd_tbl *cmdtp, int flag, int argc, | |
811 | char * const argv[]) | |
812 | { | |
813 | u8 *config_block; | |
814 | size_t size = TDX_CFG_BLOCK_MAX_SIZE; | |
815 | int offset = 0; | |
816 | int ret = CMD_RET_SUCCESS; | |
817 | int err; | |
818 | int force_overwrite = 0; | |
a2777ecb | 819 | |
587b13c6 | 820 | if (argc >= 3) { |
0c6b5588 IO |
821 | #ifdef CONFIG_TDX_CFG_BLOCK_EXTRA |
822 | if (!strcmp(argv[2], "carrier")) | |
823 | return do_cfgblock_carrier_create(cmdtp, flag, | |
824 | --argc, ++argv); | |
825 | #endif /* CONFIG_TDX_CFG_BLOCK_EXTRA */ | |
587b13c6 DS |
826 | if (argv[2][0] == '-' && argv[2][1] == 'y') |
827 | force_overwrite = 1; | |
828 | } | |
829 | ||
0c6b5588 IO |
830 | /* Allocate RAM area for config block */ |
831 | config_block = memalign(ARCH_DMA_MINALIGN, size); | |
832 | if (!config_block) { | |
833 | printf("Not enough malloc space available!\n"); | |
834 | return CMD_RET_FAILURE; | |
835 | } | |
836 | ||
837 | memset(config_block, 0xff, size); | |
838 | ||
a2777ecb MZ |
839 | read_tdx_cfg_block(); |
840 | if (valid_cfgblock) { | |
841 | #if defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NAND) | |
842 | /* | |
843 | * On NAND devices, recreation is only allowed if the page is | |
844 | * empty (config block invalid...) | |
845 | */ | |
9d364ebd | 846 | printf("NAND erase block %d need to be erased before creating a Toradex config block\n", |
bf264cd0 GS |
847 | CONFIG_TDX_CFG_BLOCK_OFFSET / |
848 | get_nand_dev_by_index(0)->erasesize); | |
a2777ecb MZ |
849 | goto out; |
850 | #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NOR) | |
851 | /* | |
852 | * On NOR devices, recreation is only allowed if the sector is | |
853 | * empty and write protection is off (config block invalid...) | |
854 | */ | |
9d364ebd | 855 | printf("NOR sector at offset 0x%02x need to be erased and unprotected before creating a Toradex config block\n", |
a2777ecb MZ |
856 | CONFIG_TDX_CFG_BLOCK_OFFSET); |
857 | goto out; | |
858 | #else | |
587b13c6 DS |
859 | if (!force_overwrite) { |
860 | char message[CONFIG_SYS_CBSIZE]; | |
a2777ecb | 861 | |
587b13c6 DS |
862 | sprintf(message, |
863 | "A valid Toradex config block is present, still recreate? [y/N] "); | |
a2777ecb | 864 | |
587b13c6 DS |
865 | if (!cli_readline(message)) |
866 | goto out; | |
867 | ||
868 | if (console_buffer[0] != 'y' && | |
869 | console_buffer[0] != 'Y') | |
870 | goto out; | |
871 | } | |
a2777ecb MZ |
872 | #endif |
873 | } | |
874 | ||
875 | /* Parse new Toradex config block data... */ | |
587b13c6 | 876 | if (argc < 3 || (force_overwrite && argc < 4)) { |
a2777ecb | 877 | err = get_cfgblock_interactive(); |
587b13c6 DS |
878 | } else { |
879 | if (force_overwrite) | |
0c6b5588 IO |
880 | err = get_cfgblock_barcode(argv[3], &tdx_hw_tag, |
881 | &tdx_serial); | |
587b13c6 | 882 | else |
0c6b5588 IO |
883 | err = get_cfgblock_barcode(argv[2], &tdx_hw_tag, |
884 | &tdx_serial); | |
587b13c6 | 885 | } |
a2777ecb MZ |
886 | if (err) { |
887 | ret = CMD_RET_FAILURE; | |
888 | goto out; | |
889 | } | |
890 | ||
891 | /* Convert serial number to MAC address (the storage format) */ | |
1cf4e79f | 892 | get_mac_from_serial(tdx_serial, &tdx_eth_addr); |
a2777ecb MZ |
893 | |
894 | /* Valid Tag */ | |
0c6b5588 | 895 | write_tag(config_block, &offset, TAG_VALID, NULL, 0); |
a2777ecb MZ |
896 | |
897 | /* Product Tag */ | |
0c6b5588 IO |
898 | write_tag(config_block, &offset, TAG_HW, (u8 *)&tdx_hw_tag, |
899 | sizeof(tdx_hw_tag)); | |
a2777ecb MZ |
900 | |
901 | /* MAC Tag */ | |
0c6b5588 IO |
902 | write_tag(config_block, &offset, TAG_MAC, (u8 *)&tdx_eth_addr, |
903 | sizeof(tdx_eth_addr)); | |
a2777ecb | 904 | |
a2777ecb | 905 | memset(config_block + offset, 0, 32 - offset); |
a2777ecb MZ |
906 | #if defined(CONFIG_TDX_CFG_BLOCK_IS_IN_MMC) |
907 | err = tdx_cfg_block_mmc_storage(config_block, 1); | |
908 | #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NAND) | |
909 | err = write_tdx_cfg_block_to_nand(config_block); | |
910 | #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NOR) | |
911 | err = write_tdx_cfg_block_to_nor(config_block); | |
0c6b5588 IO |
912 | #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_EEPROM) |
913 | err = write_tdx_cfg_block_to_eeprom(config_block); | |
a2777ecb MZ |
914 | #else |
915 | err = -EINVAL; | |
916 | #endif | |
917 | if (err) { | |
918 | printf("Failed to write Toradex config block: %d\n", ret); | |
919 | ret = CMD_RET_FAILURE; | |
920 | goto out; | |
921 | } | |
922 | ||
923 | printf("Toradex config block successfully written\n"); | |
924 | ||
925 | out: | |
926 | free(config_block); | |
927 | return ret; | |
928 | } | |
929 | ||
09140113 SG |
930 | static int do_cfgblock(struct cmd_tbl *cmdtp, int flag, int argc, |
931 | char *const argv[]) | |
a2777ecb MZ |
932 | { |
933 | int ret; | |
934 | ||
935 | if (argc < 2) | |
936 | return CMD_RET_USAGE; | |
937 | ||
938 | if (!strcmp(argv[1], "create")) { | |
939 | return do_cfgblock_create(cmdtp, flag, argc, argv); | |
940 | } else if (!strcmp(argv[1], "reload")) { | |
941 | ret = read_tdx_cfg_block(); | |
942 | if (ret) { | |
943 | printf("Failed to reload Toradex config block: %d\n", | |
944 | ret); | |
945 | return CMD_RET_FAILURE; | |
946 | } | |
947 | return CMD_RET_SUCCESS; | |
948 | } | |
949 | ||
950 | return CMD_RET_USAGE; | |
951 | } | |
952 | ||
0c6b5588 IO |
953 | U_BOOT_CMD( |
954 | cfgblock, 5, 0, do_cfgblock, | |
955 | "Toradex config block handling commands", | |
956 | "create [-y] [barcode] - (Re-)create Toradex config block\n" | |
957 | "create carrier [-y] [barcode] - (Re-)create Toradex Carrier config block\n" | |
958 | "cfgblock reload - Reload Toradex config block from flash" | |
a2777ecb | 959 | ); |