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