]>
Commit | Line | Data |
---|---|---|
54f17fa0 KY |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * (C) Copyright 2019 Rockchip Electronics Co., Ltd. | |
08d61f87 QS |
4 | * |
5 | * Copyright (C) 2019 Collabora Inc - https://www.collabora.com/ | |
6 | * Rohan Garg <[email protected]> | |
7 | * | |
8 | * Based on puma-rk3399.c: | |
9 | * (C) Copyright 2017 Theobroma Systems Design und Consulting GmbH | |
54f17fa0 | 10 | */ |
03de305e | 11 | #include <config.h> |
54f17fa0 | 12 | #include <clk.h> |
9edefc27 | 13 | #include <cpu_func.h> |
08d61f87 | 14 | #include <env.h> |
54f17fa0 | 15 | #include <dm.h> |
3b95c03d | 16 | #include <dm/uclass-internal.h> |
bea9267d | 17 | #include <efi_loader.h> |
851737ab | 18 | #include <fastboot.h> |
08d61f87 | 19 | #include <hash.h> |
5255932f | 20 | #include <init.h> |
f7ae49fc | 21 | #include <log.h> |
bea9267d | 22 | #include <mmc.h> |
08d61f87 QS |
23 | #include <dm/uclass-internal.h> |
24 | #include <misc.h> | |
bea9267d | 25 | #include <part.h> |
54f17fa0 KY |
26 | #include <ram.h> |
27 | #include <syscon.h> | |
58d825fb | 28 | #include <u-boot/uuid.h> |
08d61f87 QS |
29 | #include <u-boot/crc.h> |
30 | #include <u-boot/sha256.h> | |
90526e9f | 31 | #include <asm/cache.h> |
54f17fa0 KY |
32 | #include <asm/io.h> |
33 | #include <asm/arch-rockchip/boot_mode.h> | |
34 | #include <asm/arch-rockchip/clock.h> | |
35 | #include <asm/arch-rockchip/periph.h> | |
36 | #include <power/regulator.h> | |
37 | ||
ac58c6f3 | 38 | #if IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) && IS_ENABLED(CONFIG_EFI_PARTITION) |
bea9267d SG |
39 | |
40 | #define DFU_ALT_BUF_LEN SZ_1K | |
41 | ||
42 | static struct efi_fw_image *fw_images; | |
43 | ||
44 | static bool updatable_image(struct disk_partition *info) | |
45 | { | |
46 | int i; | |
47 | bool ret = false; | |
48 | efi_guid_t image_type_guid; | |
49 | ||
50 | uuid_str_to_bin(info->type_guid, image_type_guid.b, | |
51 | UUID_STR_FORMAT_GUID); | |
52 | ||
cccea188 | 53 | for (i = 0; i < update_info.num_images; i++) { |
bea9267d SG |
54 | if (!guidcmp(&fw_images[i].image_type_id, &image_type_guid)) { |
55 | ret = true; | |
56 | break; | |
57 | } | |
58 | } | |
59 | ||
60 | return ret; | |
61 | } | |
62 | ||
63 | static void set_image_index(struct disk_partition *info, int index) | |
64 | { | |
65 | int i; | |
66 | efi_guid_t image_type_guid; | |
67 | ||
68 | uuid_str_to_bin(info->type_guid, image_type_guid.b, | |
69 | UUID_STR_FORMAT_GUID); | |
70 | ||
cccea188 | 71 | for (i = 0; i < update_info.num_images; i++) { |
bea9267d SG |
72 | if (!guidcmp(&fw_images[i].image_type_id, &image_type_guid)) { |
73 | fw_images[i].image_index = index; | |
74 | break; | |
75 | } | |
76 | } | |
77 | } | |
78 | ||
79 | static int get_mmc_desc(struct blk_desc **desc) | |
80 | { | |
81 | int ret; | |
82 | struct mmc *mmc; | |
83 | struct udevice *dev; | |
84 | ||
85 | /* | |
86 | * For now the firmware images are assumed to | |
87 | * be on the SD card | |
88 | */ | |
89 | ret = uclass_get_device(UCLASS_MMC, 1, &dev); | |
90 | if (ret) | |
91 | return -1; | |
92 | ||
93 | mmc = mmc_get_mmc_dev(dev); | |
94 | if (!mmc) | |
95 | return -ENODEV; | |
96 | ||
97 | if ((ret = mmc_init(mmc))) | |
98 | return ret; | |
99 | ||
100 | *desc = mmc_get_blk_desc(mmc); | |
101 | if (!*desc) | |
102 | return -1; | |
103 | ||
104 | return 0; | |
105 | } | |
106 | ||
107 | void set_dfu_alt_info(char *interface, char *devstr) | |
108 | { | |
109 | const char *name; | |
110 | bool first = true; | |
111 | int p, len, devnum, ret; | |
112 | char buf[DFU_ALT_BUF_LEN]; | |
113 | struct disk_partition info; | |
114 | struct blk_desc *desc = NULL; | |
115 | ||
116 | ret = get_mmc_desc(&desc); | |
117 | if (ret) { | |
118 | log_err("Unable to get mmc desc\n"); | |
119 | return; | |
120 | } | |
121 | ||
122 | memset(buf, 0, sizeof(buf)); | |
123 | name = blk_get_uclass_name(desc->uclass_id); | |
124 | devnum = desc->devnum; | |
125 | len = strlen(buf); | |
126 | ||
127 | len += snprintf(buf + len, DFU_ALT_BUF_LEN - len, | |
128 | "%s %d=", name, devnum); | |
129 | ||
130 | for (p = 1; p <= MAX_SEARCH_PARTITIONS; p++) { | |
131 | if (part_get_info(desc, p, &info)) | |
132 | continue; | |
133 | ||
134 | /* Add entry to dfu_alt_info only for updatable images */ | |
135 | if (updatable_image(&info)) { | |
136 | if (!first) | |
137 | len += snprintf(buf + len, | |
138 | DFU_ALT_BUF_LEN - len, ";"); | |
139 | ||
140 | len += snprintf(buf + len, DFU_ALT_BUF_LEN - len, | |
141 | "%s%d_%s part %d %d", | |
142 | name, devnum, info.name, devnum, p); | |
143 | first = false; | |
144 | } | |
145 | } | |
146 | ||
147 | log_debug("dfu_alt_info => %s\n", buf); | |
148 | env_set("dfu_alt_info", buf); | |
149 | } | |
150 | ||
74029381 QS |
151 | __weak void rockchip_capsule_update_board_setup(void) |
152 | { | |
153 | } | |
154 | ||
bea9267d SG |
155 | static void gpt_capsule_update_setup(void) |
156 | { | |
157 | int p, i, ret; | |
158 | struct disk_partition info; | |
159 | struct blk_desc *desc = NULL; | |
160 | ||
161 | fw_images = update_info.images; | |
162 | rockchip_capsule_update_board_setup(); | |
163 | ||
164 | ret = get_mmc_desc(&desc); | |
165 | if (ret) { | |
166 | log_err("Unable to get mmc desc\n"); | |
167 | return; | |
168 | } | |
169 | ||
170 | for (p = 1, i = 1; p <= MAX_SEARCH_PARTITIONS; p++) { | |
171 | if (part_get_info(desc, p, &info)) | |
172 | continue; | |
173 | ||
174 | /* | |
175 | * Since we have a GPT partitioned device, the updatable | |
176 | * images could be stored in any order. Populate the | |
177 | * image_index at runtime. | |
178 | */ | |
179 | if (updatable_image(&info)) { | |
180 | set_image_index(&info, i); | |
181 | i++; | |
182 | } | |
183 | } | |
184 | } | |
185 | #endif /* CONFIG_EFI_HAVE_CAPSULE_SUPPORT && CONFIG_EFI_PARTITION */ | |
186 | ||
54f17fa0 KY |
187 | __weak int rk_board_late_init(void) |
188 | { | |
189 | return 0; | |
190 | } | |
191 | ||
192 | int board_late_init(void) | |
193 | { | |
194 | setup_boot_mode(); | |
195 | ||
ac58c6f3 JK |
196 | #if IS_ENABLED(CONFIG_EFI_HAVE_CAPSULE_SUPPORT) && IS_ENABLED(CONFIG_EFI_PARTITION) |
197 | gpt_capsule_update_setup(); | |
198 | #endif | |
199 | ||
54f17fa0 KY |
200 | return rk_board_late_init(); |
201 | } | |
202 | ||
203 | int board_init(void) | |
204 | { | |
54f17fa0 KY |
205 | return 0; |
206 | } | |
207 | ||
208 | #if !defined(CONFIG_SYS_DCACHE_OFF) && !defined(CONFIG_ARM64) | |
209 | void enable_caches(void) | |
210 | { | |
211 | /* Enable D-cache. I-cache is already enabled in start.S */ | |
212 | dcache_enable(); | |
213 | } | |
214 | #endif | |
215 | ||
06fac9dd | 216 | #if IS_ENABLED(CONFIG_USB_GADGET) |
54f17fa0 | 217 | #include <usb.h> |
2b6a013c JK |
218 | |
219 | #if IS_ENABLED(CONFIG_USB_GADGET_DOWNLOAD) | |
220 | #define ROCKCHIP_G_DNL_UMS_PRODUCT_NUM 0x0010 | |
221 | ||
222 | int g_dnl_bind_fixup(struct usb_device_descriptor *dev, const char *name) | |
223 | { | |
224 | if (!strcmp(name, "usb_dnl_ums")) | |
225 | put_unaligned(ROCKCHIP_G_DNL_UMS_PRODUCT_NUM, &dev->idProduct); | |
226 | else | |
227 | put_unaligned(CONFIG_USB_GADGET_PRODUCT_NUM, &dev->idProduct); | |
228 | ||
229 | return 0; | |
230 | } | |
231 | #endif /* CONFIG_USB_GADGET_DOWNLOAD */ | |
232 | ||
233 | #if IS_ENABLED(CONFIG_USB_GADGET_DWC2_OTG) && !IS_ENABLED(CONFIG_DM_USB_GADGET) | |
51c54080 | 234 | #include <linux/usb/otg.h> |
54f17fa0 KY |
235 | #include <usb/dwc2_udc.h> |
236 | ||
237 | static struct dwc2_plat_otg_data otg_data = { | |
238 | .rx_fifo_sz = 512, | |
239 | .np_tx_fifo_sz = 16, | |
240 | .tx_fifo_sz = 128, | |
241 | }; | |
242 | ||
243 | int board_usb_init(int index, enum usb_init_type init) | |
244 | { | |
e76943ca | 245 | ofnode node; |
54f17fa0 | 246 | bool matched = false; |
54f17fa0 KY |
247 | |
248 | /* find the usb_otg node */ | |
e76943ca KY |
249 | node = ofnode_by_compatible(ofnode_null(), "snps,dwc2"); |
250 | while (ofnode_valid(node)) { | |
51c54080 JK |
251 | switch (usb_get_dr_mode(node)) { |
252 | case USB_DR_MODE_OTG: | |
35c27506 | 253 | case USB_DR_MODE_PERIPHERAL: |
54f17fa0 KY |
254 | matched = true; |
255 | break; | |
51c54080 JK |
256 | |
257 | default: | |
258 | break; | |
54f17fa0 KY |
259 | } |
260 | ||
51c54080 JK |
261 | if (matched) |
262 | break; | |
263 | ||
e76943ca | 264 | node = ofnode_by_compatible(node, "snps,dwc2"); |
54f17fa0 KY |
265 | } |
266 | if (!matched) { | |
267 | debug("Not found usb_otg device\n"); | |
268 | return -ENODEV; | |
269 | } | |
e76943ca | 270 | otg_data.regs_otg = ofnode_get_addr(node); |
54f17fa0 | 271 | |
e0479b71 | 272 | #ifdef CONFIG_ROCKCHIP_USB2_PHY |
17224b32 KY |
273 | int ret; |
274 | u32 phandle, offset; | |
275 | ofnode phy_node; | |
276 | ||
277 | ret = ofnode_read_u32(node, "phys", &phandle); | |
278 | if (ret) | |
279 | return ret; | |
280 | ||
281 | node = ofnode_get_by_phandle(phandle); | |
282 | if (!ofnode_valid(node)) { | |
283 | debug("Not found usb phy device\n"); | |
284 | return -ENODEV; | |
285 | } | |
286 | ||
287 | phy_node = ofnode_get_parent(node); | |
288 | if (!ofnode_valid(node)) { | |
289 | debug("Not found usb phy device\n"); | |
290 | return -ENODEV; | |
291 | } | |
292 | ||
293 | otg_data.phy_of_node = phy_node; | |
294 | ret = ofnode_read_u32(node, "reg", &offset); | |
295 | if (ret) | |
296 | return ret; | |
297 | otg_data.regs_phy = offset + | |
298 | (u32)syscon_get_first_range(ROCKCHIP_SYSCON_GRF); | |
299 | #endif | |
54f17fa0 KY |
300 | return dwc2_udc_probe(&otg_data); |
301 | } | |
302 | ||
303 | int board_usb_cleanup(int index, enum usb_init_type init) | |
304 | { | |
305 | return 0; | |
306 | } | |
c618bb00 | 307 | #endif /* CONFIG_USB_GADGET_DWC2_OTG */ |
06fac9dd | 308 | #endif /* CONFIG_USB_GADGET */ |
c618bb00 | 309 | |
41782a9c | 310 | #if IS_ENABLED(CONFIG_FASTBOOT) |
851737ab | 311 | int fastboot_set_reboot_flag(enum fastboot_reboot_reason reason) |
54f17fa0 | 312 | { |
851737ab RK |
313 | if (reason != FASTBOOT_REBOOT_REASON_BOOTLOADER) |
314 | return -ENOTSUPP; | |
315 | ||
54f17fa0 KY |
316 | printf("Setting reboot to fastboot flag ...\n"); |
317 | /* Set boot mode to fastboot */ | |
318 | writel(BOOT_FASTBOOT, CONFIG_ROCKCHIP_BOOT_MODE_REG); | |
319 | ||
320 | return 0; | |
321 | } | |
322 | #endif | |
04825384 RG |
323 | |
324 | #ifdef CONFIG_MISC_INIT_R | |
08d61f87 QS |
325 | int rockchip_setup_macaddr(void) |
326 | { | |
327 | #if CONFIG_IS_ENABLED(HASH) && CONFIG_IS_ENABLED(SHA256) | |
328 | int ret; | |
329 | const char *cpuid = env_get("cpuid#"); | |
330 | u8 hash[SHA256_SUM_LEN]; | |
331 | int size = sizeof(hash); | |
332 | u8 mac_addr[6]; | |
333 | ||
334 | /* Only generate a MAC address, if none is set in the environment */ | |
335 | if (env_get("ethaddr")) | |
336 | return 0; | |
337 | ||
338 | if (!cpuid) { | |
339 | debug("%s: could not retrieve 'cpuid#'\n", __func__); | |
340 | return -1; | |
341 | } | |
342 | ||
343 | ret = hash_block("sha256", (void *)cpuid, strlen(cpuid), hash, &size); | |
344 | if (ret) { | |
345 | debug("%s: failed to calculate SHA256\n", __func__); | |
346 | return -1; | |
347 | } | |
348 | ||
349 | /* Copy 6 bytes of the hash to base the MAC address on */ | |
350 | memcpy(mac_addr, hash, 6); | |
351 | ||
352 | /* Make this a valid MAC address and set it */ | |
353 | mac_addr[0] &= 0xfe; /* clear multicast bit */ | |
354 | mac_addr[0] |= 0x02; /* set local assignment bit (IEEE802) */ | |
355 | eth_env_set_enetaddr("ethaddr", mac_addr); | |
356 | ||
357 | /* Make a valid MAC address for ethernet1 */ | |
358 | mac_addr[5] ^= 0x01; | |
359 | eth_env_set_enetaddr("eth1addr", mac_addr); | |
360 | #endif | |
361 | return 0; | |
362 | } | |
363 | ||
364 | int rockchip_cpuid_from_efuse(const u32 cpuid_offset, | |
365 | const u32 cpuid_length, | |
366 | u8 *cpuid) | |
367 | { | |
368 | #if IS_ENABLED(CONFIG_ROCKCHIP_EFUSE) || IS_ENABLED(CONFIG_ROCKCHIP_OTP) | |
369 | struct udevice *dev; | |
370 | int ret; | |
371 | ||
372 | /* retrieve the device */ | |
373 | #if IS_ENABLED(CONFIG_ROCKCHIP_EFUSE) | |
374 | ret = uclass_get_device_by_driver(UCLASS_MISC, | |
375 | DM_DRIVER_GET(rockchip_efuse), &dev); | |
376 | #elif IS_ENABLED(CONFIG_ROCKCHIP_OTP) | |
377 | ret = uclass_get_device_by_driver(UCLASS_MISC, | |
378 | DM_DRIVER_GET(rockchip_otp), &dev); | |
379 | #endif | |
380 | if (ret) { | |
381 | debug("%s: could not find efuse device\n", __func__); | |
382 | return -1; | |
383 | } | |
384 | ||
385 | /* read the cpu_id range from the efuses */ | |
386 | ret = misc_read(dev, cpuid_offset, cpuid, cpuid_length); | |
387 | if (ret < 0) { | |
388 | debug("%s: reading cpuid from the efuses failed\n", | |
389 | __func__); | |
390 | return -1; | |
391 | } | |
392 | #endif | |
393 | return 0; | |
394 | } | |
395 | ||
396 | int rockchip_cpuid_set(const u8 *cpuid, const u32 cpuid_length) | |
397 | { | |
398 | u8 low[cpuid_length / 2], high[cpuid_length / 2]; | |
399 | char cpuid_str[cpuid_length * 2 + 1]; | |
400 | u64 serialno; | |
401 | char serialno_str[17]; | |
402 | const char *oldid; | |
403 | int i; | |
404 | ||
405 | memset(cpuid_str, 0, sizeof(cpuid_str)); | |
406 | for (i = 0; i < cpuid_length; i++) | |
407 | sprintf(&cpuid_str[i * 2], "%02x", cpuid[i]); | |
408 | ||
409 | debug("cpuid: %s\n", cpuid_str); | |
410 | ||
411 | /* | |
412 | * Mix the cpuid bytes using the same rules as in | |
413 | * ${linux}/drivers/soc/rockchip/rockchip-cpuinfo.c | |
414 | */ | |
415 | for (i = 0; i < cpuid_length / 2; i++) { | |
416 | low[i] = cpuid[1 + (i << 1)]; | |
417 | high[i] = cpuid[i << 1]; | |
418 | } | |
419 | ||
420 | serialno = crc32_no_comp(0, low, cpuid_length / 2); | |
421 | serialno |= (u64)crc32_no_comp(serialno, high, cpuid_length / 2) << 32; | |
422 | snprintf(serialno_str, sizeof(serialno_str), "%016llx", serialno); | |
423 | ||
424 | oldid = env_get("cpuid#"); | |
425 | if (oldid && strcmp(oldid, cpuid_str) != 0) | |
426 | printf("cpuid: value %s present in env does not match hardware %s\n", | |
427 | oldid, cpuid_str); | |
428 | ||
429 | env_set("cpuid#", cpuid_str); | |
430 | ||
431 | /* Only generate serial# when none is set yet */ | |
432 | if (!env_get("serial#")) | |
433 | env_set("serial#", serialno_str); | |
434 | ||
435 | return 0; | |
436 | } | |
437 | ||
7400ed6a QS |
438 | __weak int rockchip_early_misc_init_r(void) |
439 | { | |
440 | return 0; | |
441 | } | |
442 | ||
04825384 RG |
443 | __weak int misc_init_r(void) |
444 | { | |
2eedb6d9 | 445 | const u32 cpuid_offset = CFG_CPUID_OFFSET; |
04825384 RG |
446 | const u32 cpuid_length = 0x10; |
447 | u8 cpuid[cpuid_length]; | |
448 | int ret; | |
449 | ||
7400ed6a QS |
450 | ret = rockchip_early_misc_init_r(); |
451 | if (ret) | |
452 | return ret; | |
453 | ||
04825384 RG |
454 | ret = rockchip_cpuid_from_efuse(cpuid_offset, cpuid_length, cpuid); |
455 | if (ret) | |
456 | return ret; | |
457 | ||
458 | ret = rockchip_cpuid_set(cpuid, cpuid_length); | |
459 | if (ret) | |
460 | return ret; | |
461 | ||
462 | ret = rockchip_setup_macaddr(); | |
463 | ||
464 | return ret; | |
465 | } | |
466 | #endif | |
d2048baf CM |
467 | |
468 | #if IS_ENABLED(CONFIG_BOARD_RNG_SEED) && IS_ENABLED(CONFIG_RNG_ROCKCHIP) | |
469 | #include <rng.h> | |
470 | ||
471 | /* Use hardware rng to seed Linux random. */ | |
472 | __weak int board_rng_seed(struct abuf *buf) | |
473 | { | |
474 | struct udevice *dev; | |
ed4ae738 | 475 | ulong len = env_get_ulong("rng_seed_size", 10, 64); |
d2048baf CM |
476 | u64 *data; |
477 | ||
ed4ae738 AS |
478 | if (len < 64) { |
479 | /* | |
480 | * rng_seed_size should be at least 32 bytes for Linux 5.19+, | |
481 | * or 64 for older Linux kernel versions | |
482 | */ | |
483 | log_warning("Value for rng_seed_size (%lu) too low, Linux kernel RNG may fail to initialize early\n", | |
484 | len); | |
485 | } | |
486 | ||
d2048baf CM |
487 | data = malloc(len); |
488 | if (!data) { | |
489 | printf("Out of memory\n"); | |
490 | return -ENOMEM; | |
491 | } | |
492 | ||
493 | if (uclass_get_device(UCLASS_RNG, 0, &dev) || !dev) { | |
494 | printf("No RNG device\n"); | |
495 | return -ENODEV; | |
496 | } | |
497 | ||
498 | if (dm_rng_read(dev, data, len)) { | |
499 | printf("Reading RNG failed\n"); | |
500 | return -EIO; | |
501 | } | |
502 | ||
503 | abuf_init_set(buf, data, len); | |
504 | ||
505 | return 0; | |
506 | } | |
507 | #endif | |
3b95c03d BW |
508 | |
509 | int mmc_get_env_dev(void) | |
510 | { | |
511 | int devnum; | |
512 | const char *boot_device; | |
513 | struct udevice *dev; | |
514 | ||
515 | #ifdef CONFIG_SYS_MMC_ENV_DEV | |
516 | devnum = CONFIG_SYS_MMC_ENV_DEV; | |
517 | #else | |
518 | devnum = 0; | |
519 | #endif | |
520 | ||
521 | boot_device = ofnode_read_chosen_string("u-boot,spl-boot-device"); | |
522 | if (!boot_device) { | |
523 | debug("%s: /chosen/u-boot,spl-boot-device not set\n", __func__); | |
524 | return devnum; | |
525 | } | |
526 | ||
527 | debug("%s: booted from %s\n", __func__, boot_device); | |
528 | ||
529 | if (uclass_find_device_by_ofnode(UCLASS_MMC, ofnode_path(boot_device), &dev)) { | |
530 | debug("%s: no U-Boot device found for %s\n", __func__, boot_device); | |
531 | return devnum; | |
532 | } | |
533 | ||
534 | devnum = dev->seq_; | |
535 | debug("%s: get MMC env from mmc%d\n", __func__, devnum); | |
536 | return devnum; | |
537 | } |