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