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