toradex: tdx-cfg-block: add new 8gb apalis-imx8
[platform/kernel/u-boot.git] / board / toradex / common / tdx-cfg-block.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2016-2020 Toradex
4  */
5
6 #include <common.h>
7 #include <asm/global_data.h>
8 #include "tdx-cfg-block.h"
9 #include "tdx-eeprom.h"
10
11 #include <command.h>
12 #include <asm/cache.h>
13
14 #if defined(CONFIG_TARGET_APALIS_IMX6) || \
15         defined(CONFIG_TARGET_APALIS_IMX8) || \
16         defined(CONFIG_TARGET_COLIBRI_IMX6) || \
17         defined(CONFIG_TARGET_COLIBRI_IMX8X) || \
18         defined(CONFIG_TARGET_VERDIN_IMX8MM) || \
19         defined(CONFIG_TARGET_VERDIN_IMX8MN) || \
20         defined(CONFIG_TARGET_VERDIN_IMX8MP)
21 #include <asm/arch/sys_proto.h>
22 #else
23 #define is_cpu_type(cpu) (0)
24 #endif
25 #include <cli.h>
26 #include <console.h>
27 #include <env.h>
28 #include <flash.h>
29 #include <malloc.h>
30 #include <mmc.h>
31 #include <nand.h>
32 #include <asm/mach-types.h>
33
34 DECLARE_GLOBAL_DATA_PTR;
35
36 #define TAG_VALID       0xcf01
37 #define TAG_MAC         0x0000
38 #define TAG_CAR_SERIAL  0x0021
39 #define TAG_HW          0x0008
40 #define TAG_INVALID     0xffff
41
42 #define TAG_FLAG_VALID  0x1
43
44 #define TDX_EEPROM_ID_MODULE            0
45 #define TDX_EEPROM_ID_CARRIER           1
46
47 #if defined(CONFIG_TDX_CFG_BLOCK_IS_IN_MMC)
48 #define TDX_CFG_BLOCK_MAX_SIZE 512
49 #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NAND)
50 #define TDX_CFG_BLOCK_MAX_SIZE 64
51 #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NOR)
52 #define TDX_CFG_BLOCK_MAX_SIZE 64
53 #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_EEPROM)
54 #define TDX_CFG_BLOCK_MAX_SIZE 64
55 #else
56 #error Toradex config block location not set
57 #endif
58
59 #ifdef CONFIG_TDX_CFG_BLOCK_EXTRA
60 #define TDX_CFG_BLOCK_EXTRA_MAX_SIZE 64
61 #endif
62
63 struct toradex_tag {
64         u32 len:14;
65         u32 flags:2;
66         u32 id:16;
67 };
68
69 bool valid_cfgblock;
70 struct toradex_hw tdx_hw_tag;
71 struct toradex_eth_addr tdx_eth_addr;
72 u32 tdx_serial;
73 #ifdef CONFIG_TDX_CFG_BLOCK_EXTRA
74 u32 tdx_car_serial;
75 bool valid_cfgblock_carrier;
76 struct toradex_hw tdx_car_hw_tag;
77 #endif
78
79 const char * const toradex_modules[] = {
80          [0] = "UNKNOWN MODULE",
81          [1] = "Colibri PXA270 312MHz",
82          [2] = "Colibri PXA270 520MHz",
83          [3] = "Colibri PXA320 806MHz",
84          [4] = "Colibri PXA300 208MHz",
85          [5] = "Colibri PXA310 624MHz",
86          [6] = "Colibri PXA320 806MHz IT",
87          [7] = "Colibri PXA300 208MHz XT",
88          [8] = "Colibri PXA270 312MHz",
89          [9] = "Colibri PXA270 520MHz",
90         [10] = "Colibri VF50 128MB", /* not currently on sale */
91         [11] = "Colibri VF61 256MB",
92         [12] = "Colibri VF61 256MB IT",
93         [13] = "Colibri VF50 128MB IT",
94         [14] = "Colibri iMX6 Solo 256MB",
95         [15] = "Colibri iMX6 DualLite 512MB",
96         [16] = "Colibri iMX6 Solo 256MB IT",
97         [17] = "Colibri iMX6 DualLite 512MB IT",
98         [18] = "UNKNOWN MODULE",
99         [19] = "UNKNOWN MODULE",
100         [20] = "Colibri T20 256MB",
101         [21] = "Colibri T20 512MB",
102         [22] = "Colibri T20 512MB IT",
103         [23] = "Colibri T30 1GB",
104         [24] = "Colibri T20 256MB IT",
105         [25] = "Apalis T30 2GB",
106         [26] = "Apalis T30 1GB",
107         [27] = "Apalis iMX6 Quad 1GB",
108         [28] = "Apalis iMX6 Quad 2GB IT",
109         [29] = "Apalis iMX6 Dual 512MB",
110         [30] = "Colibri T30 1GB IT",
111         [31] = "Apalis T30 1GB IT",
112         [32] = "Colibri iMX7 Solo 256MB",
113         [33] = "Colibri iMX7 Dual 512MB",
114         [34] = "Apalis TK1 2GB",
115         [35] = "Apalis iMX6 Dual 1GB IT",
116         [36] = "Colibri iMX6ULL 256MB",
117         [37] = "Apalis iMX8 QuadMax 4GB Wi-Fi / BT IT",
118         [38] = "Colibri iMX8 QuadXPlus 2GB Wi-Fi / BT IT",
119         [39] = "Colibri iMX7 Dual 1GB (eMMC)",
120         [40] = "Colibri iMX6ULL 512MB Wi-Fi / BT IT",
121         [41] = "Colibri iMX7 Dual 512MB EPDC",
122         [42] = "Apalis TK1 4GB",
123         [43] = "Colibri T20 512MB IT SETEK",
124         [44] = "Colibri iMX6ULL 512MB IT",
125         [45] = "Colibri iMX6ULL 512MB Wi-Fi / Bluetooth",
126         [46] = "Apalis iMX8 QuadXPlus 2GB Wi-Fi / BT IT",
127         [47] = "Apalis iMX8 QuadMax 4GB IT",
128         [48] = "Apalis iMX8 QuadPlus 2GB Wi-Fi / BT",
129         [49] = "Apalis iMX8 QuadPlus 2GB",
130         [50] = "Colibri iMX8 QuadXPlus 2GB IT",
131         [51] = "Colibri iMX8 DualX 1GB Wi-Fi / Bluetooth",
132         [52] = "Colibri iMX8 DualX 1GB",
133         [53] = "Apalis iMX8 QuadXPlus 2GB ECC IT",
134         [54] = "Apalis iMX8 DualXPlus 1GB",
135         [55] = "Verdin iMX8M Mini Quad 2GB Wi-Fi / BT IT",
136         [56] = "Verdin iMX8M Nano Quad 1GB Wi-Fi / BT", /* not currently on sale */
137         [57] = "Verdin iMX8M Mini DualLite 1GB",
138         [58] = "Verdin iMX8M Plus Quad 4GB Wi-Fi / BT IT",
139         [59] = "Verdin iMX8M Mini Quad 2GB IT",
140         [60] = "Verdin iMX8M Mini DualLite 1GB WB IT",
141         [61] = "Verdin iMX8M Plus Quad 2GB",
142         [62] = "Colibri iMX6ULL 1GB IT (eMMC)",
143         [63] = "Verdin iMX8M Plus Quad 4GB IT",
144         [64] = "Verdin iMX8M Plus Quad 2GB Wi-Fi / BT IT",
145         [65] = "Verdin iMX8M Plus QuadLite 1GB IT",
146         [66] = "Verdin iMX8M Plus Quad 8GB Wi-Fi / BT",
147         [67] = "Apalis iMX8 QuadMax 8GB Wi-Fi / BT IT",
148 };
149
150 const char * const toradex_carrier_boards[] = {
151         [0] = "UNKNOWN CARRIER BOARD",
152         [155] = "Dahlia",
153         [156] = "Verdin Development Board",
154 };
155
156 const char * const toradex_display_adapters[] = {
157         [0] = "UNKNOWN DISPLAY ADAPTER",
158         [157] = "Verdin DSI to HDMI Adapter",
159         [159] = "Verdin DSI to LVDS Adapter",
160 };
161
162 #ifdef CONFIG_TDX_CFG_BLOCK_IS_IN_MMC
163 static int tdx_cfg_block_mmc_storage(u8 *config_block, int write)
164 {
165         struct mmc *mmc;
166         int dev = CONFIG_TDX_CFG_BLOCK_DEV;
167         int offset = CONFIG_TDX_CFG_BLOCK_OFFSET;
168         uint part = CONFIG_TDX_CFG_BLOCK_PART;
169         uint blk_start;
170         int ret = 0;
171
172         /* Read production parameter config block from eMMC */
173         mmc = find_mmc_device(dev);
174         if (!mmc) {
175                 puts("No MMC card found\n");
176                 ret = -ENODEV;
177                 goto out;
178         }
179         if (mmc_init(mmc)) {
180                 puts("MMC init failed\n");
181                 return -EINVAL;
182         }
183         if (part != mmc_get_blk_desc(mmc)->hwpart) {
184                 if (blk_select_hwpart_devnum(IF_TYPE_MMC, dev, part)) {
185                         puts("MMC partition switch failed\n");
186                         ret = -ENODEV;
187                         goto out;
188                 }
189         }
190         if (offset < 0)
191                 offset += mmc->capacity;
192         blk_start = ALIGN(offset, mmc->write_bl_len) / mmc->write_bl_len;
193
194         if (!write) {
195                 /* Careful reads a whole block of 512 bytes into config_block */
196                 if (blk_dread(mmc_get_blk_desc(mmc), blk_start, 1,
197                               (unsigned char *)config_block) != 1) {
198                         ret = -EIO;
199                         goto out;
200                 }
201         } else {
202                 /* Just writing one 512 byte block */
203                 if (blk_dwrite(mmc_get_blk_desc(mmc), blk_start, 1,
204                                (unsigned char *)config_block) != 1) {
205                         ret = -EIO;
206                         goto out;
207                 }
208         }
209
210 out:
211         /* Switch back to regular eMMC user partition */
212         blk_select_hwpart_devnum(IF_TYPE_MMC, 0, 0);
213
214         return ret;
215 }
216 #endif
217
218 #ifdef CONFIG_TDX_CFG_BLOCK_IS_IN_NAND
219 static int read_tdx_cfg_block_from_nand(unsigned char *config_block)
220 {
221         size_t size = TDX_CFG_BLOCK_MAX_SIZE;
222         struct mtd_info *mtd = get_nand_dev_by_index(0);
223
224         if (!mtd)
225                 return -ENODEV;
226
227         /* Read production parameter config block from NAND page */
228         return nand_read_skip_bad(mtd, CONFIG_TDX_CFG_BLOCK_OFFSET,
229                                   &size, NULL, TDX_CFG_BLOCK_MAX_SIZE,
230                                   config_block);
231 }
232
233 static int write_tdx_cfg_block_to_nand(unsigned char *config_block)
234 {
235         size_t size = TDX_CFG_BLOCK_MAX_SIZE;
236
237         /* Write production parameter config block to NAND page */
238         return nand_write_skip_bad(get_nand_dev_by_index(0),
239                                    CONFIG_TDX_CFG_BLOCK_OFFSET,
240                                    &size, NULL, TDX_CFG_BLOCK_MAX_SIZE,
241                                    config_block, WITH_WR_VERIFY);
242 }
243 #endif
244
245 #ifdef CONFIG_TDX_CFG_BLOCK_IS_IN_NOR
246 static int read_tdx_cfg_block_from_nor(unsigned char *config_block)
247 {
248         /* Read production parameter config block from NOR flash */
249         memcpy(config_block, (void *)CONFIG_TDX_CFG_BLOCK_OFFSET,
250                TDX_CFG_BLOCK_MAX_SIZE);
251         return 0;
252 }
253
254 static int write_tdx_cfg_block_to_nor(unsigned char *config_block)
255 {
256         /* Write production parameter config block to NOR flash */
257         return flash_write((void *)config_block, CONFIG_TDX_CFG_BLOCK_OFFSET,
258                            TDX_CFG_BLOCK_MAX_SIZE);
259 }
260 #endif
261
262 #ifdef CONFIG_TDX_CFG_BLOCK_IS_IN_EEPROM
263 static int read_tdx_cfg_block_from_eeprom(unsigned char *config_block)
264 {
265         return read_tdx_eeprom_data(TDX_EEPROM_ID_MODULE, 0x0, config_block,
266                                     TDX_CFG_BLOCK_MAX_SIZE);
267 }
268
269 static int write_tdx_cfg_block_to_eeprom(unsigned char *config_block)
270 {
271         return write_tdx_eeprom_data(TDX_EEPROM_ID_MODULE, 0x0, config_block,
272                                      TDX_CFG_BLOCK_MAX_SIZE);
273 }
274 #endif
275
276 int read_tdx_cfg_block(void)
277 {
278         int ret = 0;
279         u8 *config_block = NULL;
280         struct toradex_tag *tag;
281         size_t size = TDX_CFG_BLOCK_MAX_SIZE;
282         int offset;
283
284         /* Allocate RAM area for config block */
285         config_block = memalign(ARCH_DMA_MINALIGN, size);
286         if (!config_block) {
287                 printf("Not enough malloc space available!\n");
288                 return -ENOMEM;
289         }
290
291         memset(config_block, 0, size);
292
293 #if defined(CONFIG_TDX_CFG_BLOCK_IS_IN_MMC)
294         ret = tdx_cfg_block_mmc_storage(config_block, 0);
295 #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NAND)
296         ret = read_tdx_cfg_block_from_nand(config_block);
297 #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NOR)
298         ret = read_tdx_cfg_block_from_nor(config_block);
299 #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_EEPROM)
300         ret = read_tdx_cfg_block_from_eeprom(config_block);
301 #else
302         ret = -EINVAL;
303 #endif
304         if (ret)
305                 goto out;
306
307         /* Expect a valid tag first */
308         tag = (struct toradex_tag *)config_block;
309         if (tag->flags != TAG_FLAG_VALID || tag->id != TAG_VALID) {
310                 valid_cfgblock = false;
311                 ret = -EINVAL;
312                 goto out;
313         }
314         valid_cfgblock = true;
315         offset = 4;
316
317         /*
318          * check if there is enough space for storing tag and value of the
319          * biggest element
320          */
321         while (offset + sizeof(struct toradex_tag) +
322                sizeof(struct toradex_hw) < TDX_CFG_BLOCK_MAX_SIZE) {
323                 tag = (struct toradex_tag *)(config_block + offset);
324                 offset += 4;
325                 if (tag->id == TAG_INVALID)
326                         break;
327
328                 if (tag->flags == TAG_FLAG_VALID) {
329                         switch (tag->id) {
330                         case TAG_MAC:
331                                 memcpy(&tdx_eth_addr, config_block + offset,
332                                        6);
333
334                                 /* NIC part of MAC address is serial number */
335                                 tdx_serial = ntohl(tdx_eth_addr.nic) >> 8;
336                                 break;
337                         case TAG_HW:
338                                 memcpy(&tdx_hw_tag, config_block + offset, 8);
339                                 break;
340                         }
341                 }
342
343                 /* Get to next tag according to current tags length */
344                 offset += tag->len * 4;
345         }
346
347         /* Cap product id to avoid issues with a yet unknown one */
348         if (tdx_hw_tag.prodid >= (sizeof(toradex_modules) /
349                                   sizeof(toradex_modules[0])))
350                 tdx_hw_tag.prodid = 0;
351
352 out:
353         free(config_block);
354         return ret;
355 }
356
357 static int get_cfgblock_interactive(void)
358 {
359         char message[CONFIG_SYS_CBSIZE];
360         char *soc;
361         char it = 'n';
362         char wb = 'n';
363         char mem8g = 'n';
364         int len = 0;
365
366         /* Unknown module by default */
367         tdx_hw_tag.prodid = 0;
368
369         sprintf(message, "Is the module an IT version? [y/N] ");
370
371         len = cli_readline(message);
372         it = console_buffer[0];
373
374 #if defined(CONFIG_TARGET_APALIS_IMX8) || \
375                 defined(CONFIG_TARGET_COLIBRI_IMX6ULL) || \
376                 defined(CONFIG_TARGET_COLIBRI_IMX8X) || \
377                 defined(CONFIG_TARGET_VERDIN_IMX8MM) || \
378                 defined(CONFIG_TARGET_VERDIN_IMX8MP)
379         sprintf(message, "Does the module have Wi-Fi / Bluetooth? [y/N] ");
380         len = cli_readline(message);
381         wb = console_buffer[0];
382
383 #if defined(CONFIG_TARGET_APALIS_IMX8)
384         if ((wb == 'y' || wb == 'Y') && (it == 'y' || it == 'Y')) {
385                 sprintf(message, "Does your module have 8GB of RAM? [y/N] ");
386                 len = cli_readline(message);
387                 mem8g = console_buffer[0];
388         }
389 #endif
390 #endif
391
392         soc = env_get("soc");
393         if (!strcmp("mx6", soc)) {
394 #ifdef CONFIG_TARGET_APALIS_IMX6
395                 if (it == 'y' || it == 'Y') {
396                         if (is_cpu_type(MXC_CPU_MX6Q))
397                                 tdx_hw_tag.prodid = APALIS_IMX6Q_IT;
398                         else
399                                 tdx_hw_tag.prodid = APALIS_IMX6D_IT;
400                 } else {
401                         if (is_cpu_type(MXC_CPU_MX6Q))
402                                 tdx_hw_tag.prodid = APALIS_IMX6Q;
403                         else
404                                 tdx_hw_tag.prodid = APALIS_IMX6D;
405                 }
406 #elif CONFIG_TARGET_COLIBRI_IMX6
407                 if (it == 'y' || it == 'Y') {
408                         if (is_cpu_type(MXC_CPU_MX6DL))
409                                 tdx_hw_tag.prodid = COLIBRI_IMX6DL_IT;
410                         else if (is_cpu_type(MXC_CPU_MX6SOLO))
411                                 tdx_hw_tag.prodid = COLIBRI_IMX6S_IT;
412                 } else {
413                         if (is_cpu_type(MXC_CPU_MX6DL))
414                                 tdx_hw_tag.prodid = COLIBRI_IMX6DL;
415                         else if (is_cpu_type(MXC_CPU_MX6SOLO))
416                                 tdx_hw_tag.prodid = COLIBRI_IMX6S;
417                 }
418 #elif CONFIG_TARGET_COLIBRI_IMX6ULL
419                 if (it == 'y' || it == 'Y') {
420                         if (wb == 'y' || wb == 'Y')
421                                 tdx_hw_tag.prodid = COLIBRI_IMX6ULL_WIFI_BT_IT;
422                         else
423                                 if (gd->ram_size == 0x20000000)
424                                         tdx_hw_tag.prodid = COLIBRI_IMX6ULL_IT;
425                                 else
426                                         tdx_hw_tag.prodid = COLIBRI_IMX6ULL_IT_EMMC;
427                 } else {
428                         if (wb == 'y' || wb == 'Y')
429                                 tdx_hw_tag.prodid = COLIBRI_IMX6ULL_WIFI_BT;
430                         else
431                                 tdx_hw_tag.prodid = COLIBRI_IMX6ULL;
432                 }
433 #endif
434         } else if (!strcmp("imx7d", soc))
435                 if (gd->ram_size == 0x20000000)
436                         tdx_hw_tag.prodid = COLIBRI_IMX7D;
437                 else
438                         tdx_hw_tag.prodid = COLIBRI_IMX7D_EMMC;
439         else if (!strcmp("imx7s", soc))
440                 tdx_hw_tag.prodid = COLIBRI_IMX7S;
441         else if (is_cpu_type(MXC_CPU_IMX8QM)) {
442                 if (it == 'y' || it == 'Y') {
443                         if (wb == 'y' || wb == 'Y') {
444                                 if (mem8g == 'y' || mem8g == 'Y')
445                                         tdx_hw_tag.prodid = APALIS_IMX8QM_8GB_WIFI_BT_IT;
446                                 else
447                                         tdx_hw_tag.prodid = APALIS_IMX8QM_WIFI_BT_IT;
448                         }
449                         else
450                                 tdx_hw_tag.prodid = APALIS_IMX8QM_IT;
451                 } else {
452                         if (wb == 'y' || wb == 'Y')
453                                 tdx_hw_tag.prodid = APALIS_IMX8QP_WIFI_BT;
454                         else
455                                 tdx_hw_tag.prodid = APALIS_IMX8QP;
456                 }
457         } else if (is_cpu_type(MXC_CPU_IMX8QXP)) {
458 #ifdef CONFIG_TARGET_COLIBRI_IMX8X
459                 if (it == 'y' || it == 'Y') {
460                         if (wb == 'y' || wb == 'Y')
461                                 tdx_hw_tag.prodid = COLIBRI_IMX8QXP_WIFI_BT_IT;
462                         else
463                                 tdx_hw_tag.prodid = COLIBRI_IMX8QXP_IT;
464                 } else {
465                         if (wb == 'y' || wb == 'Y')
466                                 tdx_hw_tag.prodid = COLIBRI_IMX8DX_WIFI_BT;
467                         else
468                                 tdx_hw_tag.prodid = COLIBRI_IMX8DX;
469                 }
470 #endif
471         } else if (is_cpu_type(MXC_CPU_IMX8MMDL)) {
472                 if (wb == 'y' || wb == 'Y')
473                         tdx_hw_tag.prodid = VERDIN_IMX8MMDL_WIFI_BT_IT;
474                 else
475                         tdx_hw_tag.prodid = VERDIN_IMX8MMDL;
476         } else if (is_cpu_type(MXC_CPU_IMX8MM)) {
477                 if (wb == 'y' || wb == 'Y')
478                         tdx_hw_tag.prodid = VERDIN_IMX8MMQ_WIFI_BT_IT;
479                 else
480                         tdx_hw_tag.prodid = VERDIN_IMX8MMQ_IT;
481         } else if (is_cpu_type(MXC_CPU_IMX8MN)) {
482                 tdx_hw_tag.prodid = VERDIN_IMX8MNQ_WIFI_BT;
483         } else if (is_cpu_type(MXC_CPU_IMX8MPL)) {
484                 tdx_hw_tag.prodid = VERDIN_IMX8MPQL_IT;
485         } else if (is_cpu_type(MXC_CPU_IMX8MP)) {
486                 if (wb == 'y' || wb == 'Y')
487                         if (gd->ram_size == 0x80000000)
488                                 tdx_hw_tag.prodid = VERDIN_IMX8MPQ_2GB_WIFI_BT_IT;
489                         else if (gd->ram_size == 0x200000000)
490                                 tdx_hw_tag.prodid = VERDIN_IMX8MPQ_8GB_WIFI_BT;
491                         else
492                                 tdx_hw_tag.prodid = VERDIN_IMX8MPQ_WIFI_BT_IT;
493                 else
494                         if (it == 'y' || it == 'Y')
495                                 tdx_hw_tag.prodid = VERDIN_IMX8MPQ_IT;
496                         else
497                                 tdx_hw_tag.prodid = VERDIN_IMX8MPQ;
498         } else if (!strcmp("tegra20", soc)) {
499                 if (it == 'y' || it == 'Y')
500                         if (gd->ram_size == 0x10000000)
501                                 tdx_hw_tag.prodid = COLIBRI_T20_256MB_IT;
502                         else
503                                 tdx_hw_tag.prodid = COLIBRI_T20_512MB_IT;
504                 else
505                         if (gd->ram_size == 0x10000000)
506                                 tdx_hw_tag.prodid = COLIBRI_T20_256MB;
507                         else
508                                 tdx_hw_tag.prodid = COLIBRI_T20_512MB;
509         }
510 #if defined(CONFIG_TARGET_APALIS_T30) || defined(CONFIG_TARGET_COLIBRI_T30)
511         else if (!strcmp("tegra30", soc)) {
512 #ifdef CONFIG_TARGET_APALIS_T30
513                 if (it == 'y' || it == 'Y')
514                         tdx_hw_tag.prodid = APALIS_T30_IT;
515                 else
516                         if (gd->ram_size == 0x40000000)
517                                 tdx_hw_tag.prodid = APALIS_T30_1GB;
518                         else
519                                 tdx_hw_tag.prodid = APALIS_T30_2GB;
520 #else
521                 if (it == 'y' || it == 'Y')
522                         tdx_hw_tag.prodid = COLIBRI_T30_IT;
523                 else
524                         tdx_hw_tag.prodid = COLIBRI_T30;
525 #endif
526         }
527 #endif /* CONFIG_TARGET_APALIS_T30 || CONFIG_TARGET_COLIBRI_T30 */
528         else if (!strcmp("tegra124", soc)) {
529                 tdx_hw_tag.prodid = APALIS_TK1_2GB;
530         } else if (!strcmp("vf500", soc)) {
531                 if (it == 'y' || it == 'Y')
532                         tdx_hw_tag.prodid = COLIBRI_VF50_IT;
533                 else
534                         tdx_hw_tag.prodid = COLIBRI_VF50;
535         } else if (!strcmp("vf610", soc)) {
536                 if (it == 'y' || it == 'Y')
537                         tdx_hw_tag.prodid = COLIBRI_VF61_IT;
538                 else
539                         tdx_hw_tag.prodid = COLIBRI_VF61;
540         }
541
542         if (!tdx_hw_tag.prodid) {
543                 printf("Module type not detectable due to unknown SoC\n");
544                 return -1;
545         }
546
547         while (len < 4) {
548                 sprintf(message, "Enter the module version (e.g. V1.1B): V");
549                 len = cli_readline(message);
550         }
551
552         tdx_hw_tag.ver_major = console_buffer[0] - '0';
553         tdx_hw_tag.ver_minor = console_buffer[2] - '0';
554         tdx_hw_tag.ver_assembly = console_buffer[3] - 'A';
555
556         while (len < 8) {
557                 sprintf(message, "Enter module serial number: ");
558                 len = cli_readline(message);
559         }
560
561         tdx_serial = dectoul(console_buffer, NULL);
562
563         return 0;
564 }
565
566 static int get_cfgblock_barcode(char *barcode, struct toradex_hw *tag,
567                                 u32 *serial)
568 {
569         char revision[3] = {barcode[6], barcode[7], '\0'};
570
571         if (strlen(barcode) < 16) {
572                 printf("Argument too short, barcode is 16 chars long\n");
573                 return -1;
574         }
575
576         /* Get hardware information from the first 8 digits */
577         tag->ver_major = barcode[4] - '0';
578         tag->ver_minor = barcode[5] - '0';
579         tag->ver_assembly = dectoul(revision, NULL);
580
581         barcode[4] = '\0';
582         tag->prodid = dectoul(barcode, NULL);
583
584         /* Parse second part of the barcode (serial number */
585         barcode += 8;
586         *serial = dectoul(barcode, NULL);
587
588         return 0;
589 }
590
591 static int write_tag(u8 *config_block, int *offset, int tag_id,
592                      u8 *tag_data, size_t tag_data_size)
593 {
594         struct toradex_tag *tag;
595
596         if (!offset || !config_block)
597                 return -EINVAL;
598
599         tag = (struct toradex_tag *)(config_block + *offset);
600         tag->id = tag_id;
601         tag->flags = TAG_FLAG_VALID;
602         /* len is provided as number of 32bit values after the tag */
603         tag->len = (tag_data_size + sizeof(u32) - 1) / sizeof(u32);
604         *offset += sizeof(struct toradex_tag);
605         if (tag_data && tag_data_size) {
606                 memcpy(config_block + *offset, tag_data,
607                        tag_data_size);
608                 *offset += tag_data_size;
609         }
610
611         return 0;
612 }
613
614 #ifdef CONFIG_TDX_CFG_BLOCK_EXTRA
615 int read_tdx_cfg_block_carrier(void)
616 {
617         int ret = 0;
618         u8 *config_block = NULL;
619         struct toradex_tag *tag;
620         size_t size = TDX_CFG_BLOCK_EXTRA_MAX_SIZE;
621         int offset;
622
623         /* Allocate RAM area for carrier config block */
624         config_block = memalign(ARCH_DMA_MINALIGN, size);
625         if (!config_block) {
626                 printf("Not enough malloc space available!\n");
627                 return -ENOMEM;
628         }
629
630         memset(config_block, 0, size);
631
632         ret = read_tdx_eeprom_data(TDX_EEPROM_ID_CARRIER, 0x0, config_block,
633                                    size);
634         if (ret)
635                 return ret;
636
637         /* Expect a valid tag first */
638         tag = (struct toradex_tag *)config_block;
639         if (tag->flags != TAG_FLAG_VALID || tag->id != TAG_VALID) {
640                 valid_cfgblock_carrier = false;
641                 ret = -EINVAL;
642                 goto out;
643         }
644         valid_cfgblock_carrier = true;
645         offset = 4;
646
647         while (offset + sizeof(struct toradex_tag) +
648                sizeof(struct toradex_hw) < TDX_CFG_BLOCK_MAX_SIZE) {
649                 tag = (struct toradex_tag *)(config_block + offset);
650                 offset += 4;
651                 if (tag->id == TAG_INVALID)
652                         break;
653
654                 if (tag->flags == TAG_FLAG_VALID) {
655                         switch (tag->id) {
656                         case TAG_CAR_SERIAL:
657                                 memcpy(&tdx_car_serial, config_block + offset,
658                                        sizeof(tdx_car_serial));
659                                 break;
660                         case TAG_HW:
661                                 memcpy(&tdx_car_hw_tag, config_block +
662                                        offset, 8);
663                                 break;
664                         }
665                 }
666
667                 /* Get to next tag according to current tags length */
668                 offset += tag->len * 4;
669         }
670 out:
671         free(config_block);
672         return ret;
673 }
674
675 int check_pid8_sanity(char *pid8)
676 {
677         char s_carrierid_verdin_dev[5];
678         char s_carrierid_dahlia[5];
679
680         sprintf(s_carrierid_verdin_dev, "0%d", VERDIN_DEVELOPMENT_BOARD);
681         sprintf(s_carrierid_dahlia, "0%d", DAHLIA);
682
683         /* sane value check, first 4 chars which represent carrier id */
684         if (!strncmp(pid8, s_carrierid_verdin_dev, 4))
685                 return 0;
686
687         if (!strncmp(pid8, s_carrierid_dahlia, 4))
688                 return 0;
689
690         return -EINVAL;
691 }
692
693 int try_migrate_tdx_cfg_block_carrier(void)
694 {
695         char pid8[8];
696         int offset = 0;
697         int ret = CMD_RET_SUCCESS;
698         size_t size = TDX_CFG_BLOCK_EXTRA_MAX_SIZE;
699         u8 *config_block;
700
701         memset(pid8, 0x0, 8);
702         ret = read_tdx_eeprom_data(TDX_EEPROM_ID_CARRIER, 0x0, (u8 *)pid8, 8);
703         if (ret)
704                 return ret;
705
706         if (check_pid8_sanity(pid8))
707                 return -EINVAL;
708
709         /* Allocate RAM area for config block */
710         config_block = memalign(ARCH_DMA_MINALIGN, size);
711         if (!config_block) {
712                 printf("Not enough malloc space available!\n");
713                 return CMD_RET_FAILURE;
714         }
715
716         memset(config_block, 0xff, size);
717         /* we try parse PID8 concatenating zeroed serial number */
718         tdx_car_hw_tag.ver_major = pid8[4] - '0';
719         tdx_car_hw_tag.ver_minor = pid8[5] - '0';
720         tdx_car_hw_tag.ver_assembly = pid8[7] - '0';
721
722         pid8[4] = '\0';
723         tdx_car_hw_tag.prodid = dectoul(pid8, NULL);
724
725         /* Valid Tag */
726         write_tag(config_block, &offset, TAG_VALID, NULL, 0);
727
728         /* Product Tag */
729         write_tag(config_block, &offset, TAG_HW, (u8 *)&tdx_car_hw_tag,
730                   sizeof(tdx_car_hw_tag));
731
732         /* Serial Tag */
733         write_tag(config_block, &offset, TAG_CAR_SERIAL, (u8 *)&tdx_car_serial,
734                   sizeof(tdx_car_serial));
735
736         memset(config_block + offset, 0, 32 - offset);
737         ret = write_tdx_eeprom_data(TDX_EEPROM_ID_CARRIER, 0x0, config_block,
738                                     size);
739         if (ret) {
740                 printf("Failed to write Toradex Extra config block: %d\n",
741                        ret);
742                 ret = CMD_RET_FAILURE;
743                 goto out;
744         }
745
746         printf("Successfully migrated to Toradex Config Block from PID8\n");
747
748 out:
749         free(config_block);
750         return ret;
751 }
752
753 static int get_cfgblock_carrier_interactive(void)
754 {
755         char message[CONFIG_SYS_CBSIZE];
756         int len;
757
758         printf("Supported carrier boards:\n");
759         printf("CARRIER BOARD NAME\t\t [ID]\n");
760         for (int i = 0; i < sizeof(toradex_carrier_boards) /
761                             sizeof(toradex_carrier_boards[0]); i++)
762                 if (toradex_carrier_boards[i])
763                         printf("%s \t\t [%d]\n", toradex_carrier_boards[i], i);
764
765         sprintf(message, "Choose your carrier board (provide ID): ");
766         len = cli_readline(message);
767         tdx_car_hw_tag.prodid = dectoul(console_buffer, NULL);
768
769         do {
770                 sprintf(message, "Enter carrier board version (e.g. V1.1B): V");
771                 len = cli_readline(message);
772         } while (len < 4);
773
774         tdx_car_hw_tag.ver_major = console_buffer[0] - '0';
775         tdx_car_hw_tag.ver_minor = console_buffer[2] - '0';
776         tdx_car_hw_tag.ver_assembly = console_buffer[3] - 'A';
777
778         while (len < 8) {
779                 sprintf(message, "Enter carrier board serial number: ");
780                 len = cli_readline(message);
781         }
782
783         tdx_car_serial = dectoul(console_buffer, NULL);
784
785         return 0;
786 }
787
788 static int do_cfgblock_carrier_create(struct cmd_tbl *cmdtp, int flag, int argc,
789                                       char * const argv[])
790 {
791         u8 *config_block;
792         size_t size = TDX_CFG_BLOCK_EXTRA_MAX_SIZE;
793         int offset = 0;
794         int ret = CMD_RET_SUCCESS;
795         int err;
796         int force_overwrite = 0;
797
798         if (argc >= 3) {
799                 if (argv[2][0] == '-' && argv[2][1] == 'y')
800                         force_overwrite = 1;
801         }
802
803         /* Allocate RAM area for config block */
804         config_block = memalign(ARCH_DMA_MINALIGN, size);
805         if (!config_block) {
806                 printf("Not enough malloc space available!\n");
807                 return CMD_RET_FAILURE;
808         }
809
810         memset(config_block, 0xff, size);
811         read_tdx_cfg_block_carrier();
812         if (valid_cfgblock_carrier && !force_overwrite) {
813                 char message[CONFIG_SYS_CBSIZE];
814
815                 sprintf(message, "A valid Toradex Carrier config block is present, still recreate? [y/N] ");
816
817                 if (!cli_readline(message))
818                         goto out;
819
820                 if (console_buffer[0] != 'y' &&
821                     console_buffer[0] != 'Y')
822                         goto out;
823         }
824
825         if (argc < 3 || (force_overwrite && argc < 4)) {
826                 err = get_cfgblock_carrier_interactive();
827         } else {
828                 if (force_overwrite)
829                         err = get_cfgblock_barcode(argv[3], &tdx_car_hw_tag,
830                                                    &tdx_car_serial);
831                 else
832                         err = get_cfgblock_barcode(argv[2], &tdx_car_hw_tag,
833                                                    &tdx_car_serial);
834         }
835
836         if (err) {
837                 ret = CMD_RET_FAILURE;
838                 goto out;
839         }
840
841         /* Valid Tag */
842         write_tag(config_block, &offset, TAG_VALID, NULL, 0);
843
844         /* Product Tag */
845         write_tag(config_block, &offset, TAG_HW, (u8 *)&tdx_car_hw_tag,
846                   sizeof(tdx_car_hw_tag));
847
848         /* Serial Tag */
849         write_tag(config_block, &offset, TAG_CAR_SERIAL, (u8 *)&tdx_car_serial,
850                   sizeof(tdx_car_serial));
851
852         memset(config_block + offset, 0, 32 - offset);
853         err = write_tdx_eeprom_data(TDX_EEPROM_ID_CARRIER, 0x0, config_block,
854                                     size);
855         if (err) {
856                 printf("Failed to write Toradex Extra config block: %d\n",
857                        ret);
858                 ret = CMD_RET_FAILURE;
859                 goto out;
860         }
861
862         printf("Toradex Extra config block successfully written\n");
863
864 out:
865         free(config_block);
866         return ret;
867 }
868
869 #endif /* CONFIG_TDX_CFG_BLOCK_EXTRA */
870
871 static int do_cfgblock_create(struct cmd_tbl *cmdtp, int flag, int argc,
872                               char * const argv[])
873 {
874         u8 *config_block;
875         size_t size = TDX_CFG_BLOCK_MAX_SIZE;
876         int offset = 0;
877         int ret = CMD_RET_SUCCESS;
878         int err;
879         int force_overwrite = 0;
880
881         if (argc >= 3) {
882 #ifdef CONFIG_TDX_CFG_BLOCK_EXTRA
883                 if (!strcmp(argv[2], "carrier"))
884                         return do_cfgblock_carrier_create(cmdtp, flag,
885                                                           --argc, ++argv);
886 #endif /* CONFIG_TDX_CFG_BLOCK_EXTRA */
887                 if (argv[2][0] == '-' && argv[2][1] == 'y')
888                         force_overwrite = 1;
889         }
890
891         /* Allocate RAM area for config block */
892         config_block = memalign(ARCH_DMA_MINALIGN, size);
893         if (!config_block) {
894                 printf("Not enough malloc space available!\n");
895                 return CMD_RET_FAILURE;
896         }
897
898         memset(config_block, 0xff, size);
899
900         read_tdx_cfg_block();
901         if (valid_cfgblock) {
902 #if defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NAND)
903                 /*
904                  * On NAND devices, recreation is only allowed if the page is
905                  * empty (config block invalid...)
906                  */
907                 printf("NAND erase block %d need to be erased before creating a Toradex config block\n",
908                        CONFIG_TDX_CFG_BLOCK_OFFSET /
909                        get_nand_dev_by_index(0)->erasesize);
910                 goto out;
911 #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NOR)
912                 /*
913                  * On NOR devices, recreation is only allowed if the sector is
914                  * empty and write protection is off (config block invalid...)
915                  */
916                 printf("NOR sector at offset 0x%02x need to be erased and unprotected before creating a Toradex config block\n",
917                        CONFIG_TDX_CFG_BLOCK_OFFSET);
918                 goto out;
919 #else
920                 if (!force_overwrite) {
921                         char message[CONFIG_SYS_CBSIZE];
922
923                         sprintf(message,
924                                 "A valid Toradex config block is present, still recreate? [y/N] ");
925
926                         if (!cli_readline(message))
927                                 goto out;
928
929                         if (console_buffer[0] != 'y' &&
930                             console_buffer[0] != 'Y')
931                                 goto out;
932                 }
933 #endif
934         }
935
936         /* Parse new Toradex config block data... */
937         if (argc < 3 || (force_overwrite && argc < 4)) {
938                 err = get_cfgblock_interactive();
939         } else {
940                 if (force_overwrite)
941                         err = get_cfgblock_barcode(argv[3], &tdx_hw_tag,
942                                                    &tdx_serial);
943                 else
944                         err = get_cfgblock_barcode(argv[2], &tdx_hw_tag,
945                                                    &tdx_serial);
946         }
947         if (err) {
948                 ret = CMD_RET_FAILURE;
949                 goto out;
950         }
951
952         /* Convert serial number to MAC address (the storage format) */
953         tdx_eth_addr.oui = htonl(0x00142dUL << 8);
954         tdx_eth_addr.nic = htonl(tdx_serial << 8);
955
956         /* Valid Tag */
957         write_tag(config_block, &offset, TAG_VALID, NULL, 0);
958
959         /* Product Tag */
960         write_tag(config_block, &offset, TAG_HW, (u8 *)&tdx_hw_tag,
961                   sizeof(tdx_hw_tag));
962
963         /* MAC Tag */
964         write_tag(config_block, &offset, TAG_MAC, (u8 *)&tdx_eth_addr,
965                   sizeof(tdx_eth_addr));
966
967         memset(config_block + offset, 0, 32 - offset);
968 #if defined(CONFIG_TDX_CFG_BLOCK_IS_IN_MMC)
969         err = tdx_cfg_block_mmc_storage(config_block, 1);
970 #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NAND)
971         err = write_tdx_cfg_block_to_nand(config_block);
972 #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_NOR)
973         err = write_tdx_cfg_block_to_nor(config_block);
974 #elif defined(CONFIG_TDX_CFG_BLOCK_IS_IN_EEPROM)
975         err = write_tdx_cfg_block_to_eeprom(config_block);
976 #else
977         err = -EINVAL;
978 #endif
979         if (err) {
980                 printf("Failed to write Toradex config block: %d\n", ret);
981                 ret = CMD_RET_FAILURE;
982                 goto out;
983         }
984
985         printf("Toradex config block successfully written\n");
986
987 out:
988         free(config_block);
989         return ret;
990 }
991
992 static int do_cfgblock(struct cmd_tbl *cmdtp, int flag, int argc,
993                        char *const argv[])
994 {
995         int ret;
996
997         if (argc < 2)
998                 return CMD_RET_USAGE;
999
1000         if (!strcmp(argv[1], "create")) {
1001                 return do_cfgblock_create(cmdtp, flag, argc, argv);
1002         } else if (!strcmp(argv[1], "reload")) {
1003                 ret = read_tdx_cfg_block();
1004                 if (ret) {
1005                         printf("Failed to reload Toradex config block: %d\n",
1006                                ret);
1007                         return CMD_RET_FAILURE;
1008                 }
1009                 return CMD_RET_SUCCESS;
1010         }
1011
1012         return CMD_RET_USAGE;
1013 }
1014
1015 U_BOOT_CMD(
1016         cfgblock, 5, 0, do_cfgblock,
1017         "Toradex config block handling commands",
1018         "create [-y] [barcode] - (Re-)create Toradex config block\n"
1019         "create carrier [-y] [barcode] - (Re-)create Toradex Carrier config block\n"
1020         "cfgblock reload - Reload Toradex config block from flash"
1021 );