1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+ 2a2777ecbSMarcel Ziswiler /* 3a2777ecbSMarcel Ziswiler * Copyright (c) 2016 Toradex, Inc. 4a2777ecbSMarcel Ziswiler */ 5a2777ecbSMarcel Ziswiler 6a2777ecbSMarcel Ziswiler #include <common.h> 7a2777ecbSMarcel Ziswiler #include "tdx-cfg-block.h" 8a2777ecbSMarcel Ziswiler 9a2777ecbSMarcel Ziswiler #if defined(CONFIG_TARGET_APALIS_IMX6) || defined(CONFIG_TARGET_COLIBRI_IMX6) 10a2777ecbSMarcel Ziswiler #include <asm/arch/sys_proto.h> 11a2777ecbSMarcel Ziswiler #else 12a2777ecbSMarcel Ziswiler #define is_cpu_type(cpu) (0) 13a2777ecbSMarcel Ziswiler #endif 14a2777ecbSMarcel Ziswiler #if defined(CONFIG_CPU_PXA27X) 15a2777ecbSMarcel Ziswiler #include <asm/arch-pxa/pxa.h> 16a2777ecbSMarcel Ziswiler #else 17a2777ecbSMarcel Ziswiler #define cpu_is_pxa27x(cpu) (0) 18a2777ecbSMarcel Ziswiler #endif 19a2777ecbSMarcel Ziswiler #include <cli.h> 20a2777ecbSMarcel Ziswiler #include <console.h> 21a2777ecbSMarcel Ziswiler #include <flash.h> 22a2777ecbSMarcel Ziswiler #include <malloc.h> 23a2777ecbSMarcel Ziswiler #include <mmc.h> 24a2777ecbSMarcel Ziswiler #include <nand.h> 25c62db35dSSimon Glass #include <asm/mach-types.h> 26a2777ecbSMarcel Ziswiler 27a2777ecbSMarcel Ziswiler DECLARE_GLOBAL_DATA_PTR; 28a2777ecbSMarcel Ziswiler 29a2777ecbSMarcel Ziswiler #define TAG_VALID 0xcf01 30a2777ecbSMarcel Ziswiler #define TAG_MAC 0x0000 31a2777ecbSMarcel Ziswiler #define TAG_HW 0x0008 32a2777ecbSMarcel Ziswiler #define TAG_INVALID 0xffff 33a2777ecbSMarcel Ziswiler 34a2777ecbSMarcel Ziswiler #define TAG_FLAG_VALID 0x1 35a2777ecbSMarcel Ziswiler 36a2777ecbSMarcel Ziswiler #if defined(CONFIG_TDX_CFG_BLOCK_IS_IN_MMC) 37a2777ecbSMarcel Ziswiler #define TDX_CFG_BLOCK_MAX_SIZE 512 38a2777ecbSMarcel Ziswiler #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NAND) 39a2777ecbSMarcel Ziswiler #define TDX_CFG_BLOCK_MAX_SIZE 64 40a2777ecbSMarcel Ziswiler #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NOR) 41a2777ecbSMarcel Ziswiler #define TDX_CFG_BLOCK_MAX_SIZE 64 42a2777ecbSMarcel Ziswiler #else 43a2777ecbSMarcel Ziswiler #error Toradex config block location not set 44a2777ecbSMarcel Ziswiler #endif 45a2777ecbSMarcel Ziswiler 46a2777ecbSMarcel Ziswiler struct toradex_tag { 47a2777ecbSMarcel Ziswiler u32 len:14; 48a2777ecbSMarcel Ziswiler u32 flags:2; 49a2777ecbSMarcel Ziswiler u32 id:16; 50a2777ecbSMarcel Ziswiler }; 51a2777ecbSMarcel Ziswiler 52a2777ecbSMarcel Ziswiler bool valid_cfgblock; 53a2777ecbSMarcel Ziswiler struct toradex_hw tdx_hw_tag; 54a2777ecbSMarcel Ziswiler struct toradex_eth_addr tdx_eth_addr; 55a2777ecbSMarcel Ziswiler u32 tdx_serial; 56a2777ecbSMarcel Ziswiler 57a2777ecbSMarcel Ziswiler const char * const toradex_modules[] = { 58a2777ecbSMarcel Ziswiler [0] = "UNKNOWN MODULE", 59a2777ecbSMarcel Ziswiler [1] = "Colibri PXA270 312MHz", 60a2777ecbSMarcel Ziswiler [2] = "Colibri PXA270 520MHz", 61a2777ecbSMarcel Ziswiler [3] = "Colibri PXA320 806MHz", 62a2777ecbSMarcel Ziswiler [4] = "Colibri PXA300 208MHz", 63a2777ecbSMarcel Ziswiler [5] = "Colibri PXA310 624MHz", 64a2777ecbSMarcel Ziswiler [6] = "Colibri PXA320 806MHz IT", 65a2777ecbSMarcel Ziswiler [7] = "Colibri PXA300 208MHz XT", 66a2777ecbSMarcel Ziswiler [8] = "Colibri PXA270 312MHz", 67a2777ecbSMarcel Ziswiler [9] = "Colibri PXA270 520MHz", 68a2777ecbSMarcel Ziswiler [10] = "Colibri VF50 128MB", /* not currently on sale */ 69a2777ecbSMarcel Ziswiler [11] = "Colibri VF61 256MB", 70a2777ecbSMarcel Ziswiler [12] = "Colibri VF61 256MB IT", 71a2777ecbSMarcel Ziswiler [13] = "Colibri VF50 128MB IT", 72a2777ecbSMarcel Ziswiler [14] = "Colibri iMX6 Solo 256MB", 73a2777ecbSMarcel Ziswiler [15] = "Colibri iMX6 DualLite 512MB", 74a2777ecbSMarcel Ziswiler [16] = "Colibri iMX6 Solo 256MB IT", 75a2777ecbSMarcel Ziswiler [17] = "Colibri iMX6 DualLite 512MB IT", 76a2777ecbSMarcel Ziswiler [18] = "UNKNOWN MODULE", 77a2777ecbSMarcel Ziswiler [19] = "UNKNOWN MODULE", 78a2777ecbSMarcel Ziswiler [20] = "Colibri T20 256MB", 79a2777ecbSMarcel Ziswiler [21] = "Colibri T20 512MB", 80a2777ecbSMarcel Ziswiler [22] = "Colibri T20 512MB IT", 81a2777ecbSMarcel Ziswiler [23] = "Colibri T30 1GB", 82a2777ecbSMarcel Ziswiler [24] = "Colibri T20 256MB IT", 83a2777ecbSMarcel Ziswiler [25] = "Apalis T30 2GB", 84a2777ecbSMarcel Ziswiler [26] = "Apalis T30 1GB", 85a2777ecbSMarcel Ziswiler [27] = "Apalis iMX6 Quad 1GB", 86a2777ecbSMarcel Ziswiler [28] = "Apalis iMX6 Quad 2GB IT", 87a2777ecbSMarcel Ziswiler [29] = "Apalis iMX6 Dual 512MB", 88a2777ecbSMarcel Ziswiler [30] = "Colibri T30 1GB IT", 89a2777ecbSMarcel Ziswiler [31] = "Apalis T30 1GB IT", 90a2777ecbSMarcel Ziswiler [32] = "Colibri iMX7 Solo 256MB", 91a2777ecbSMarcel Ziswiler [33] = "Colibri iMX7 Dual 512MB", 92a2777ecbSMarcel Ziswiler [34] = "Apalis TK1 2GB", 93a2777ecbSMarcel Ziswiler [35] = "Apalis iMX6 Dual 1GB IT", 94a2777ecbSMarcel Ziswiler }; 95a2777ecbSMarcel Ziswiler 96a2777ecbSMarcel Ziswiler #ifdef CONFIG_TDX_CFG_BLOCK_IS_IN_MMC 97a2777ecbSMarcel Ziswiler static int tdx_cfg_block_mmc_storage(u8 *config_block, int write) 98a2777ecbSMarcel Ziswiler { 99a2777ecbSMarcel Ziswiler struct mmc *mmc; 100a2777ecbSMarcel Ziswiler int dev = CONFIG_TDX_CFG_BLOCK_DEV; 101a2777ecbSMarcel Ziswiler int offset = CONFIG_TDX_CFG_BLOCK_OFFSET; 102a2777ecbSMarcel Ziswiler uint part = CONFIG_TDX_CFG_BLOCK_PART; 103a2777ecbSMarcel Ziswiler uint blk_start; 104a2777ecbSMarcel Ziswiler int ret = 0; 105a2777ecbSMarcel Ziswiler 106a2777ecbSMarcel Ziswiler /* Read production parameter config block from eMMC */ 107a2777ecbSMarcel Ziswiler mmc = find_mmc_device(dev); 108a2777ecbSMarcel Ziswiler if (!mmc) { 109a2777ecbSMarcel Ziswiler puts("No MMC card found\n"); 110a2777ecbSMarcel Ziswiler ret = -ENODEV; 111a2777ecbSMarcel Ziswiler goto out; 112a2777ecbSMarcel Ziswiler } 1130e513e78SSimon Glass if (part != mmc_get_blk_desc(mmc)->hwpart) { 114a2777ecbSMarcel Ziswiler if (blk_select_hwpart_devnum(IF_TYPE_MMC, dev, part)) { 115a2777ecbSMarcel Ziswiler puts("MMC partition switch failed\n"); 116a2777ecbSMarcel Ziswiler ret = -ENODEV; 117a2777ecbSMarcel Ziswiler goto out; 118a2777ecbSMarcel Ziswiler } 119a2777ecbSMarcel Ziswiler } 120a2777ecbSMarcel Ziswiler if (offset < 0) 121a2777ecbSMarcel Ziswiler offset += mmc->capacity; 122a2777ecbSMarcel Ziswiler blk_start = ALIGN(offset, mmc->write_bl_len) / mmc->write_bl_len; 123a2777ecbSMarcel Ziswiler 124a2777ecbSMarcel Ziswiler if (!write) { 125a2777ecbSMarcel Ziswiler /* Careful reads a whole block of 512 bytes into config_block */ 126a2777ecbSMarcel Ziswiler if (blk_dread(mmc_get_blk_desc(mmc), blk_start, 1, 127a2777ecbSMarcel Ziswiler (unsigned char *)config_block) != 1) { 128a2777ecbSMarcel Ziswiler ret = -EIO; 129a2777ecbSMarcel Ziswiler goto out; 130a2777ecbSMarcel Ziswiler } 131a2777ecbSMarcel Ziswiler } else { 132a2777ecbSMarcel Ziswiler /* Just writing one 512 byte block */ 133a2777ecbSMarcel Ziswiler if (blk_dwrite(mmc_get_blk_desc(mmc), blk_start, 1, 134a2777ecbSMarcel Ziswiler (unsigned char *)config_block) != 1) { 135a2777ecbSMarcel Ziswiler ret = -EIO; 136a2777ecbSMarcel Ziswiler goto out; 137a2777ecbSMarcel Ziswiler } 138a2777ecbSMarcel Ziswiler } 139a2777ecbSMarcel Ziswiler 140a2777ecbSMarcel Ziswiler out: 141a2777ecbSMarcel Ziswiler /* Switch back to regular eMMC user partition */ 142a2777ecbSMarcel Ziswiler blk_select_hwpart_devnum(IF_TYPE_MMC, 0, 0); 143a2777ecbSMarcel Ziswiler 144a2777ecbSMarcel Ziswiler return ret; 145a2777ecbSMarcel Ziswiler } 146a2777ecbSMarcel Ziswiler #endif 147a2777ecbSMarcel Ziswiler 148a2777ecbSMarcel Ziswiler #ifdef CONFIG_TDX_CFG_BLOCK_IS_IN_NAND 149a2777ecbSMarcel Ziswiler static int read_tdx_cfg_block_from_nand(unsigned char *config_block) 150a2777ecbSMarcel Ziswiler { 151a2777ecbSMarcel Ziswiler size_t size = TDX_CFG_BLOCK_MAX_SIZE; 152a2777ecbSMarcel Ziswiler 153a2777ecbSMarcel Ziswiler /* Read production parameter config block from NAND page */ 154bf264cd0SGrygorii Strashko return nand_read_skip_bad(get_nand_dev_by_index(0), 155bf264cd0SGrygorii Strashko CONFIG_TDX_CFG_BLOCK_OFFSET, 156bf264cd0SGrygorii Strashko &size, NULL, TDX_CFG_BLOCK_MAX_SIZE, 157bf264cd0SGrygorii Strashko config_block); 158a2777ecbSMarcel Ziswiler } 159a2777ecbSMarcel Ziswiler 160a2777ecbSMarcel Ziswiler static int write_tdx_cfg_block_to_nand(unsigned char *config_block) 161a2777ecbSMarcel Ziswiler { 162a2777ecbSMarcel Ziswiler size_t size = TDX_CFG_BLOCK_MAX_SIZE; 163a2777ecbSMarcel Ziswiler 164a2777ecbSMarcel Ziswiler /* Write production parameter config block to NAND page */ 165bf264cd0SGrygorii Strashko return nand_write_skip_bad(get_nand_dev_by_index(0), 166bf264cd0SGrygorii Strashko CONFIG_TDX_CFG_BLOCK_OFFSET, 167a2777ecbSMarcel Ziswiler &size, NULL, TDX_CFG_BLOCK_MAX_SIZE, 168a2777ecbSMarcel Ziswiler config_block, WITH_WR_VERIFY); 169a2777ecbSMarcel Ziswiler } 170a2777ecbSMarcel Ziswiler #endif 171a2777ecbSMarcel Ziswiler 172a2777ecbSMarcel Ziswiler #ifdef CONFIG_TDX_CFG_BLOCK_IS_IN_NOR 173a2777ecbSMarcel Ziswiler static int read_tdx_cfg_block_from_nor(unsigned char *config_block) 174a2777ecbSMarcel Ziswiler { 175a2777ecbSMarcel Ziswiler /* Read production parameter config block from NOR flash */ 176a2777ecbSMarcel Ziswiler memcpy(config_block, (void *)CONFIG_TDX_CFG_BLOCK_OFFSET, 177a2777ecbSMarcel Ziswiler TDX_CFG_BLOCK_MAX_SIZE); 178a2777ecbSMarcel Ziswiler return 0; 179a2777ecbSMarcel Ziswiler } 180a2777ecbSMarcel Ziswiler 181a2777ecbSMarcel Ziswiler static int write_tdx_cfg_block_to_nor(unsigned char *config_block) 182a2777ecbSMarcel Ziswiler { 183a2777ecbSMarcel Ziswiler /* Write production parameter config block to NOR flash */ 184a2777ecbSMarcel Ziswiler return flash_write((void *)config_block, CONFIG_TDX_CFG_BLOCK_OFFSET, 185a2777ecbSMarcel Ziswiler TDX_CFG_BLOCK_MAX_SIZE); 186a2777ecbSMarcel Ziswiler } 187a2777ecbSMarcel Ziswiler #endif 188a2777ecbSMarcel Ziswiler 189a2777ecbSMarcel Ziswiler int read_tdx_cfg_block(void) 190a2777ecbSMarcel Ziswiler { 191a2777ecbSMarcel Ziswiler int ret = 0; 192a2777ecbSMarcel Ziswiler u8 *config_block = NULL; 193a2777ecbSMarcel Ziswiler struct toradex_tag *tag; 194a2777ecbSMarcel Ziswiler size_t size = TDX_CFG_BLOCK_MAX_SIZE; 195a2777ecbSMarcel Ziswiler int offset; 196a2777ecbSMarcel Ziswiler 197a2777ecbSMarcel Ziswiler /* Allocate RAM area for config block */ 198a2777ecbSMarcel Ziswiler config_block = memalign(ARCH_DMA_MINALIGN, size); 199a2777ecbSMarcel Ziswiler if (!config_block) { 200a2777ecbSMarcel Ziswiler printf("Not enough malloc space available!\n"); 201a2777ecbSMarcel Ziswiler return -ENOMEM; 202a2777ecbSMarcel Ziswiler } 203a2777ecbSMarcel Ziswiler 204a2777ecbSMarcel Ziswiler memset(config_block, 0, size); 205a2777ecbSMarcel Ziswiler 206a2777ecbSMarcel Ziswiler #if defined(CONFIG_TDX_CFG_BLOCK_IS_IN_MMC) 207a2777ecbSMarcel Ziswiler ret = tdx_cfg_block_mmc_storage(config_block, 0); 208a2777ecbSMarcel Ziswiler #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NAND) 209a2777ecbSMarcel Ziswiler ret = read_tdx_cfg_block_from_nand(config_block); 210a2777ecbSMarcel Ziswiler #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NOR) 211a2777ecbSMarcel Ziswiler ret = read_tdx_cfg_block_from_nor(config_block); 212a2777ecbSMarcel Ziswiler #else 213a2777ecbSMarcel Ziswiler ret = -EINVAL; 214a2777ecbSMarcel Ziswiler #endif 215a2777ecbSMarcel Ziswiler if (ret) 216a2777ecbSMarcel Ziswiler goto out; 217a2777ecbSMarcel Ziswiler 218a2777ecbSMarcel Ziswiler /* Expect a valid tag first */ 219a2777ecbSMarcel Ziswiler tag = (struct toradex_tag *)config_block; 220a2777ecbSMarcel Ziswiler if (tag->flags != TAG_FLAG_VALID || tag->id != TAG_VALID) { 221a2777ecbSMarcel Ziswiler valid_cfgblock = false; 222a2777ecbSMarcel Ziswiler ret = -EINVAL; 223a2777ecbSMarcel Ziswiler goto out; 224a2777ecbSMarcel Ziswiler } 225a2777ecbSMarcel Ziswiler valid_cfgblock = true; 226a2777ecbSMarcel Ziswiler offset = 4; 227a2777ecbSMarcel Ziswiler 228a2777ecbSMarcel Ziswiler while (offset < TDX_CFG_BLOCK_MAX_SIZE) { 229a2777ecbSMarcel Ziswiler tag = (struct toradex_tag *)(config_block + offset); 230a2777ecbSMarcel Ziswiler offset += 4; 231a2777ecbSMarcel Ziswiler if (tag->id == TAG_INVALID) 232a2777ecbSMarcel Ziswiler break; 233a2777ecbSMarcel Ziswiler 234a2777ecbSMarcel Ziswiler if (tag->flags == TAG_FLAG_VALID) { 235a2777ecbSMarcel Ziswiler switch (tag->id) { 236a2777ecbSMarcel Ziswiler case TAG_MAC: 237a2777ecbSMarcel Ziswiler memcpy(&tdx_eth_addr, config_block + offset, 238a2777ecbSMarcel Ziswiler 6); 239a2777ecbSMarcel Ziswiler 240a2777ecbSMarcel Ziswiler /* NIC part of MAC address is serial number */ 241a2777ecbSMarcel Ziswiler tdx_serial = ntohl(tdx_eth_addr.nic) >> 8; 242a2777ecbSMarcel Ziswiler break; 243a2777ecbSMarcel Ziswiler case TAG_HW: 244a2777ecbSMarcel Ziswiler memcpy(&tdx_hw_tag, config_block + offset, 8); 245a2777ecbSMarcel Ziswiler break; 246a2777ecbSMarcel Ziswiler } 247a2777ecbSMarcel Ziswiler } 248a2777ecbSMarcel Ziswiler 249a2777ecbSMarcel Ziswiler /* Get to next tag according to current tags length */ 250a2777ecbSMarcel Ziswiler offset += tag->len * 4; 251a2777ecbSMarcel Ziswiler } 252a2777ecbSMarcel Ziswiler 253a2777ecbSMarcel Ziswiler /* Cap product id to avoid issues with a yet unknown one */ 254a2777ecbSMarcel Ziswiler if (tdx_hw_tag.prodid > (sizeof(toradex_modules) / 255a2777ecbSMarcel Ziswiler sizeof(toradex_modules[0]))) 256a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = 0; 257a2777ecbSMarcel Ziswiler 258a2777ecbSMarcel Ziswiler out: 259a2777ecbSMarcel Ziswiler free(config_block); 260a2777ecbSMarcel Ziswiler return ret; 261a2777ecbSMarcel Ziswiler } 262a2777ecbSMarcel Ziswiler 263a2777ecbSMarcel Ziswiler static int get_cfgblock_interactive(void) 264a2777ecbSMarcel Ziswiler { 265a2777ecbSMarcel Ziswiler char message[CONFIG_SYS_CBSIZE]; 266a2777ecbSMarcel Ziswiler char *soc; 267a2777ecbSMarcel Ziswiler char it = 'n'; 268a2777ecbSMarcel Ziswiler int len; 269a2777ecbSMarcel Ziswiler 270a2777ecbSMarcel Ziswiler if (cpu_is_pxa27x()) 271a2777ecbSMarcel Ziswiler sprintf(message, "Is the module the 312 MHz version? [y/N] "); 272a2777ecbSMarcel Ziswiler else 273a2777ecbSMarcel Ziswiler sprintf(message, "Is the module an IT version? [y/N] "); 274a2777ecbSMarcel Ziswiler 275a2777ecbSMarcel Ziswiler len = cli_readline(message); 276a2777ecbSMarcel Ziswiler it = console_buffer[0]; 277a2777ecbSMarcel Ziswiler 27800caae6dSSimon Glass soc = env_get("soc"); 279a2777ecbSMarcel Ziswiler if (!strcmp("mx6", soc)) { 280a2777ecbSMarcel Ziswiler #ifdef CONFIG_MACH_TYPE 281a2777ecbSMarcel Ziswiler if (it == 'y' || it == 'Y') 282a2777ecbSMarcel Ziswiler if (is_cpu_type(MXC_CPU_MX6Q)) 283a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = APALIS_IMX6Q_IT; 284a2777ecbSMarcel Ziswiler else 285a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = APALIS_IMX6D_IT; 286a2777ecbSMarcel Ziswiler else 287a2777ecbSMarcel Ziswiler if (is_cpu_type(MXC_CPU_MX6Q)) 288a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = APALIS_IMX6Q; 289a2777ecbSMarcel Ziswiler else 290a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = APALIS_IMX6D; 291a2777ecbSMarcel Ziswiler #else 292a2777ecbSMarcel Ziswiler if (it == 'y' || it == 'Y') 293a2777ecbSMarcel Ziswiler if (is_cpu_type(MXC_CPU_MX6DL)) 294a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_IMX6DL_IT; 295a2777ecbSMarcel Ziswiler else 296a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_IMX6S_IT; 297a2777ecbSMarcel Ziswiler else 298a2777ecbSMarcel Ziswiler if (is_cpu_type(MXC_CPU_MX6DL)) 299a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_IMX6DL; 300a2777ecbSMarcel Ziswiler else 301a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_IMX6S; 302a2777ecbSMarcel Ziswiler #endif /* CONFIG_MACH_TYPE */ 303a2777ecbSMarcel Ziswiler } else if (!strcmp("imx7d", soc)) { 304a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_IMX7D; 305a2777ecbSMarcel Ziswiler } else if (!strcmp("imx7s", soc)) { 306a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_IMX7S; 307a2777ecbSMarcel Ziswiler } else if (!strcmp("tegra20", soc)) { 308a2777ecbSMarcel Ziswiler if (it == 'y' || it == 'Y') 309a2777ecbSMarcel Ziswiler if (gd->ram_size == 0x10000000) 310a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_T20_256MB_IT; 311a2777ecbSMarcel Ziswiler else 312a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_T20_512MB_IT; 313a2777ecbSMarcel Ziswiler else 314a2777ecbSMarcel Ziswiler if (gd->ram_size == 0x10000000) 315a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_T20_256MB; 316a2777ecbSMarcel Ziswiler else 317a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_T20_512MB; 318a2777ecbSMarcel Ziswiler } else if (cpu_is_pxa27x()) { 319a2777ecbSMarcel Ziswiler if (it == 'y' || it == 'Y') 320a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_PXA270_312MHZ; 321a2777ecbSMarcel Ziswiler else 322a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_PXA270_520MHZ; 323a2777ecbSMarcel Ziswiler #ifdef CONFIG_MACH_TYPE 324a2777ecbSMarcel Ziswiler } else if (!strcmp("tegra30", soc)) { 325a2777ecbSMarcel Ziswiler if (CONFIG_MACH_TYPE == MACH_TYPE_APALIS_T30) { 326a2777ecbSMarcel Ziswiler if (it == 'y' || it == 'Y') 327a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = APALIS_T30_IT; 328a2777ecbSMarcel Ziswiler else 329a2777ecbSMarcel Ziswiler if (gd->ram_size == 0x40000000) 330a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = APALIS_T30_1GB; 331a2777ecbSMarcel Ziswiler else 332a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = APALIS_T30_2GB; 333a2777ecbSMarcel Ziswiler } else { 334a2777ecbSMarcel Ziswiler if (it == 'y' || it == 'Y') 335a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_T30_IT; 336a2777ecbSMarcel Ziswiler else 337a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_T30; 338a2777ecbSMarcel Ziswiler } 339a2777ecbSMarcel Ziswiler #endif /* CONFIG_MACH_TYPE */ 340a2777ecbSMarcel Ziswiler } else if (!strcmp("tegra124", soc)) { 341a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = APALIS_TK1_2GB; 342a2777ecbSMarcel Ziswiler } else if (!strcmp("vf500", soc)) { 343a2777ecbSMarcel Ziswiler if (it == 'y' || it == 'Y') 344a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_VF50_IT; 345a2777ecbSMarcel Ziswiler else 346a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_VF50; 347a2777ecbSMarcel Ziswiler } else if (!strcmp("vf610", soc)) { 348a2777ecbSMarcel Ziswiler if (it == 'y' || it == 'Y') 349a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_VF61_IT; 350a2777ecbSMarcel Ziswiler else 351a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_VF61; 352a2777ecbSMarcel Ziswiler } else { 353a2777ecbSMarcel Ziswiler printf("Module type not detectable due to unknown SoC\n"); 354a2777ecbSMarcel Ziswiler return -1; 355a2777ecbSMarcel Ziswiler } 356a2777ecbSMarcel Ziswiler 357a2777ecbSMarcel Ziswiler while (len < 4) { 358a2777ecbSMarcel Ziswiler sprintf(message, "Enter the module version (e.g. V1.1B): V"); 359a2777ecbSMarcel Ziswiler len = cli_readline(message); 360a2777ecbSMarcel Ziswiler } 361a2777ecbSMarcel Ziswiler 362a2777ecbSMarcel Ziswiler tdx_hw_tag.ver_major = console_buffer[0] - '0'; 363a2777ecbSMarcel Ziswiler tdx_hw_tag.ver_minor = console_buffer[2] - '0'; 364a2777ecbSMarcel Ziswiler tdx_hw_tag.ver_assembly = console_buffer[3] - 'A'; 365a2777ecbSMarcel Ziswiler 366a2777ecbSMarcel Ziswiler if (cpu_is_pxa27x() && (tdx_hw_tag.ver_major == 1)) 367a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid -= (COLIBRI_PXA270_312MHZ - 368a2777ecbSMarcel Ziswiler COLIBRI_PXA270_V1_312MHZ); 369a2777ecbSMarcel Ziswiler 370a2777ecbSMarcel Ziswiler while (len < 8) { 371a2777ecbSMarcel Ziswiler sprintf(message, "Enter module serial number: "); 372a2777ecbSMarcel Ziswiler len = cli_readline(message); 373a2777ecbSMarcel Ziswiler } 374a2777ecbSMarcel Ziswiler 375a2777ecbSMarcel Ziswiler tdx_serial = simple_strtoul(console_buffer, NULL, 10); 376a2777ecbSMarcel Ziswiler 377a2777ecbSMarcel Ziswiler return 0; 378a2777ecbSMarcel Ziswiler } 379a2777ecbSMarcel Ziswiler 380a2777ecbSMarcel Ziswiler static int get_cfgblock_barcode(char *barcode) 381a2777ecbSMarcel Ziswiler { 382a2777ecbSMarcel Ziswiler if (strlen(barcode) < 16) { 383a2777ecbSMarcel Ziswiler printf("Argument too short, barcode is 16 chars long\n"); 384a2777ecbSMarcel Ziswiler return -1; 385a2777ecbSMarcel Ziswiler } 386a2777ecbSMarcel Ziswiler 387a2777ecbSMarcel Ziswiler /* Get hardware information from the first 8 digits */ 388a2777ecbSMarcel Ziswiler tdx_hw_tag.ver_major = barcode[4] - '0'; 389a2777ecbSMarcel Ziswiler tdx_hw_tag.ver_minor = barcode[5] - '0'; 390a2777ecbSMarcel Ziswiler tdx_hw_tag.ver_assembly = barcode[7] - '0'; 391a2777ecbSMarcel Ziswiler 392a2777ecbSMarcel Ziswiler barcode[4] = '\0'; 393a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = simple_strtoul(barcode, NULL, 10); 394a2777ecbSMarcel Ziswiler 395a2777ecbSMarcel Ziswiler /* Parse second part of the barcode (serial number */ 396a2777ecbSMarcel Ziswiler barcode += 8; 397a2777ecbSMarcel Ziswiler tdx_serial = simple_strtoul(barcode, NULL, 10); 398a2777ecbSMarcel Ziswiler 399a2777ecbSMarcel Ziswiler return 0; 400a2777ecbSMarcel Ziswiler } 401a2777ecbSMarcel Ziswiler 402a2777ecbSMarcel Ziswiler static int do_cfgblock_create(cmd_tbl_t *cmdtp, int flag, int argc, 403a2777ecbSMarcel Ziswiler char * const argv[]) 404a2777ecbSMarcel Ziswiler { 405a2777ecbSMarcel Ziswiler u8 *config_block; 406a2777ecbSMarcel Ziswiler struct toradex_tag *tag; 407a2777ecbSMarcel Ziswiler size_t size = TDX_CFG_BLOCK_MAX_SIZE; 408a2777ecbSMarcel Ziswiler int offset = 0; 409a2777ecbSMarcel Ziswiler int ret = CMD_RET_SUCCESS; 410a2777ecbSMarcel Ziswiler int err; 411a2777ecbSMarcel Ziswiler 412a2777ecbSMarcel Ziswiler /* Allocate RAM area for config block */ 413a2777ecbSMarcel Ziswiler config_block = memalign(ARCH_DMA_MINALIGN, size); 414a2777ecbSMarcel Ziswiler if (!config_block) { 415a2777ecbSMarcel Ziswiler printf("Not enough malloc space available!\n"); 416a2777ecbSMarcel Ziswiler return CMD_RET_FAILURE; 417a2777ecbSMarcel Ziswiler } 418a2777ecbSMarcel Ziswiler 419a2777ecbSMarcel Ziswiler memset(config_block, 0xff, size); 420a2777ecbSMarcel Ziswiler 421a2777ecbSMarcel Ziswiler read_tdx_cfg_block(); 422a2777ecbSMarcel Ziswiler if (valid_cfgblock) { 423a2777ecbSMarcel Ziswiler #if defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NAND) 424a2777ecbSMarcel Ziswiler /* 425a2777ecbSMarcel Ziswiler * On NAND devices, recreation is only allowed if the page is 426a2777ecbSMarcel Ziswiler * empty (config block invalid...) 427a2777ecbSMarcel Ziswiler */ 428a2777ecbSMarcel Ziswiler printf("NAND erase block %d need to be erased before creating a Toradex config block\n", 429bf264cd0SGrygorii Strashko CONFIG_TDX_CFG_BLOCK_OFFSET / 430bf264cd0SGrygorii Strashko get_nand_dev_by_index(0)->erasesize); 431a2777ecbSMarcel Ziswiler goto out; 432a2777ecbSMarcel Ziswiler #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NOR) 433a2777ecbSMarcel Ziswiler /* 434a2777ecbSMarcel Ziswiler * On NOR devices, recreation is only allowed if the sector is 435a2777ecbSMarcel Ziswiler * empty and write protection is off (config block invalid...) 436a2777ecbSMarcel Ziswiler */ 437a2777ecbSMarcel Ziswiler printf("NOR sector at offset 0x%02x need to be erased and unprotected before creating a Toradex config block\n", 438a2777ecbSMarcel Ziswiler CONFIG_TDX_CFG_BLOCK_OFFSET); 439a2777ecbSMarcel Ziswiler goto out; 440a2777ecbSMarcel Ziswiler #else 441a2777ecbSMarcel Ziswiler char message[CONFIG_SYS_CBSIZE]; 442a2777ecbSMarcel Ziswiler sprintf(message, 443a2777ecbSMarcel Ziswiler "A valid Toradex config block is present, still recreate? [y/N] "); 444a2777ecbSMarcel Ziswiler 445a2777ecbSMarcel Ziswiler if (!cli_readline(message)) 446a2777ecbSMarcel Ziswiler goto out; 447a2777ecbSMarcel Ziswiler 448a2777ecbSMarcel Ziswiler if (console_buffer[0] != 'y' && console_buffer[0] != 'Y') 449a2777ecbSMarcel Ziswiler goto out; 450a2777ecbSMarcel Ziswiler #endif 451a2777ecbSMarcel Ziswiler } 452a2777ecbSMarcel Ziswiler 453a2777ecbSMarcel Ziswiler /* Parse new Toradex config block data... */ 454a2777ecbSMarcel Ziswiler if (argc < 3) 455a2777ecbSMarcel Ziswiler err = get_cfgblock_interactive(); 456a2777ecbSMarcel Ziswiler else 457a2777ecbSMarcel Ziswiler err = get_cfgblock_barcode(argv[2]); 458a2777ecbSMarcel Ziswiler 459a2777ecbSMarcel Ziswiler if (err) { 460a2777ecbSMarcel Ziswiler ret = CMD_RET_FAILURE; 461a2777ecbSMarcel Ziswiler goto out; 462a2777ecbSMarcel Ziswiler } 463a2777ecbSMarcel Ziswiler 464a2777ecbSMarcel Ziswiler /* Convert serial number to MAC address (the storage format) */ 465a2777ecbSMarcel Ziswiler tdx_eth_addr.oui = htonl(0x00142dUL << 8); 466a2777ecbSMarcel Ziswiler tdx_eth_addr.nic = htonl(tdx_serial << 8); 467a2777ecbSMarcel Ziswiler 468a2777ecbSMarcel Ziswiler /* Valid Tag */ 469a2777ecbSMarcel Ziswiler tag = (struct toradex_tag *)config_block; 470a2777ecbSMarcel Ziswiler tag->id = TAG_VALID; 471a2777ecbSMarcel Ziswiler tag->flags = TAG_FLAG_VALID; 472a2777ecbSMarcel Ziswiler tag->len = 0; 473a2777ecbSMarcel Ziswiler offset += 4; 474a2777ecbSMarcel Ziswiler 475a2777ecbSMarcel Ziswiler /* Product Tag */ 476a2777ecbSMarcel Ziswiler tag = (struct toradex_tag *)(config_block + offset); 477a2777ecbSMarcel Ziswiler tag->id = TAG_HW; 478a2777ecbSMarcel Ziswiler tag->flags = TAG_FLAG_VALID; 479a2777ecbSMarcel Ziswiler tag->len = 2; 480a2777ecbSMarcel Ziswiler offset += 4; 481a2777ecbSMarcel Ziswiler 482a2777ecbSMarcel Ziswiler memcpy(config_block + offset, &tdx_hw_tag, 8); 483a2777ecbSMarcel Ziswiler offset += 8; 484a2777ecbSMarcel Ziswiler 485a2777ecbSMarcel Ziswiler /* MAC Tag */ 486a2777ecbSMarcel Ziswiler tag = (struct toradex_tag *)(config_block + offset); 487a2777ecbSMarcel Ziswiler tag->id = TAG_MAC; 488a2777ecbSMarcel Ziswiler tag->flags = TAG_FLAG_VALID; 489a2777ecbSMarcel Ziswiler tag->len = 2; 490a2777ecbSMarcel Ziswiler offset += 4; 491a2777ecbSMarcel Ziswiler 492a2777ecbSMarcel Ziswiler memcpy(config_block + offset, &tdx_eth_addr, 6); 493a2777ecbSMarcel Ziswiler offset += 6; 494a2777ecbSMarcel Ziswiler memset(config_block + offset, 0, 32 - offset); 495a2777ecbSMarcel Ziswiler 496a2777ecbSMarcel Ziswiler #if defined(CONFIG_TDX_CFG_BLOCK_IS_IN_MMC) 497a2777ecbSMarcel Ziswiler err = tdx_cfg_block_mmc_storage(config_block, 1); 498a2777ecbSMarcel Ziswiler #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NAND) 499a2777ecbSMarcel Ziswiler err = write_tdx_cfg_block_to_nand(config_block); 500a2777ecbSMarcel Ziswiler #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NOR) 501a2777ecbSMarcel Ziswiler err = write_tdx_cfg_block_to_nor(config_block); 502a2777ecbSMarcel Ziswiler #else 503a2777ecbSMarcel Ziswiler err = -EINVAL; 504a2777ecbSMarcel Ziswiler #endif 505a2777ecbSMarcel Ziswiler if (err) { 506a2777ecbSMarcel Ziswiler printf("Failed to write Toradex config block: %d\n", ret); 507a2777ecbSMarcel Ziswiler ret = CMD_RET_FAILURE; 508a2777ecbSMarcel Ziswiler goto out; 509a2777ecbSMarcel Ziswiler } 510a2777ecbSMarcel Ziswiler 511a2777ecbSMarcel Ziswiler printf("Toradex config block successfully written\n"); 512a2777ecbSMarcel Ziswiler 513a2777ecbSMarcel Ziswiler out: 514a2777ecbSMarcel Ziswiler free(config_block); 515a2777ecbSMarcel Ziswiler return ret; 516a2777ecbSMarcel Ziswiler } 517a2777ecbSMarcel Ziswiler 518a2777ecbSMarcel Ziswiler static int do_cfgblock(cmd_tbl_t *cmdtp, int flag, int argc, 519a2777ecbSMarcel Ziswiler char * const argv[]) 520a2777ecbSMarcel Ziswiler { 521a2777ecbSMarcel Ziswiler int ret; 522a2777ecbSMarcel Ziswiler 523a2777ecbSMarcel Ziswiler if (argc < 2) 524a2777ecbSMarcel Ziswiler return CMD_RET_USAGE; 525a2777ecbSMarcel Ziswiler 526a2777ecbSMarcel Ziswiler if (!strcmp(argv[1], "create")) { 527a2777ecbSMarcel Ziswiler return do_cfgblock_create(cmdtp, flag, argc, argv); 528a2777ecbSMarcel Ziswiler } else if (!strcmp(argv[1], "reload")) { 529a2777ecbSMarcel Ziswiler ret = read_tdx_cfg_block(); 530a2777ecbSMarcel Ziswiler if (ret) { 531a2777ecbSMarcel Ziswiler printf("Failed to reload Toradex config block: %d\n", 532a2777ecbSMarcel Ziswiler ret); 533a2777ecbSMarcel Ziswiler return CMD_RET_FAILURE; 534a2777ecbSMarcel Ziswiler } 535a2777ecbSMarcel Ziswiler return CMD_RET_SUCCESS; 536a2777ecbSMarcel Ziswiler } 537a2777ecbSMarcel Ziswiler 538a2777ecbSMarcel Ziswiler return CMD_RET_USAGE; 539a2777ecbSMarcel Ziswiler } 540a2777ecbSMarcel Ziswiler 541a2777ecbSMarcel Ziswiler U_BOOT_CMD( 542a2777ecbSMarcel Ziswiler cfgblock, 3, 0, do_cfgblock, 543a2777ecbSMarcel Ziswiler "Toradex config block handling commands", 544a2777ecbSMarcel Ziswiler "create [barcode] - (Re-)create Toradex config block\n" 545a2777ecbSMarcel Ziswiler "cfgblock reload - Reload Toradex config block from flash" 546a2777ecbSMarcel Ziswiler ); 547