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