blob: 4b30b66e208f178fd596032c563338b3d6781f79 [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 Glassed38aef2020-05-10 11:40:03 -060012#include <command.h>
Simon Glass63334482019-11-14 12:57:39 -070013#include <cpu_func.h>
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -040014#include <div64.h>
Simon Glass5e6201b2019-08-01 09:46:51 -060015#include <env.h>
Simon Glass8e201882020-05-10 11:39:54 -060016#include <flash.h>
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -040017#include <malloc.h>
18#include <spi_flash.h>
Oleksandr Zhadanba280332019-06-17 16:10:23 -040019#include <mmc.h>
20#include <version.h>
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -040021#include <asm/io.h>
Simon Glassfb64e362020-05-10 11:40:09 -060022#include <linux/stringify.h>
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -040023
Oleksandr Zhadanba280332019-06-17 16:10:23 -040024static ulong fwenv_addr[MAX_FWENV_ADDR];
25const char mystrerr[] = "ERROR: Failed to save factory info";
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -040026
27static 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
Oleksandr Zhadanba280332019-06-17 16:10:23 -040039#if (FWENV_TYPE == FWENV_MMC)
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -040040
Oleksandr Zhadanba280332019-06-17 16:10:23 -040041static char smac[29][18] __attribute__ ((aligned(0x200))); /* 1 MMC block is 512 bytes */
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -040042
Oleksandr Zhadanba280332019-06-17 16:10:23 -040043int 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;
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -040050
Oleksandr Zhadanba280332019-06-17 16:10:23 -040051 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 }
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -040065
Oleksandr Zhadanba280332019-06-17 16:10:23 -040066 /* Save factory defaults */
67 addr = (void *)smac;
68 cnt = 1; /* One 512 bytes block */
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -040069
Oleksandr Zhadanba280332019-06-17 16:10:23 -040070 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;
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -040081
Oleksandr Zhadanba280332019-06-17 16:10:23 -040082 return err;
83}
84
85static 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;
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -040092
Oleksandr Zhadanba280332019-06-17 16:10:23 -040093 mmc = find_mmc_device(mmc_dev_num);
94 if (!mmc) {
95 printf("No SD/MMC/eMMC card found\n");
96 return 0;
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -040097 }
Oleksandr Zhadanba280332019-06-17 16:10:23 -040098 if (mmc_init(mmc)) {
99 printf("%s(%d) init failed\n", IS_SD(mmc) ? "SD" : "MMC",
100 mmc_dev_num);
101 return 0;
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400102 }
103
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400104 addr = (void *)smac;
105 cnt = 1; /* One 512 bytes block */
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400106
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400107 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
121static struct spi_flash *flash;
122static char smac[4][18];
123
124int 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;
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400134 }
135
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400136 /* 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)
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400145 return -2;
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400146
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400147 return err;
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400148}
149
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400150static int read_spi_arc_info(void)
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400151{
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400152 int i;
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400153
154 flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS,
155 CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE);
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400156 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
172static char smac[4][18];
173
174int 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;
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400182
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400183 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);
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400191 }
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400192 if (err)
193 return -2;
194
195 return err;
196}
197
198static 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);
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400206 }
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400207
208 return 0;
209}
210#endif
211
212int 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
242static 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
256static 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;
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400269 }
270
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400271 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 }
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400285
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400286 printf("HWADDR0: ");
287 if (smac[1][0] == EMPY_CHAR) {
288 printf("<not found>\n");
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400289 } else {
Simon Glass64b723f2017-08-03 12:22:12 -0600290 char *ret = env_get("ethaddr");
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400291
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400292 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]);
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400298 } else {
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400299 printf("%s\n", ret);
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400300 }
301 }
302
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400303 if (strcmp(smac[2], "00:00:00:00:00:00") == 0) {
304 env_set("eth1addr", NULL);
305 env_set("eth2addr", NULL);
306 goto done;
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400307 }
308
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400309 printf("HWADDR1: ");
310 if (smac[2][0] == EMPY_CHAR) {
311 printf("<not found>\n");
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400312 } else {
Simon Glass64b723f2017-08-03 12:22:12 -0600313 char *ret = env_get("eth1addr");
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400314
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400315 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]);
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400321 } else {
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400322 printf("%s\n", ret);
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400323 }
324 }
325
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400326 if (strcmp(smac[3], "00:00:00:00:00:00") == 0) {
327 env_set("eth2addr", NULL);
328 goto done;
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400329 }
330
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400331 printf("HWADDR2: ");
332 if (smac[3][0] == EMPY_CHAR) {
333 printf("<not found>\n");
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400334 } else {
Simon Glass64b723f2017-08-03 12:22:12 -0600335 char *ret = env_get("eth2addr");
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400336
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400337 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]);
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400343 } else {
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400344 printf("%s\n", ret);
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400345 }
346 }
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400347done:
348 if (oldserial == NULL || oldversion == NULL) {
349 if (oldversion == NULL)
350 env_set("VERSION", U_BOOT_VERSION);
351 env_save();
352 }
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400353
354 return 0;
355}
356
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400357static 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
375void get_arc_info(void)
376{
377 if (!init_fwenv())
378 do_get_arc_info();
379}
380
Simon Glassed38aef2020-05-10 11:40:03 -0600381static int do_arc_cmd(struct cmd_tbl *cmdtp, int flag, int argc,
382 char *const argv[])
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400383{
384 const char *cmd;
385 int ret = -1;
386
387 cmd = argv[1];
388 --argc;
389 ++argv;
390
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400391 if (init_fwenv())
392 return ret;
393
394 if (strcmp(cmd, "product") == 0)
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400395 ret = set_arc_product(argc, argv);
Oleksandr Zhadanba280332019-06-17 16:10:23 -0400396 else if (strcmp(cmd, "info") == 0)
397 ret = do_get_arc_info();
398
Oleksandr G Zhadan19ac6882015-04-29 16:57:39 -0400399 if (ret == -1)
400 return CMD_RET_USAGE;
401
402 return ret;
403}
404
405U_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");