blob: 3656cf4cbc45113e7834c0323742226abae7742b [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>
Simon Glass09140112020-05-10 11:40:03 -060012#include <command.h>
Simon Glass1eb69ae2019-11-14 12:57:39 -070013#include <cpu_func.h>
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -040014#include <div64.h>
Simon Glass9fb625c2019-08-01 09:46:51 -060015#include <env.h>
Simon Glassb79fdc72020-05-10 11:39:54 -060016#include <flash.h>
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -040017#include <malloc.h>
18#include <spi_flash.h>
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -040019#include <mmc.h>
20#include <version.h>
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -040021#include <asm/io.h>
22
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -040023static ulong fwenv_addr[MAX_FWENV_ADDR];
24const char mystrerr[] = "ERROR: Failed to save factory info";
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -040025
26static int ishwaddr(char *hwaddr)
27{
28 if (strlen(hwaddr) == MAX_HWADDR_SIZE)
29 if (hwaddr[2] == ':' &&
30 hwaddr[5] == ':' &&
31 hwaddr[8] == ':' &&
32 hwaddr[11] == ':' &&
33 hwaddr[14] == ':')
34 return 0;
35 return -1;
36}
37
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -040038#if (FWENV_TYPE == FWENV_MMC)
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -040039
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -040040static char smac[29][18] __attribute__ ((aligned(0x200))); /* 1 MMC block is 512 bytes */
41
42int set_mmc_arc_product(int argc, char *const argv[])
43{
44 struct mmc *mmc;
45 u32 blk, cnt, n;
46 int i, err = 1;
47 void *addr;
48 const u8 mmc_dev_num = CONFIG_SYS_MMC_ENV_DEV;
49
50 mmc = find_mmc_device(mmc_dev_num);
51 if (!mmc) {
52 printf("No SD/MMC/eMMC card found\n");
53 return 0;
54 }
55 if (mmc_init(mmc)) {
56 printf("%s(%d) init failed\n", IS_SD(mmc) ? "SD" : "MMC",
57 mmc_dev_num);
58 return 0;
59 }
60 if (mmc_getwp(mmc) == 1) {
61 printf("Error: card is write protected!\n");
62 return CMD_RET_FAILURE;
63 }
64
65 /* Save factory defaults */
66 addr = (void *)smac;
67 cnt = 1; /* One 512 bytes block */
68
69 for (i = 0; i < MAX_FWENV_ADDR; i++)
70 if (fwenv_addr[i] != -1) {
71 blk = fwenv_addr[i] / 512;
72 n = blk_dwrite(mmc_get_blk_desc(mmc), blk, cnt, addr);
73 if (n != cnt)
74 printf("%s: %s [%d]\n", __func__, mystrerr, i);
75 else
76 err = 0;
77 }
78 if (err)
79 return -2;
80
81 return err;
82}
83
84static int read_mmc_arc_info(void)
85{
86 struct mmc *mmc;
87 u32 blk, cnt, n;
88 int i;
89 void *addr;
90 const u8 mmc_dev_num = CONFIG_SYS_MMC_ENV_DEV;
91
92 mmc = find_mmc_device(mmc_dev_num);
93 if (!mmc) {
94 printf("No SD/MMC/eMMC card found\n");
95 return 0;
96 }
97 if (mmc_init(mmc)) {
98 printf("%s(%d) init failed\n", IS_SD(mmc) ? "SD" : "MMC",
99 mmc_dev_num);
100 return 0;
101 }
102
103 addr = (void *)smac;
104 cnt = 1; /* One 512 bytes block */
105
106 for (i = 0; i < MAX_FWENV_ADDR; i++)
107 if (fwenv_addr[i] != -1) {
108 blk = fwenv_addr[i] / 512;
109 n = blk_dread(mmc_get_blk_desc(mmc), blk, cnt, addr);
110 flush_cache((ulong) addr, 512);
111 if (n == cnt)
112 return (i + 1);
113 }
114 return 0;
115}
116#endif
117
118#if (FWENV_TYPE == FWENV_SPI_FLASH)
119
120static struct spi_flash *flash;
121static char smac[4][18];
122
123int set_spi_arc_product(int argc, char *const argv[])
124{
125 int i, err = 1;
126
127 flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS,
128 CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE);
129 if (!flash) {
130 printf("Failed to initialize SPI flash at %u:%u\n",
131 CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS);
132 return -1;
133 }
134
135 /* Save factory defaults */
136 for (i = 0; i < MAX_FWENV_ADDR; i++)
137 if (fwenv_addr[i] != -1)
138 if (spi_flash_write
139 (flash, fwenv_addr[i], sizeof(smac), smac))
140 printf("%s: %s [%d]\n", __func__, mystrerr, i);
141 else
142 err = 0;
143 if (err)
144 return -2;
145
146 return err;
147}
148
149static int read_spi_arc_info(void)
150{
151 int i;
152
153 flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS,
154 CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE);
155 if (!flash) {
156 printf("Failed to initialize SPI flash at %u:%u\n",
157 CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS);
158 return 0;
159 }
160 for (i = 0; i < MAX_FWENV_ADDR; i++)
161 if (fwenv_addr[i] != -1)
162 if (!spi_flash_read
163 (flash, fwenv_addr[i], sizeof(smac), smac))
164 return (i + 1);
165 return 0;
166}
167#endif
168
169#if (FWENV_TYPE == FWENV_NOR_FLASH)
170
171static char smac[4][18];
172
173int set_nor_arc_product(int argc, char *const argv[])
174{
175 int i, err = 1;
176
177 /* Save factory defaults */
178 for (i = 0; i < MAX_FWENV_ADDR; i++)
179 if (fwenv_addr[i] != -1) {
180 ulong fwenv_end = fwenv_addr[i] + 4;
181
182 flash_sect_roundb(&fwenv_end);
183 flash_sect_protect(0, fwenv_addr[i], fwenv_end);
184 if (flash_write
185 ((char *)smac, fwenv_addr[i], sizeof(smac)))
186 printf("%s: %s [%d]\n", __func__, mystrerr, i);
187 else
188 err = 0;
189 flash_sect_protect(1, fwenv_addr[i], fwenv_end);
190 }
191 if (err)
192 return -2;
193
194 return err;
195}
196
197static int read_nor_arc_info(void)
198{
199 int i;
200
201 for (i = 0; i < MAX_FWENV_ADDR; i++)
202 if (fwenv_addr[i] != -1) {
203 memcpy(smac, (void *)fwenv_addr[i], sizeof(smac));
204 return (i + 1);
205 }
206
207 return 0;
208}
209#endif
210
211int set_arc_product(int argc, char *const argv[])
212{
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400213 if (argc != 5)
214 return -1;
215
216 /* Check serial number */
217 if (strlen(argv[1]) != MAX_SERIAL_SIZE)
218 return -1;
219
220 /* Check HWaddrs */
221 if (ishwaddr(argv[2]) || ishwaddr(argv[3]) || ishwaddr(argv[4]))
222 return -1;
223
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400224 strcpy(smac[0], argv[1]);
225 strcpy(smac[1], argv[2]);
226 strcpy(smac[2], argv[3]);
227 strcpy(smac[3], argv[4]);
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400228
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400229#if (FWENV_TYPE == FWENV_NOR_FLASH)
230 return set_nor_arc_product(argc, argv);
231#endif
232#if (FWENV_TYPE == FWENV_SPI_FLASH)
233 return set_spi_arc_product(argc, argv);
234#endif
235#if (FWENV_TYPE == FWENV_MMC)
236 return set_mmc_arc_product(argc, argv);
237#endif
238 return -2;
239}
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400240
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400241static int read_arc_info(void)
242{
243#if (FWENV_TYPE == FWENV_NOR_FLASH)
244 return read_nor_arc_info();
245#endif
246#if (FWENV_TYPE == FWENV_SPI_FLASH)
247 return read_spi_arc_info();
248#endif
249#if (FWENV_TYPE == FWENV_MMC)
250 return read_mmc_arc_info();
251#endif
252 return 0;
253}
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400254
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400255static int do_get_arc_info(void)
256{
257 int l = read_arc_info();
258 char *oldserial = env_get("SERIAL");
259 char *oldversion = env_get("VERSION");
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400260
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400261 if (oldversion != NULL)
262 if (strcmp(oldversion, U_BOOT_VERSION) != 0)
263 oldversion = NULL;
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400264
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400265 if (l == 0) {
266 printf("%s: failed to read factory info\n", __func__);
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400267 return -2;
268 }
269
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400270 printf("\rSERIAL: ");
271 if (smac[0][0] == EMPY_CHAR) {
272 printf("<not found>\n");
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400273 } else {
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400274 printf("%s\n", smac[0]);
275 env_set("SERIAL", smac[0]);
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400276 }
277
278 if (strcmp(smac[1], "00:00:00:00:00:00") == 0) {
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400279 env_set("ethaddr", NULL);
280 env_set("eth1addr", NULL);
281 env_set("eth2addr", NULL);
282 goto done;
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400283 }
284
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400285 printf("HWADDR0: ");
286 if (smac[1][0] == EMPY_CHAR) {
287 printf("<not found>\n");
288 } else {
289 char *ret = env_get("ethaddr");
290
291 if (ret == NULL) {
292 env_set("ethaddr", smac[1]);
293 printf("%s\n", smac[1]);
294 } else if (strcmp(ret, __stringify(CONFIG_ETHADDR)) == 0) {
295 env_set("ethaddr", smac[1]);
296 printf("%s (factory)\n", smac[1]);
297 } else {
298 printf("%s\n", ret);
299 }
300 }
301
302 if (strcmp(smac[2], "00:00:00:00:00:00") == 0) {
303 env_set("eth1addr", NULL);
304 env_set("eth2addr", NULL);
305 goto done;
306 }
307
308 printf("HWADDR1: ");
309 if (smac[2][0] == EMPY_CHAR) {
310 printf("<not found>\n");
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400311 } else {
Simon Glass00caae62017-08-03 12:22:12 -0600312 char *ret = env_get("eth1addr");
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400313
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400314 if (ret == NULL) {
315 env_set("ethaddr", smac[2]);
316 printf("%s\n", smac[2]);
317 } else if (strcmp(ret, __stringify(CONFIG_ETH1ADDR)) == 0) {
318 env_set("eth1addr", smac[2]);
319 printf("%s (factory)\n", smac[2]);
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400320 } else {
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400321 printf("%s\n", ret);
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400322 }
323 }
324
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400325 if (strcmp(smac[3], "00:00:00:00:00:00") == 0) {
326 env_set("eth2addr", NULL);
327 goto done;
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400328 }
329
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400330 printf("HWADDR2: ");
331 if (smac[3][0] == EMPY_CHAR) {
332 printf("<not found>\n");
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400333 } else {
Simon Glass00caae62017-08-03 12:22:12 -0600334 char *ret = env_get("eth2addr");
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400335
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400336 if (ret == NULL) {
337 env_set("ethaddr", smac[3]);
338 printf("%s\n", smac[3]);
339 } else if (strcmp(ret, __stringify(CONFIG_ETH2ADDR)) == 0) {
340 env_set("eth2addr", smac[3]);
341 printf("%s (factory)\n", smac[3]);
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400342 } else {
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400343 printf("%s\n", ret);
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400344 }
345 }
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400346done:
347 if (oldserial == NULL || oldversion == NULL) {
348 if (oldversion == NULL)
349 env_set("VERSION", U_BOOT_VERSION);
350 env_save();
351 }
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400352
353 return 0;
354}
355
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400356static int init_fwenv(void)
357{
358 int i, ret = -1;
359
360 fwenv_addr[0] = FWENV_ADDR1;
361 fwenv_addr[1] = FWENV_ADDR2;
362 fwenv_addr[2] = FWENV_ADDR3;
363 fwenv_addr[3] = FWENV_ADDR4;
364
365 for (i = 0; i < MAX_FWENV_ADDR; i++)
366 if (fwenv_addr[i] != -1)
367 ret = 0;
368 if (ret)
369 printf("%s: No firmfare info storage address is defined\n",
370 __func__);
371 return ret;
372}
373
374void get_arc_info(void)
375{
376 if (!init_fwenv())
377 do_get_arc_info();
378}
379
Simon Glass09140112020-05-10 11:40:03 -0600380static int do_arc_cmd(struct cmd_tbl *cmdtp, int flag, int argc,
381 char *const argv[])
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400382{
383 const char *cmd;
384 int ret = -1;
385
386 cmd = argv[1];
387 --argc;
388 ++argv;
389
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400390 if (init_fwenv())
391 return ret;
392
393 if (strcmp(cmd, "product") == 0)
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400394 ret = set_arc_product(argc, argv);
Oleksandr Zhadanf51d7fc2019-06-17 16:10:23 -0400395 else if (strcmp(cmd, "info") == 0)
396 ret = do_get_arc_info();
397
Oleksandr G Zhadan8b0044f2015-04-29 16:57:39 -0400398 if (ret == -1)
399 return CMD_RET_USAGE;
400
401 return ret;
402}
403
404U_BOOT_CMD(arc, 6, 1, do_arc_cmd,
405 "Arcturus product command sub-system",
406 "product serial hwaddr0 hwaddr1 hwaddr2 - save Arcturus factory env\n"
407 "info - show Arcturus factory env\n\n");