1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (c) 2016-2020 Toradex
7 #include "tdx-cfg-block.h"
8 #include "tdx-eeprom.h"
11 #include <asm/cache.h>
13 #if defined(CONFIG_TARGET_APALIS_IMX6) || \
14 defined(CONFIG_TARGET_APALIS_IMX8) || \
15 defined(CONFIG_TARGET_APALIS_IMX8X) || \
16 defined(CONFIG_TARGET_COLIBRI_IMX6) || \
17 defined(CONFIG_TARGET_COLIBRI_IMX8X) || \
18 defined(CONFIG_TARGET_VERDIN_IMX8MM) || \
19 defined(CONFIG_TARGET_VERDIN_IMX8MN)
20 #include <asm/arch/sys_proto.h>
22 #define is_cpu_type(cpu) (0)
24 #if defined(CONFIG_CPU_PXA27X)
25 #include <asm/arch-pxa/pxa.h>
27 #define cpu_is_pxa27x(cpu) (0)
36 #include <asm/mach-types.h>
38 DECLARE_GLOBAL_DATA_PTR;
40 #define TAG_VALID 0xcf01
41 #define TAG_MAC 0x0000
42 #define TAG_CAR_SERIAL 0x0021
44 #define TAG_INVALID 0xffff
46 #define TAG_FLAG_VALID 0x1
48 #define TDX_EEPROM_ID_MODULE 0
49 #define TDX_EEPROM_ID_CARRIER 1
51 #if defined(CONFIG_TDX_CFG_BLOCK_IS_IN_MMC)
52 #define TDX_CFG_BLOCK_MAX_SIZE 512
53 #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NAND)
54 #define TDX_CFG_BLOCK_MAX_SIZE 64
55 #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NOR)
56 #define TDX_CFG_BLOCK_MAX_SIZE 64
57 #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_EEPROM)
58 #define TDX_CFG_BLOCK_MAX_SIZE 64
60 #error Toradex config block location not set
63 #ifdef CONFIG_TDX_CFG_BLOCK_EXTRA
64 #define TDX_CFG_BLOCK_EXTRA_MAX_SIZE 64
74 struct toradex_hw tdx_hw_tag;
75 struct toradex_eth_addr tdx_eth_addr;
77 #ifdef CONFIG_TDX_CFG_BLOCK_EXTRA
79 bool valid_cfgblock_carrier;
80 struct toradex_hw tdx_car_hw_tag;
83 const char * const toradex_modules[] = {
84 [0] = "UNKNOWN MODULE",
85 [1] = "Colibri PXA270 312MHz",
86 [2] = "Colibri PXA270 520MHz",
87 [3] = "Colibri PXA320 806MHz",
88 [4] = "Colibri PXA300 208MHz",
89 [5] = "Colibri PXA310 624MHz",
90 [6] = "Colibri PXA320 806MHz IT",
91 [7] = "Colibri PXA300 208MHz XT",
92 [8] = "Colibri PXA270 312MHz",
93 [9] = "Colibri PXA270 520MHz",
94 [10] = "Colibri VF50 128MB", /* not currently on sale */
95 [11] = "Colibri VF61 256MB",
96 [12] = "Colibri VF61 256MB IT",
97 [13] = "Colibri VF50 128MB IT",
98 [14] = "Colibri iMX6 Solo 256MB",
99 [15] = "Colibri iMX6 DualLite 512MB",
100 [16] = "Colibri iMX6 Solo 256MB IT",
101 [17] = "Colibri iMX6 DualLite 512MB IT",
102 [18] = "UNKNOWN MODULE",
103 [19] = "UNKNOWN MODULE",
104 [20] = "Colibri T20 256MB",
105 [21] = "Colibri T20 512MB",
106 [22] = "Colibri T20 512MB IT",
107 [23] = "Colibri T30 1GB",
108 [24] = "Colibri T20 256MB IT",
109 [25] = "Apalis T30 2GB",
110 [26] = "Apalis T30 1GB",
111 [27] = "Apalis iMX6 Quad 1GB",
112 [28] = "Apalis iMX6 Quad 2GB IT",
113 [29] = "Apalis iMX6 Dual 512MB",
114 [30] = "Colibri T30 1GB IT",
115 [31] = "Apalis T30 1GB IT",
116 [32] = "Colibri iMX7 Solo 256MB",
117 [33] = "Colibri iMX7 Dual 512MB",
118 [34] = "Apalis TK1 2GB",
119 [35] = "Apalis iMX6 Dual 1GB IT",
120 [36] = "Colibri iMX6ULL 256MB",
121 [37] = "Apalis iMX8 QuadMax 4GB Wi-Fi / BT IT",
122 [38] = "Colibri iMX8 QuadXPlus 2GB Wi-Fi / BT IT",
123 [39] = "Colibri iMX7 Dual 1GB (eMMC)",
124 [40] = "Colibri iMX6ULL 512MB Wi-Fi / BT IT",
125 [41] = "Colibri iMX7 Dual 512MB EPDC",
126 [42] = "Apalis TK1 4GB",
127 [43] = "Colibri T20 512MB IT SETEK",
128 [44] = "Colibri iMX6ULL 512MB IT",
129 [45] = "Colibri iMX6ULL 512MB Wi-Fi / Bluetooth",
130 [46] = "Apalis iMX8 QuadXPlus 2GB Wi-Fi / BT IT",
131 [47] = "Apalis iMX8 QuadMax 4GB IT",
132 [48] = "Apalis iMX8 QuadPlus 2GB Wi-Fi / BT",
133 [49] = "Apalis iMX8 QuadPlus 2GB",
134 [50] = "Colibri iMX8 QuadXPlus 2GB IT",
135 [51] = "Colibri iMX8 DualX 1GB Wi-Fi / Bluetooth",
136 [52] = "Colibri iMX8 DualX 1GB",
137 [53] = "Apalis iMX8 QuadXPlus 2GB ECC IT",
138 [54] = "Apalis iMX8 DualXPlus 1GB",
139 [55] = "Verdin iMX8M Mini Quad 2GB Wi-Fi / BT IT",
140 [56] = "Verdin iMX8M Nano SoloLite 1GB", /* not currently on sale */
141 [57] = "Verdin iMX8M Mini DualLite 1GB",
144 const char * const toradex_carrier_boards[] = {
145 [0] = "UNKNOWN CARRIER BOARD",
147 [156] = "Verdin Development Board",
150 const char * const toradex_display_adapters[] = {
151 [0] = "UNKNOWN DISPLAY ADAPTER",
152 [157] = "Verdin DSI to HDMI Adapter",
153 [159] = "Verdin DSI to LVDS Adapter",
156 #ifdef CONFIG_TDX_CFG_BLOCK_IS_IN_MMC
157 static int tdx_cfg_block_mmc_storage(u8 *config_block, int write)
160 int dev = CONFIG_TDX_CFG_BLOCK_DEV;
161 int offset = CONFIG_TDX_CFG_BLOCK_OFFSET;
162 uint part = CONFIG_TDX_CFG_BLOCK_PART;
166 /* Read production parameter config block from eMMC */
167 mmc = find_mmc_device(dev);
169 puts("No MMC card found\n");
174 puts("MMC init failed\n");
177 if (part != mmc_get_blk_desc(mmc)->hwpart) {
178 if (blk_select_hwpart_devnum(IF_TYPE_MMC, dev, part)) {
179 puts("MMC partition switch failed\n");
185 offset += mmc->capacity;
186 blk_start = ALIGN(offset, mmc->write_bl_len) / mmc->write_bl_len;
189 /* Careful reads a whole block of 512 bytes into config_block */
190 if (blk_dread(mmc_get_blk_desc(mmc), blk_start, 1,
191 (unsigned char *)config_block) != 1) {
196 /* Just writing one 512 byte block */
197 if (blk_dwrite(mmc_get_blk_desc(mmc), blk_start, 1,
198 (unsigned char *)config_block) != 1) {
205 /* Switch back to regular eMMC user partition */
206 blk_select_hwpart_devnum(IF_TYPE_MMC, 0, 0);
212 #ifdef CONFIG_TDX_CFG_BLOCK_IS_IN_NAND
213 static int read_tdx_cfg_block_from_nand(unsigned char *config_block)
215 size_t size = TDX_CFG_BLOCK_MAX_SIZE;
216 struct mtd_info *mtd = get_nand_dev_by_index(0);
221 /* Read production parameter config block from NAND page */
222 return nand_read_skip_bad(mtd, CONFIG_TDX_CFG_BLOCK_OFFSET,
223 &size, NULL, TDX_CFG_BLOCK_MAX_SIZE,
227 static int write_tdx_cfg_block_to_nand(unsigned char *config_block)
229 size_t size = TDX_CFG_BLOCK_MAX_SIZE;
231 /* Write production parameter config block to NAND page */
232 return nand_write_skip_bad(get_nand_dev_by_index(0),
233 CONFIG_TDX_CFG_BLOCK_OFFSET,
234 &size, NULL, TDX_CFG_BLOCK_MAX_SIZE,
235 config_block, WITH_WR_VERIFY);
239 #ifdef CONFIG_TDX_CFG_BLOCK_IS_IN_NOR
240 static int read_tdx_cfg_block_from_nor(unsigned char *config_block)
242 /* Read production parameter config block from NOR flash */
243 memcpy(config_block, (void *)CONFIG_TDX_CFG_BLOCK_OFFSET,
244 TDX_CFG_BLOCK_MAX_SIZE);
248 static int write_tdx_cfg_block_to_nor(unsigned char *config_block)
250 /* Write production parameter config block to NOR flash */
251 return flash_write((void *)config_block, CONFIG_TDX_CFG_BLOCK_OFFSET,
252 TDX_CFG_BLOCK_MAX_SIZE);
256 #ifdef CONFIG_TDX_CFG_BLOCK_IS_IN_EEPROM
257 static int read_tdx_cfg_block_from_eeprom(unsigned char *config_block)
259 return read_tdx_eeprom_data(TDX_EEPROM_ID_MODULE, 0x0, config_block,
260 TDX_CFG_BLOCK_MAX_SIZE);
263 static int write_tdx_cfg_block_to_eeprom(unsigned char *config_block)
265 return write_tdx_eeprom_data(TDX_EEPROM_ID_MODULE, 0x0, config_block,
266 TDX_CFG_BLOCK_MAX_SIZE);
270 int read_tdx_cfg_block(void)
273 u8 *config_block = NULL;
274 struct toradex_tag *tag;
275 size_t size = TDX_CFG_BLOCK_MAX_SIZE;
278 /* Allocate RAM area for config block */
279 config_block = memalign(ARCH_DMA_MINALIGN, size);
281 printf("Not enough malloc space available!\n");
285 memset(config_block, 0, size);
287 #if defined(CONFIG_TDX_CFG_BLOCK_IS_IN_MMC)
288 ret = tdx_cfg_block_mmc_storage(config_block, 0);
289 #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NAND)
290 ret = read_tdx_cfg_block_from_nand(config_block);
291 #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NOR)
292 ret = read_tdx_cfg_block_from_nor(config_block);
293 #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_EEPROM)
294 ret = read_tdx_cfg_block_from_eeprom(config_block);
301 /* Expect a valid tag first */
302 tag = (struct toradex_tag *)config_block;
303 if (tag->flags != TAG_FLAG_VALID || tag->id != TAG_VALID) {
304 valid_cfgblock = false;
308 valid_cfgblock = true;
312 * check if there is enough space for storing tag and value of the
315 while (offset + sizeof(struct toradex_tag) +
316 sizeof(struct toradex_hw) < TDX_CFG_BLOCK_MAX_SIZE) {
317 tag = (struct toradex_tag *)(config_block + offset);
319 if (tag->id == TAG_INVALID)
322 if (tag->flags == TAG_FLAG_VALID) {
325 memcpy(&tdx_eth_addr, config_block + offset,
328 /* NIC part of MAC address is serial number */
329 tdx_serial = ntohl(tdx_eth_addr.nic) >> 8;
332 memcpy(&tdx_hw_tag, config_block + offset, 8);
337 /* Get to next tag according to current tags length */
338 offset += tag->len * 4;
341 /* Cap product id to avoid issues with a yet unknown one */
342 if (tdx_hw_tag.prodid >= (sizeof(toradex_modules) /
343 sizeof(toradex_modules[0])))
344 tdx_hw_tag.prodid = 0;
351 static int get_cfgblock_interactive(void)
353 char message[CONFIG_SYS_CBSIZE];
359 /* Unknown module by default */
360 tdx_hw_tag.prodid = 0;
363 sprintf(message, "Is the module the 312 MHz version? [y/N] ");
364 #if !defined(CONFIG_TARGET_VERDIN_IMX8MM) || !defined(CONFIG_TARGET_VERDIN_IMX8MN)
366 sprintf(message, "Is the module an IT version? [y/N] ");
368 len = cli_readline(message);
369 it = console_buffer[0];
375 #if defined(CONFIG_TARGET_APALIS_IMX8) || \
376 defined(CONFIG_TARGET_APALIS_IMX8X) || \
377 defined(CONFIG_TARGET_COLIBRI_IMX6ULL) || \
378 defined(CONFIG_TARGET_COLIBRI_IMX8X)
379 sprintf(message, "Does the module have Wi-Fi / Bluetooth? [y/N] ");
380 len = cli_readline(message);
381 wb = console_buffer[0];
384 soc = env_get("soc");
385 if (!strcmp("mx6", soc)) {
386 #ifdef CONFIG_TARGET_APALIS_IMX6
387 if (it == 'y' || it == 'Y') {
388 if (is_cpu_type(MXC_CPU_MX6Q))
389 tdx_hw_tag.prodid = APALIS_IMX6Q_IT;
391 tdx_hw_tag.prodid = APALIS_IMX6D_IT;
393 if (is_cpu_type(MXC_CPU_MX6Q))
394 tdx_hw_tag.prodid = APALIS_IMX6Q;
396 tdx_hw_tag.prodid = APALIS_IMX6D;
398 #elif CONFIG_TARGET_COLIBRI_IMX6
399 if (it == 'y' || it == 'Y') {
400 if (is_cpu_type(MXC_CPU_MX6DL))
401 tdx_hw_tag.prodid = COLIBRI_IMX6DL_IT;
402 else if (is_cpu_type(MXC_CPU_MX6SOLO))
403 tdx_hw_tag.prodid = COLIBRI_IMX6S_IT;
405 if (is_cpu_type(MXC_CPU_MX6DL))
406 tdx_hw_tag.prodid = COLIBRI_IMX6DL;
407 else if (is_cpu_type(MXC_CPU_MX6SOLO))
408 tdx_hw_tag.prodid = COLIBRI_IMX6S;
410 #elif CONFIG_TARGET_COLIBRI_IMX6ULL
411 if (it == 'y' || it == 'Y') {
412 if (wb == 'y' || wb == 'Y')
413 tdx_hw_tag.prodid = COLIBRI_IMX6ULL_WIFI_BT_IT;
415 tdx_hw_tag.prodid = COLIBRI_IMX6ULL_IT;
417 if (wb == 'y' || wb == 'Y')
418 tdx_hw_tag.prodid = COLIBRI_IMX6ULL_WIFI_BT;
420 tdx_hw_tag.prodid = COLIBRI_IMX6ULL;
423 } else if (!strcmp("imx7d", soc))
424 tdx_hw_tag.prodid = COLIBRI_IMX7D;
425 else if (!strcmp("imx7s", soc))
426 tdx_hw_tag.prodid = COLIBRI_IMX7S;
427 else if (is_cpu_type(MXC_CPU_IMX8MM))
428 tdx_hw_tag.prodid = VERDIN_IMX8MMQ_WIFI_BT_IT;
429 else if (is_cpu_type(MXC_CPU_IMX8MMDL))
430 tdx_hw_tag.prodid = VERDIN_IMX8MMDL;
431 else if (is_cpu_type(MXC_CPU_IMX8MN))
432 tdx_hw_tag.prodid = VERDIN_IMX8MNSL;
433 else if (is_cpu_type(MXC_CPU_IMX8QM)) {
434 if (it == 'y' || it == 'Y') {
435 if (wb == 'y' || wb == 'Y')
436 tdx_hw_tag.prodid = APALIS_IMX8QM_WIFI_BT_IT;
438 tdx_hw_tag.prodid = APALIS_IMX8QM_IT;
440 if (wb == 'y' || wb == 'Y')
441 tdx_hw_tag.prodid = APALIS_IMX8QP_WIFI_BT;
443 tdx_hw_tag.prodid = APALIS_IMX8QP;
445 } else if (is_cpu_type(MXC_CPU_IMX8QXP)) {
446 #ifdef CONFIG_TARGET_APALIS_IMX8X
447 if (it == 'y' || it == 'Y' || wb == 'y' || wb == 'Y') {
448 tdx_hw_tag.prodid = APALIS_IMX8QXP_WIFI_BT_IT;
450 if (gd->ram_size == 0x40000000)
451 tdx_hw_tag.prodid = APALIS_IMX8DXP;
453 tdx_hw_tag.prodid = APALIS_IMX8QXP;
455 #elif CONFIG_TARGET_COLIBRI_IMX8X
456 if (it == 'y' || it == 'Y') {
457 if (wb == 'y' || wb == 'Y')
458 tdx_hw_tag.prodid = COLIBRI_IMX8QXP_WIFI_BT_IT;
460 tdx_hw_tag.prodid = COLIBRI_IMX8QXP_IT;
462 if (wb == 'y' || wb == 'Y')
463 tdx_hw_tag.prodid = COLIBRI_IMX8DX_WIFI_BT;
465 tdx_hw_tag.prodid = COLIBRI_IMX8DX;
468 } else if (!strcmp("tegra20", soc)) {
469 if (it == 'y' || it == 'Y')
470 if (gd->ram_size == 0x10000000)
471 tdx_hw_tag.prodid = COLIBRI_T20_256MB_IT;
473 tdx_hw_tag.prodid = COLIBRI_T20_512MB_IT;
475 if (gd->ram_size == 0x10000000)
476 tdx_hw_tag.prodid = COLIBRI_T20_256MB;
478 tdx_hw_tag.prodid = COLIBRI_T20_512MB;
479 } else if (cpu_is_pxa27x()) {
480 if (it == 'y' || it == 'Y')
481 tdx_hw_tag.prodid = COLIBRI_PXA270_312MHZ;
483 tdx_hw_tag.prodid = COLIBRI_PXA270_520MHZ;
485 #ifdef CONFIG_MACH_TYPE
486 else if (!strcmp("tegra30", soc)) {
487 if (CONFIG_MACH_TYPE == MACH_TYPE_APALIS_T30) {
488 if (it == 'y' || it == 'Y')
489 tdx_hw_tag.prodid = APALIS_T30_IT;
491 if (gd->ram_size == 0x40000000)
492 tdx_hw_tag.prodid = APALIS_T30_1GB;
494 tdx_hw_tag.prodid = APALIS_T30_2GB;
496 if (it == 'y' || it == 'Y')
497 tdx_hw_tag.prodid = COLIBRI_T30_IT;
499 tdx_hw_tag.prodid = COLIBRI_T30;
502 #endif /* CONFIG_MACH_TYPE */
503 else if (!strcmp("tegra124", soc)) {
504 tdx_hw_tag.prodid = APALIS_TK1_2GB;
505 } else if (!strcmp("vf500", soc)) {
506 if (it == 'y' || it == 'Y')
507 tdx_hw_tag.prodid = COLIBRI_VF50_IT;
509 tdx_hw_tag.prodid = COLIBRI_VF50;
510 } else if (!strcmp("vf610", soc)) {
511 if (it == 'y' || it == 'Y')
512 tdx_hw_tag.prodid = COLIBRI_VF61_IT;
514 tdx_hw_tag.prodid = COLIBRI_VF61;
517 if (!tdx_hw_tag.prodid) {
518 printf("Module type not detectable due to unknown SoC\n");
523 sprintf(message, "Enter the module version (e.g. V1.1B): V");
524 len = cli_readline(message);
527 tdx_hw_tag.ver_major = console_buffer[0] - '0';
528 tdx_hw_tag.ver_minor = console_buffer[2] - '0';
529 tdx_hw_tag.ver_assembly = console_buffer[3] - 'A';
531 if (cpu_is_pxa27x() && tdx_hw_tag.ver_major == 1)
532 tdx_hw_tag.prodid -= (COLIBRI_PXA270_312MHZ -
533 COLIBRI_PXA270_V1_312MHZ);
536 sprintf(message, "Enter module serial number: ");
537 len = cli_readline(message);
540 tdx_serial = simple_strtoul(console_buffer, NULL, 10);
545 static int get_cfgblock_barcode(char *barcode, struct toradex_hw *tag,
548 if (strlen(barcode) < 16) {
549 printf("Argument too short, barcode is 16 chars long\n");
553 /* Get hardware information from the first 8 digits */
554 tag->ver_major = barcode[4] - '0';
555 tag->ver_minor = barcode[5] - '0';
556 tag->ver_assembly = barcode[7] - '0';
559 tag->prodid = simple_strtoul(barcode, NULL, 10);
561 /* Parse second part of the barcode (serial number */
563 *serial = simple_strtoul(barcode, NULL, 10);
568 static int write_tag(u8 *config_block, int *offset, int tag_id,
569 u8 *tag_data, size_t tag_data_size)
571 struct toradex_tag *tag;
573 if (!offset || !config_block)
576 tag = (struct toradex_tag *)(config_block + *offset);
578 tag->flags = TAG_FLAG_VALID;
579 /* len is provided as number of 32bit values after the tag */
580 tag->len = (tag_data_size + sizeof(u32) - 1) / sizeof(u32);
581 *offset += sizeof(struct toradex_tag);
582 if (tag_data && tag_data_size) {
583 memcpy(config_block + *offset, tag_data,
585 *offset += tag_data_size;
591 #ifdef CONFIG_TDX_CFG_BLOCK_EXTRA
592 int read_tdx_cfg_block_carrier(void)
595 u8 *config_block = NULL;
596 struct toradex_tag *tag;
597 size_t size = TDX_CFG_BLOCK_EXTRA_MAX_SIZE;
600 /* Allocate RAM area for carrier config block */
601 config_block = memalign(ARCH_DMA_MINALIGN, size);
603 printf("Not enough malloc space available!\n");
607 memset(config_block, 0, size);
609 ret = read_tdx_eeprom_data(TDX_EEPROM_ID_CARRIER, 0x0, config_block,
614 /* Expect a valid tag first */
615 tag = (struct toradex_tag *)config_block;
616 if (tag->flags != TAG_FLAG_VALID || tag->id != TAG_VALID) {
617 valid_cfgblock_carrier = false;
621 valid_cfgblock_carrier = true;
624 while (offset + sizeof(struct toradex_tag) +
625 sizeof(struct toradex_hw) < TDX_CFG_BLOCK_MAX_SIZE) {
626 tag = (struct toradex_tag *)(config_block + offset);
628 if (tag->id == TAG_INVALID)
631 if (tag->flags == TAG_FLAG_VALID) {
634 memcpy(&tdx_car_serial, config_block + offset,
635 sizeof(tdx_car_serial));
638 memcpy(&tdx_car_hw_tag, config_block +
644 /* Get to next tag according to current tags length */
645 offset += tag->len * 4;
652 static int get_cfgblock_carrier_interactive(void)
654 char message[CONFIG_SYS_CBSIZE];
657 printf("Supported carrier boards:\n");
658 printf("CARRIER BOARD NAME\t\t [ID]\n");
659 for (int i = 0; i < sizeof(toradex_carrier_boards) /
660 sizeof(toradex_carrier_boards[0]); i++)
661 if (toradex_carrier_boards[i])
662 printf("%s \t\t [%d]\n", toradex_carrier_boards[i], i);
664 sprintf(message, "Choose your carrier board (provide ID): ");
665 len = cli_readline(message);
666 tdx_car_hw_tag.prodid = simple_strtoul(console_buffer, NULL, 10);
669 sprintf(message, "Enter carrier board version (e.g. V1.1B): V");
670 len = cli_readline(message);
673 tdx_car_hw_tag.ver_major = console_buffer[0] - '0';
674 tdx_car_hw_tag.ver_minor = console_buffer[2] - '0';
675 tdx_car_hw_tag.ver_assembly = console_buffer[3] - 'A';
678 sprintf(message, "Enter carrier board serial number: ");
679 len = cli_readline(message);
682 tdx_car_serial = simple_strtoul(console_buffer, NULL, 10);
687 static int do_cfgblock_carrier_create(struct cmd_tbl *cmdtp, int flag, int argc,
691 size_t size = TDX_CFG_BLOCK_EXTRA_MAX_SIZE;
693 int ret = CMD_RET_SUCCESS;
695 int force_overwrite = 0;
698 if (argv[2][0] == '-' && argv[2][1] == 'y')
702 /* Allocate RAM area for config block */
703 config_block = memalign(ARCH_DMA_MINALIGN, size);
705 printf("Not enough malloc space available!\n");
706 return CMD_RET_FAILURE;
709 memset(config_block, 0xff, size);
710 read_tdx_cfg_block_carrier();
711 if (valid_cfgblock_carrier && !force_overwrite) {
712 char message[CONFIG_SYS_CBSIZE];
714 sprintf(message, "A valid Toradex Carrier config block is present, still recreate? [y/N] ");
716 if (!cli_readline(message))
719 if (console_buffer[0] != 'y' &&
720 console_buffer[0] != 'Y')
724 if (argc < 3 || (force_overwrite && argc < 4)) {
725 err = get_cfgblock_carrier_interactive();
728 err = get_cfgblock_barcode(argv[3], &tdx_car_hw_tag,
731 err = get_cfgblock_barcode(argv[2], &tdx_car_hw_tag,
736 ret = CMD_RET_FAILURE;
741 write_tag(config_block, &offset, TAG_VALID, NULL, 0);
744 write_tag(config_block, &offset, TAG_HW, (u8 *)&tdx_car_hw_tag,
745 sizeof(tdx_car_hw_tag));
748 write_tag(config_block, &offset, TAG_CAR_SERIAL, (u8 *)&tdx_car_serial,
749 sizeof(tdx_car_serial));
751 memset(config_block + offset, 0, 32 - offset);
752 err = write_tdx_eeprom_data(TDX_EEPROM_ID_CARRIER, 0x0, config_block,
755 printf("Failed to write Toradex Extra config block: %d\n",
757 ret = CMD_RET_FAILURE;
761 printf("Toradex Extra config block successfully written\n");
768 #endif /* CONFIG_TDX_CFG_BLOCK_EXTRA */
770 static int do_cfgblock_create(struct cmd_tbl *cmdtp, int flag, int argc,
774 size_t size = TDX_CFG_BLOCK_MAX_SIZE;
776 int ret = CMD_RET_SUCCESS;
778 int force_overwrite = 0;
781 #ifdef CONFIG_TDX_CFG_BLOCK_EXTRA
782 if (!strcmp(argv[2], "carrier"))
783 return do_cfgblock_carrier_create(cmdtp, flag,
785 #endif /* CONFIG_TDX_CFG_BLOCK_EXTRA */
786 if (argv[2][0] == '-' && argv[2][1] == 'y')
790 /* Allocate RAM area for config block */
791 config_block = memalign(ARCH_DMA_MINALIGN, size);
793 printf("Not enough malloc space available!\n");
794 return CMD_RET_FAILURE;
797 memset(config_block, 0xff, size);
799 read_tdx_cfg_block();
800 if (valid_cfgblock) {
801 #if defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NAND)
803 * On NAND devices, recreation is only allowed if the page is
804 * empty (config block invalid...)
806 printf("NAND erase block %d need to be erased before creating a Toradex config block\n",
807 CONFIG_TDX_CFG_BLOCK_OFFSET /
808 get_nand_dev_by_index(0)->erasesize);
810 #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NOR)
812 * On NOR devices, recreation is only allowed if the sector is
813 * empty and write protection is off (config block invalid...)
815 printf("NOR sector at offset 0x%02x need to be erased and unprotected before creating a Toradex config block\n",
816 CONFIG_TDX_CFG_BLOCK_OFFSET);
819 if (!force_overwrite) {
820 char message[CONFIG_SYS_CBSIZE];
823 "A valid Toradex config block is present, still recreate? [y/N] ");
825 if (!cli_readline(message))
828 if (console_buffer[0] != 'y' &&
829 console_buffer[0] != 'Y')
835 /* Parse new Toradex config block data... */
836 if (argc < 3 || (force_overwrite && argc < 4)) {
837 err = get_cfgblock_interactive();
840 err = get_cfgblock_barcode(argv[3], &tdx_hw_tag,
843 err = get_cfgblock_barcode(argv[2], &tdx_hw_tag,
847 ret = CMD_RET_FAILURE;
851 /* Convert serial number to MAC address (the storage format) */
852 tdx_eth_addr.oui = htonl(0x00142dUL << 8);
853 tdx_eth_addr.nic = htonl(tdx_serial << 8);
856 write_tag(config_block, &offset, TAG_VALID, NULL, 0);
859 write_tag(config_block, &offset, TAG_HW, (u8 *)&tdx_hw_tag,
863 write_tag(config_block, &offset, TAG_MAC, (u8 *)&tdx_eth_addr,
864 sizeof(tdx_eth_addr));
866 memset(config_block + offset, 0, 32 - offset);
867 #if defined(CONFIG_TDX_CFG_BLOCK_IS_IN_MMC)
868 err = tdx_cfg_block_mmc_storage(config_block, 1);
869 #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NAND)
870 err = write_tdx_cfg_block_to_nand(config_block);
871 #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NOR)
872 err = write_tdx_cfg_block_to_nor(config_block);
873 #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_EEPROM)
874 err = write_tdx_cfg_block_to_eeprom(config_block);
879 printf("Failed to write Toradex config block: %d\n", ret);
880 ret = CMD_RET_FAILURE;
884 printf("Toradex config block successfully written\n");
891 static int do_cfgblock(struct cmd_tbl *cmdtp, int flag, int argc,
897 return CMD_RET_USAGE;
899 if (!strcmp(argv[1], "create")) {
900 return do_cfgblock_create(cmdtp, flag, argc, argv);
901 } else if (!strcmp(argv[1], "reload")) {
902 ret = read_tdx_cfg_block();
904 printf("Failed to reload Toradex config block: %d\n",
906 return CMD_RET_FAILURE;
908 return CMD_RET_SUCCESS;
911 return CMD_RET_USAGE;
915 cfgblock, 5, 0, do_cfgblock,
916 "Toradex config block handling commands",
917 "create [-y] [barcode] - (Re-)create Toradex config block\n"
918 "create carrier [-y] [barcode] - (Re-)create Toradex Carrier config block\n"
919 "cfgblock reload - Reload Toradex config block from flash"