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