blob: bf27b2fa66a001d077d808a69635535ada93f482 [file] [log] [blame]
Tom Rini83d290c2018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Marcel Ziswilera2777ec2016-11-16 17:49:22 +01002/*
Marcel Ziswiler842ddf82020-01-28 14:42:23 +01003 * Copyright (c) 2016-2020 Toradex
Marcel Ziswilera2777ec2016-11-16 17:49:22 +01004 */
5
6#include <common.h>
7#include "tdx-cfg-block.h"
Igor Opaniuk0c6b5582020-07-15 13:30:55 +03008#include "tdx-eeprom.h"
9
Simon Glass09140112020-05-10 11:40:03 -060010#include <command.h>
Simon Glass90526e92020-05-10 11:39:56 -060011#include <asm/cache.h>
Marcel Ziswilera2777ec2016-11-16 17:49:22 +010012
Marcel Ziswiler4adc9fc2019-04-09 17:25:32 +020013#if defined(CONFIG_TARGET_APALIS_IMX6) || \
Marcel Ziswiler9d63c7d2019-07-12 12:35:08 +020014 defined(CONFIG_TARGET_APALIS_IMX8) || \
Marcel Ziswiler842ddf82020-01-28 14:42:23 +010015 defined(CONFIG_TARGET_APALIS_IMX8X) || \
Marcel Ziswiler4adc9fc2019-04-09 17:25:32 +020016 defined(CONFIG_TARGET_COLIBRI_IMX6) || \
Marcel Ziswilerc0c39782020-01-28 14:42:24 +010017 defined(CONFIG_TARGET_COLIBRI_IMX8X) || \
18 defined(CONFIG_TARGET_VERDIN_IMX8MM) || \
19 defined(CONFIG_TARGET_VERDIN_IMX8MN)
Marcel Ziswilera2777ec2016-11-16 17:49:22 +010020#include <asm/arch/sys_proto.h>
21#else
22#define is_cpu_type(cpu) (0)
23#endif
24#if defined(CONFIG_CPU_PXA27X)
25#include <asm/arch-pxa/pxa.h>
26#else
27#define cpu_is_pxa27x(cpu) (0)
28#endif
29#include <cli.h>
30#include <console.h>
Simon Glass7b51b572019-08-01 09:46:52 -060031#include <env.h>
Marcel Ziswilera2777ec2016-11-16 17:49:22 +010032#include <flash.h>
33#include <malloc.h>
34#include <mmc.h>
35#include <nand.h>
Simon Glassc62db352017-05-31 19:47:48 -060036#include <asm/mach-types.h>
Marcel Ziswilera2777ec2016-11-16 17:49:22 +010037
38DECLARE_GLOBAL_DATA_PTR;
39
40#define TAG_VALID 0xcf01
41#define TAG_MAC 0x0000
Igor Opaniuk0c6b5582020-07-15 13:30:55 +030042#define TAG_CAR_SERIAL 0x0021
Marcel Ziswilera2777ec2016-11-16 17:49:22 +010043#define TAG_HW 0x0008
44#define TAG_INVALID 0xffff
45
46#define TAG_FLAG_VALID 0x1
47
Igor Opaniuk0c6b5582020-07-15 13:30:55 +030048#define TDX_EEPROM_ID_MODULE 0
49#define TDX_EEPROM_ID_CARRIER 1
50
Marcel Ziswilera2777ec2016-11-16 17:49:22 +010051#if defined(CONFIG_TDX_CFG_BLOCK_IS_IN_MMC)
52#define TDX_CFG_BLOCK_MAX_SIZE 512
53#elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NAND)
54#define TDX_CFG_BLOCK_MAX_SIZE 64
55#elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NOR)
56#define TDX_CFG_BLOCK_MAX_SIZE 64
Igor Opaniuk0c6b5582020-07-15 13:30:55 +030057#elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_EEPROM)
58#define TDX_CFG_BLOCK_MAX_SIZE 64
Marcel Ziswilera2777ec2016-11-16 17:49:22 +010059#else
60#error Toradex config block location not set
61#endif
62
Igor Opaniuk0c6b5582020-07-15 13:30:55 +030063#ifdef CONFIG_TDX_CFG_BLOCK_EXTRA
64#define TDX_CFG_BLOCK_EXTRA_MAX_SIZE 64
65#endif
66
Marcel Ziswilera2777ec2016-11-16 17:49:22 +010067struct toradex_tag {
68 u32 len:14;
69 u32 flags:2;
70 u32 id:16;
71};
72
73bool valid_cfgblock;
74struct toradex_hw tdx_hw_tag;
75struct toradex_eth_addr tdx_eth_addr;
76u32 tdx_serial;
Igor Opaniuk0c6b5582020-07-15 13:30:55 +030077#ifdef CONFIG_TDX_CFG_BLOCK_EXTRA
78u32 tdx_car_serial;
79bool valid_cfgblock_carrier;
80struct toradex_hw tdx_car_hw_tag;
81#endif
Marcel Ziswilera2777ec2016-11-16 17:49:22 +010082
83const char * const toradex_modules[] = {
84 [0] = "UNKNOWN MODULE",
85 [1] = "Colibri PXA270 312MHz",
86 [2] = "Colibri PXA270 520MHz",
87 [3] = "Colibri PXA320 806MHz",
88 [4] = "Colibri PXA300 208MHz",
89 [5] = "Colibri PXA310 624MHz",
90 [6] = "Colibri PXA320 806MHz IT",
91 [7] = "Colibri PXA300 208MHz XT",
92 [8] = "Colibri PXA270 312MHz",
93 [9] = "Colibri PXA270 520MHz",
94 [10] = "Colibri VF50 128MB", /* not currently on sale */
95 [11] = "Colibri VF61 256MB",
96 [12] = "Colibri VF61 256MB IT",
97 [13] = "Colibri VF50 128MB IT",
98 [14] = "Colibri iMX6 Solo 256MB",
99 [15] = "Colibri iMX6 DualLite 512MB",
100 [16] = "Colibri iMX6 Solo 256MB IT",
101 [17] = "Colibri iMX6 DualLite 512MB IT",
102 [18] = "UNKNOWN MODULE",
103 [19] = "UNKNOWN MODULE",
104 [20] = "Colibri T20 256MB",
105 [21] = "Colibri T20 512MB",
106 [22] = "Colibri T20 512MB IT",
107 [23] = "Colibri T30 1GB",
108 [24] = "Colibri T20 256MB IT",
109 [25] = "Apalis T30 2GB",
110 [26] = "Apalis T30 1GB",
111 [27] = "Apalis iMX6 Quad 1GB",
112 [28] = "Apalis iMX6 Quad 2GB IT",
113 [29] = "Apalis iMX6 Dual 512MB",
114 [30] = "Colibri T30 1GB IT",
115 [31] = "Apalis T30 1GB IT",
116 [32] = "Colibri iMX7 Solo 256MB",
117 [33] = "Colibri iMX7 Dual 512MB",
118 [34] = "Apalis TK1 2GB",
119 [35] = "Apalis iMX6 Dual 1GB IT",
Stefan Agnerd826b872018-05-30 19:01:47 +0200120 [36] = "Colibri iMX6ULL 256MB",
Marcel Ziswiler4adc9fc2019-04-09 17:25:32 +0200121 [37] = "Apalis iMX8 QuadMax 4GB Wi-Fi / BT IT",
122 [38] = "Colibri iMX8 QuadXPlus 2GB Wi-Fi / BT IT",
Stefan Agnerd826b872018-05-30 19:01:47 +0200123 [39] = "Colibri iMX7 Dual 1GB (eMMC)",
Marcel Ziswiler4adc9fc2019-04-09 17:25:32 +0200124 [40] = "Colibri iMX6ULL 512MB Wi-Fi / BT IT",
Stefan Agnerd826b872018-05-30 19:01:47 +0200125 [41] = "Colibri iMX7 Dual 512MB EPDC",
126 [42] = "Apalis TK1 4GB",
Gerard Salvatella08f80552019-04-09 17:24:07 +0200127 [43] = "Colibri T20 512MB IT SETEK",
128 [44] = "Colibri iMX6ULL 512MB IT",
129 [45] = "Colibri iMX6ULL 512MB Wi-Fi / Bluetooth",
Marcel Ziswiler6988a3a2019-04-09 17:25:33 +0200130 [46] = "Apalis iMX8 QuadXPlus 2GB Wi-Fi / BT IT",
131 [47] = "Apalis iMX8 QuadMax 4GB IT",
132 [48] = "Apalis iMX8 QuadPlus 2GB Wi-Fi / BT",
133 [49] = "Apalis iMX8 QuadPlus 2GB",
134 [50] = "Colibri iMX8 QuadXPlus 2GB IT",
135 [51] = "Colibri iMX8 DualX 1GB Wi-Fi / Bluetooth",
136 [52] = "Colibri iMX8 DualX 1GB",
Marcel Ziswiler842ddf82020-01-28 14:42:23 +0100137 [53] = "Apalis iMX8 QuadXPlus 2GB ECC IT",
138 [54] = "Apalis iMX8 DualXPlus 1GB",
Marcel Ziswilerc0c39782020-01-28 14:42:24 +0100139 [55] = "Verdin iMX8M Mini Quad 2GB Wi-Fi / BT IT",
140 [56] = "Verdin iMX8M Nano SoloLite 1GB", /* not currently on sale */
141 [57] = "Verdin iMX8M Mini DualLite 1GB",
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100142};
143
Igor Opaniuk26921f52020-07-15 13:30:54 +0300144const char * const toradex_carrier_boards[] = {
145 [0] = "UNKNOWN CARRIER BOARD",
146 [155] = "Dahlia",
147 [156] = "Verdin Development Board",
148};
149
150const char * const toradex_display_adapters[] = {
151 [0] = "UNKNOWN DISPLAY ADAPTER",
152 [157] = "Verdin DSI to HDMI Adapter",
153 [159] = "Verdin DSI to LVDS Adapter",
154};
155
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100156#ifdef CONFIG_TDX_CFG_BLOCK_IS_IN_MMC
157static int tdx_cfg_block_mmc_storage(u8 *config_block, int write)
158{
159 struct mmc *mmc;
160 int dev = CONFIG_TDX_CFG_BLOCK_DEV;
161 int offset = CONFIG_TDX_CFG_BLOCK_OFFSET;
162 uint part = CONFIG_TDX_CFG_BLOCK_PART;
163 uint blk_start;
164 int ret = 0;
165
166 /* Read production parameter config block from eMMC */
167 mmc = find_mmc_device(dev);
168 if (!mmc) {
169 puts("No MMC card found\n");
170 ret = -ENODEV;
171 goto out;
172 }
Stefan Agner42a4f182019-07-12 12:35:05 +0200173 if (mmc_init(mmc)) {
174 puts("MMC init failed\n");
175 return -EINVAL;
176 }
Simon Glass0e513e72017-04-23 20:02:11 -0600177 if (part != mmc_get_blk_desc(mmc)->hwpart) {
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100178 if (blk_select_hwpart_devnum(IF_TYPE_MMC, dev, part)) {
179 puts("MMC partition switch failed\n");
180 ret = -ENODEV;
181 goto out;
182 }
183 }
184 if (offset < 0)
185 offset += mmc->capacity;
186 blk_start = ALIGN(offset, mmc->write_bl_len) / mmc->write_bl_len;
187
188 if (!write) {
189 /* Careful reads a whole block of 512 bytes into config_block */
190 if (blk_dread(mmc_get_blk_desc(mmc), blk_start, 1,
191 (unsigned char *)config_block) != 1) {
192 ret = -EIO;
193 goto out;
194 }
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100195 } else {
196 /* Just writing one 512 byte block */
197 if (blk_dwrite(mmc_get_blk_desc(mmc), blk_start, 1,
198 (unsigned char *)config_block) != 1) {
199 ret = -EIO;
200 goto out;
201 }
202 }
203
204out:
205 /* Switch back to regular eMMC user partition */
206 blk_select_hwpart_devnum(IF_TYPE_MMC, 0, 0);
207
208 return ret;
209}
210#endif
211
212#ifdef CONFIG_TDX_CFG_BLOCK_IS_IN_NAND
213static int read_tdx_cfg_block_from_nand(unsigned char *config_block)
214{
215 size_t size = TDX_CFG_BLOCK_MAX_SIZE;
Stefan Agnerbc53fb12018-08-06 09:19:18 +0200216 struct mtd_info *mtd = get_nand_dev_by_index(0);
217
218 if (!mtd)
219 return -ENODEV;
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100220
221 /* Read production parameter config block from NAND page */
Stefan Agnerbc53fb12018-08-06 09:19:18 +0200222 return nand_read_skip_bad(mtd, CONFIG_TDX_CFG_BLOCK_OFFSET,
Grygorii Strashkobf264cd2017-06-26 19:13:06 -0500223 &size, NULL, TDX_CFG_BLOCK_MAX_SIZE,
224 config_block);
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100225}
226
227static int write_tdx_cfg_block_to_nand(unsigned char *config_block)
228{
229 size_t size = TDX_CFG_BLOCK_MAX_SIZE;
230
231 /* Write production parameter config block to NAND page */
Grygorii Strashkobf264cd2017-06-26 19:13:06 -0500232 return nand_write_skip_bad(get_nand_dev_by_index(0),
233 CONFIG_TDX_CFG_BLOCK_OFFSET,
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100234 &size, NULL, TDX_CFG_BLOCK_MAX_SIZE,
235 config_block, WITH_WR_VERIFY);
236}
237#endif
238
239#ifdef CONFIG_TDX_CFG_BLOCK_IS_IN_NOR
240static int read_tdx_cfg_block_from_nor(unsigned char *config_block)
241{
242 /* Read production parameter config block from NOR flash */
243 memcpy(config_block, (void *)CONFIG_TDX_CFG_BLOCK_OFFSET,
244 TDX_CFG_BLOCK_MAX_SIZE);
245 return 0;
246}
247
248static int write_tdx_cfg_block_to_nor(unsigned char *config_block)
249{
250 /* Write production parameter config block to NOR flash */
251 return flash_write((void *)config_block, CONFIG_TDX_CFG_BLOCK_OFFSET,
252 TDX_CFG_BLOCK_MAX_SIZE);
253}
254#endif
255
Igor Opaniuk0c6b5582020-07-15 13:30:55 +0300256#ifdef CONFIG_TDX_CFG_BLOCK_IS_IN_EEPROM
257static int read_tdx_cfg_block_from_eeprom(unsigned char *config_block)
258{
259 return read_tdx_eeprom_data(TDX_EEPROM_ID_MODULE, 0x0, config_block,
260 TDX_CFG_BLOCK_MAX_SIZE);
261}
262
263static int write_tdx_cfg_block_to_eeprom(unsigned char *config_block)
264{
265 return write_tdx_eeprom_data(TDX_EEPROM_ID_MODULE, 0x0, config_block,
266 TDX_CFG_BLOCK_MAX_SIZE);
267}
268#endif
269
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100270int read_tdx_cfg_block(void)
271{
272 int ret = 0;
273 u8 *config_block = NULL;
274 struct toradex_tag *tag;
275 size_t size = TDX_CFG_BLOCK_MAX_SIZE;
276 int offset;
277
278 /* Allocate RAM area for config block */
279 config_block = memalign(ARCH_DMA_MINALIGN, size);
280 if (!config_block) {
281 printf("Not enough malloc space available!\n");
282 return -ENOMEM;
283 }
284
285 memset(config_block, 0, size);
286
287#if defined(CONFIG_TDX_CFG_BLOCK_IS_IN_MMC)
288 ret = tdx_cfg_block_mmc_storage(config_block, 0);
289#elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NAND)
290 ret = read_tdx_cfg_block_from_nand(config_block);
291#elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NOR)
292 ret = read_tdx_cfg_block_from_nor(config_block);
Igor Opaniuk0c6b5582020-07-15 13:30:55 +0300293#elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_EEPROM)
294 ret = read_tdx_cfg_block_from_eeprom(config_block);
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100295#else
296 ret = -EINVAL;
297#endif
298 if (ret)
299 goto out;
300
301 /* Expect a valid tag first */
302 tag = (struct toradex_tag *)config_block;
303 if (tag->flags != TAG_FLAG_VALID || tag->id != TAG_VALID) {
304 valid_cfgblock = false;
305 ret = -EINVAL;
306 goto out;
307 }
308 valid_cfgblock = true;
309 offset = 4;
310
Igor Opaniuk0c6b5582020-07-15 13:30:55 +0300311 /*
312 * check if there is enough space for storing tag and value of the
313 * biggest element
314 */
315 while (offset + sizeof(struct toradex_tag) +
316 sizeof(struct toradex_hw) < TDX_CFG_BLOCK_MAX_SIZE) {
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100317 tag = (struct toradex_tag *)(config_block + offset);
318 offset += 4;
319 if (tag->id == TAG_INVALID)
320 break;
321
322 if (tag->flags == TAG_FLAG_VALID) {
323 switch (tag->id) {
324 case TAG_MAC:
325 memcpy(&tdx_eth_addr, config_block + offset,
326 6);
327
328 /* NIC part of MAC address is serial number */
329 tdx_serial = ntohl(tdx_eth_addr.nic) >> 8;
330 break;
331 case TAG_HW:
332 memcpy(&tdx_hw_tag, config_block + offset, 8);
333 break;
334 }
335 }
336
337 /* Get to next tag according to current tags length */
338 offset += tag->len * 4;
339 }
340
341 /* Cap product id to avoid issues with a yet unknown one */
Marcel Ziswilerccdd3712019-03-25 17:18:29 +0100342 if (tdx_hw_tag.prodid >= (sizeof(toradex_modules) /
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100343 sizeof(toradex_modules[0])))
344 tdx_hw_tag.prodid = 0;
345
346out:
347 free(config_block);
348 return ret;
349}
350
351static int get_cfgblock_interactive(void)
352{
353 char message[CONFIG_SYS_CBSIZE];
354 char *soc;
355 char it = 'n';
Marcel Ziswilerd1aa14442019-07-12 12:35:06 +0200356 char wb = 'n';
Marcel Ziswilerc0c39782020-01-28 14:42:24 +0100357 int len = 0;
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100358
Stefan Agner89315f32019-04-09 17:24:08 +0200359 /* Unknown module by default */
360 tdx_hw_tag.prodid = 0;
361
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100362 if (cpu_is_pxa27x())
363 sprintf(message, "Is the module the 312 MHz version? [y/N] ");
Marcel Ziswilerc0c39782020-01-28 14:42:24 +0100364#if !defined(CONFIG_TARGET_VERDIN_IMX8MM) || !defined(CONFIG_TARGET_VERDIN_IMX8MN)
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100365 else
366 sprintf(message, "Is the module an IT version? [y/N] ");
Marcel Ziswilerc0c39782020-01-28 14:42:24 +0100367
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100368 len = cli_readline(message);
369 it = console_buffer[0];
Marcel Ziswilerc0c39782020-01-28 14:42:24 +0100370#else
371 else
372 it = 'y';
373#endif
374
Marcel Ziswilerd1aa14442019-07-12 12:35:06 +0200375#if defined(CONFIG_TARGET_APALIS_IMX8) || \
Marcel Ziswiler842ddf82020-01-28 14:42:23 +0100376 defined(CONFIG_TARGET_APALIS_IMX8X) || \
Marcel Ziswilerd1aa14442019-07-12 12:35:06 +0200377 defined(CONFIG_TARGET_COLIBRI_IMX6ULL) || \
378 defined(CONFIG_TARGET_COLIBRI_IMX8X)
379 sprintf(message, "Does the module have Wi-Fi / Bluetooth? [y/N] ");
380 len = cli_readline(message);
381 wb = console_buffer[0];
382#endif
383
Simon Glass00caae62017-08-03 12:22:12 -0600384 soc = env_get("soc");
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100385 if (!strcmp("mx6", soc)) {
Stefan Agner89315f32019-04-09 17:24:08 +0200386#ifdef CONFIG_TARGET_APALIS_IMX6
387 if (it == 'y' || it == 'Y') {
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100388 if (is_cpu_type(MXC_CPU_MX6Q))
389 tdx_hw_tag.prodid = APALIS_IMX6Q_IT;
390 else
391 tdx_hw_tag.prodid = APALIS_IMX6D_IT;
Stefan Agner89315f32019-04-09 17:24:08 +0200392 } else {
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100393 if (is_cpu_type(MXC_CPU_MX6Q))
394 tdx_hw_tag.prodid = APALIS_IMX6Q;
395 else
396 tdx_hw_tag.prodid = APALIS_IMX6D;
Stefan Agner89315f32019-04-09 17:24:08 +0200397 }
398#elif CONFIG_TARGET_COLIBRI_IMX6
399 if (it == 'y' || it == 'Y') {
400 if (is_cpu_type(MXC_CPU_MX6DL))
401 tdx_hw_tag.prodid = COLIBRI_IMX6DL_IT;
402 else if (is_cpu_type(MXC_CPU_MX6SOLO))
403 tdx_hw_tag.prodid = COLIBRI_IMX6S_IT;
404 } else {
405 if (is_cpu_type(MXC_CPU_MX6DL))
406 tdx_hw_tag.prodid = COLIBRI_IMX6DL;
407 else if (is_cpu_type(MXC_CPU_MX6SOLO))
408 tdx_hw_tag.prodid = COLIBRI_IMX6S;
409 }
410#elif CONFIG_TARGET_COLIBRI_IMX6ULL
Gerard Salvatella08f80552019-04-09 17:24:07 +0200411 if (it == 'y' || it == 'Y') {
Stefan Agner89315f32019-04-09 17:24:08 +0200412 if (wb == 'y' || wb == 'Y')
413 tdx_hw_tag.prodid = COLIBRI_IMX6ULL_WIFI_BT_IT;
414 else
415 tdx_hw_tag.prodid = COLIBRI_IMX6ULL_IT;
Gerard Salvatella08f80552019-04-09 17:24:07 +0200416 } else {
Stefan Agner89315f32019-04-09 17:24:08 +0200417 if (wb == 'y' || wb == 'Y')
418 tdx_hw_tag.prodid = COLIBRI_IMX6ULL_WIFI_BT;
419 else
420 tdx_hw_tag.prodid = COLIBRI_IMX6ULL;
Gerard Salvatella08f80552019-04-09 17:24:07 +0200421 }
Stefan Agner89315f32019-04-09 17:24:08 +0200422#endif
Gerard Salvatella08f80552019-04-09 17:24:07 +0200423 } else if (!strcmp("imx7d", soc))
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100424 tdx_hw_tag.prodid = COLIBRI_IMX7D;
Gerard Salvatella08f80552019-04-09 17:24:07 +0200425 else if (!strcmp("imx7s", soc))
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100426 tdx_hw_tag.prodid = COLIBRI_IMX7S;
Marcel Ziswilerc0c39782020-01-28 14:42:24 +0100427 else if (is_cpu_type(MXC_CPU_IMX8MM))
428 tdx_hw_tag.prodid = VERDIN_IMX8MMQ_WIFI_BT_IT;
429 else if (is_cpu_type(MXC_CPU_IMX8MMDL))
430 tdx_hw_tag.prodid = VERDIN_IMX8MMDL;
431 else if (is_cpu_type(MXC_CPU_IMX8MN))
432 tdx_hw_tag.prodid = VERDIN_IMX8MNSL;
Marcel Ziswiler9d63c7d2019-07-12 12:35:08 +0200433 else if (is_cpu_type(MXC_CPU_IMX8QM)) {
434 if (it == 'y' || it == 'Y') {
435 if (wb == 'y' || wb == 'Y')
436 tdx_hw_tag.prodid = APALIS_IMX8QM_WIFI_BT_IT;
437 else
438 tdx_hw_tag.prodid = APALIS_IMX8QM_IT;
439 } else {
440 if (wb == 'y' || wb == 'Y')
441 tdx_hw_tag.prodid = APALIS_IMX8QP_WIFI_BT;
442 else
443 tdx_hw_tag.prodid = APALIS_IMX8QP;
444 }
445 } else if (is_cpu_type(MXC_CPU_IMX8QXP)) {
Marcel Ziswiler842ddf82020-01-28 14:42:23 +0100446#ifdef CONFIG_TARGET_APALIS_IMX8X
447 if (it == 'y' || it == 'Y' || wb == 'y' || wb == 'Y') {
448 tdx_hw_tag.prodid = APALIS_IMX8QXP_WIFI_BT_IT;
449 } else {
450 if (gd->ram_size == 0x40000000)
451 tdx_hw_tag.prodid = APALIS_IMX8DXP;
452 else
453 tdx_hw_tag.prodid = APALIS_IMX8QXP;
454 }
455#elif CONFIG_TARGET_COLIBRI_IMX8X
Marcel Ziswiler6c297ee2019-07-12 12:35:07 +0200456 if (it == 'y' || it == 'Y') {
457 if (wb == 'y' || wb == 'Y')
458 tdx_hw_tag.prodid = COLIBRI_IMX8QXP_WIFI_BT_IT;
459 else
460 tdx_hw_tag.prodid = COLIBRI_IMX8QXP_IT;
461 } else {
462 if (wb == 'y' || wb == 'Y')
463 tdx_hw_tag.prodid = COLIBRI_IMX8DX_WIFI_BT;
464 else
465 tdx_hw_tag.prodid = COLIBRI_IMX8DX;
466 }
Marcel Ziswiler842ddf82020-01-28 14:42:23 +0100467#endif
Marcel Ziswiler6c297ee2019-07-12 12:35:07 +0200468 } else if (!strcmp("tegra20", soc)) {
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100469 if (it == 'y' || it == 'Y')
470 if (gd->ram_size == 0x10000000)
471 tdx_hw_tag.prodid = COLIBRI_T20_256MB_IT;
472 else
473 tdx_hw_tag.prodid = COLIBRI_T20_512MB_IT;
474 else
475 if (gd->ram_size == 0x10000000)
476 tdx_hw_tag.prodid = COLIBRI_T20_256MB;
477 else
478 tdx_hw_tag.prodid = COLIBRI_T20_512MB;
479 } else if (cpu_is_pxa27x()) {
480 if (it == 'y' || it == 'Y')
481 tdx_hw_tag.prodid = COLIBRI_PXA270_312MHZ;
482 else
483 tdx_hw_tag.prodid = COLIBRI_PXA270_520MHZ;
Gerard Salvatella08f80552019-04-09 17:24:07 +0200484 }
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100485#ifdef CONFIG_MACH_TYPE
Gerard Salvatella08f80552019-04-09 17:24:07 +0200486 else if (!strcmp("tegra30", soc)) {
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100487 if (CONFIG_MACH_TYPE == MACH_TYPE_APALIS_T30) {
488 if (it == 'y' || it == 'Y')
489 tdx_hw_tag.prodid = APALIS_T30_IT;
490 else
491 if (gd->ram_size == 0x40000000)
492 tdx_hw_tag.prodid = APALIS_T30_1GB;
493 else
494 tdx_hw_tag.prodid = APALIS_T30_2GB;
495 } else {
496 if (it == 'y' || it == 'Y')
497 tdx_hw_tag.prodid = COLIBRI_T30_IT;
498 else
499 tdx_hw_tag.prodid = COLIBRI_T30;
500 }
Gerard Salvatella08f80552019-04-09 17:24:07 +0200501 }
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100502#endif /* CONFIG_MACH_TYPE */
Gerard Salvatella08f80552019-04-09 17:24:07 +0200503 else if (!strcmp("tegra124", soc)) {
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100504 tdx_hw_tag.prodid = APALIS_TK1_2GB;
505 } else if (!strcmp("vf500", soc)) {
506 if (it == 'y' || it == 'Y')
507 tdx_hw_tag.prodid = COLIBRI_VF50_IT;
508 else
509 tdx_hw_tag.prodid = COLIBRI_VF50;
510 } else if (!strcmp("vf610", soc)) {
511 if (it == 'y' || it == 'Y')
512 tdx_hw_tag.prodid = COLIBRI_VF61_IT;
513 else
514 tdx_hw_tag.prodid = COLIBRI_VF61;
Stefan Agner89315f32019-04-09 17:24:08 +0200515 }
516
517 if (!tdx_hw_tag.prodid) {
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100518 printf("Module type not detectable due to unknown SoC\n");
519 return -1;
520 }
521
522 while (len < 4) {
523 sprintf(message, "Enter the module version (e.g. V1.1B): V");
524 len = cli_readline(message);
525 }
526
527 tdx_hw_tag.ver_major = console_buffer[0] - '0';
528 tdx_hw_tag.ver_minor = console_buffer[2] - '0';
529 tdx_hw_tag.ver_assembly = console_buffer[3] - 'A';
530
Gerard Salvatella08f80552019-04-09 17:24:07 +0200531 if (cpu_is_pxa27x() && tdx_hw_tag.ver_major == 1)
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100532 tdx_hw_tag.prodid -= (COLIBRI_PXA270_312MHZ -
533 COLIBRI_PXA270_V1_312MHZ);
534
535 while (len < 8) {
536 sprintf(message, "Enter module serial number: ");
537 len = cli_readline(message);
538 }
539
540 tdx_serial = simple_strtoul(console_buffer, NULL, 10);
541
542 return 0;
543}
544
Igor Opaniuk0c6b5582020-07-15 13:30:55 +0300545static int get_cfgblock_barcode(char *barcode, struct toradex_hw *tag,
546 u32 *serial)
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100547{
548 if (strlen(barcode) < 16) {
549 printf("Argument too short, barcode is 16 chars long\n");
550 return -1;
551 }
552
553 /* Get hardware information from the first 8 digits */
Igor Opaniuk0c6b5582020-07-15 13:30:55 +0300554 tag->ver_major = barcode[4] - '0';
555 tag->ver_minor = barcode[5] - '0';
556 tag->ver_assembly = barcode[7] - '0';
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100557
558 barcode[4] = '\0';
Igor Opaniuk0c6b5582020-07-15 13:30:55 +0300559 tag->prodid = simple_strtoul(barcode, NULL, 10);
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100560
561 /* Parse second part of the barcode (serial number */
562 barcode += 8;
Igor Opaniuk0c6b5582020-07-15 13:30:55 +0300563 *serial = simple_strtoul(barcode, NULL, 10);
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100564
565 return 0;
566}
567
Igor Opaniuk0c6b5582020-07-15 13:30:55 +0300568static int write_tag(u8 *config_block, int *offset, int tag_id,
569 u8 *tag_data, size_t tag_data_size)
570{
571 struct toradex_tag *tag;
572
573 if (!offset || !config_block)
574 return -EINVAL;
575
576 tag = (struct toradex_tag *)(config_block + *offset);
577 tag->id = tag_id;
578 tag->flags = TAG_FLAG_VALID;
579 /* len is provided as number of 32bit values after the tag */
580 tag->len = (tag_data_size + sizeof(u32) - 1) / sizeof(u32);
581 *offset += sizeof(struct toradex_tag);
582 if (tag_data && tag_data_size) {
583 memcpy(config_block + *offset, tag_data,
584 tag_data_size);
585 *offset += tag_data_size;
586 }
587
588 return 0;
589}
590
591#ifdef CONFIG_TDX_CFG_BLOCK_EXTRA
592int read_tdx_cfg_block_carrier(void)
593{
594 int ret = 0;
595 u8 *config_block = NULL;
596 struct toradex_tag *tag;
597 size_t size = TDX_CFG_BLOCK_EXTRA_MAX_SIZE;
598 int offset;
599
600 /* Allocate RAM area for carrier config block */
601 config_block = memalign(ARCH_DMA_MINALIGN, size);
602 if (!config_block) {
603 printf("Not enough malloc space available!\n");
604 return -ENOMEM;
605 }
606
607 memset(config_block, 0, size);
608
609 ret = read_tdx_eeprom_data(TDX_EEPROM_ID_CARRIER, 0x0, config_block,
610 size);
611 if (ret)
612 return ret;
613
614 /* Expect a valid tag first */
615 tag = (struct toradex_tag *)config_block;
616 if (tag->flags != TAG_FLAG_VALID || tag->id != TAG_VALID) {
617 valid_cfgblock_carrier = false;
618 ret = -EINVAL;
619 goto out;
620 }
621 valid_cfgblock_carrier = true;
622 offset = 4;
623
624 while (offset + sizeof(struct toradex_tag) +
625 sizeof(struct toradex_hw) < TDX_CFG_BLOCK_MAX_SIZE) {
626 tag = (struct toradex_tag *)(config_block + offset);
627 offset += 4;
628 if (tag->id == TAG_INVALID)
629 break;
630
631 if (tag->flags == TAG_FLAG_VALID) {
632 switch (tag->id) {
633 case TAG_CAR_SERIAL:
634 memcpy(&tdx_car_serial, config_block + offset,
635 sizeof(tdx_car_serial));
636 break;
637 case TAG_HW:
638 memcpy(&tdx_car_hw_tag, config_block +
639 offset, 8);
640 break;
641 }
642 }
643
644 /* Get to next tag according to current tags length */
645 offset += tag->len * 4;
646 }
647out:
648 free(config_block);
649 return ret;
650}
651
Igor Opaniukdb4ab6d2020-07-15 13:30:56 +0300652int check_pid8_sanity(char *pid8)
653{
654 char s_carrierid_verdin_dev[5];
655 char s_carrierid_dahlia[5];
656
657 sprintf(s_carrierid_verdin_dev, "0%d", VERDIN_DEVELOPMENT_BOARD);
658 sprintf(s_carrierid_dahlia, "0%d", DAHLIA);
659
660 /* sane value check, first 4 chars which represent carrier id */
661 if (!strncmp(pid8, s_carrierid_verdin_dev, 4))
662 return 0;
663
664 if (!strncmp(pid8, s_carrierid_dahlia, 4))
665 return 0;
666
667 return -EINVAL;
668}
669
670int try_migrate_tdx_cfg_block_carrier(void)
671{
672 char pid8[8];
673 int offset = 0;
674 int ret = CMD_RET_SUCCESS;
675 size_t size = TDX_CFG_BLOCK_EXTRA_MAX_SIZE;
676 u8 *config_block;
677
678 memset(pid8, 0x0, 8);
679 ret = read_tdx_eeprom_data(TDX_EEPROM_ID_CARRIER, 0x0, (u8 *)pid8, 8);
680 if (ret)
681 return ret;
682
683 if (check_pid8_sanity(pid8))
684 return -EINVAL;
685
686 /* Allocate RAM area for config block */
687 config_block = memalign(ARCH_DMA_MINALIGN, size);
688 if (!config_block) {
689 printf("Not enough malloc space available!\n");
690 return CMD_RET_FAILURE;
691 }
692
693 memset(config_block, 0xff, size);
694 /* we try parse PID8 concatenating zeroed serial number */
695 tdx_car_hw_tag.ver_major = pid8[4] - '0';
696 tdx_car_hw_tag.ver_minor = pid8[5] - '0';
697 tdx_car_hw_tag.ver_assembly = pid8[7] - '0';
698
699 pid8[4] = '\0';
700 tdx_car_hw_tag.prodid = simple_strtoul(pid8, NULL, 10);
701
702 /* Valid Tag */
703 write_tag(config_block, &offset, TAG_VALID, NULL, 0);
704
705 /* Product Tag */
706 write_tag(config_block, &offset, TAG_HW, (u8 *)&tdx_car_hw_tag,
707 sizeof(tdx_car_hw_tag));
708
709 /* Serial Tag */
710 write_tag(config_block, &offset, TAG_CAR_SERIAL, (u8 *)&tdx_car_serial,
711 sizeof(tdx_car_serial));
712
713 memset(config_block + offset, 0, 32 - offset);
714 ret = write_tdx_eeprom_data(TDX_EEPROM_ID_CARRIER, 0x0, config_block,
715 size);
716 if (ret) {
717 printf("Failed to write Toradex Extra config block: %d\n",
718 ret);
719 ret = CMD_RET_FAILURE;
720 goto out;
721 }
722
723 printf("Successfully migrated to Toradex Config Block from PID8\n");
724
725out:
726 free(config_block);
727 return ret;
728}
729
Igor Opaniuk0c6b5582020-07-15 13:30:55 +0300730static int get_cfgblock_carrier_interactive(void)
731{
732 char message[CONFIG_SYS_CBSIZE];
733 int len;
734
735 printf("Supported carrier boards:\n");
736 printf("CARRIER BOARD NAME\t\t [ID]\n");
737 for (int i = 0; i < sizeof(toradex_carrier_boards) /
738 sizeof(toradex_carrier_boards[0]); i++)
739 if (toradex_carrier_boards[i])
740 printf("%s \t\t [%d]\n", toradex_carrier_boards[i], i);
741
742 sprintf(message, "Choose your carrier board (provide ID): ");
743 len = cli_readline(message);
744 tdx_car_hw_tag.prodid = simple_strtoul(console_buffer, NULL, 10);
745
746 do {
747 sprintf(message, "Enter carrier board version (e.g. V1.1B): V");
748 len = cli_readline(message);
749 } while (len < 4);
750
751 tdx_car_hw_tag.ver_major = console_buffer[0] - '0';
752 tdx_car_hw_tag.ver_minor = console_buffer[2] - '0';
753 tdx_car_hw_tag.ver_assembly = console_buffer[3] - 'A';
754
755 while (len < 8) {
756 sprintf(message, "Enter carrier board serial number: ");
757 len = cli_readline(message);
758 }
759
760 tdx_car_serial = simple_strtoul(console_buffer, NULL, 10);
761
762 return 0;
763}
764
765static int do_cfgblock_carrier_create(struct cmd_tbl *cmdtp, int flag, int argc,
766 char * const argv[])
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100767{
768 u8 *config_block;
Igor Opaniuk0c6b5582020-07-15 13:30:55 +0300769 size_t size = TDX_CFG_BLOCK_EXTRA_MAX_SIZE;
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100770 int offset = 0;
771 int ret = CMD_RET_SUCCESS;
772 int err;
Dominik Sliwa587b13c2019-03-25 17:18:27 +0100773 int force_overwrite = 0;
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100774
Igor Opaniuk0c6b5582020-07-15 13:30:55 +0300775 if (argc >= 3) {
776 if (argv[2][0] == '-' && argv[2][1] == 'y')
777 force_overwrite = 1;
778 }
779
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100780 /* Allocate RAM area for config block */
781 config_block = memalign(ARCH_DMA_MINALIGN, size);
782 if (!config_block) {
783 printf("Not enough malloc space available!\n");
784 return CMD_RET_FAILURE;
785 }
786
787 memset(config_block, 0xff, size);
Igor Opaniuk0c6b5582020-07-15 13:30:55 +0300788 read_tdx_cfg_block_carrier();
789 if (valid_cfgblock_carrier && !force_overwrite) {
790 char message[CONFIG_SYS_CBSIZE];
791
792 sprintf(message, "A valid Toradex Carrier config block is present, still recreate? [y/N] ");
793
794 if (!cli_readline(message))
795 goto out;
796
797 if (console_buffer[0] != 'y' &&
798 console_buffer[0] != 'Y')
799 goto out;
800 }
801
802 if (argc < 3 || (force_overwrite && argc < 4)) {
803 err = get_cfgblock_carrier_interactive();
804 } else {
805 if (force_overwrite)
806 err = get_cfgblock_barcode(argv[3], &tdx_car_hw_tag,
807 &tdx_car_serial);
808 else
809 err = get_cfgblock_barcode(argv[2], &tdx_car_hw_tag,
810 &tdx_car_serial);
811 }
812
813 if (err) {
814 ret = CMD_RET_FAILURE;
815 goto out;
816 }
817
818 /* Valid Tag */
819 write_tag(config_block, &offset, TAG_VALID, NULL, 0);
820
821 /* Product Tag */
822 write_tag(config_block, &offset, TAG_HW, (u8 *)&tdx_car_hw_tag,
823 sizeof(tdx_car_hw_tag));
824
825 /* Serial Tag */
826 write_tag(config_block, &offset, TAG_CAR_SERIAL, (u8 *)&tdx_car_serial,
827 sizeof(tdx_car_serial));
828
829 memset(config_block + offset, 0, 32 - offset);
830 err = write_tdx_eeprom_data(TDX_EEPROM_ID_CARRIER, 0x0, config_block,
831 size);
832 if (err) {
833 printf("Failed to write Toradex Extra config block: %d\n",
834 ret);
835 ret = CMD_RET_FAILURE;
836 goto out;
837 }
838
839 printf("Toradex Extra config block successfully written\n");
840
841out:
842 free(config_block);
843 return ret;
844}
845
846#endif /* CONFIG_TDX_CFG_BLOCK_EXTRA */
847
848static int do_cfgblock_create(struct cmd_tbl *cmdtp, int flag, int argc,
849 char * const argv[])
850{
851 u8 *config_block;
852 size_t size = TDX_CFG_BLOCK_MAX_SIZE;
853 int offset = 0;
854 int ret = CMD_RET_SUCCESS;
855 int err;
856 int force_overwrite = 0;
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100857
Dominik Sliwa587b13c2019-03-25 17:18:27 +0100858 if (argc >= 3) {
Igor Opaniuk0c6b5582020-07-15 13:30:55 +0300859#ifdef CONFIG_TDX_CFG_BLOCK_EXTRA
860 if (!strcmp(argv[2], "carrier"))
861 return do_cfgblock_carrier_create(cmdtp, flag,
862 --argc, ++argv);
863#endif /* CONFIG_TDX_CFG_BLOCK_EXTRA */
Dominik Sliwa587b13c2019-03-25 17:18:27 +0100864 if (argv[2][0] == '-' && argv[2][1] == 'y')
865 force_overwrite = 1;
866 }
867
Igor Opaniuk0c6b5582020-07-15 13:30:55 +0300868 /* Allocate RAM area for config block */
869 config_block = memalign(ARCH_DMA_MINALIGN, size);
870 if (!config_block) {
871 printf("Not enough malloc space available!\n");
872 return CMD_RET_FAILURE;
873 }
874
875 memset(config_block, 0xff, size);
876
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100877 read_tdx_cfg_block();
878 if (valid_cfgblock) {
879#if defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NAND)
880 /*
881 * On NAND devices, recreation is only allowed if the page is
882 * empty (config block invalid...)
883 */
Marcel Ziswiler9d364eb2019-07-12 12:35:09 +0200884 printf("NAND erase block %d need to be erased before creating a Toradex config block\n",
Grygorii Strashkobf264cd2017-06-26 19:13:06 -0500885 CONFIG_TDX_CFG_BLOCK_OFFSET /
886 get_nand_dev_by_index(0)->erasesize);
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100887 goto out;
888#elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NOR)
889 /*
890 * On NOR devices, recreation is only allowed if the sector is
891 * empty and write protection is off (config block invalid...)
892 */
Marcel Ziswiler9d364eb2019-07-12 12:35:09 +0200893 printf("NOR sector at offset 0x%02x need to be erased and unprotected before creating a Toradex config block\n",
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100894 CONFIG_TDX_CFG_BLOCK_OFFSET);
895 goto out;
896#else
Dominik Sliwa587b13c2019-03-25 17:18:27 +0100897 if (!force_overwrite) {
898 char message[CONFIG_SYS_CBSIZE];
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100899
Dominik Sliwa587b13c2019-03-25 17:18:27 +0100900 sprintf(message,
901 "A valid Toradex config block is present, still recreate? [y/N] ");
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100902
Dominik Sliwa587b13c2019-03-25 17:18:27 +0100903 if (!cli_readline(message))
904 goto out;
905
906 if (console_buffer[0] != 'y' &&
907 console_buffer[0] != 'Y')
908 goto out;
909 }
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100910#endif
911 }
912
913 /* Parse new Toradex config block data... */
Dominik Sliwa587b13c2019-03-25 17:18:27 +0100914 if (argc < 3 || (force_overwrite && argc < 4)) {
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100915 err = get_cfgblock_interactive();
Dominik Sliwa587b13c2019-03-25 17:18:27 +0100916 } else {
917 if (force_overwrite)
Igor Opaniuk0c6b5582020-07-15 13:30:55 +0300918 err = get_cfgblock_barcode(argv[3], &tdx_hw_tag,
919 &tdx_serial);
Dominik Sliwa587b13c2019-03-25 17:18:27 +0100920 else
Igor Opaniuk0c6b5582020-07-15 13:30:55 +0300921 err = get_cfgblock_barcode(argv[2], &tdx_hw_tag,
922 &tdx_serial);
Dominik Sliwa587b13c2019-03-25 17:18:27 +0100923 }
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100924 if (err) {
925 ret = CMD_RET_FAILURE;
926 goto out;
927 }
928
929 /* Convert serial number to MAC address (the storage format) */
930 tdx_eth_addr.oui = htonl(0x00142dUL << 8);
931 tdx_eth_addr.nic = htonl(tdx_serial << 8);
932
933 /* Valid Tag */
Igor Opaniuk0c6b5582020-07-15 13:30:55 +0300934 write_tag(config_block, &offset, TAG_VALID, NULL, 0);
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100935
936 /* Product Tag */
Igor Opaniuk0c6b5582020-07-15 13:30:55 +0300937 write_tag(config_block, &offset, TAG_HW, (u8 *)&tdx_hw_tag,
938 sizeof(tdx_hw_tag));
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100939
940 /* MAC Tag */
Igor Opaniuk0c6b5582020-07-15 13:30:55 +0300941 write_tag(config_block, &offset, TAG_MAC, (u8 *)&tdx_eth_addr,
942 sizeof(tdx_eth_addr));
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100943
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100944 memset(config_block + offset, 0, 32 - offset);
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100945#if defined(CONFIG_TDX_CFG_BLOCK_IS_IN_MMC)
946 err = tdx_cfg_block_mmc_storage(config_block, 1);
947#elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NAND)
948 err = write_tdx_cfg_block_to_nand(config_block);
949#elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NOR)
950 err = write_tdx_cfg_block_to_nor(config_block);
Igor Opaniuk0c6b5582020-07-15 13:30:55 +0300951#elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_EEPROM)
952 err = write_tdx_cfg_block_to_eeprom(config_block);
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100953#else
954 err = -EINVAL;
955#endif
956 if (err) {
957 printf("Failed to write Toradex config block: %d\n", ret);
958 ret = CMD_RET_FAILURE;
959 goto out;
960 }
961
962 printf("Toradex config block successfully written\n");
963
964out:
965 free(config_block);
966 return ret;
967}
968
Simon Glass09140112020-05-10 11:40:03 -0600969static int do_cfgblock(struct cmd_tbl *cmdtp, int flag, int argc,
970 char *const argv[])
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100971{
972 int ret;
973
974 if (argc < 2)
975 return CMD_RET_USAGE;
976
977 if (!strcmp(argv[1], "create")) {
978 return do_cfgblock_create(cmdtp, flag, argc, argv);
979 } else if (!strcmp(argv[1], "reload")) {
980 ret = read_tdx_cfg_block();
981 if (ret) {
982 printf("Failed to reload Toradex config block: %d\n",
983 ret);
984 return CMD_RET_FAILURE;
985 }
986 return CMD_RET_SUCCESS;
987 }
988
989 return CMD_RET_USAGE;
990}
991
Igor Opaniuk0c6b5582020-07-15 13:30:55 +0300992U_BOOT_CMD(
993 cfgblock, 5, 0, do_cfgblock,
994 "Toradex config block handling commands",
995 "create [-y] [barcode] - (Re-)create Toradex config block\n"
996 "create carrier [-y] [barcode] - (Re-)create Toradex Carrier config block\n"
997 "cfgblock reload - Reload Toradex config block from flash"
Marcel Ziswilera2777ec2016-11-16 17:49:22 +0100998);