]>
Commit | Line | Data |
---|---|---|
4549e789 | 1 | // SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause |
8b0044ff OZ |
2 | /* |
3 | * Command for accessing Arcturus factory environment. | |
4 | * | |
f51d7fc8 OZ |
5 | * Copyright 2013-2019 Arcturus Networks Inc. |
6 | * https://www.arcturusnetworks.com/products/ | |
8b0044ff OZ |
7 | * by Oleksandr G Zhadan et al. |
8 | * | |
8b0044ff OZ |
9 | */ |
10 | ||
11 | #include <common.h> | |
09140113 | 12 | #include <command.h> |
1eb69ae4 | 13 | #include <cpu_func.h> |
8b0044ff | 14 | #include <div64.h> |
9fb625ce | 15 | #include <env.h> |
b79fdc76 | 16 | #include <flash.h> |
8b0044ff OZ |
17 | #include <malloc.h> |
18 | #include <spi_flash.h> | |
f51d7fc8 OZ |
19 | #include <mmc.h> |
20 | #include <version.h> | |
8b0044ff OZ |
21 | #include <asm/io.h> |
22 | ||
f51d7fc8 OZ |
23 | static ulong fwenv_addr[MAX_FWENV_ADDR]; |
24 | const char mystrerr[] = "ERROR: Failed to save factory info"; | |
8b0044ff OZ |
25 | |
26 | static 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 | ||
f51d7fc8 OZ |
38 | #if (FWENV_TYPE == FWENV_MMC) |
39 | ||
40 | static char smac[29][18] __attribute__ ((aligned(0x200))); /* 1 MMC block is 512 bytes */ | |
41 | ||
42 | int set_mmc_arc_product(int argc, char *const argv[]) | |
8b0044ff | 43 | { |
f51d7fc8 OZ |
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 | } | |
8b0044ff | 64 | |
f51d7fc8 OZ |
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; | |
8b0044ff | 80 | |
f51d7fc8 OZ |
81 | return err; |
82 | } | |
8b0044ff | 83 | |
f51d7fc8 OZ |
84 | static 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 | } | |
8b0044ff | 102 | |
f51d7fc8 OZ |
103 | addr = (void *)smac; |
104 | cnt = 1; /* One 512 bytes block */ | |
8b0044ff | 105 | |
f51d7fc8 OZ |
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 | |
8b0044ff | 117 | |
f51d7fc8 | 118 | #if (FWENV_TYPE == FWENV_SPI_FLASH) |
8b0044ff | 119 | |
f51d7fc8 OZ |
120 | static struct spi_flash *flash; |
121 | static char smac[4][18]; | |
8b0044ff | 122 | |
f51d7fc8 OZ |
123 | int set_spi_arc_product(int argc, char *const argv[]) |
124 | { | |
125 | int i, err = 1; | |
8b0044ff | 126 | |
f51d7fc8 OZ |
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; | |
8b0044ff OZ |
133 | } |
134 | ||
f51d7fc8 OZ |
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) | |
8b0044ff | 144 | return -2; |
8b0044ff | 145 | |
f51d7fc8 | 146 | return err; |
8b0044ff OZ |
147 | } |
148 | ||
f51d7fc8 | 149 | static int read_spi_arc_info(void) |
8b0044ff | 150 | { |
f51d7fc8 | 151 | int i; |
8b0044ff OZ |
152 | |
153 | flash = spi_flash_probe(CONFIG_ENV_SPI_BUS, CONFIG_ENV_SPI_CS, | |
154 | CONFIG_ENV_SPI_MAX_HZ, CONFIG_ENV_SPI_MODE); | |
f51d7fc8 OZ |
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) | |
8b0044ff | 170 | |
f51d7fc8 OZ |
171 | static char smac[4][18]; |
172 | ||
173 | int 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); | |
8b0044ff | 190 | } |
f51d7fc8 OZ |
191 | if (err) |
192 | return -2; | |
193 | ||
194 | return err; | |
195 | } | |
196 | ||
197 | static 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); | |
8b0044ff | 205 | } |
f51d7fc8 OZ |
206 | |
207 | return 0; | |
208 | } | |
209 | #endif | |
210 | ||
211 | int set_arc_product(int argc, char *const argv[]) | |
212 | { | |
213 | 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 | ||
224 | strcpy(smac[0], argv[1]); | |
225 | strcpy(smac[1], argv[2]); | |
226 | strcpy(smac[2], argv[3]); | |
227 | strcpy(smac[3], argv[4]); | |
228 | ||
229 | #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 | } | |
240 | ||
241 | static 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 | } | |
254 | ||
255 | static 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"); | |
260 | ||
261 | if (oldversion != NULL) | |
262 | if (strcmp(oldversion, U_BOOT_VERSION) != 0) | |
263 | oldversion = NULL; | |
264 | ||
265 | if (l == 0) { | |
266 | printf("%s: failed to read factory info\n", __func__); | |
267 | return -2; | |
8b0044ff OZ |
268 | } |
269 | ||
f51d7fc8 OZ |
270 | printf("\rSERIAL: "); |
271 | if (smac[0][0] == EMPY_CHAR) { | |
272 | printf("<not found>\n"); | |
273 | } else { | |
274 | printf("%s\n", smac[0]); | |
275 | env_set("SERIAL", smac[0]); | |
276 | } | |
8b0044ff | 277 | |
f51d7fc8 OZ |
278 | if (strcmp(smac[1], "00:00:00:00:00:00") == 0) { |
279 | env_set("ethaddr", NULL); | |
280 | env_set("eth1addr", NULL); | |
281 | env_set("eth2addr", NULL); | |
282 | goto done; | |
283 | } | |
284 | ||
285 | printf("HWADDR0: "); | |
286 | if (smac[1][0] == EMPY_CHAR) { | |
287 | printf("<not found>\n"); | |
8b0044ff | 288 | } else { |
00caae6d | 289 | char *ret = env_get("ethaddr"); |
8b0044ff | 290 | |
f51d7fc8 OZ |
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]); | |
8b0044ff | 297 | } else { |
f51d7fc8 | 298 | printf("%s\n", ret); |
8b0044ff OZ |
299 | } |
300 | } | |
301 | ||
f51d7fc8 OZ |
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; | |
8b0044ff OZ |
306 | } |
307 | ||
f51d7fc8 OZ |
308 | printf("HWADDR1: "); |
309 | if (smac[2][0] == EMPY_CHAR) { | |
310 | printf("<not found>\n"); | |
8b0044ff | 311 | } else { |
00caae6d | 312 | char *ret = env_get("eth1addr"); |
8b0044ff | 313 | |
f51d7fc8 OZ |
314 | 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]); | |
8b0044ff | 320 | } else { |
f51d7fc8 | 321 | printf("%s\n", ret); |
8b0044ff OZ |
322 | } |
323 | } | |
324 | ||
f51d7fc8 OZ |
325 | if (strcmp(smac[3], "00:00:00:00:00:00") == 0) { |
326 | env_set("eth2addr", NULL); | |
327 | goto done; | |
8b0044ff OZ |
328 | } |
329 | ||
f51d7fc8 OZ |
330 | printf("HWADDR2: "); |
331 | if (smac[3][0] == EMPY_CHAR) { | |
332 | printf("<not found>\n"); | |
8b0044ff | 333 | } else { |
00caae6d | 334 | char *ret = env_get("eth2addr"); |
8b0044ff | 335 | |
f51d7fc8 OZ |
336 | 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]); | |
8b0044ff | 342 | } else { |
f51d7fc8 | 343 | printf("%s\n", ret); |
8b0044ff OZ |
344 | } |
345 | } | |
f51d7fc8 OZ |
346 | done: |
347 | if (oldserial == NULL || oldversion == NULL) { | |
348 | if (oldversion == NULL) | |
349 | env_set("VERSION", U_BOOT_VERSION); | |
350 | env_save(); | |
351 | } | |
8b0044ff OZ |
352 | |
353 | return 0; | |
354 | } | |
355 | ||
f51d7fc8 OZ |
356 | static 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 | ||
374 | void get_arc_info(void) | |
375 | { | |
376 | if (!init_fwenv()) | |
377 | do_get_arc_info(); | |
378 | } | |
379 | ||
09140113 SG |
380 | static int do_arc_cmd(struct cmd_tbl *cmdtp, int flag, int argc, |
381 | char *const argv[]) | |
8b0044ff OZ |
382 | { |
383 | const char *cmd; | |
384 | int ret = -1; | |
385 | ||
386 | cmd = argv[1]; | |
387 | --argc; | |
388 | ++argv; | |
389 | ||
f51d7fc8 OZ |
390 | if (init_fwenv()) |
391 | return ret; | |
392 | ||
393 | if (strcmp(cmd, "product") == 0) | |
8b0044ff | 394 | ret = set_arc_product(argc, argv); |
f51d7fc8 OZ |
395 | else if (strcmp(cmd, "info") == 0) |
396 | ret = do_get_arc_info(); | |
397 | ||
8b0044ff OZ |
398 | if (ret == -1) |
399 | return CMD_RET_USAGE; | |
400 | ||
401 | return ret; | |
402 | } | |
403 | ||
404 | U_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"); |