blob: b50de63c5e0154a498fbd9b0444606ac4ae9d2cd [file] [log] [blame]
Tom Rini8b0c8a12018-05-06 18:27:01 -04001// SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -04002/*
3 * Command for accessing Arcturus factory environment.
4 *
Oleksandr Zhadanba280332019-06-17 16:10:23 -04005 * Copyright 2013-2019 Arcturus Networks Inc.
6 * https://www.arcturusnetworks.com/products/
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -04007 * by Oleksandr G Zhadan et al.
8 *
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -04009 */
10
11#include <common.h>
Simon Glass63334482019-11-14 12:57:39 -070012#include <cpu_func.h>
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -040013#include <div64.h>
Simon Glass5e6201b2019-08-01 09:46:51 -060014#include <env.h>
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -040015#include <malloc.h>
16#include <spi_flash.h>
Oleksandr Zhadanba280332019-06-17 16:10:23 -040017#include <mmc.h>
18#include <version.h>
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -040019#include <asm/io.h>
20
Oleksandr Zhadanba280332019-06-17 16:10:23 -040021static ulong fwenv_addr[MAX_FWENV_ADDR];
22const char mystrerr[] = "ERROR: Failed to save factory info";
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -040023
24static int ishwaddr(char *hwaddr)
25{
26 if (strlen(hwaddr) == MAX_HWADDR_SIZE)
27 if (hwaddr[2] == ':' &&
28 hwaddr[5] == ':' &&
29 hwaddr[8] == ':' &&
30 hwaddr[11] == ':' &&
31 hwaddr[14] == ':')
32 return 0;
33 return -1;
34}
35
Oleksandr Zhadanba280332019-06-17 16:10:23 -040036#if (FWENV_TYPE == FWENV_MMC)
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -040037
Oleksandr Zhadanba280332019-06-17 16:10:23 -040038static char smac[29][18] __attribute__ ((aligned(0x200))); /* 1 MMC block is 512 bytes */
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -040039
Oleksandr Zhadanba280332019-06-17 16:10:23 -040040int set_mmc_arc_product(int argc, char *const argv[])
41{
42 struct mmc *mmc;
43 u32 blk, cnt, n;
44 int i, err = 1;
45 void *addr;
46 const u8 mmc_dev_num = CONFIG_SYS_MMC_ENV_DEV;
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -040047
Oleksandr Zhadanba280332019-06-17 16:10:23 -040048 mmc = find_mmc_device(mmc_dev_num);
49 if (!mmc) {
50 printf("No SD/MMC/eMMC card found\n");
51 return 0;
52 }
53 if (mmc_init(mmc)) {
54 printf("%s(%d) init failed\n", IS_SD(mmc) ? "SD" : "MMC",
55 mmc_dev_num);
56 return 0;
57 }
58 if (mmc_getwp(mmc) == 1) {
59 printf("Error: card is write protected!\n");
60 return CMD_RET_FAILURE;
61 }
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -040062
Oleksandr Zhadanba280332019-06-17 16:10:23 -040063 /* Save factory defaults */
64 addr = (void *)smac;
65 cnt = 1; /* One 512 bytes block */
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -040066
Oleksandr Zhadanba280332019-06-17 16:10:23 -040067 for (i = 0; i < MAX_FWENV_ADDR; i++)
68 if (fwenv_addr[i] != -1) {
69 blk = fwenv_addr[i] / 512;
70 n = blk_dwrite(mmc_get_blk_desc(mmc), blk, cnt, addr);
71 if (n != cnt)
72 printf("%s: %s [%d]\n", __func__, mystrerr, i);
73 else
74 err = 0;
75 }
76 if (err)
77 return -2;
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -040078
Oleksandr Zhadanba280332019-06-17 16:10:23 -040079 return err;
80}
81
82static int read_mmc_arc_info(void)
83{
84 struct mmc *mmc;
85 u32 blk, cnt, n;
86 int i;
87 void *addr;
88 const u8 mmc_dev_num = CONFIG_SYS_MMC_ENV_DEV;
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -040089
Oleksandr Zhadanba280332019-06-17 16:10:23 -040090 mmc = find_mmc_device(mmc_dev_num);
91 if (!mmc) {
92 printf("No SD/MMC/eMMC card found\n");
93 return 0;
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -040094 }
Oleksandr Zhadanba280332019-06-17 16:10:23 -040095 if (mmc_init(mmc)) {
96 printf("%s(%d) init failed\n", IS_SD(mmc) ? "SD" : "MMC",
97 mmc_dev_num);
98 return 0;
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -040099 }
100
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400101 addr = (void *)smac;
102 cnt = 1; /* One 512 bytes block */
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400103
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400104 for (i = 0; i < MAX_FWENV_ADDR; i++)
105 if (fwenv_addr[i] != -1) {
106 blk = fwenv_addr[i] / 512;
107 n = blk_dread(mmc_get_blk_desc(mmc), blk, cnt, addr);
108 flush_cache((ulong) addr, 512);
109 if (n == cnt)
110 return (i + 1);
111 }
112 return 0;
113}
114#endif
115
116#if (FWENV_TYPE == FWENV_SPI_FLASH)
117
118static struct spi_flash *flash;
119static char smac[4][18];
120
121int set_spi_arc_product(int argc, char *const argv[])
122{
123 int i, err = 1;
124
125 flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS,
126 CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE);
127 if (!flash) {
128 printf("Failed to initialize SPI flash at %u:%u\n",
129 CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS);
130 return -1;
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400131 }
132
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400133 /* Save factory defaults */
134 for (i = 0; i < MAX_FWENV_ADDR; i++)
135 if (fwenv_addr[i] != -1)
136 if (spi_flash_write
137 (flash, fwenv_addr[i], sizeof(smac), smac))
138 printf("%s: %s [%d]\n", __func__, mystrerr, i);
139 else
140 err = 0;
141 if (err)
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400142 return -2;
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400143
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400144 return err;
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400145}
146
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400147static int read_spi_arc_info(void)
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400148{
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400149 int i;
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400150
151 flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS,
152 CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE);
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400153 if (!flash) {
154 printf("Failed to initialize SPI flash at %u:%u\n",
155 CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS);
156 return 0;
157 }
158 for (i = 0; i < MAX_FWENV_ADDR; i++)
159 if (fwenv_addr[i] != -1)
160 if (!spi_flash_read
161 (flash, fwenv_addr[i], sizeof(smac), smac))
162 return (i + 1);
163 return 0;
164}
165#endif
166
167#if (FWENV_TYPE == FWENV_NOR_FLASH)
168
169static char smac[4][18];
170
171int set_nor_arc_product(int argc, char *const argv[])
172{
173 int i, err = 1;
174
175 /* Save factory defaults */
176 for (i = 0; i < MAX_FWENV_ADDR; i++)
177 if (fwenv_addr[i] != -1) {
178 ulong fwenv_end = fwenv_addr[i] + 4;
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400179
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400180 flash_sect_roundb(&fwenv_end);
181 flash_sect_protect(0, fwenv_addr[i], fwenv_end);
182 if (flash_write
183 ((char *)smac, fwenv_addr[i], sizeof(smac)))
184 printf("%s: %s [%d]\n", __func__, mystrerr, i);
185 else
186 err = 0;
187 flash_sect_protect(1, fwenv_addr[i], fwenv_end);
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400188 }
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400189 if (err)
190 return -2;
191
192 return err;
193}
194
195static int read_nor_arc_info(void)
196{
197 int i;
198
199 for (i = 0; i < MAX_FWENV_ADDR; i++)
200 if (fwenv_addr[i] != -1) {
201 memcpy(smac, (void *)fwenv_addr[i], sizeof(smac));
202 return (i + 1);
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400203 }
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400204
205 return 0;
206}
207#endif
208
209int set_arc_product(int argc, char *const argv[])
210{
211 if (argc != 5)
212 return -1;
213
214 /* Check serial number */
215 if (strlen(argv[1]) != MAX_SERIAL_SIZE)
216 return -1;
217
218 /* Check HWaddrs */
219 if (ishwaddr(argv[2]) || ishwaddr(argv[3]) || ishwaddr(argv[4]))
220 return -1;
221
222 strcpy(smac[0], argv[1]);
223 strcpy(smac[1], argv[2]);
224 strcpy(smac[2], argv[3]);
225 strcpy(smac[3], argv[4]);
226
227#if (FWENV_TYPE == FWENV_NOR_FLASH)
228 return set_nor_arc_product(argc, argv);
229#endif
230#if (FWENV_TYPE == FWENV_SPI_FLASH)
231 return set_spi_arc_product(argc, argv);
232#endif
233#if (FWENV_TYPE == FWENV_MMC)
234 return set_mmc_arc_product(argc, argv);
235#endif
236 return -2;
237}
238
239static int read_arc_info(void)
240{
241#if (FWENV_TYPE == FWENV_NOR_FLASH)
242 return read_nor_arc_info();
243#endif
244#if (FWENV_TYPE == FWENV_SPI_FLASH)
245 return read_spi_arc_info();
246#endif
247#if (FWENV_TYPE == FWENV_MMC)
248 return read_mmc_arc_info();
249#endif
250 return 0;
251}
252
253static int do_get_arc_info(void)
254{
255 int l = read_arc_info();
256 char *oldserial = env_get("SERIAL");
257 char *oldversion = env_get("VERSION");
258
259 if (oldversion != NULL)
260 if (strcmp(oldversion, U_BOOT_VERSION) != 0)
261 oldversion = NULL;
262
263 if (l == 0) {
264 printf("%s: failed to read factory info\n", __func__);
265 return -2;
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400266 }
267
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400268 printf("\rSERIAL: ");
269 if (smac[0][0] == EMPY_CHAR) {
270 printf("<not found>\n");
271 } else {
272 printf("%s\n", smac[0]);
273 env_set("SERIAL", smac[0]);
274 }
275
276 if (strcmp(smac[1], "00:00:00:00:00:00") == 0) {
277 env_set("ethaddr", NULL);
278 env_set("eth1addr", NULL);
279 env_set("eth2addr", NULL);
280 goto done;
281 }
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400282
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400283 printf("HWADDR0: ");
284 if (smac[1][0] == EMPY_CHAR) {
285 printf("<not found>\n");
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400286 } else {
Simon Glass64b723f2017-08-03 12:22:12 -0600287 char *ret = env_get("ethaddr");
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400288
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400289 if (ret == NULL) {
290 env_set("ethaddr", smac[1]);
291 printf("%s\n", smac[1]);
292 } else if (strcmp(ret, __stringify(CONFIG_ETHADDR)) == 0) {
293 env_set("ethaddr", smac[1]);
294 printf("%s (factory)\n", smac[1]);
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400295 } else {
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400296 printf("%s\n", ret);
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400297 }
298 }
299
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400300 if (strcmp(smac[2], "00:00:00:00:00:00") == 0) {
301 env_set("eth1addr", NULL);
302 env_set("eth2addr", NULL);
303 goto done;
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400304 }
305
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400306 printf("HWADDR1: ");
307 if (smac[2][0] == EMPY_CHAR) {
308 printf("<not found>\n");
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400309 } else {
Simon Glass64b723f2017-08-03 12:22:12 -0600310 char *ret = env_get("eth1addr");
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400311
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400312 if (ret == NULL) {
313 env_set("ethaddr", smac[2]);
314 printf("%s\n", smac[2]);
315 } else if (strcmp(ret, __stringify(CONFIG_ETH1ADDR)) == 0) {
316 env_set("eth1addr", smac[2]);
317 printf("%s (factory)\n", smac[2]);
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400318 } else {
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400319 printf("%s\n", ret);
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400320 }
321 }
322
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400323 if (strcmp(smac[3], "00:00:00:00:00:00") == 0) {
324 env_set("eth2addr", NULL);
325 goto done;
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400326 }
327
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400328 printf("HWADDR2: ");
329 if (smac[3][0] == EMPY_CHAR) {
330 printf("<not found>\n");
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400331 } else {
Simon Glass64b723f2017-08-03 12:22:12 -0600332 char *ret = env_get("eth2addr");
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400333
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400334 if (ret == NULL) {
335 env_set("ethaddr", smac[3]);
336 printf("%s\n", smac[3]);
337 } else if (strcmp(ret, __stringify(CONFIG_ETH2ADDR)) == 0) {
338 env_set("eth2addr", smac[3]);
339 printf("%s (factory)\n", smac[3]);
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400340 } else {
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400341 printf("%s\n", ret);
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400342 }
343 }
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400344done:
345 if (oldserial == NULL || oldversion == NULL) {
346 if (oldversion == NULL)
347 env_set("VERSION", U_BOOT_VERSION);
348 env_save();
349 }
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400350
351 return 0;
352}
353
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400354static int init_fwenv(void)
355{
356 int i, ret = -1;
357
358 fwenv_addr[0] = FWENV_ADDR1;
359 fwenv_addr[1] = FWENV_ADDR2;
360 fwenv_addr[2] = FWENV_ADDR3;
361 fwenv_addr[3] = FWENV_ADDR4;
362
363 for (i = 0; i < MAX_FWENV_ADDR; i++)
364 if (fwenv_addr[i] != -1)
365 ret = 0;
366 if (ret)
367 printf("%s: No firmfare info storage address is defined\n",
368 __func__);
369 return ret;
370}
371
372void get_arc_info(void)
373{
374 if (!init_fwenv())
375 do_get_arc_info();
376}
377
378static int do_arc_cmd(cmd_tbl_t * cmdtp, int flag, int argc, char *const argv[])
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400379{
380 const char *cmd;
381 int ret = -1;
382
383 cmd = argv[1];
384 --argc;
385 ++argv;
386
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400387 if (init_fwenv())
388 return ret;
389
390 if (strcmp(cmd, "product") == 0)
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400391 ret = set_arc_product(argc, argv);
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400392 else if (strcmp(cmd, "info") == 0)
393 ret = do_get_arc_info();
394
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400395 if (ret == -1)
396 return CMD_RET_USAGE;
397
398 return ret;
399}
400
401U_BOOT_CMD(arc, 6, 1, do_arc_cmd,
402 "Arcturus product command sub-system",
403 "product serial hwaddr0 hwaddr1 hwaddr2 - save Arcturus factory env\n"
404 "info - show Arcturus factory env\n\n");