xref: /rk3399_rockchip-uboot/arch/arm/mach-rockchip/boot_rkimg.c (revision 3a00cba2d05061ed8f5f4308972fe59b252933da)
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 
rk_board_early_fdt_fixup(void * blob)43 __weak int rk_board_early_fdt_fixup(void *blob)
44 {
45 	return 0;
46 }
47 
rk_board_scan_bootdev(void)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 
bootdev_init(const char * devtype,const char * devnum)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) || defined(CONFIG_UFS))
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  */
boot_devtype_init(void)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 
get_bootdev_type(void)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 
rockchip_get_bootdev(void)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 
rockchip_set_bootdev(struct blk_desc * desc)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 
rockchip_dnl_key_pressed(void)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 
setup_download_mode(void)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 
board_run_recovery_wipe_data(void)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
fdt_check_hash(void * fdt_addr,u32 fdt_size,char * hash_cmp,u32 hash_size)400 static int fdt_check_hash(void *fdt_addr, u32 fdt_size,
401 			  char *hash_cmp, u32 hash_size)
402 {
403 	uchar hash[32];
404 #ifdef CONFIG_ARMV8_CRYPTO
405 	char *engine = "ce";
406 #elif defined(CONFIG_DM_CRYPTO)
407 	char *engine = "c";
408 #else
409 	char *engine = "s";
410 #endif
411 
412 	if (!hash_size)
413 		return 0;
414 
415 	if (hash_size == 20)
416 		sha1_csum((const uchar *)fdt_addr, fdt_size, hash);
417 	else if (hash_size == 32)
418 		sha256_csum((const uchar *)fdt_addr, fdt_size, hash);
419 	else
420 		return -EINVAL;
421 
422 	printf("HASH(%s): ", engine);
423 	if (memcmp(hash, hash_cmp, hash_size)) {
424 		printf("error\n");
425 		return -EBADF;
426 	}
427 
428 	printf("OK\n");
429 
430 	return 0;
431 }
432 #endif	/* CONFIG_ROCKCHIP_DTB_VERIFY */
433 
434 #if defined(CONFIG_ROCKCHIP_EARLY_DISTRO_DTB)
rockchip_read_distro_dtb(void * fdt_addr)435 static int rockchip_read_distro_dtb(void *fdt_addr)
436 {
437 	const char *cmd = "part list ${devtype} ${devnum} -bootable devplist";
438 	char *devnum, *devtype, *devplist;
439 	char devnum_part[12];
440 	char fdt_hex_str[19];
441 	char *fs_argv[5];
442 
443 	if (!rockchip_get_bootdev() || !fdt_addr)
444 		return -ENODEV;
445 
446 	if (run_command_list(cmd, -1, 0)) {
447 		printf("Failed to find -bootable\n");
448 		return -EINVAL;
449 	}
450 
451 	devplist = env_get("devplist");
452 	if (!devplist)
453 		devplist = "1";
454 
455 	devtype = env_get("devtype");
456 	devnum = env_get("devnum");
457 	sprintf(devnum_part, "%s:%s", devnum, devplist);
458 	sprintf(fdt_hex_str, "0x%lx", (ulong)fdt_addr);
459 
460 	fs_argv[0] = "load";
461 	fs_argv[1] = devtype,
462 	fs_argv[2] = devnum_part;
463 	fs_argv[3] = fdt_hex_str;
464 	fs_argv[4] = CONFIG_ROCKCHIP_EARLY_DISTRO_DTB_PATH;
465 
466 	if (do_load(NULL, 0, 5, fs_argv, FS_TYPE_ANY))
467 		return -EIO;
468 
469 	if (fdt_check_header(fdt_addr))
470 		return -EBADF;
471 
472 	printf("DTB(Distro): %s\n", CONFIG_ROCKCHIP_EARLY_DISTRO_DTB_PATH);
473 
474 	return 0;
475 }
476 #endif
477 
478 enum {
479 	LOCATE_DISTRO,
480 	LOCATE_RESOURCE,
481 	LOCATE_FIT,
482 	LOCATE_END,
483 };
484 
dtb_scan(void * fdt,int where)485 static int dtb_scan(void *fdt, int where)
486 {
487 	if (where == LOCATE_DISTRO) {
488 #ifdef CONFIG_ROCKCHIP_EARLY_DISTRO_DTB
489 		return rockchip_read_distro_dtb(fdt);
490 #endif
491 	} else if (where == LOCATE_RESOURCE) {
492 #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE
493 		int hash_size = 0;
494 		char *hash;
495 		u32 ret;
496 
497 		ret = rockchip_read_resource_dtb(fdt, &hash, &hash_size);
498 		if (ret) {
499 			printf("Failed to load DTB, ret=%d\n", ret);
500 			return ret;
501 		}
502 
503 		if (fdt_check_header(fdt)) {
504 			printf("Invalid DTB magic !\n");
505 			return -EBADF;
506 		}
507 #ifdef CONFIG_ROCKCHIP_DTB_VERIFY
508 		if (hash_size && fdt_check_hash(fdt,
509 			fdt_totalsize(fdt), hash, hash_size)) {
510 			printf("Invalid DTB hash !\n");
511 			return -EBADF;
512 		}
513 #endif
514 		return 0;
515 #endif
516 	} else if (where == LOCATE_FIT) {
517 #if defined(CONFIG_ROCKCHIP_FIT_IMAGE) && !defined(CONFIG_ROCKCHIP_RESOURCE_IMAGE)
518 		return fit_image_read_dtb(fdt);
519 #endif
520 	}
521 
522 	return -EINVAL;
523 }
524 
rockchip_read_dtb_file(void * fdt)525 int rockchip_read_dtb_file(void *fdt)
526 {
527 	int locate, ret;
528 	int size;
529 
530 	for (locate = 0; locate < LOCATE_END; locate++) {
531 		ret = dtb_scan(fdt, locate);
532 		if (!ret)
533 			break;
534 	}
535 	if (ret) {
536 		printf("No valid DTB, ret=%d\n", ret);
537 		return ret;
538 	}
539 
540 	/* reserved memory */
541 	size = fdt_totalsize(fdt);
542 	if (!sysmem_alloc_base(MEM_FDT, (phys_addr_t)fdt,
543 		ALIGN(size, RK_BLK_SIZE) + CONFIG_SYS_FDT_PAD))
544 		return -ENOMEM;
545 
546 	/* fixup/overlay */
547 	rk_board_early_fdt_fixup(fdt);
548 #if defined(CONFIG_ANDROID_BOOT_IMAGE) && defined(CONFIG_OF_LIBFDT_OVERLAY)
549 	android_fdt_overlay_apply((void *)fdt);
550 #endif
551 
552 	return 0;
553 }
554 #endif
555 
rockchip_ram_read_dtb_file(void * img,void * fdt)556 int rockchip_ram_read_dtb_file(void *img, void *fdt)
557 {
558 	int format;
559 	int ret;
560 
561 	format = (genimg_get_format(img));
562 #ifdef CONFIG_ANDROID_BOOT_IMAGE
563 	if (format == IMAGE_FORMAT_ANDROID) {
564 		struct andr_img_hdr *hdr = img;
565 		struct blk_desc *dev_desc;
566 		ulong offset;
567 
568 		dev_desc = rockchip_get_bootdev();
569 		if (!dev_desc)
570 			return -ENODEV;
571 
572 		offset = hdr->page_size + ALIGN(hdr->kernel_size, hdr->page_size) +
573 			ALIGN(hdr->ramdisk_size, hdr->page_size);
574 #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE
575 		ret = resource_setup_ram_list(dev_desc, (void *)hdr + offset);
576 		if (ret)
577 			return ret;
578 
579 		return rockchip_read_dtb_file((void *)fdt);
580 #else
581 		if (fdt_check_header((void *)offset))
582 			return -EINVAL;
583 
584 		memcpy(fdt, (char *)offset, fdt_totalsize(offset));
585 		if (!sysmem_alloc_base(MEM_FDT, (phys_addr_t)fdt,
586 			ALIGN(fdt_totalsize(fdt), RK_BLK_SIZE) + CONFIG_SYS_FDT_PAD))
587 			return -ENOMEM;
588 
589 		return 0;
590 #endif
591 	}
592 #endif
593 #if IMAGE_ENABLE_FIT
594 	if (format == IMAGE_FORMAT_FIT) {
595 		const void *data;
596 		size_t size;
597 		int noffset;
598 #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE
599 		const char *path = "/images/resource";
600 #else
601 		const char *path = "/images/fdt";
602 #endif
603 
604 		noffset = fdt_path_offset(img, path);
605 		if (noffset < 0)
606 			return noffset;
607 
608 #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE
609 		ret = fit_image_get_data(img, noffset, &data, &size);
610 		if (ret < 0)
611 			return ret;
612 
613 		dev_desc = rockchip_get_bootdev();
614 		if (!dev_desc)
615 			return -ENODEV;
616 
617 		ret = resource_setup_ram_list(dev_desc, (void *)data);
618 		if (ret) {
619 			printf("resource_setup_ram_list fail, ret=%d\n", ret);
620 			return ret;
621 		}
622 
623 		return rockchip_read_dtb_file((void *)fdt);
624 #else
625 
626 		ret = fit_image_get_data(img, noffset, &data, &size);
627 		if (ret)
628 			return ret;
629 
630 		if (fdt_check_header(data))
631 			return -EINVAL;
632 
633 		memcpy(fdt, data, size);
634 		if (!sysmem_alloc_base(MEM_FDT, (phys_addr_t)fdt,
635 			ALIGN(fdt_totalsize(fdt), RK_BLK_SIZE) + CONFIG_SYS_FDT_PAD))
636 			return -ENOMEM;
637 
638 		printf("Load DTB from 'images/fdt'\n");
639 
640 		return 0;
641 #endif
642 	}
643 #endif
644 
645 	return -EINVAL;
646 }
647