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