blob: fea823b2d0dec140970f96779836a4f3799e032a [file] [log] [blame]
Stefan Roese115802d2018-08-16 15:27:31 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2018 Stefan Roese <sr@denx.de>
4 */
5
6#include <common.h>
Simon Glass5e6201b2019-08-01 09:46:51 -06007#include <env.h>
Simon Glass9d1f6192019-08-02 09:44:25 -06008#include <env_internal.h>
Stefan Roesed0fdd672018-10-09 08:59:13 +02009#include <led.h>
Stefan Roese9c550d62018-11-30 07:46:30 +010010#include <net.h>
11#include <spi.h>
12#include <spi_flash.h>
Simon Glass48b6c6b2019-11-14 12:57:16 -070013#include <u-boot/crc.h>
Stefan Roese9c550d62018-11-30 07:46:30 +010014#include <uuid.h>
15#include <linux/ctype.h>
Stefan Roese51cb80c2018-10-09 08:59:11 +020016#include <linux/io.h>
17
18#define MT76XX_AGPIO_CFG 0x1000003c
Stefan Roese115802d2018-08-16 15:27:31 +020019
Stefan Roese9c550d62018-11-30 07:46:30 +010020#define FACTORY_DATA_OFFS 0xc0000
21#define FACTORY_DATA_SECT_SIZE 0x10000
Tom Rinib6c9e0d2019-11-18 20:02:06 -050022#if ((CONFIG_ENV_OFFSET_REDUND + CONFIG_ENV_SIZE) > FACTORY_DATA_OFFS)
Stefan Roese9c550d62018-11-30 07:46:30 +010023#error "U-Boot image with environment too big (overlapping with factory-data)!"
24#endif
25#define FACTORY_DATA_USER_OFFS 0x140
26#define FACTORY_DATA_SIZE 0x1f0
27#define FACTORY_DATA_CRC_LEN (FACTORY_DATA_SIZE - \
28 FACTORY_DATA_USER_OFFS - sizeof(u32))
29
30#define FACTORY_DATA_MAGIC 0xCAFEBABE
31
32struct factory_data_values {
33 u8 pad_1[4];
34 u8 wifi_mac[6]; /* offs: 0x004: binary value */
35 u8 pad_2[30];
36 u8 eth_mac[6]; /* offs: 0x028: binary value */
37 u8 pad_3[FACTORY_DATA_USER_OFFS - 4 - 6 - 30 - 6];
38 /* User values start here at offset 0x140 */
39 u32 crc;
40 u32 magic;
41 u32 version;
42 char ipr_id[UUID_STR_LEN]; /* UUID as string w/o ending \0 */
43 char hqv_id[UUID_STR_LEN]; /* UUID as string w/o ending \0 */
44 char unielec_id[UUID_STR_LEN]; /* UUID as string w/o ending \0 */
45};
46
Stefan Roese115802d2018-08-16 15:27:31 +020047int board_early_init_f(void)
48{
Stefan Roese51cb80c2018-10-09 08:59:11 +020049 void __iomem *gpio_mode;
50
51 /* Configure digital vs analog GPIOs */
52 gpio_mode = ioremap_nocache(MT76XX_AGPIO_CFG, 0x100);
53 iowrite32(0x00fe01ff, gpio_mode);
54
Stefan Roese115802d2018-08-16 15:27:31 +020055 return 0;
56}
Stefan Roesed0fdd672018-10-09 08:59:13 +020057
Stefan Roese9c550d62018-11-30 07:46:30 +010058static bool prepare_uuid_var(const char *fd_ptr, const char *env_var_name,
59 char errorchar)
60{
61 char str[UUID_STR_LEN + 1] = { 0 }; /* Enough for UUID stuff */
62 bool env_updated = false;
63 char *env;
64 int i;
65
66 memcpy(str, fd_ptr, UUID_STR_LEN);
67
68 /* Convert non-ascii character to 'X' */
69 for (i = 0; i < UUID_STR_LEN; i++) {
70 if (!(isascii(str[i]) && isprint(str[i])))
71 str[i] = errorchar;
72 }
73
74 env = env_get(env_var_name);
75 if (strcmp(env, str)) {
76 env_set(env_var_name, str);
77 env_updated = true;
78 }
79
80 return env_updated;
81}
82
83static void factory_data_env_config(void)
84{
85 struct factory_data_values *fd;
86 struct spi_flash *sf;
87 int env_updated = 0;
88 char str[UUID_STR_LEN + 1]; /* Enough for UUID stuff */
89 char *env;
90 u8 *buf;
91 u32 crc;
92 int ret;
93 u8 *ptr;
94
95 buf = malloc(FACTORY_DATA_SIZE);
96 if (!buf) {
97 printf("F-Data:Unable to allocate buffer\n");
98 return;
99 }
100
101 /*
102 * Get values from factory-data area in SPI NOR
103 */
104 sf = spi_flash_probe(CONFIG_SF_DEFAULT_BUS,
105 CONFIG_SF_DEFAULT_CS,
106 CONFIG_SF_DEFAULT_SPEED,
107 CONFIG_SF_DEFAULT_MODE);
108 if (!sf) {
109 printf("F-Data:Unable to access SPI NOR flash\n");
110 goto err_free;
111 }
112
113 ret = spi_flash_read(sf, FACTORY_DATA_OFFS, FACTORY_DATA_SIZE,
114 (void *)buf);
115 if (ret) {
116 printf("F-Data:Unable to read factory-data from SPI NOR\n");
117 goto err_spi_flash;
118 }
119
120 fd = (struct factory_data_values *)buf;
121
122 if (fd->magic != FACTORY_DATA_MAGIC)
123 printf("F-Data:Magic value not correct\n");
124
125 crc = crc32(0, (u8 *)&fd->magic, FACTORY_DATA_CRC_LEN);
126 if (crc != fd->crc)
127 printf("F-Data:CRC not correct\n");
128 else
129 printf("F-Data:factory-data version %x detected\n",
130 fd->version);
131
132 /* Handle wifi_mac env variable */
133 ptr = fd->wifi_mac;
134 sprintf(str, "%pM", ptr);
135 if (!is_valid_ethaddr(ptr))
136 printf("F-Data:Invalid MAC addr: wifi_mac %s\n", str);
137
138 env = env_get("wifiaddr");
139 if (strcmp(env, str)) {
140 env_set("wifiaddr", str);
141 env_updated = 1;
142 }
143
144 /* Handle eth_mac env variable */
145 ptr = fd->eth_mac;
146 sprintf(str, "%pM", ptr);
147 if (!is_valid_ethaddr(ptr))
148 printf("F-Data:Invalid MAC addr: eth_mac %s\n", str);
149
150 env = env_get("ethaddr");
151 if (strcmp(env, str)) {
152 env_set("ethaddr", str);
153 env_updated = 1;
154 }
155
156 /* Handle UUID env variables */
157 env_updated |= prepare_uuid_var(fd->ipr_id, "linuxmoduleid", 'X');
158 env_updated |= prepare_uuid_var(fd->hqv_id, "linuxmodulehqvid", '\0');
159 env_updated |= prepare_uuid_var(fd->unielec_id,
160 "linuxmoduleunielecid", '\0');
161
162 /* Check if the environment was updated and needs to get stored */
163 if (env_updated != 0) {
164 printf("F-Data:Values don't match env values -> saving\n");
165 env_save();
166 } else {
167 debug("F-Data:Values match current env values\n");
168 }
169
170err_spi_flash:
171 spi_flash_free(sf);
172
173err_free:
174 free(buf);
175}
176
Stefan Roesed0fdd672018-10-09 08:59:13 +0200177int board_late_init(void)
178{
179 if (IS_ENABLED(CONFIG_LED))
180 led_default_state();
181
Stefan Roese9c550d62018-11-30 07:46:30 +0100182 factory_data_env_config();
183
Stefan Roesed0fdd672018-10-09 08:59:13 +0200184 return 0;
185}
Stefan Roese9c550d62018-11-30 07:46:30 +0100186
187static void copy_or_generate_uuid(char *fd_ptr, const char *env_var_name)
188{
189 char str[UUID_STR_LEN + 1] = { 0 }; /* Enough for UUID stuff */
190 char *env;
191
192 /* Don't use the UUID dest place, as the \0 char won't fit */
193 env = env_get(env_var_name);
194 if (env)
195 strncpy(str, env, UUID_STR_LEN);
196 else
197 gen_rand_uuid_str(str, UUID_STR_FORMAT_STD);
198
199 memcpy(fd_ptr, str, UUID_STR_LEN);
200}
201
202/*
203 * Helper function to provide some sane factory-data values for testing
204 * purpose, when these values are not programmed correctly
205 */
206int do_fd_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
207{
208 struct factory_data_values *fd;
209 struct spi_flash *sf;
210 u8 *buf;
211 int ret = CMD_RET_FAILURE;
212
213 buf = malloc(FACTORY_DATA_SECT_SIZE);
214 if (!buf) {
215 printf("F-Data:Unable to allocate buffer\n");
216 return CMD_RET_FAILURE;
217 }
218
219 sf = spi_flash_probe(CONFIG_SF_DEFAULT_BUS,
220 CONFIG_SF_DEFAULT_CS,
221 CONFIG_SF_DEFAULT_SPEED,
222 CONFIG_SF_DEFAULT_MODE);
223 if (!sf) {
224 printf("F-Data:Unable to access SPI NOR flash\n");
225 goto err_free;
226 }
227
228 /* Generate the factory-data struct */
229
230 /* Fist read complete sector into buffer */
231 ret = spi_flash_read(sf, FACTORY_DATA_OFFS, FACTORY_DATA_SECT_SIZE,
232 (void *)buf);
233 if (ret) {
234 printf("F-Data:spi_flash_read failed (%d)\n", ret);
235 goto err_spi_flash;
236 }
237
238 fd = (struct factory_data_values *)buf;
239 fd->magic = FACTORY_DATA_MAGIC;
240 fd->version = 0x1;
241
242 /* Use existing MAC and UUID values or generate some random ones */
243 if (!eth_env_get_enetaddr("wifiaddr", fd->wifi_mac)) {
244 net_random_ethaddr(fd->wifi_mac);
245 /* to get a different seed value for the MAC address */
246 mdelay(10);
247 }
248
249 if (!eth_env_get_enetaddr("ethaddr", fd->eth_mac))
250 net_random_ethaddr(fd->eth_mac);
251
252 copy_or_generate_uuid(fd->ipr_id, "linuxmoduleid");
253 copy_or_generate_uuid(fd->hqv_id, "linuxmodulehqvid");
254 copy_or_generate_uuid(fd->unielec_id, "linuxmoduleunielecid");
255
256 printf("New factory-data values:\n");
257 printf("wifiaddr=%pM\n", fd->wifi_mac);
258 printf("ethaddr=%pM\n", fd->eth_mac);
259
260 /*
261 * We don't have the \0 char at the end, so we need to specify the
262 * length in the printf format instead
263 */
264 printf("linuxmoduleid=%." __stringify(UUID_STR_LEN) "s\n", fd->ipr_id);
265 printf("linuxmodulehqvid=%." __stringify(UUID_STR_LEN) "s\n",
266 fd->hqv_id);
267 printf("linuxmoduleunielecid=%." __stringify(UUID_STR_LEN) "s\n",
268 fd->unielec_id);
269
270 fd->crc = crc32(0, (u8 *)&fd->magic, FACTORY_DATA_CRC_LEN);
271
272 ret = spi_flash_erase(sf, FACTORY_DATA_OFFS, FACTORY_DATA_SECT_SIZE);
273 if (ret) {
274 printf("F-Data:spi_flash_erase failed (%d)\n", ret);
275 goto err_spi_flash;
276 }
277
278 ret = spi_flash_write(sf, FACTORY_DATA_OFFS, FACTORY_DATA_SECT_SIZE,
279 buf);
280 if (ret) {
281 printf("F-Data:spi_flash_write failed (%d)\n", ret);
282 goto err_spi_flash;
283 }
284
285 printf("F-Data:factory-data values written to SPI NOR flash\n");
286
287err_spi_flash:
288 spi_flash_free(sf);
289
290err_free:
291 free(buf);
292
293 return ret;
294}
295
296U_BOOT_CMD(
297 fd_write, 1, 0, do_fd_write,
298 "Write test factory-data values to SPI NOR",
299 "\n"
300);