xref: /rk3399_rockchip-uboot/arch/arm/mach-rockchip/boot_rkimg.c (revision 257c8a70660eec65519a481f1dd33e4e060766c8)
1 /*
2  * (C) Copyright 2017 Rockchip Electronics Co., Ltd
3  *
4  * SPDX-License-Identifier:     GPL-2.0+
5  */
6 
7 #include <common.h>
8 #include <adc.h>
9 #include <android_bootloader.h>
10 #include <android_image.h>
11 #include <bidram.h>
12 #include <bootm.h>
13 #include <boot_rkimg.h>
14 #include <cli.h>
15 #include <crypto.h>
16 #include <dm.h>
17 #include <fs.h>
18 #include <image.h>
19 #include <key.h>
20 #include <mmc.h>
21 #include <malloc.h>
22 #include <mp_boot.h>
23 #include <mtd_blk.h>
24 #include <nvme.h>
25 #include <scsi.h>
26 #include <stdlib.h>
27 #include <sysmem.h>
28 #include <asm/io.h>
29 #include <asm/arch/boot_mode.h>
30 #include <asm/arch/fit.h>
31 #include <asm/arch/hotkey.h>
32 #include <asm/arch/param.h>
33 #include <asm/arch/resource_img.h>
34 #include <asm/arch/uimage.h>
35 #include <dm/ofnode.h>
36 #include <linux/list.h>
37 #include <u-boot/sha1.h>
38 #include <u-boot/sha256.h>
39 #include <linux/usb/phy-rockchip-usb2.h>
40 
41 DECLARE_GLOBAL_DATA_PTR;
42 
43 __weak int rk_board_early_fdt_fixup(void *blob)
44 {
45 	return 0;
46 }
47 
48 __weak int rk_board_scan_bootdev(void)
49 {
50 	const char *devtype_num_set = "run rkimg_bootdev";
51 
52 	return run_command_list(devtype_num_set, -1, 0);
53 }
54 
55 static int bootdev_init(const char *devtype, const char *devnum)
56 {
57 #ifdef CONFIG_MMC
58 	if (!strcmp("mmc", devtype))
59 		mmc_initialize(gd->bd);
60 #endif
61 #ifdef CONFIG_NVME
62 	if (!strcmp("nvme", devtype)) {
63 		pci_init();
64 		if (nvme_scan_namespace())
65 			return -ENODEV;
66 	}
67 #endif
68 #if defined(CONFIG_SCSI) && defined(CONFIG_CMD_SCSI) && defined(CONFIG_AHCI)
69 	if (!strcmp("scsi", devtype)) {
70 		if (scsi_scan(true))
71 			return -ENODEV;
72 	}
73 #endif
74 	/* Ok, let's test whether we can get the expected boot device or not */
75 	if (!blk_get_devnum_by_typename(devtype, atoi(devnum)))
76 		return -ENODEV;
77 
78 	env_set("devtype", devtype);
79 	env_set("devnum", devnum);
80 
81 	return 0;
82 }
83 
84 /*
85  * Priority: configuration > atags > scan list.
86  */
87 static void boot_devtype_init(void)
88 {
89 	char *devtype = NULL, *devnum = NULL;
90 	char *src = "scan";
91 	static int done;	/* static */
92 	int ret;
93 
94 	if (done)
95 		return;
96 
97 #ifdef CONFIG_MP_BOOT
98 	mpb_post(0);
99 #endif
100 
101 	/* configuration */
102 	if (!param_parse_assign_bootdev(&devtype, &devnum)) {
103 		if (!bootdev_init(devtype, devnum)) {
104 			src = "assign";
105 			goto finish;
106 		}
107 	}
108 
109 	/* atags */
110 #ifdef CONFIG_ROCKCHIP_PRELOADER_ATAGS
111 	if (!param_parse_atags_bootdev(&devtype, &devnum)) {
112 		if (!bootdev_init(devtype, devnum)) {
113 			src = "atags";
114 			goto finish;
115 		}
116 	}
117 #endif
118 
119 	/* scan list */
120 #ifdef CONFIG_MMC
121 	mmc_initialize(gd->bd);
122 #endif
123 	ret = rk_board_scan_bootdev();
124 	if (ret) {
125 		/* Set default if all failed */
126 		devtype = "mmc";
127 		devnum = "0";
128 		env_set("devtype", devtype);
129 		env_set("devnum", devnum);
130 	}
131 finish:
132 	done = 1;
133 	printf("Bootdev(%s): %s %s\n", src,
134 	       env_get("devtype"), env_get("devnum"));
135 }
136 
137 static int get_bootdev_type(void)
138 {
139 	char *boot_media = NULL, *devtype = NULL;
140 	char boot_options[128] = {0};
141 	static int appended;
142 	ulong devnum = 0;
143 	int type = 0;
144 
145 	devtype = env_get("devtype");
146 	devnum = env_get_ulong("devnum", 10, 0);
147 
148 	/* For current use(Only EMMC support!) */
149 	if (!devtype) {
150 		devtype = "mmc";
151 		printf("Use emmc as default boot media\n");
152 	}
153 
154 	if (!strcmp(devtype, "mmc")) {
155 		type = IF_TYPE_MMC;
156 		if (devnum == 1)
157 			boot_media = "sd";
158 		else
159 			boot_media = "emmc";
160 	} else if (!strcmp(devtype, "rknand")) {
161 		type = IF_TYPE_RKNAND;
162 		boot_media = "nand";
163 	} else if (!strcmp(devtype, "spinand")) {
164 		type = IF_TYPE_SPINAND;
165 		boot_media = "nand"; /* kernel treat sfc nand as nand device */
166 	} else if (!strcmp(devtype, "spinor")) {
167 		type = IF_TYPE_SPINOR;
168 		boot_media = "nor";
169 	} else if (!strcmp(devtype, "ramdisk")) {
170 		type = IF_TYPE_RAMDISK;
171 		boot_media = "ramdisk";
172 	} else if (!strcmp(devtype, "mtd")) {
173 		type = IF_TYPE_MTD;
174 		boot_media = "mtd";
175 	} else if (!strcmp(devtype, "scsi")) {
176 		type = IF_TYPE_SCSI;
177 		boot_media = "scsi";
178 	} else if (!strcmp(devtype, "nvme")) {
179 		type = IF_TYPE_NVME;
180 		boot_media = "nvme";
181 	} else {
182 		/* Add new to support */
183 	}
184 
185 	if (!appended && boot_media) {
186 		appended = 1;
187 
188 	/*
189 	 * The legacy rockchip Android (SDK < 8.1) requires "androidboot.mode="
190 	 * to be "charger" or boot media which is a rockchip private solution.
191 	 *
192 	 * The official Android rule (SDK >= 8.1) is:
193 	 * "androidboot.mode=normal" or "androidboot.mode=charger".
194 	 *
195 	 * Now that this U-Boot is usually working with higher version
196 	 * Android (SDK >= 8.1), we follow the official rules.
197 	 *
198 	 * Common: androidboot.mode=charger has higher priority, don't override;
199 	 */
200 #ifdef CONFIG_RKIMG_ANDROID_BOOTMODE_LEGACY
201 		/* rknand doesn't need "androidboot.mode="; */
202 		if (env_exist("bootargs", "androidboot.mode=charger") ||
203 		    (type == IF_TYPE_RKNAND) ||
204 		    (type == IF_TYPE_SPINAND) ||
205 		    (type == IF_TYPE_SPINOR))
206 			snprintf(boot_options, sizeof(boot_options),
207 				 "storagemedia=%s", boot_media);
208 		else
209 			snprintf(boot_options, sizeof(boot_options),
210 				 "storagemedia=%s androidboot.mode=%s",
211 				 boot_media, boot_media);
212 #else
213 		/*
214 		 * 1. "storagemedia": This is a legacy variable to indicate board
215 		 *    storage media for kernel and android.
216 		 *
217 		 * 2. "androidboot.storagemedia": The same purpose as "storagemedia",
218 		 *    but the android framework will auto create property by
219 		 *    variable with format "androidboot.xxx", eg:
220 		 *
221 		 *    "androidboot.storagemedia" => "ro.boot.storagemedia".
222 		 *
223 		 *    So, U-Boot pass this new variable is only for the convenience
224 		 *    to Android.
225 		 */
226 		if (env_exist("bootargs", "androidboot.mode=charger"))
227 			snprintf(boot_options, sizeof(boot_options),
228 				 "storagemedia=%s androidboot.storagemedia=%s",
229 				 boot_media, boot_media);
230 		else
231 			snprintf(boot_options, sizeof(boot_options),
232 				 "storagemedia=%s androidboot.storagemedia=%s "
233 				 "androidboot.mode=normal ",
234 				 boot_media, boot_media);
235 #endif
236 		env_update("bootargs", boot_options);
237 	}
238 
239 	return type;
240 }
241 
242 static struct blk_desc *dev_desc;
243 
244 struct blk_desc *rockchip_get_bootdev(void)
245 {
246 	int dev_type;
247 	int devnum;
248 
249 	if (dev_desc)
250 		return dev_desc;
251 
252 	boot_devtype_init();
253 	dev_type = get_bootdev_type();
254 	devnum = env_get_ulong("devnum", 10, 0);
255 
256 	dev_desc = blk_get_devnum_by_type(dev_type, devnum);
257 	if (!dev_desc) {
258 		printf("%s: Can't find dev_desc!\n", __func__);
259 		return NULL;
260 	}
261 
262 #ifdef CONFIG_MMC
263 	if (dev_type == IF_TYPE_MMC) {
264 		struct mmc *mmc;
265 		const char *timing[] = {
266 			"Legacy", "High Speed", "High Speed", "SDR12",
267 			"SDR25", "SDR50", "SDR104", "DDR50",
268 			"DDR52", "HS200", "HS400", "HS400 Enhanced Strobe"};
269 
270 		mmc = find_mmc_device(devnum);
271 		printf("MMC%d: %s, %dMhz\n", devnum,
272 		       timing[mmc->timing], mmc->clock / 1000000);
273 	}
274 #endif
275 
276 	printf("PartType: %s\n", part_get_type(dev_desc));
277 
278 #ifdef CONFIG_MTD_BLK
279 	mtd_blk_map_partitions(dev_desc);
280 #endif
281 	return dev_desc;
282 }
283 
284 void rockchip_set_bootdev(struct blk_desc *desc)
285 {
286 	dev_desc = desc;
287 }
288 
289 /*
290  * detect download key status by adc, most rockchip
291  * based boards use adc sample the download key status,
292  * but there are also some use gpio. So it's better to
293  * make this a weak function that can be override by
294  * some special boards.
295  */
296 #define KEY_DOWN_MIN_VAL	0
297 #define KEY_DOWN_MAX_VAL	30
298 
299 __weak int rockchip_dnl_key_pressed(void)
300 {
301 #if defined(CONFIG_DM_KEY)
302 	return key_is_pressed(key_read(KEY_VOLUMEUP));
303 
304 #elif defined(CONFIG_ADC)
305 	const void *blob = gd->fdt_blob;
306 	int node, ret, channel = 1;
307 	u32 val, chns[2];
308 
309 	node = fdt_node_offset_by_compatible(blob, 0, "adc-keys");
310 	if (node >= 0) {
311 		if (!fdtdec_get_int_array(blob, node, "io-channels", chns, 2))
312 			channel = chns[1];
313 	}
314 
315 	ret = adc_channel_single_shot("saradc", channel, &val);
316 	if (ret)
317 		ret = adc_channel_single_shot("adc", channel, &val);
318 	if (ret) {
319 		printf("%s: Failed to read saradc, ret=%d\n", __func__, ret);
320 		return 0;
321 	}
322 
323 	return ((val >= KEY_DOWN_MIN_VAL) && (val <= KEY_DOWN_MAX_VAL));
324 #endif
325 
326 	return 0;
327 }
328 
329 void setup_download_mode(void)
330 {
331 	int vbus = 1; /* Assumed 1 in case of no rockusb */
332 
333 	boot_devtype_init();
334 
335 	if (rockchip_dnl_key_pressed() || is_hotkey(HK_ROCKUSB_DNL)) {
336 		printf("download %skey pressed... ",
337 		       is_hotkey(HK_ROCKUSB_DNL) ? "hot" : "");
338 #ifdef CONFIG_CMD_ROCKUSB
339 		vbus = rockchip_u2phy_vbus_detect();
340 #endif
341 		if (vbus > 0) {
342 			printf("%sentering download mode...\n",
343 			       IS_ENABLED(CONFIG_CMD_ROCKUSB) ?
344 			       "" : "no rockusb, ");
345 
346 			/* try rockusb download and brom download */
347 			run_command("download", 0);
348 		} else {
349 			printf("entering recovery mode!\n");
350 			env_set("reboot_mode", "recovery-key");
351 		}
352 	} else if (is_hotkey(HK_FASTBOOT)) {
353 		env_set("reboot_mode", "fastboot");
354 	}
355 }
356 
357 void board_run_recovery_wipe_data(void)
358 {
359 	struct bootloader_message bmsg;
360 	struct blk_desc *dev_desc;
361 	disk_partition_t part_info;
362 #ifdef CONFIG_ANDROID_BOOT_IMAGE
363 	u32 bcb_offset = android_bcb_msg_sector_offset();
364 #else
365 	u32 bcb_offset = BCB_MESSAGE_BLK_OFFSET;
366 #endif
367 	int cnt, ret;
368 
369 	printf("Rebooting into recovery to do wipe_data\n");
370 	dev_desc = rockchip_get_bootdev();
371 	if (!dev_desc) {
372 		printf("%s: dev_desc is NULL!\n", __func__);
373 		return;
374 	}
375 
376 	ret = part_get_info_by_name(dev_desc, PART_MISC, &part_info);
377 	if (ret < 0) {
378 		printf("%s: Could not found misc partition, just run recovery\n",
379 		       __func__);
380 		goto out;
381 	}
382 
383 	memset((char *)&bmsg, 0, sizeof(struct bootloader_message));
384 	strcpy(bmsg.command, "boot-recovery");
385 	strcpy(bmsg.recovery, "recovery\n--wipe_data");
386 	bmsg.status[0] = 0;
387 	cnt = DIV_ROUND_UP(sizeof(struct bootloader_message), dev_desc->blksz);
388 	ret = blk_dwrite(dev_desc, part_info.start + bcb_offset, cnt, &bmsg);
389 	if (ret != cnt)
390 		printf("Wipe data failed, ret=%d\n", ret);
391 out:
392 	/* now reboot to recovery */
393 	env_set("reboot_mode", "recovery");
394 	run_command("run bootcmd", 0);
395 }
396 
397 #if defined(CONFIG_USING_KERNEL_DTB) || defined(CONFIG_CMD_BOOTM) || \
398     defined(CONFIG_CMD_BOOTZ) || defined(CONFIG_CMD_BOOTI)
399 #ifdef CONFIG_ROCKCHIP_DTB_VERIFY
400 #ifdef CONFIG_DM_CRYPTO
401 static int crypto_csum(u32 cap, char *input, u32 input_len, u8 *output)
402 {
403 	sha_context csha_ctx;
404 	struct udevice *dev;
405 
406 	dev = crypto_get_device(cap);
407 	if (!dev) {
408 		printf("Can't find expected crypto device\n");
409 		return -ENODEV;
410 	}
411 
412 	csha_ctx.algo = cap;
413 	csha_ctx.length = input_len;
414 	crypto_sha_csum(dev, &csha_ctx, (char *)input,
415 			input_len, output);
416 
417 	return 0;
418 }
419 
420 static int fdt_check_hash(void *fdt_addr, u32 fdt_size,
421 			  char *hash_cmp, u32 hash_size)
422 {
423 	uchar hash[32];
424 
425 	if (!hash_size)
426 		return 0;
427 
428 	if (hash_size == 20)
429 		crypto_csum(CRYPTO_SHA1, fdt_addr, fdt_size, hash);
430 	else if (hash_size == 32)
431 		crypto_csum(CRYPTO_SHA256, fdt_addr, fdt_size, hash);
432 	else
433 		return -EINVAL;
434 
435 	printf("HASH(c): ");
436 	if (memcmp(hash, hash_cmp, hash_size)) {
437 		printf("error\n");
438 		return -EBADF;
439 	}
440 
441 	printf("OK\n");
442 
443 	return 0;
444 }
445 
446 #else
447 static int fdt_check_hash(void *fdt_addr, u32 fdt_size,
448 			  char *hash_cmp, u32 hash_size)
449 {
450 	uchar hash[32];
451 
452 	if (!hash_size)
453 		return 0;
454 
455 	if (hash_size == 20)
456 		sha1_csum((const uchar *)fdt_addr, fdt_size, hash);
457 	else if (hash_size == 32)
458 		sha256_csum((const uchar *)fdt_addr, fdt_size, hash);
459 	else
460 		return -EINVAL;
461 
462 	printf("HASH(s): ");
463 	if (memcmp(hash, hash_cmp, hash_size)) {
464 		printf("error\n");
465 		return -EBADF;
466 	}
467 
468 	printf("OK\n");
469 
470 	return 0;
471 }
472 #endif
473 #endif	/* CONFIG_ROCKCHIP_DTB_VERIFY */
474 
475 #if defined(CONFIG_ROCKCHIP_EARLY_DISTRO_DTB)
476 static int rockchip_read_distro_dtb(void *fdt_addr)
477 {
478 	const char *cmd = "part list ${devtype} ${devnum} -bootable devplist";
479 	char *devnum, *devtype, *devplist;
480 	char devnum_part[12];
481 	char fdt_hex_str[19];
482 	char *fs_argv[5];
483 
484 	if (!rockchip_get_bootdev() || !fdt_addr)
485 		return -ENODEV;
486 
487 	if (run_command_list(cmd, -1, 0)) {
488 		printf("Failed to find -bootable\n");
489 		return -EINVAL;
490 	}
491 
492 	devplist = env_get("devplist");
493 	if (!devplist)
494 		devplist = "1";
495 
496 	devtype = env_get("devtype");
497 	devnum = env_get("devnum");
498 	sprintf(devnum_part, "%s:%s", devnum, devplist);
499 	sprintf(fdt_hex_str, "0x%lx", (ulong)fdt_addr);
500 
501 	fs_argv[0] = "load";
502 	fs_argv[1] = devtype,
503 	fs_argv[2] = devnum_part;
504 	fs_argv[3] = fdt_hex_str;
505 	fs_argv[4] = CONFIG_ROCKCHIP_EARLY_DISTRO_DTB_PATH;
506 
507 	if (do_load(NULL, 0, 5, fs_argv, FS_TYPE_ANY))
508 		return -EIO;
509 
510 	if (fdt_check_header(fdt_addr))
511 		return -EBADF;
512 
513 	printf("DTB(Distro): %s\n", CONFIG_ROCKCHIP_EARLY_DISTRO_DTB_PATH);
514 
515 	return 0;
516 }
517 #endif
518 
519 enum {
520 	LOCATE_DISTRO,
521 	LOCATE_RESOURCE,
522 	LOCATE_FIT,
523 	LOCATE_END,
524 };
525 
526 static int dtb_scan(void *fdt, int where)
527 {
528 	if (where == LOCATE_DISTRO) {
529 #ifdef CONFIG_ROCKCHIP_EARLY_DISTRO_DTB
530 		return rockchip_read_distro_dtb(fdt);
531 #endif
532 	} else if (where == LOCATE_RESOURCE) {
533 #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE
534 		int hash_size = 0;
535 		char *hash;
536 		u32 ret;
537 
538 		ret = rockchip_read_resource_dtb(fdt, &hash, &hash_size);
539 		if (ret) {
540 			printf("Failed to load DTB, ret=%d\n", ret);
541 			return ret;
542 		}
543 
544 		if (fdt_check_header(fdt)) {
545 			printf("Invalid DTB magic !\n");
546 			return -EBADF;
547 		}
548 #ifdef CONFIG_ROCKCHIP_DTB_VERIFY
549 		if (hash_size && fdt_check_hash(fdt,
550 			fdt_totalsize(fdt), hash, hash_size)) {
551 			printf("Invalid DTB hash !\n");
552 			return -EBADF;
553 		}
554 #endif
555 		return 0;
556 #endif
557 	} else if (where == LOCATE_FIT) {
558 #if defined(CONFIG_ROCKCHIP_FIT_IMAGE) && !defined(CONFIG_ROCKCHIP_RESOURCE_IMAGE)
559 		return fit_image_read_dtb(fdt);
560 #endif
561 	}
562 
563 	return -EINVAL;
564 }
565 
566 int rockchip_read_dtb_file(void *fdt)
567 {
568 	int locate, ret;
569 	int size;
570 
571 	for (locate = 0; locate < LOCATE_END; locate++) {
572 		ret = dtb_scan(fdt, locate);
573 		if (!ret)
574 			break;
575 	}
576 	if (ret) {
577 		printf("No valid DTB, ret=%d\n", ret);
578 		return ret;
579 	}
580 
581 	/* reserved memory */
582 	size = fdt_totalsize(fdt);
583 	if (!sysmem_alloc_base(MEM_FDT, (phys_addr_t)fdt,
584 		ALIGN(size, RK_BLK_SIZE) + CONFIG_SYS_FDT_PAD))
585 		return -ENOMEM;
586 
587 	/* fixup/overlay */
588 	rk_board_early_fdt_fixup(fdt);
589 #if defined(CONFIG_ANDROID_BOOT_IMAGE) && defined(CONFIG_OF_LIBFDT_OVERLAY)
590 	android_fdt_overlay_apply((void *)fdt);
591 #endif
592 
593 	return 0;
594 }
595 #endif
596 
597 int rockchip_ram_read_dtb_file(void *img, void *fdt)
598 {
599 	int format;
600 	int ret;
601 
602 	format = (genimg_get_format(img));
603 #ifdef CONFIG_ANDROID_BOOT_IMAGE
604 	if (format == IMAGE_FORMAT_ANDROID) {
605 		struct andr_img_hdr *hdr = img;
606 		struct blk_desc *dev_desc;
607 		ulong offset;
608 
609 		dev_desc = rockchip_get_bootdev();
610 		if (!dev_desc)
611 			return -ENODEV;
612 
613 		offset = hdr->page_size + ALIGN(hdr->kernel_size, hdr->page_size) +
614 			ALIGN(hdr->ramdisk_size, hdr->page_size);
615 #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE
616 		ret = resource_setup_ram_list(dev_desc, (void *)hdr + offset);
617 		if (ret)
618 			return ret;
619 
620 		return rockchip_read_dtb_file((void *)fdt);
621 #else
622 		if (fdt_check_header((void *)offset))
623 			return -EINVAL;
624 
625 		memcpy(fdt, (char *)offset, fdt_totalsize(offset));
626 		if (!sysmem_alloc_base(MEM_FDT, (phys_addr_t)fdt,
627 			ALIGN(fdt_totalsize(fdt), RK_BLK_SIZE) + CONFIG_SYS_FDT_PAD))
628 			return -ENOMEM;
629 
630 		return 0;
631 #endif
632 	}
633 #endif
634 #if IMAGE_ENABLE_FIT
635 	if (format == IMAGE_FORMAT_FIT) {
636 		const void *data;
637 		size_t size;
638 		int noffset;
639 #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE
640 		const char *path = "/images/resource";
641 #else
642 		const char *path = "/images/fdt";
643 #endif
644 
645 		noffset = fdt_path_offset(img, path);
646 		if (noffset < 0)
647 			return noffset;
648 
649 #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE
650 		ret = fit_image_get_data(img, noffset, &data, &size);
651 		if (ret < 0)
652 			return ret;
653 
654 		dev_desc = rockchip_get_bootdev();
655 		if (!dev_desc)
656 			return -ENODEV;
657 
658 		ret = resource_setup_ram_list(dev_desc, (void *)data);
659 		if (ret) {
660 			printf("resource_setup_ram_list fail, ret=%d\n", ret);
661 			return ret;
662 		}
663 
664 		return rockchip_read_dtb_file((void *)fdt);
665 #else
666 
667 		ret = fit_image_get_data(img, noffset, &data, &size);
668 		if (ret)
669 			return ret;
670 
671 		if (fdt_check_header(data))
672 			return -EINVAL;
673 
674 		memcpy(fdt, data, size);
675 		if (!sysmem_alloc_base(MEM_FDT, (phys_addr_t)fdt,
676 			ALIGN(fdt_totalsize(fdt), RK_BLK_SIZE) + CONFIG_SYS_FDT_PAD))
677 			return -ENOMEM;
678 
679 		printf("Load DTB from 'images/fdt'\n");
680 
681 		return 0;
682 #endif
683 	}
684 #endif
685 
686 	return -EINVAL;
687 }
688