2 * Copyright (c) 2011-2015 Toradex, Inc.
4 * SPDX-License-Identifier: GPL-2.0+
7 #include "configblock.h"
15 DECLARE_GLOBAL_DATA_PTR;
17 #define TAG_VALID 0xcf01
18 #define TAG_MAC 0x0000
21 #define TAG_FLAG_VALID 0x1
23 #if defined(CONFIG_TRDX_CFG_BLOCK_IS_IN_MMC)
24 #define TRDX_CFG_BLOCK_MAX_SIZE 512
25 #elif defined(CONFIG_TRDX_CFG_BLOCK_IS_IN_NAND)
26 #define TRDX_CFG_BLOCK_MAX_SIZE 64
28 #error Toradex config block location not set
38 struct toradex_hw trdx_hw_tag;
39 struct toradex_eth_addr trdx_eth_addr;
42 const char* const toradex_modules[] = {
43 [1] = "Colibri PXA270 312MHz",
44 [2] = "Colibri PXA270 520MHz",
45 [3] = "Colibri PXA320 806MHz",
46 [4] = "Colibri PXA300 208MHz",
47 [5] = "Colibri PXA310 624MHz",
48 [6] = "Colibri PXA320 806MHz IT",
49 [7] = "Colibri PXA300 208MHz XT",
50 [8] = "Colibri PXA270 312MHz",
51 [9] = "Colibri PXA270 520MHz",
52 [10] = "Colibri VF50 128MB", /* not currently on sale */
53 [11] = "Colibri VF61 256MB",
54 [12] = "Colibri VF61 256MB IT",
55 [13] = "Colibri VF50 128MB IT",
56 [14] = "Colibri iMX6 Solo 256MB",
57 [15] = "Colibri iMX6 DualLite 512MB",
58 [16] = "Colibri iMX6 Solo 256MB IT",
59 [17] = "Colibri iMX6 DualLite 512MB IT",
60 [20] = "Colibri T20 256MB",
61 [21] = "Colibri T20 512MB",
62 [22] = "Colibri T20 512MB IT",
63 [23] = "Colibri T30 1GB",
64 [24] = "Colibri T20 256MB IT",
65 [25] = "Apalis T30 2GB",
66 [26] = "Apalis T30 1GB",
67 [27] = "Apalis iMX6 Quad 1GB",
68 [28] = "Apalis iMX6 Quad 2GB IT",
69 [29] = "Apalis iMX6 Dual 512MB",
70 [30] = "Colibri T30 1GB IT",
71 [31] = "Apalis T30 1GB IT",
74 #ifdef CONFIG_TRDX_CFG_BLOCK_IS_IN_MMC
75 static int trdx_cfg_block_mmc_storage(u8 *config_block, int write)
78 int dev = CONFIG_TRDX_CFG_BLOCK_DEV;
79 int offset = CONFIG_TRDX_CFG_BLOCK_OFFSET;
80 uint part = CONFIG_TRDX_CFG_BLOCK_PART;
84 /* Read production parameter config block from eMMC */
85 mmc = find_mmc_device(dev);
87 puts("No MMC card found\n");
91 if (part != mmc->part_num) {
92 if (mmc_switch_part(dev, part)) {
93 puts("MMC partition switch failed\n");
99 offset += mmc->capacity;
100 blk_start = ALIGN(offset, mmc->write_bl_len) / mmc->write_bl_len;
103 /* Careful reads a whole block of 512 bytes into config_block */
104 if (mmc->block_dev.block_read(dev, blk_start, 1,
105 (unsigned char *)config_block) !=
111 /* Just writing one 512 byte block */
112 if (mmc->block_dev.block_write(dev, blk_start, 1,
113 (unsigned char *)config_block) !=
121 /* Switch back to regular eMMC user partition */
122 mmc_switch_part(0, 0);
128 #ifdef CONFIG_TRDX_CFG_BLOCK_IS_IN_NAND
129 static int read_trdx_cfg_block_from_nand(unsigned char *config_block)
131 size_t size = TRDX_CFG_BLOCK_MAX_SIZE;
133 /* Read production parameter config block from NAND page */
134 return nand_read(&nand_info[0], CONFIG_TRDX_CFG_BLOCK_OFFSET,
135 &size, config_block);
138 static int write_trdx_cfg_block_to_nand(unsigned char *config_block)
140 size_t size = TRDX_CFG_BLOCK_MAX_SIZE;
142 /* Write production parameter config block to NAND page */
143 return nand_write(&nand_info[0], CONFIG_TRDX_CFG_BLOCK_OFFSET,
144 &size, config_block);
148 int read_trdx_cfg_block(void)
151 u8 *config_block = NULL;
152 struct toradex_tag *tag;
153 size_t size = TRDX_CFG_BLOCK_MAX_SIZE;
156 /* Allocate RAM area for config block */
157 config_block = memalign(ARCH_DMA_MINALIGN, size);
159 printf("Not enough malloc space available!\n");
163 memset(config_block, 0, size);
165 #if defined(CONFIG_TRDX_CFG_BLOCK_IS_IN_MMC)
166 ret = trdx_cfg_block_mmc_storage(config_block, 0);
167 #elif defined(CONFIG_TRDX_CFG_BLOCK_IS_IN_NAND)
168 ret = read_trdx_cfg_block_from_nand(config_block);
175 /* Expect a valid tag first */
176 tag = (struct toradex_tag *)config_block;
177 if (tag->flags != TAG_FLAG_VALID || tag->id != TAG_VALID) {
178 valid_cfgblock = false;
182 valid_cfgblock = true;
186 tag = (struct toradex_tag *)(config_block + offset);
188 if (tag->flags != TAG_FLAG_VALID)
194 memcpy(&trdx_eth_addr, config_block + offset, 6);
196 /* NIC part of MAC address is serial number */
197 trdx_serial = ntohl(trdx_eth_addr.nic) >> 8;
200 memcpy(&trdx_hw_tag, config_block + offset, 8);
204 /* Get to next tag according to current tags length */
205 offset += tag->len * 4;
213 static int get_cfgblock_interactive(void)
215 char message[CONFIG_SYS_CBSIZE];
220 sprintf(message, "Is the module an IT version? [y/N] ");
221 len = cli_readline(message);
222 it = console_buffer[0];
225 if (!strcmp("mx6", soc)) {
226 #ifdef CONFIG_MACH_TYPE
227 if (it == 'y' || it == 'Y')
228 trdx_hw_tag.prodid = APALIS_IMX6Q_IT;
230 if (gd->ram_size == 0x40000000)
231 trdx_hw_tag.prodid = APALIS_IMX6Q;
233 trdx_hw_tag.prodid = APALIS_IMX6D;
235 if (it == 'y' || it == 'Y')
236 if (gd->ram_size == 0x20000000)
237 trdx_hw_tag.prodid = COLIBRI_IMX6DL_IT;
239 trdx_hw_tag.prodid = COLIBRI_IMX6S_IT;
241 if (gd->ram_size == 0x20000000)
242 trdx_hw_tag.prodid = COLIBRI_IMX6DL;
244 trdx_hw_tag.prodid = COLIBRI_IMX6S;
245 #endif /* CONFIG_MACH_TYPE */
246 } else if (!strcmp("tegra20", soc)) {
247 if (it == 'y' || it == 'Y')
248 if (gd->ram_size == 0x10000000)
249 trdx_hw_tag.prodid = COLIBRI_T20_256MB_IT;
251 trdx_hw_tag.prodid = COLIBRI_T20_512MB_IT;
253 if (gd->ram_size == 0x10000000)
254 trdx_hw_tag.prodid = COLIBRI_T20_256MB;
256 trdx_hw_tag.prodid = COLIBRI_T20_512MB;
257 #ifdef CONFIG_MACH_TYPE
258 } else if (!strcmp("tegra30", soc)) {
259 if (CONFIG_MACH_TYPE == MACH_TYPE_APALIS_T30) {
260 if (it == 'y' || it == 'Y')
261 trdx_hw_tag.prodid = APALIS_T30_IT;
263 if (gd->ram_size == 0x40000000)
264 trdx_hw_tag.prodid = APALIS_T30_1GB;
266 trdx_hw_tag.prodid = APALIS_T30_2GB;
268 if (it == 'y' || it == 'Y')
269 trdx_hw_tag.prodid = COLIBRI_T30_IT;
271 trdx_hw_tag.prodid = COLIBRI_T30;
273 #endif /* CONFIG_MACH_TYPE */
274 } else if (!strcmp("vf500", soc)) {
275 if (it == 'y' || it == 'Y')
276 trdx_hw_tag.prodid = COLIBRI_VF50_IT;
278 trdx_hw_tag.prodid = COLIBRI_VF50;
279 } else if (!strcmp("vf610", soc)) {
280 if (it == 'y' || it == 'Y')
281 trdx_hw_tag.prodid = COLIBRI_VF61_IT;
283 trdx_hw_tag.prodid = COLIBRI_VF61;
285 printf("Module type not detectable due to unknown SoC\n");
290 sprintf(message, "Enter the module version (e.g. V1.1B): V");
291 len = cli_readline(message);
294 trdx_hw_tag.ver_major = console_buffer[0] - '0';
295 trdx_hw_tag.ver_minor = console_buffer[2] - '0';
296 trdx_hw_tag.ver_assembly = console_buffer[3] - 'A';
299 sprintf(message, "Enter module serial number: ");
300 len = cli_readline(message);
303 trdx_serial = simple_strtoul(console_buffer, NULL, 10);
308 static int get_cfgblock_barcode(char *barcode)
310 if (strlen(barcode) < 16) {
311 printf("Argument too short, barcode is 16 chars long\n");
315 /* Get hardware information from the first 8 digits */
316 trdx_hw_tag.ver_major = barcode[4] - '0';
317 trdx_hw_tag.ver_minor = barcode[5] - '0';
318 trdx_hw_tag.ver_assembly = barcode[7] - '0';
321 trdx_hw_tag.prodid = simple_strtoul(barcode, NULL, 10);
323 /* Parse second part of the barcode (serial number */
325 trdx_serial = simple_strtoul(barcode, NULL, 10);
330 static int do_cfgblock_create(cmd_tbl_t *cmdtp, int flag, int argc,
334 struct toradex_tag *tag;
335 size_t size = TRDX_CFG_BLOCK_MAX_SIZE;
339 /* Allocate RAM area for config block */
340 config_block = memalign(ARCH_DMA_MINALIGN, size);
342 printf("Not enough malloc space available!\n");
346 memset(config_block, 0xff, size);
348 read_trdx_cfg_block();
349 if (valid_cfgblock) {
350 #ifdef CONFIG_TRDX_CFG_BLOCK_IS_IN_NAND
352 * On NAND devices, recreation is only allowed if the page is
353 * empty (config block invalid...)
355 printf("NAND erase block %d need to be erased before creating "
356 "a Toradex config block\n",
357 CONFIG_TRDX_CFG_BLOCK_OFFSET / nand_info[0].erasesize);
361 char message[CONFIG_SYS_CBSIZE];
362 sprintf(message, "A valid Toradex config block is present, "
363 "still recreate? [y/N] ");
365 if (!cli_readline(message)) {
370 if (console_buffer[0] != 'y' && console_buffer[0] != 'Y') {
377 /* Parse new Toradex config block data... */
379 ret = get_cfgblock_interactive();
381 ret = get_cfgblock_barcode(argv[2]);
386 /* Convert serial number to MAC address (the storage format) */
387 trdx_eth_addr.oui = htonl(0x00142dUL << 8);
388 trdx_eth_addr.nic = htonl(trdx_serial << 8);
391 tag = (struct toradex_tag *)config_block;
393 tag->flags = TAG_FLAG_VALID;
398 tag = (struct toradex_tag *)(config_block + offset);
400 tag->flags = TAG_FLAG_VALID;
404 memcpy(config_block + offset, &trdx_hw_tag, 8);
408 tag = (struct toradex_tag *)(config_block + offset);
410 tag->flags = TAG_FLAG_VALID;
414 memcpy(config_block + offset, &trdx_eth_addr, 6);
416 memset(config_block + offset, 0, 32 - offset);
418 #ifdef CONFIG_TRDX_CFG_BLOCK_IS_IN_MMC
419 ret = trdx_cfg_block_mmc_storage(config_block, 1);
420 #elif defined(CONFIG_TRDX_CFG_BLOCK_IS_IN_NAND)
421 ret = write_trdx_cfg_block_to_nand(config_block);
426 printf("Failed to write Toradex config block: %d\n", ret);
430 printf("Toradex config block successfully written\n");
437 static int do_cfgblock(cmd_tbl_t *cmdtp, int flag, int argc,
443 return CMD_RET_USAGE;
445 if (!strcmp(argv[1], "create")) {
446 return do_cfgblock_create(cmdtp, flag, argc, argv);
447 } else if (!strcmp(argv[1], "reload")) {
448 ret = read_trdx_cfg_block();
450 printf("Failed to reload Toradex config block: %d\n",
455 return CMD_RET_USAGE;
459 cfgblock, 3, 0, do_cfgblock,
460 "Toradex config block handling commands",
461 "create [barcode] - (Re-)create Toradex config block\n"
462 "cfgblock reload - Reload Toradex config block from flash"