blob: 7a510c61fb015c5d9c08a149f247b4e1e6e2e0bd [file] [log] [blame]
Tom Rini4549e782018-05-06 18:27:01 -04001// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -04002/*
3 * Command for accessing Arcturus factory environment.
4 *
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -04005 * Copyright 2013-2019 Arcturus Networks Inc.
6 * https://www.arcturusnetworks.com/products/
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -04007 * by Oleksandr G Zhadan et al.
8 *
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -04009 */
10
11#include <common.h>
12#include <div64.h>
13#include <malloc.h>
14#include <spi_flash.h>
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -040015#include <mmc.h>
16#include <version.h>
17#include <environment.h>
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -040018#include <asm/io.h>
19
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -040020static ulong fwenv_addr[MAX_FWENV_ADDR];
21const char mystrerr[] = "ERROR: Failed to save factory info";
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -040022
23static int ishwaddr(char *hwaddr)
24{
25 if (strlen(hwaddr) == MAX_HWADDR_SIZE)
26 if (hwaddr[2] == ':' &&
27 hwaddr[5] == ':' &&
28 hwaddr[8] == ':' &&
29 hwaddr[11] == ':' &&
30 hwaddr[14] == ':')
31 return 0;
32 return -1;
33}
34
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -040035#if (FWENV_TYPE == FWENV_MMC)
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -040036
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -040037static char smac[29][18] __attribute__ ((aligned(0x200))); /* 1 MMC block is 512 bytes */
38
39int set_mmc_arc_product(int argc, char *const argv[])
40{
41 struct mmc *mmc;
42 u32 blk, cnt, n;
43 int i, err = 1;
44 void *addr;
45 const u8 mmc_dev_num = CONFIG_SYS_MMC_ENV_DEV;
46
47 mmc = find_mmc_device(mmc_dev_num);
48 if (!mmc) {
49 printf("No SD/MMC/eMMC card found\n");
50 return 0;
51 }
52 if (mmc_init(mmc)) {
53 printf("%s(%d) init failed\n", IS_SD(mmc) ? "SD" : "MMC",
54 mmc_dev_num);
55 return 0;
56 }
57 if (mmc_getwp(mmc) == 1) {
58 printf("Error: card is write protected!\n");
59 return CMD_RET_FAILURE;
60 }
61
62 /* Save factory defaults */
63 addr = (void *)smac;
64 cnt = 1; /* One 512 bytes block */
65
66 for (i = 0; i < MAX_FWENV_ADDR; i++)
67 if (fwenv_addr[i] != -1) {
68 blk = fwenv_addr[i] / 512;
69 n = blk_dwrite(mmc_get_blk_desc(mmc), blk, cnt, addr);
70 if (n != cnt)
71 printf("%s: %s [%d]\n", __func__, mystrerr, i);
72 else
73 err = 0;
74 }
75 if (err)
76 return -2;
77
78 return err;
79}
80
81static int read_mmc_arc_info(void)
82{
83 struct mmc *mmc;
84 u32 blk, cnt, n;
85 int i;
86 void *addr;
87 const u8 mmc_dev_num = CONFIG_SYS_MMC_ENV_DEV;
88
89 mmc = find_mmc_device(mmc_dev_num);
90 if (!mmc) {
91 printf("No SD/MMC/eMMC card found\n");
92 return 0;
93 }
94 if (mmc_init(mmc)) {
95 printf("%s(%d) init failed\n", IS_SD(mmc) ? "SD" : "MMC",
96 mmc_dev_num);
97 return 0;
98 }
99
100 addr = (void *)smac;
101 cnt = 1; /* One 512 bytes block */
102
103 for (i = 0; i < MAX_FWENV_ADDR; i++)
104 if (fwenv_addr[i] != -1) {
105 blk = fwenv_addr[i] / 512;
106 n = blk_dread(mmc_get_blk_desc(mmc), blk, cnt, addr);
107 flush_cache((ulong) addr, 512);
108 if (n == cnt)
109 return (i + 1);
110 }
111 return 0;
112}
113#endif
114
115#if (FWENV_TYPE == FWENV_SPI_FLASH)
116
117static struct spi_flash *flash;
118static char smac[4][18];
119
120int set_spi_arc_product(int argc, char *const argv[])
121{
122 int i, err = 1;
123
124 flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS,
125 CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE);
126 if (!flash) {
127 printf("Failed to initialize SPI flash at %u:%u\n",
128 CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS);
129 return -1;
130 }
131
132 /* Save factory defaults */
133 for (i = 0; i < MAX_FWENV_ADDR; i++)
134 if (fwenv_addr[i] != -1)
135 if (spi_flash_write
136 (flash, fwenv_addr[i], sizeof(smac), smac))
137 printf("%s: %s [%d]\n", __func__, mystrerr, i);
138 else
139 err = 0;
140 if (err)
141 return -2;
142
143 return err;
144}
145
146static int read_spi_arc_info(void)
147{
148 int i;
149
150 flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS,
151 CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE);
152 if (!flash) {
153 printf("Failed to initialize SPI flash at %u:%u\n",
154 CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS);
155 return 0;
156 }
157 for (i = 0; i < MAX_FWENV_ADDR; i++)
158 if (fwenv_addr[i] != -1)
159 if (!spi_flash_read
160 (flash, fwenv_addr[i], sizeof(smac), smac))
161 return (i + 1);
162 return 0;
163}
164#endif
165
166#if (FWENV_TYPE == FWENV_NOR_FLASH)
167
168static char smac[4][18];
169
170int set_nor_arc_product(int argc, char *const argv[])
171{
172 int i, err = 1;
173
174 /* Save factory defaults */
175 for (i = 0; i < MAX_FWENV_ADDR; i++)
176 if (fwenv_addr[i] != -1) {
177 ulong fwenv_end = fwenv_addr[i] + 4;
178
179 flash_sect_roundb(&fwenv_end);
180 flash_sect_protect(0, fwenv_addr[i], fwenv_end);
181 if (flash_write
182 ((char *)smac, fwenv_addr[i], sizeof(smac)))
183 printf("%s: %s [%d]\n", __func__, mystrerr, i);
184 else
185 err = 0;
186 flash_sect_protect(1, fwenv_addr[i], fwenv_end);
187 }
188 if (err)
189 return -2;
190
191 return err;
192}
193
194static int read_nor_arc_info(void)
195{
196 int i;
197
198 for (i = 0; i < MAX_FWENV_ADDR; i++)
199 if (fwenv_addr[i] != -1) {
200 memcpy(smac, (void *)fwenv_addr[i], sizeof(smac));
201 return (i + 1);
202 }
203
204 return 0;
205}
206#endif
207
208int set_arc_product(int argc, char *const argv[])
209{
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400210 if (argc != 5)
211 return -1;
212
213 /* Check serial number */
214 if (strlen(argv[1]) != MAX_SERIAL_SIZE)
215 return -1;
216
217 /* Check HWaddrs */
218 if (ishwaddr(argv[2]) || ishwaddr(argv[3]) || ishwaddr(argv[4]))
219 return -1;
220
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400221 strcpy(smac[0], argv[1]);
222 strcpy(smac[1], argv[2]);
223 strcpy(smac[2], argv[3]);
224 strcpy(smac[3], argv[4]);
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400225
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400226#if (FWENV_TYPE == FWENV_NOR_FLASH)
227 return set_nor_arc_product(argc, argv);
228#endif
229#if (FWENV_TYPE == FWENV_SPI_FLASH)
230 return set_spi_arc_product(argc, argv);
231#endif
232#if (FWENV_TYPE == FWENV_MMC)
233 return set_mmc_arc_product(argc, argv);
234#endif
235 return -2;
236}
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400237
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400238static int read_arc_info(void)
239{
240#if (FWENV_TYPE == FWENV_NOR_FLASH)
241 return read_nor_arc_info();
242#endif
243#if (FWENV_TYPE == FWENV_SPI_FLASH)
244 return read_spi_arc_info();
245#endif
246#if (FWENV_TYPE == FWENV_MMC)
247 return read_mmc_arc_info();
248#endif
249 return 0;
250}
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400251
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400252static int do_get_arc_info(void)
253{
254 int l = read_arc_info();
255 char *oldserial = env_get("SERIAL");
256 char *oldversion = env_get("VERSION");
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400257
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400258 if (oldversion != NULL)
259 if (strcmp(oldversion, U_BOOT_VERSION) != 0)
260 oldversion = NULL;
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400261
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400262 if (l == 0) {
263 printf("%s: failed to read factory info\n", __func__);
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400264 return -2;
265 }
266
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400267 printf("\rSERIAL: ");
268 if (smac[0][0] == EMPY_CHAR) {
269 printf("<not found>\n");
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400270 } else {
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400271 printf("%s\n", smac[0]);
272 env_set("SERIAL", smac[0]);
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400273 }
274
275 if (strcmp(smac[1], "00:00:00:00:00:00") == 0) {
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400276 env_set("ethaddr", NULL);
277 env_set("eth1addr", NULL);
278 env_set("eth2addr", NULL);
279 goto done;
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400280 }
281
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400282 printf("HWADDR0: ");
283 if (smac[1][0] == EMPY_CHAR) {
284 printf("<not found>\n");
285 } else {
286 char *ret = env_get("ethaddr");
287
288 if (ret == NULL) {
289 env_set("ethaddr", smac[1]);
290 printf("%s\n", smac[1]);
291 } else if (strcmp(ret, __stringify(CONFIG_ETHADDR)) == 0) {
292 env_set("ethaddr", smac[1]);
293 printf("%s (factory)\n", smac[1]);
294 } else {
295 printf("%s\n", ret);
296 }
297 }
298
299 if (strcmp(smac[2], "00:00:00:00:00:00") == 0) {
300 env_set("eth1addr", NULL);
301 env_set("eth2addr", NULL);
302 goto done;
303 }
304
305 printf("HWADDR1: ");
306 if (smac[2][0] == EMPY_CHAR) {
307 printf("<not found>\n");
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400308 } else {
Simon Glass00caae62017-08-03 12:22:12 -0600309 char *ret = env_get("eth1addr");
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400310
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400311 if (ret == NULL) {
312 env_set("ethaddr", smac[2]);
313 printf("%s\n", smac[2]);
314 } else if (strcmp(ret, __stringify(CONFIG_ETH1ADDR)) == 0) {
315 env_set("eth1addr", smac[2]);
316 printf("%s (factory)\n", smac[2]);
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400317 } else {
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400318 printf("%s\n", ret);
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400319 }
320 }
321
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400322 if (strcmp(smac[3], "00:00:00:00:00:00") == 0) {
323 env_set("eth2addr", NULL);
324 goto done;
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400325 }
326
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400327 printf("HWADDR2: ");
328 if (smac[3][0] == EMPY_CHAR) {
329 printf("<not found>\n");
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400330 } else {
Simon Glass00caae62017-08-03 12:22:12 -0600331 char *ret = env_get("eth2addr");
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400332
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400333 if (ret == NULL) {
334 env_set("ethaddr", smac[3]);
335 printf("%s\n", smac[3]);
336 } else if (strcmp(ret, __stringify(CONFIG_ETH2ADDR)) == 0) {
337 env_set("eth2addr", smac[3]);
338 printf("%s (factory)\n", smac[3]);
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400339 } else {
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400340 printf("%s\n", ret);
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400341 }
342 }
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400343done:
344 if (oldserial == NULL || oldversion == NULL) {
345 if (oldversion == NULL)
346 env_set("VERSION", U_BOOT_VERSION);
347 env_save();
348 }
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400349
350 return 0;
351}
352
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400353static int init_fwenv(void)
354{
355 int i, ret = -1;
356
357 fwenv_addr[0] = FWENV_ADDR1;
358 fwenv_addr[1] = FWENV_ADDR2;
359 fwenv_addr[2] = FWENV_ADDR3;
360 fwenv_addr[3] = FWENV_ADDR4;
361
362 for (i = 0; i < MAX_FWENV_ADDR; i++)
363 if (fwenv_addr[i] != -1)
364 ret = 0;
365 if (ret)
366 printf("%s: No firmfare info storage address is defined\n",
367 __func__);
368 return ret;
369}
370
371void get_arc_info(void)
372{
373 if (!init_fwenv())
374 do_get_arc_info();
375}
376
377static int do_arc_cmd(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[])
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400378{
379 const char *cmd;
380 int ret = -1;
381
382 cmd = argv[1];
383 --argc;
384 ++argv;
385
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400386 if (init_fwenv())
387 return ret;
388
389 if (strcmp(cmd, "product") == 0)
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400390 ret = set_arc_product(argc, argv);
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400391 else if (strcmp(cmd, "info") == 0)
392 ret = do_get_arc_info();
393
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400394 if (ret == -1)
395 return CMD_RET_USAGE;
396
397 return ret;
398}
399
400U_BOOT_CMD(arc, 6, 1, do_arc_cmd,
401 "Arcturus product command sub-system",
402 "product serial hwaddr0 hwaddr1 hwaddr2 - save Arcturus factory env\n"
403 "info - show Arcturus factory env\n\n");