1a2777ecbSMarcel Ziswiler /* 2a2777ecbSMarcel Ziswiler * Copyright (c) 2016 Toradex, Inc. 3a2777ecbSMarcel Ziswiler * 4a2777ecbSMarcel Ziswiler * SPDX-License-Identifier: GPL-2.0+ 5a2777ecbSMarcel Ziswiler */ 6a2777ecbSMarcel Ziswiler 7a2777ecbSMarcel Ziswiler #include <common.h> 8a2777ecbSMarcel Ziswiler #include "tdx-cfg-block.h" 9a2777ecbSMarcel Ziswiler 10a2777ecbSMarcel Ziswiler #if defined(CONFIG_TARGET_APALIS_IMX6) || defined(CONFIG_TARGET_COLIBRI_IMX6) 11a2777ecbSMarcel Ziswiler #include <asm/arch/sys_proto.h> 12a2777ecbSMarcel Ziswiler #else 13a2777ecbSMarcel Ziswiler #define is_cpu_type(cpu) (0) 14a2777ecbSMarcel Ziswiler #endif 15a2777ecbSMarcel Ziswiler #if defined(CONFIG_CPU_PXA27X) 16a2777ecbSMarcel Ziswiler #include <asm/arch-pxa/pxa.h> 17a2777ecbSMarcel Ziswiler #else 18a2777ecbSMarcel Ziswiler #define cpu_is_pxa27x(cpu) (0) 19a2777ecbSMarcel Ziswiler #endif 20a2777ecbSMarcel Ziswiler #include <cli.h> 21a2777ecbSMarcel Ziswiler #include <console.h> 22a2777ecbSMarcel Ziswiler #include <flash.h> 23a2777ecbSMarcel Ziswiler #include <malloc.h> 24a2777ecbSMarcel Ziswiler #include <mmc.h> 25a2777ecbSMarcel Ziswiler #include <nand.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 } 113*0e513e78SSimon 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 /* Flush cache after read */ 132a2777ecbSMarcel Ziswiler flush_cache((ulong)(unsigned char *)config_block, 512); 133a2777ecbSMarcel Ziswiler } else { 134a2777ecbSMarcel Ziswiler /* Just writing one 512 byte block */ 135a2777ecbSMarcel Ziswiler if (blk_dwrite(mmc_get_blk_desc(mmc), blk_start, 1, 136a2777ecbSMarcel Ziswiler (unsigned char *)config_block) != 1) { 137a2777ecbSMarcel Ziswiler ret = -EIO; 138a2777ecbSMarcel Ziswiler goto out; 139a2777ecbSMarcel Ziswiler } 140a2777ecbSMarcel Ziswiler } 141a2777ecbSMarcel Ziswiler 142a2777ecbSMarcel Ziswiler out: 143a2777ecbSMarcel Ziswiler /* Switch back to regular eMMC user partition */ 144a2777ecbSMarcel Ziswiler blk_select_hwpart_devnum(IF_TYPE_MMC, 0, 0); 145a2777ecbSMarcel Ziswiler 146a2777ecbSMarcel Ziswiler return ret; 147a2777ecbSMarcel Ziswiler } 148a2777ecbSMarcel Ziswiler #endif 149a2777ecbSMarcel Ziswiler 150a2777ecbSMarcel Ziswiler #ifdef CONFIG_TDX_CFG_BLOCK_IS_IN_NAND 151a2777ecbSMarcel Ziswiler static int read_tdx_cfg_block_from_nand(unsigned char *config_block) 152a2777ecbSMarcel Ziswiler { 153a2777ecbSMarcel Ziswiler size_t size = TDX_CFG_BLOCK_MAX_SIZE; 154a2777ecbSMarcel Ziswiler 155a2777ecbSMarcel Ziswiler /* Read production parameter config block from NAND page */ 156a2777ecbSMarcel Ziswiler return nand_read_skip_bad(nand_info[0], CONFIG_TDX_CFG_BLOCK_OFFSET, 157a2777ecbSMarcel Ziswiler &size, NULL, TDX_CFG_BLOCK_MAX_SIZE, 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 */ 165a2777ecbSMarcel Ziswiler return nand_write_skip_bad(nand_info[0], CONFIG_TDX_CFG_BLOCK_OFFSET, 166a2777ecbSMarcel Ziswiler &size, NULL, TDX_CFG_BLOCK_MAX_SIZE, 167a2777ecbSMarcel Ziswiler config_block, WITH_WR_VERIFY); 168a2777ecbSMarcel Ziswiler } 169a2777ecbSMarcel Ziswiler #endif 170a2777ecbSMarcel Ziswiler 171a2777ecbSMarcel Ziswiler #ifdef CONFIG_TDX_CFG_BLOCK_IS_IN_NOR 172a2777ecbSMarcel Ziswiler static int read_tdx_cfg_block_from_nor(unsigned char *config_block) 173a2777ecbSMarcel Ziswiler { 174a2777ecbSMarcel Ziswiler /* Read production parameter config block from NOR flash */ 175a2777ecbSMarcel Ziswiler memcpy(config_block, (void *)CONFIG_TDX_CFG_BLOCK_OFFSET, 176a2777ecbSMarcel Ziswiler TDX_CFG_BLOCK_MAX_SIZE); 177a2777ecbSMarcel Ziswiler return 0; 178a2777ecbSMarcel Ziswiler } 179a2777ecbSMarcel Ziswiler 180a2777ecbSMarcel Ziswiler static int write_tdx_cfg_block_to_nor(unsigned char *config_block) 181a2777ecbSMarcel Ziswiler { 182a2777ecbSMarcel Ziswiler /* Write production parameter config block to NOR flash */ 183a2777ecbSMarcel Ziswiler return flash_write((void *)config_block, CONFIG_TDX_CFG_BLOCK_OFFSET, 184a2777ecbSMarcel Ziswiler TDX_CFG_BLOCK_MAX_SIZE); 185a2777ecbSMarcel Ziswiler } 186a2777ecbSMarcel Ziswiler #endif 187a2777ecbSMarcel Ziswiler 188a2777ecbSMarcel Ziswiler int read_tdx_cfg_block(void) 189a2777ecbSMarcel Ziswiler { 190a2777ecbSMarcel Ziswiler int ret = 0; 191a2777ecbSMarcel Ziswiler u8 *config_block = NULL; 192a2777ecbSMarcel Ziswiler struct toradex_tag *tag; 193a2777ecbSMarcel Ziswiler size_t size = TDX_CFG_BLOCK_MAX_SIZE; 194a2777ecbSMarcel Ziswiler int offset; 195a2777ecbSMarcel Ziswiler 196a2777ecbSMarcel Ziswiler /* Allocate RAM area for config block */ 197a2777ecbSMarcel Ziswiler config_block = memalign(ARCH_DMA_MINALIGN, size); 198a2777ecbSMarcel Ziswiler if (!config_block) { 199a2777ecbSMarcel Ziswiler printf("Not enough malloc space available!\n"); 200a2777ecbSMarcel Ziswiler return -ENOMEM; 201a2777ecbSMarcel Ziswiler } 202a2777ecbSMarcel Ziswiler 203a2777ecbSMarcel Ziswiler memset(config_block, 0, size); 204a2777ecbSMarcel Ziswiler 205a2777ecbSMarcel Ziswiler #if defined(CONFIG_TDX_CFG_BLOCK_IS_IN_MMC) 206a2777ecbSMarcel Ziswiler ret = tdx_cfg_block_mmc_storage(config_block, 0); 207a2777ecbSMarcel Ziswiler #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NAND) 208a2777ecbSMarcel Ziswiler ret = read_tdx_cfg_block_from_nand(config_block); 209a2777ecbSMarcel Ziswiler #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NOR) 210a2777ecbSMarcel Ziswiler ret = read_tdx_cfg_block_from_nor(config_block); 211a2777ecbSMarcel Ziswiler #else 212a2777ecbSMarcel Ziswiler ret = -EINVAL; 213a2777ecbSMarcel Ziswiler #endif 214a2777ecbSMarcel Ziswiler if (ret) 215a2777ecbSMarcel Ziswiler goto out; 216a2777ecbSMarcel Ziswiler 217a2777ecbSMarcel Ziswiler /* Expect a valid tag first */ 218a2777ecbSMarcel Ziswiler tag = (struct toradex_tag *)config_block; 219a2777ecbSMarcel Ziswiler if (tag->flags != TAG_FLAG_VALID || tag->id != TAG_VALID) { 220a2777ecbSMarcel Ziswiler valid_cfgblock = false; 221a2777ecbSMarcel Ziswiler ret = -EINVAL; 222a2777ecbSMarcel Ziswiler goto out; 223a2777ecbSMarcel Ziswiler } 224a2777ecbSMarcel Ziswiler valid_cfgblock = true; 225a2777ecbSMarcel Ziswiler offset = 4; 226a2777ecbSMarcel Ziswiler 227a2777ecbSMarcel Ziswiler while (offset < TDX_CFG_BLOCK_MAX_SIZE) { 228a2777ecbSMarcel Ziswiler tag = (struct toradex_tag *)(config_block + offset); 229a2777ecbSMarcel Ziswiler offset += 4; 230a2777ecbSMarcel Ziswiler if (tag->id == TAG_INVALID) 231a2777ecbSMarcel Ziswiler break; 232a2777ecbSMarcel Ziswiler 233a2777ecbSMarcel Ziswiler if (tag->flags == TAG_FLAG_VALID) { 234a2777ecbSMarcel Ziswiler switch (tag->id) { 235a2777ecbSMarcel Ziswiler case TAG_MAC: 236a2777ecbSMarcel Ziswiler memcpy(&tdx_eth_addr, config_block + offset, 237a2777ecbSMarcel Ziswiler 6); 238a2777ecbSMarcel Ziswiler 239a2777ecbSMarcel Ziswiler /* NIC part of MAC address is serial number */ 240a2777ecbSMarcel Ziswiler tdx_serial = ntohl(tdx_eth_addr.nic) >> 8; 241a2777ecbSMarcel Ziswiler break; 242a2777ecbSMarcel Ziswiler case TAG_HW: 243a2777ecbSMarcel Ziswiler memcpy(&tdx_hw_tag, config_block + offset, 8); 244a2777ecbSMarcel Ziswiler break; 245a2777ecbSMarcel Ziswiler } 246a2777ecbSMarcel Ziswiler } 247a2777ecbSMarcel Ziswiler 248a2777ecbSMarcel Ziswiler /* Get to next tag according to current tags length */ 249a2777ecbSMarcel Ziswiler offset += tag->len * 4; 250a2777ecbSMarcel Ziswiler } 251a2777ecbSMarcel Ziswiler 252a2777ecbSMarcel Ziswiler /* Cap product id to avoid issues with a yet unknown one */ 253a2777ecbSMarcel Ziswiler if (tdx_hw_tag.prodid > (sizeof(toradex_modules) / 254a2777ecbSMarcel Ziswiler sizeof(toradex_modules[0]))) 255a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = 0; 256a2777ecbSMarcel Ziswiler 257a2777ecbSMarcel Ziswiler out: 258a2777ecbSMarcel Ziswiler free(config_block); 259a2777ecbSMarcel Ziswiler return ret; 260a2777ecbSMarcel Ziswiler } 261a2777ecbSMarcel Ziswiler 262a2777ecbSMarcel Ziswiler static int get_cfgblock_interactive(void) 263a2777ecbSMarcel Ziswiler { 264a2777ecbSMarcel Ziswiler char message[CONFIG_SYS_CBSIZE]; 265a2777ecbSMarcel Ziswiler char *soc; 266a2777ecbSMarcel Ziswiler char it = 'n'; 267a2777ecbSMarcel Ziswiler int len; 268a2777ecbSMarcel Ziswiler 269a2777ecbSMarcel Ziswiler if (cpu_is_pxa27x()) 270a2777ecbSMarcel Ziswiler sprintf(message, "Is the module the 312 MHz version? [y/N] "); 271a2777ecbSMarcel Ziswiler else 272a2777ecbSMarcel Ziswiler sprintf(message, "Is the module an IT version? [y/N] "); 273a2777ecbSMarcel Ziswiler 274a2777ecbSMarcel Ziswiler len = cli_readline(message); 275a2777ecbSMarcel Ziswiler it = console_buffer[0]; 276a2777ecbSMarcel Ziswiler 277a2777ecbSMarcel Ziswiler soc = getenv("soc"); 278a2777ecbSMarcel Ziswiler if (!strcmp("mx6", soc)) { 279a2777ecbSMarcel Ziswiler #ifdef CONFIG_MACH_TYPE 280a2777ecbSMarcel Ziswiler if (it == 'y' || it == 'Y') 281a2777ecbSMarcel Ziswiler if (is_cpu_type(MXC_CPU_MX6Q)) 282a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = APALIS_IMX6Q_IT; 283a2777ecbSMarcel Ziswiler else 284a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = APALIS_IMX6D_IT; 285a2777ecbSMarcel Ziswiler else 286a2777ecbSMarcel Ziswiler if (is_cpu_type(MXC_CPU_MX6Q)) 287a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = APALIS_IMX6Q; 288a2777ecbSMarcel Ziswiler else 289a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = APALIS_IMX6D; 290a2777ecbSMarcel Ziswiler #else 291a2777ecbSMarcel Ziswiler if (it == 'y' || it == 'Y') 292a2777ecbSMarcel Ziswiler if (is_cpu_type(MXC_CPU_MX6DL)) 293a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_IMX6DL_IT; 294a2777ecbSMarcel Ziswiler else 295a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_IMX6S_IT; 296a2777ecbSMarcel Ziswiler else 297a2777ecbSMarcel Ziswiler if (is_cpu_type(MXC_CPU_MX6DL)) 298a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_IMX6DL; 299a2777ecbSMarcel Ziswiler else 300a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_IMX6S; 301a2777ecbSMarcel Ziswiler #endif /* CONFIG_MACH_TYPE */ 302a2777ecbSMarcel Ziswiler } else if (!strcmp("imx7d", soc)) { 303a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_IMX7D; 304a2777ecbSMarcel Ziswiler } else if (!strcmp("imx7s", soc)) { 305a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_IMX7S; 306a2777ecbSMarcel Ziswiler } else if (!strcmp("tegra20", soc)) { 307a2777ecbSMarcel Ziswiler if (it == 'y' || it == 'Y') 308a2777ecbSMarcel Ziswiler if (gd->ram_size == 0x10000000) 309a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_T20_256MB_IT; 310a2777ecbSMarcel Ziswiler else 311a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_T20_512MB_IT; 312a2777ecbSMarcel Ziswiler else 313a2777ecbSMarcel Ziswiler if (gd->ram_size == 0x10000000) 314a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_T20_256MB; 315a2777ecbSMarcel Ziswiler else 316a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_T20_512MB; 317a2777ecbSMarcel Ziswiler } else if (cpu_is_pxa27x()) { 318a2777ecbSMarcel Ziswiler if (it == 'y' || it == 'Y') 319a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_PXA270_312MHZ; 320a2777ecbSMarcel Ziswiler else 321a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_PXA270_520MHZ; 322a2777ecbSMarcel Ziswiler #ifdef CONFIG_MACH_TYPE 323a2777ecbSMarcel Ziswiler } else if (!strcmp("tegra30", soc)) { 324a2777ecbSMarcel Ziswiler if (CONFIG_MACH_TYPE == MACH_TYPE_APALIS_T30) { 325a2777ecbSMarcel Ziswiler if (it == 'y' || it == 'Y') 326a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = APALIS_T30_IT; 327a2777ecbSMarcel Ziswiler else 328a2777ecbSMarcel Ziswiler if (gd->ram_size == 0x40000000) 329a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = APALIS_T30_1GB; 330a2777ecbSMarcel Ziswiler else 331a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = APALIS_T30_2GB; 332a2777ecbSMarcel Ziswiler } else { 333a2777ecbSMarcel Ziswiler if (it == 'y' || it == 'Y') 334a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_T30_IT; 335a2777ecbSMarcel Ziswiler else 336a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_T30; 337a2777ecbSMarcel Ziswiler } 338a2777ecbSMarcel Ziswiler #endif /* CONFIG_MACH_TYPE */ 339a2777ecbSMarcel Ziswiler } else if (!strcmp("tegra124", soc)) { 340a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = APALIS_TK1_2GB; 341a2777ecbSMarcel Ziswiler } else if (!strcmp("vf500", soc)) { 342a2777ecbSMarcel Ziswiler if (it == 'y' || it == 'Y') 343a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_VF50_IT; 344a2777ecbSMarcel Ziswiler else 345a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_VF50; 346a2777ecbSMarcel Ziswiler } else if (!strcmp("vf610", soc)) { 347a2777ecbSMarcel Ziswiler if (it == 'y' || it == 'Y') 348a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_VF61_IT; 349a2777ecbSMarcel Ziswiler else 350a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = COLIBRI_VF61; 351a2777ecbSMarcel Ziswiler } else { 352a2777ecbSMarcel Ziswiler printf("Module type not detectable due to unknown SoC\n"); 353a2777ecbSMarcel Ziswiler return -1; 354a2777ecbSMarcel Ziswiler } 355a2777ecbSMarcel Ziswiler 356a2777ecbSMarcel Ziswiler while (len < 4) { 357a2777ecbSMarcel Ziswiler sprintf(message, "Enter the module version (e.g. V1.1B): V"); 358a2777ecbSMarcel Ziswiler len = cli_readline(message); 359a2777ecbSMarcel Ziswiler } 360a2777ecbSMarcel Ziswiler 361a2777ecbSMarcel Ziswiler tdx_hw_tag.ver_major = console_buffer[0] - '0'; 362a2777ecbSMarcel Ziswiler tdx_hw_tag.ver_minor = console_buffer[2] - '0'; 363a2777ecbSMarcel Ziswiler tdx_hw_tag.ver_assembly = console_buffer[3] - 'A'; 364a2777ecbSMarcel Ziswiler 365a2777ecbSMarcel Ziswiler if (cpu_is_pxa27x() && (tdx_hw_tag.ver_major == 1)) 366a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid -= (COLIBRI_PXA270_312MHZ - 367a2777ecbSMarcel Ziswiler COLIBRI_PXA270_V1_312MHZ); 368a2777ecbSMarcel Ziswiler 369a2777ecbSMarcel Ziswiler while (len < 8) { 370a2777ecbSMarcel Ziswiler sprintf(message, "Enter module serial number: "); 371a2777ecbSMarcel Ziswiler len = cli_readline(message); 372a2777ecbSMarcel Ziswiler } 373a2777ecbSMarcel Ziswiler 374a2777ecbSMarcel Ziswiler tdx_serial = simple_strtoul(console_buffer, NULL, 10); 375a2777ecbSMarcel Ziswiler 376a2777ecbSMarcel Ziswiler return 0; 377a2777ecbSMarcel Ziswiler } 378a2777ecbSMarcel Ziswiler 379a2777ecbSMarcel Ziswiler static int get_cfgblock_barcode(char *barcode) 380a2777ecbSMarcel Ziswiler { 381a2777ecbSMarcel Ziswiler if (strlen(barcode) < 16) { 382a2777ecbSMarcel Ziswiler printf("Argument too short, barcode is 16 chars long\n"); 383a2777ecbSMarcel Ziswiler return -1; 384a2777ecbSMarcel Ziswiler } 385a2777ecbSMarcel Ziswiler 386a2777ecbSMarcel Ziswiler /* Get hardware information from the first 8 digits */ 387a2777ecbSMarcel Ziswiler tdx_hw_tag.ver_major = barcode[4] - '0'; 388a2777ecbSMarcel Ziswiler tdx_hw_tag.ver_minor = barcode[5] - '0'; 389a2777ecbSMarcel Ziswiler tdx_hw_tag.ver_assembly = barcode[7] - '0'; 390a2777ecbSMarcel Ziswiler 391a2777ecbSMarcel Ziswiler barcode[4] = '\0'; 392a2777ecbSMarcel Ziswiler tdx_hw_tag.prodid = simple_strtoul(barcode, NULL, 10); 393a2777ecbSMarcel Ziswiler 394a2777ecbSMarcel Ziswiler /* Parse second part of the barcode (serial number */ 395a2777ecbSMarcel Ziswiler barcode += 8; 396a2777ecbSMarcel Ziswiler tdx_serial = simple_strtoul(barcode, NULL, 10); 397a2777ecbSMarcel Ziswiler 398a2777ecbSMarcel Ziswiler return 0; 399a2777ecbSMarcel Ziswiler } 400a2777ecbSMarcel Ziswiler 401a2777ecbSMarcel Ziswiler static int do_cfgblock_create(cmd_tbl_t *cmdtp, int flag, int argc, 402a2777ecbSMarcel Ziswiler char * const argv[]) 403a2777ecbSMarcel Ziswiler { 404a2777ecbSMarcel Ziswiler u8 *config_block; 405a2777ecbSMarcel Ziswiler struct toradex_tag *tag; 406a2777ecbSMarcel Ziswiler size_t size = TDX_CFG_BLOCK_MAX_SIZE; 407a2777ecbSMarcel Ziswiler int offset = 0; 408a2777ecbSMarcel Ziswiler int ret = CMD_RET_SUCCESS; 409a2777ecbSMarcel Ziswiler int err; 410a2777ecbSMarcel Ziswiler 411a2777ecbSMarcel Ziswiler /* Allocate RAM area for config block */ 412a2777ecbSMarcel Ziswiler config_block = memalign(ARCH_DMA_MINALIGN, size); 413a2777ecbSMarcel Ziswiler if (!config_block) { 414a2777ecbSMarcel Ziswiler printf("Not enough malloc space available!\n"); 415a2777ecbSMarcel Ziswiler return CMD_RET_FAILURE; 416a2777ecbSMarcel Ziswiler } 417a2777ecbSMarcel Ziswiler 418a2777ecbSMarcel Ziswiler memset(config_block, 0xff, size); 419a2777ecbSMarcel Ziswiler 420a2777ecbSMarcel Ziswiler read_tdx_cfg_block(); 421a2777ecbSMarcel Ziswiler if (valid_cfgblock) { 422a2777ecbSMarcel Ziswiler #if defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NAND) 423a2777ecbSMarcel Ziswiler /* 424a2777ecbSMarcel Ziswiler * On NAND devices, recreation is only allowed if the page is 425a2777ecbSMarcel Ziswiler * empty (config block invalid...) 426a2777ecbSMarcel Ziswiler */ 427a2777ecbSMarcel Ziswiler printf("NAND erase block %d need to be erased before creating a Toradex config block\n", 428a2777ecbSMarcel Ziswiler CONFIG_TDX_CFG_BLOCK_OFFSET / nand_info[0]->erasesize); 429a2777ecbSMarcel Ziswiler goto out; 430a2777ecbSMarcel Ziswiler #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NOR) 431a2777ecbSMarcel Ziswiler /* 432a2777ecbSMarcel Ziswiler * On NOR devices, recreation is only allowed if the sector is 433a2777ecbSMarcel Ziswiler * empty and write protection is off (config block invalid...) 434a2777ecbSMarcel Ziswiler */ 435a2777ecbSMarcel Ziswiler printf("NOR sector at offset 0x%02x need to be erased and unprotected before creating a Toradex config block\n", 436a2777ecbSMarcel Ziswiler CONFIG_TDX_CFG_BLOCK_OFFSET); 437a2777ecbSMarcel Ziswiler goto out; 438a2777ecbSMarcel Ziswiler #else 439a2777ecbSMarcel Ziswiler char message[CONFIG_SYS_CBSIZE]; 440a2777ecbSMarcel Ziswiler sprintf(message, 441a2777ecbSMarcel Ziswiler "A valid Toradex config block is present, still recreate? [y/N] "); 442a2777ecbSMarcel Ziswiler 443a2777ecbSMarcel Ziswiler if (!cli_readline(message)) 444a2777ecbSMarcel Ziswiler goto out; 445a2777ecbSMarcel Ziswiler 446a2777ecbSMarcel Ziswiler if (console_buffer[0] != 'y' && console_buffer[0] != 'Y') 447a2777ecbSMarcel Ziswiler goto out; 448a2777ecbSMarcel Ziswiler #endif 449a2777ecbSMarcel Ziswiler } 450a2777ecbSMarcel Ziswiler 451a2777ecbSMarcel Ziswiler /* Parse new Toradex config block data... */ 452a2777ecbSMarcel Ziswiler if (argc < 3) 453a2777ecbSMarcel Ziswiler err = get_cfgblock_interactive(); 454a2777ecbSMarcel Ziswiler else 455a2777ecbSMarcel Ziswiler err = get_cfgblock_barcode(argv[2]); 456a2777ecbSMarcel Ziswiler 457a2777ecbSMarcel Ziswiler if (err) { 458a2777ecbSMarcel Ziswiler ret = CMD_RET_FAILURE; 459a2777ecbSMarcel Ziswiler goto out; 460a2777ecbSMarcel Ziswiler } 461a2777ecbSMarcel Ziswiler 462a2777ecbSMarcel Ziswiler /* Convert serial number to MAC address (the storage format) */ 463a2777ecbSMarcel Ziswiler tdx_eth_addr.oui = htonl(0x00142dUL << 8); 464a2777ecbSMarcel Ziswiler tdx_eth_addr.nic = htonl(tdx_serial << 8); 465a2777ecbSMarcel Ziswiler 466a2777ecbSMarcel Ziswiler /* Valid Tag */ 467a2777ecbSMarcel Ziswiler tag = (struct toradex_tag *)config_block; 468a2777ecbSMarcel Ziswiler tag->id = TAG_VALID; 469a2777ecbSMarcel Ziswiler tag->flags = TAG_FLAG_VALID; 470a2777ecbSMarcel Ziswiler tag->len = 0; 471a2777ecbSMarcel Ziswiler offset += 4; 472a2777ecbSMarcel Ziswiler 473a2777ecbSMarcel Ziswiler /* Product Tag */ 474a2777ecbSMarcel Ziswiler tag = (struct toradex_tag *)(config_block + offset); 475a2777ecbSMarcel Ziswiler tag->id = TAG_HW; 476a2777ecbSMarcel Ziswiler tag->flags = TAG_FLAG_VALID; 477a2777ecbSMarcel Ziswiler tag->len = 2; 478a2777ecbSMarcel Ziswiler offset += 4; 479a2777ecbSMarcel Ziswiler 480a2777ecbSMarcel Ziswiler memcpy(config_block + offset, &tdx_hw_tag, 8); 481a2777ecbSMarcel Ziswiler offset += 8; 482a2777ecbSMarcel Ziswiler 483a2777ecbSMarcel Ziswiler /* MAC Tag */ 484a2777ecbSMarcel Ziswiler tag = (struct toradex_tag *)(config_block + offset); 485a2777ecbSMarcel Ziswiler tag->id = TAG_MAC; 486a2777ecbSMarcel Ziswiler tag->flags = TAG_FLAG_VALID; 487a2777ecbSMarcel Ziswiler tag->len = 2; 488a2777ecbSMarcel Ziswiler offset += 4; 489a2777ecbSMarcel Ziswiler 490a2777ecbSMarcel Ziswiler memcpy(config_block + offset, &tdx_eth_addr, 6); 491a2777ecbSMarcel Ziswiler offset += 6; 492a2777ecbSMarcel Ziswiler memset(config_block + offset, 0, 32 - offset); 493a2777ecbSMarcel Ziswiler 494a2777ecbSMarcel Ziswiler #if defined(CONFIG_TDX_CFG_BLOCK_IS_IN_MMC) 495a2777ecbSMarcel Ziswiler err = tdx_cfg_block_mmc_storage(config_block, 1); 496a2777ecbSMarcel Ziswiler #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NAND) 497a2777ecbSMarcel Ziswiler err = write_tdx_cfg_block_to_nand(config_block); 498a2777ecbSMarcel Ziswiler #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NOR) 499a2777ecbSMarcel Ziswiler err = write_tdx_cfg_block_to_nor(config_block); 500a2777ecbSMarcel Ziswiler #else 501a2777ecbSMarcel Ziswiler err = -EINVAL; 502a2777ecbSMarcel Ziswiler #endif 503a2777ecbSMarcel Ziswiler if (err) { 504a2777ecbSMarcel Ziswiler printf("Failed to write Toradex config block: %d\n", ret); 505a2777ecbSMarcel Ziswiler ret = CMD_RET_FAILURE; 506a2777ecbSMarcel Ziswiler goto out; 507a2777ecbSMarcel Ziswiler } 508a2777ecbSMarcel Ziswiler 509a2777ecbSMarcel Ziswiler printf("Toradex config block successfully written\n"); 510a2777ecbSMarcel Ziswiler 511a2777ecbSMarcel Ziswiler out: 512a2777ecbSMarcel Ziswiler free(config_block); 513a2777ecbSMarcel Ziswiler return ret; 514a2777ecbSMarcel Ziswiler } 515a2777ecbSMarcel Ziswiler 516a2777ecbSMarcel Ziswiler static int do_cfgblock(cmd_tbl_t *cmdtp, int flag, int argc, 517a2777ecbSMarcel Ziswiler char * const argv[]) 518a2777ecbSMarcel Ziswiler { 519a2777ecbSMarcel Ziswiler int ret; 520a2777ecbSMarcel Ziswiler 521a2777ecbSMarcel Ziswiler if (argc < 2) 522a2777ecbSMarcel Ziswiler return CMD_RET_USAGE; 523a2777ecbSMarcel Ziswiler 524a2777ecbSMarcel Ziswiler if (!strcmp(argv[1], "create")) { 525a2777ecbSMarcel Ziswiler return do_cfgblock_create(cmdtp, flag, argc, argv); 526a2777ecbSMarcel Ziswiler } else if (!strcmp(argv[1], "reload")) { 527a2777ecbSMarcel Ziswiler ret = read_tdx_cfg_block(); 528a2777ecbSMarcel Ziswiler if (ret) { 529a2777ecbSMarcel Ziswiler printf("Failed to reload Toradex config block: %d\n", 530a2777ecbSMarcel Ziswiler ret); 531a2777ecbSMarcel Ziswiler return CMD_RET_FAILURE; 532a2777ecbSMarcel Ziswiler } 533a2777ecbSMarcel Ziswiler return CMD_RET_SUCCESS; 534a2777ecbSMarcel Ziswiler } 535a2777ecbSMarcel Ziswiler 536a2777ecbSMarcel Ziswiler return CMD_RET_USAGE; 537a2777ecbSMarcel Ziswiler } 538a2777ecbSMarcel Ziswiler 539a2777ecbSMarcel Ziswiler U_BOOT_CMD( 540a2777ecbSMarcel Ziswiler cfgblock, 3, 0, do_cfgblock, 541a2777ecbSMarcel Ziswiler "Toradex config block handling commands", 542a2777ecbSMarcel Ziswiler "create [barcode] - (Re-)create Toradex config block\n" 543a2777ecbSMarcel Ziswiler "cfgblock reload - Reload Toradex config block from flash" 544a2777ecbSMarcel Ziswiler ); 545