xref: /rk3399_rockchip-uboot/arch/arm/mach-rockchip/boot_rkimg.c (revision a1f6fc00a03ae255aefc9170884a5086b29d3fa5)
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 <stdlib.h>
23 #include <sysmem.h>
24 #include <asm/io.h>
25 #include <asm/arch/boot_mode.h>
26 #include <asm/arch/fit.h>
27 #include <asm/arch/hotkey.h>
28 #include <asm/arch/param.h>
29 #include <asm/arch/resource_img.h>
30 #include <asm/arch/uimage.h>
31 #include <dm/ofnode.h>
32 #include <linux/list.h>
33 #include <u-boot/sha1.h>
34 #include <u-boot/sha256.h>
35 #include <linux/usb/phy-rockchip-usb2.h>
36 
37 DECLARE_GLOBAL_DATA_PTR;
38 
39 static void boot_devtype_init(void)
40 {
41 	const char *devtype_num_set = "run rkimg_bootdev";
42 	char *devtype = NULL, *devnum = NULL;
43 	static int done;	/* static */
44 	int atags_en = 0;
45 	int ret;
46 
47 	if (done)
48 		return;
49 
50 #if defined(CONFIG_SCSI) && defined(CONFIG_CMD_SCSI) && defined(CONFIG_AHCI)
51 	ret = run_command("scsi scan", 0);
52 	if (!ret) {
53 		ret = run_command("scsi dev 0", 0);
54 		if (!ret) {
55 			devtype = "scsi";
56 			devnum = "0";
57 			env_set("devtype", devtype);
58 			env_set("devnum", devnum);
59 			goto finish;
60 		}
61 	}
62 #endif
63 
64 	/* High priority: get bootdev from atags */
65 #ifdef CONFIG_ROCKCHIP_PRELOADER_ATAGS
66 	ret = param_parse_bootdev(&devtype, &devnum);
67 	if (!ret) {
68 		atags_en = 1;
69 		env_set("devtype", devtype);
70 		env_set("devnum", devnum);
71 
72 #ifdef CONFIG_MMC
73 		if (!strcmp("mmc", devtype))
74 			mmc_initialize(gd->bd);
75 #endif
76 		/*
77 		 * For example, the pre-loader do not have mtd device,
78 		 * and pass devtype is nand. Then U-Boot can not get
79 		 * dev_desc when use mtd driver to read firmware. So
80 		 * test the block dev is exist or not here.
81 		 *
82 		 * And the devtype & devnum maybe wrong sometimes, it
83 		 * is better to test first.
84 		 */
85 		if (blk_get_devnum_by_typename(devtype, atoi(devnum)))
86 			goto finish;
87 	}
88 #endif
89 
90 	/* Low priority: if not get bootdev by atags, scan all possible */
91 #ifdef CONFIG_MMC
92 	mmc_initialize(gd->bd);
93 #endif
94 	ret = run_command_list(devtype_num_set, -1, 0);
95 	if (ret) {
96 		/* Set default dev type/num if command not valid */
97 		devtype = "mmc";
98 		devnum = "0";
99 		env_set("devtype", devtype);
100 		env_set("devnum", devnum);
101 	}
102 
103 finish:
104 	done = 1;
105 	printf("Bootdev%s: %s %s\n", atags_en ? "(atags)" : "",
106 	       env_get("devtype"), env_get("devnum"));
107 }
108 
109 static int get_bootdev_type(void)
110 {
111 	char *boot_media = NULL, *devtype = NULL;
112 	char boot_options[128] = {0};
113 	static int appended;
114 	ulong devnum = 0;
115 	int type = 0;
116 
117 	devtype = env_get("devtype");
118 	devnum = env_get_ulong("devnum", 10, 0);
119 
120 	/* For current use(Only EMMC support!) */
121 	if (!devtype) {
122 		devtype = "mmc";
123 		printf("Use emmc as default boot media\n");
124 	}
125 
126 	if (!strcmp(devtype, "mmc")) {
127 		type = IF_TYPE_MMC;
128 		if (devnum == 1)
129 			boot_media = "sd";
130 		else
131 			boot_media = "emmc";
132 	} else if (!strcmp(devtype, "rknand")) {
133 		type = IF_TYPE_RKNAND;
134 		boot_media = "nand";
135 	} else if (!strcmp(devtype, "spinand")) {
136 		type = IF_TYPE_SPINAND;
137 		boot_media = "nand"; /* kernel treat sfc nand as nand device */
138 	} else if (!strcmp(devtype, "spinor")) {
139 		type = IF_TYPE_SPINOR;
140 		boot_media = "nor";
141 	} else if (!strcmp(devtype, "ramdisk")) {
142 		type = IF_TYPE_RAMDISK;
143 		boot_media = "ramdisk";
144 	} else if (!strcmp(devtype, "mtd")) {
145 		type = IF_TYPE_MTD;
146 		boot_media = "mtd";
147 	} else if (!strcmp(devtype, "scsi")) {
148 		type = IF_TYPE_SCSI;
149 		boot_media = "scsi";
150 	} else {
151 		/* Add new to support */
152 	}
153 
154 	if (!appended && boot_media) {
155 		appended = 1;
156 
157 	/*
158 	 * The legacy rockchip Android (SDK < 8.1) requires "androidboot.mode="
159 	 * to be "charger" or boot media which is a rockchip private solution.
160 	 *
161 	 * The official Android rule (SDK >= 8.1) is:
162 	 * "androidboot.mode=normal" or "androidboot.mode=charger".
163 	 *
164 	 * Now that this U-Boot is usually working with higher version
165 	 * Android (SDK >= 8.1), we follow the official rules.
166 	 *
167 	 * Common: androidboot.mode=charger has higher priority, don't override;
168 	 */
169 #ifdef CONFIG_RKIMG_ANDROID_BOOTMODE_LEGACY
170 		/* rknand doesn't need "androidboot.mode="; */
171 		if (env_exist("bootargs", "androidboot.mode=charger") ||
172 		    (type == IF_TYPE_RKNAND) ||
173 		    (type == IF_TYPE_SPINAND) ||
174 		    (type == IF_TYPE_SPINOR))
175 			snprintf(boot_options, sizeof(boot_options),
176 				 "storagemedia=%s", boot_media);
177 		else
178 			snprintf(boot_options, sizeof(boot_options),
179 				 "storagemedia=%s androidboot.mode=%s",
180 				 boot_media, boot_media);
181 #else
182 		/*
183 		 * 1. "storagemedia": This is a legacy variable to indicate board
184 		 *    storage media for kernel and android.
185 		 *
186 		 * 2. "androidboot.storagemedia": The same purpose as "storagemedia",
187 		 *    but the android framework will auto create property by
188 		 *    variable with format "androidboot.xxx", eg:
189 		 *
190 		 *    "androidboot.storagemedia" => "ro.boot.storagemedia".
191 		 *
192 		 *    So, U-Boot pass this new variable is only for the convenience
193 		 *    to Android.
194 		 */
195 		if (env_exist("bootargs", "androidboot.mode=charger"))
196 			snprintf(boot_options, sizeof(boot_options),
197 				 "storagemedia=%s androidboot.storagemedia=%s",
198 				 boot_media, boot_media);
199 		else
200 			snprintf(boot_options, sizeof(boot_options),
201 				 "storagemedia=%s androidboot.storagemedia=%s "
202 				 "androidboot.mode=normal ",
203 				 boot_media, boot_media);
204 #endif
205 		env_update("bootargs", boot_options);
206 	}
207 
208 	return type;
209 }
210 
211 static struct blk_desc *dev_desc;
212 
213 struct blk_desc *rockchip_get_bootdev(void)
214 {
215 	int dev_type;
216 	int devnum;
217 
218 	if (dev_desc)
219 		return dev_desc;
220 
221 	boot_devtype_init();
222 	dev_type = get_bootdev_type();
223 	devnum = env_get_ulong("devnum", 10, 0);
224 
225 	dev_desc = blk_get_devnum_by_type(dev_type, devnum);
226 	if (!dev_desc) {
227 		printf("%s: Can't find dev_desc!\n", __func__);
228 		return NULL;
229 	}
230 
231 #ifdef CONFIG_MMC
232 	if (dev_type == IF_TYPE_MMC) {
233 		struct mmc *mmc;
234 		const char *timing[] = {
235 			"Legacy", "High Speed", "High Speed", "SDR12",
236 			"SDR25", "SDR50", "SDR104", "DDR50",
237 			"DDR52", "HS200", "HS400", "HS400 Enhanced Strobe"};
238 
239 		mmc = find_mmc_device(devnum);
240 		printf("MMC%d: %s, %dMhz\n", devnum,
241 		       timing[mmc->timing], mmc->clock / 1000000);
242 	}
243 #endif
244 
245 	printf("PartType: %s\n", part_get_type(dev_desc));
246 
247 	return dev_desc;
248 }
249 
250 void rockchip_set_bootdev(struct blk_desc *desc)
251 {
252 	dev_desc = desc;
253 }
254 
255 /*
256  * detect download key status by adc, most rockchip
257  * based boards use adc sample the download key status,
258  * but there are also some use gpio. So it's better to
259  * make this a weak function that can be override by
260  * some special boards.
261  */
262 #define KEY_DOWN_MIN_VAL	0
263 #define KEY_DOWN_MAX_VAL	30
264 
265 __weak int rockchip_dnl_key_pressed(void)
266 {
267 #if defined(CONFIG_DM_KEY)
268 #ifdef CONFIG_CMD_ROCKUSB
269 	return key_is_pressed(key_read(KEY_VOLUMEUP));
270 #else
271 	return key_is_pressed(key_read(KEY_MENU));
272 #endif
273 
274 #elif defined(CONFIG_ADC)
275 	const void *blob = gd->fdt_blob;
276 	int node, ret, channel = 1;
277 	u32 val, chns[2];
278 
279 	node = fdt_node_offset_by_compatible(blob, 0, "adc-keys");
280 	if (node >= 0) {
281 		if (!fdtdec_get_int_array(blob, node, "io-channels", chns, 2))
282 			channel = chns[1];
283 	}
284 
285 	ret = adc_channel_single_shot("saradc", channel, &val);
286 	if (ret) {
287 		printf("%s: Failed to read saradc, ret=%d\n", __func__, ret);
288 		return 0;
289 	}
290 
291 	return ((val >= KEY_DOWN_MIN_VAL) && (val <= KEY_DOWN_MAX_VAL));
292 #endif
293 
294 	return 0;
295 }
296 
297 void setup_download_mode(void)
298 {
299 	int vbus = 1; /* Assumed 1 in case of no rockusb */
300 
301 	boot_devtype_init();
302 
303 	/*
304 	 * rockchip_dnl_key_pressed():
305 	 *
306 	 * (1) volume-up key (default)
307 	 * (2) menu key (If no rockusb)
308 	 *
309 	 * It's possible that USB is disabled due to developer needs
310 	 * a critial size of u-boot.bin.
311 	 *
312 	 * Disabling USB makes vbus can't be detected any more, so that
313 	 * we add menu key. The events trigger are changed:
314 	 *
315 	 * - rockusb mode(actually fallback to bootrom mode):
316 	 *	"volume-up pressed + vbus=1" replaced with "menu pressed"
317 	 * - recovery mode:
318 	 *	"volume-up pressed + vbus=0" replaced with "volume-up pressed"
319 	 *
320 	 * At the most time, USB is enabled and this feature is not applied.
321 	 */
322 	if (rockchip_dnl_key_pressed() || is_hotkey(HK_ROCKUSB_DNL)) {
323 		printf("download %skey pressed... ",
324 		       is_hotkey(HK_ROCKUSB_DNL) ? "hot" : "");
325 #ifdef CONFIG_CMD_ROCKUSB
326 		vbus = rockchip_u2phy_vbus_detect();
327 #endif
328 		if (vbus > 0) {
329 			printf("%sentering download mode...\n",
330 			       IS_ENABLED(CONFIG_CMD_ROCKUSB) ?
331 			       "" : "no rockusb, ");
332 
333 			/* try rockusb download and brom download */
334 			run_command("download", 0);
335 		} else {
336 			printf("entering recovery mode!\n");
337 			env_set("reboot_mode", "recovery-key");
338 		}
339 	} else if (is_hotkey(HK_FASTBOOT)) {
340 		env_set("reboot_mode", "fastboot");
341 	}
342 }
343 
344 void board_run_recovery_wipe_data(void)
345 {
346 	struct bootloader_message bmsg;
347 	struct blk_desc *dev_desc;
348 	disk_partition_t part_info;
349 #ifdef CONFIG_ANDROID_BOOT_IMAGE
350 	u32 bcb_offset = android_bcb_msg_sector_offset();
351 #else
352 	u32 bcb_offset = BCB_MESSAGE_BLK_OFFSET;
353 #endif
354 	int cnt, ret;
355 
356 	printf("Rebooting into recovery to do wipe_data\n");
357 	dev_desc = rockchip_get_bootdev();
358 	if (!dev_desc) {
359 		printf("%s: dev_desc is NULL!\n", __func__);
360 		return;
361 	}
362 
363 	ret = part_get_info_by_name(dev_desc, PART_MISC, &part_info);
364 	if (ret < 0) {
365 		printf("%s: Could not found misc partition, just run recovery\n",
366 		       __func__);
367 		goto out;
368 	}
369 
370 	memset((char *)&bmsg, 0, sizeof(struct bootloader_message));
371 	strcpy(bmsg.command, "boot-recovery");
372 	strcpy(bmsg.recovery, "recovery\n--wipe_data");
373 	bmsg.status[0] = 0;
374 	cnt = DIV_ROUND_UP(sizeof(struct bootloader_message), dev_desc->blksz);
375 	ret = blk_dwrite(dev_desc, part_info.start + bcb_offset, cnt, &bmsg);
376 	if (ret != cnt)
377 		printf("Wipe data failed, ret=%d\n", ret);
378 out:
379 	/* now reboot to recovery */
380 	env_set("reboot_mode", "recovery");
381 	run_command("run bootcmd", 0);
382 }
383 
384 #if defined(CONFIG_USING_KERNEL_DTB) || defined(CONFIG_CMD_BOOTM) || \
385     defined(CONFIG_CMD_BOOTZ) || defined(CONFIG_CMD_BOOTI)
386 #ifdef CONFIG_ROCKCHIP_DTB_VERIFY
387 #ifdef CONFIG_DM_CRYPTO
388 static int crypto_csum(u32 cap, char *input, u32 input_len, u8 *output)
389 {
390 	sha_context csha_ctx;
391 	struct udevice *dev;
392 
393 	dev = crypto_get_device(cap);
394 	if (!dev) {
395 		printf("Can't find expected crypto device\n");
396 		return -ENODEV;
397 	}
398 
399 	csha_ctx.algo = cap;
400 	csha_ctx.length = input_len;
401 	crypto_sha_csum(dev, &csha_ctx, (char *)input,
402 			input_len, output);
403 
404 	return 0;
405 }
406 
407 static int fdt_check_hash(void *fdt_addr, u32 fdt_size,
408 			  char *hash_cmp, u32 hash_size)
409 {
410 	uchar hash[32];
411 
412 	if (!hash_size)
413 		return 0;
414 
415 	if (hash_size == 20)
416 		crypto_csum(CRYPTO_SHA1, fdt_addr, fdt_size, hash);
417 	else if (hash_size == 32)
418 		crypto_csum(CRYPTO_SHA256, fdt_addr, fdt_size, hash);
419 	else
420 		return -EINVAL;
421 
422 	printf("HASH(c): ");
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 
433 #else
434 static int fdt_check_hash(void *fdt_addr, u32 fdt_size,
435 			  char *hash_cmp, u32 hash_size)
436 {
437 	uchar hash[32];
438 
439 	if (!hash_size)
440 		return 0;
441 
442 	if (hash_size == 20)
443 		sha1_csum((const uchar *)fdt_addr, fdt_size, hash);
444 	else if (hash_size == 32)
445 		sha256_csum((const uchar *)fdt_addr, fdt_size, hash);
446 	else
447 		return -EINVAL;
448 
449 	printf("HASH(s): ");
450 	if (memcmp(hash, hash_cmp, hash_size)) {
451 		printf("error\n");
452 		return -EBADF;
453 	}
454 
455 	printf("OK\n");
456 
457 	return 0;
458 }
459 #endif
460 #endif	/* CONFIG_ROCKCHIP_DTB_VERIFY */
461 
462 #if defined(CONFIG_ROCKCHIP_EARLY_DISTRO_DTB)
463 static int rockchip_read_distro_dtb(void *fdt_addr)
464 {
465 	const char *cmd = "part list ${devtype} ${devnum} -bootable devplist";
466 	char *devnum, *devtype, *devplist;
467 	char devnum_part[12];
468 	char fdt_hex_str[19];
469 	char *fs_argv[5];
470 
471 	if (!rockchip_get_bootdev() || !fdt_addr)
472 		return -ENODEV;
473 
474 	if (run_command_list(cmd, -1, 0)) {
475 		printf("Failed to find -bootable\n");
476 		return -EINVAL;
477 	}
478 
479 	devplist = env_get("devplist");
480 	if (!devplist)
481 		return -ENODEV;
482 
483 	devtype = env_get("devtype");
484 	devnum = env_get("devnum");
485 	sprintf(devnum_part, "%s:%s", devnum, devplist);
486 	sprintf(fdt_hex_str, "0x%lx", (ulong)fdt_addr);
487 
488 	fs_argv[0] = "load";
489 	fs_argv[1] = devtype,
490 	fs_argv[2] = devnum_part;
491 	fs_argv[3] = fdt_hex_str;
492 	fs_argv[4] = CONFIG_ROCKCHIP_EARLY_DISTRO_DTB_PATH;
493 
494 	if (do_load(NULL, 0, 5, fs_argv, FS_TYPE_ANY))
495 		return -EIO;
496 
497 	if (fdt_check_header(fdt_addr))
498 		return -EBADF;
499 
500 	printf("DTB(Distro): %s\n", CONFIG_ROCKCHIP_EARLY_DISTRO_DTB_PATH);
501 
502 	return 0;
503 }
504 #endif
505 
506 int rockchip_read_dtb_file(void *fdt_addr)
507 {
508 	int hash_size;
509 	char *hash;
510 	u32 size;
511 	int ret = -1;
512 
513 #ifdef CONFIG_ROCKCHIP_FIT_IMAGE
514 	if (ret) {
515 		hash_size = 0;
516 		ret = rockchip_read_fit_dtb(fdt_addr, &hash, &hash_size);
517 	}
518 #endif
519 #ifdef CONFIG_ROCKCHIP_UIMAGE
520 	if (ret) {
521 		hash_size = 0;
522 		ret = rockchip_read_uimage_dtb(fdt_addr, &hash, &hash_size);
523 	}
524 #endif
525 #ifdef CONFIG_ROCKCHIP_EARLY_DISTRO_DTB
526 	if (ret) {
527 		hash_size = 0;
528 		ret = rockchip_read_distro_dtb(fdt_addr);
529 	}
530 #endif
531 #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE
532 	if (ret) {
533 		hash_size = 0;
534 		ret = rockchip_read_resource_dtb(fdt_addr, &hash, &hash_size);
535 	}
536 #endif
537 	if (ret) {
538 		printf("Failed to load DTB\n");
539 		return ret;
540 	}
541 
542 	if (fdt_check_header(fdt_addr)) {
543 		printf("Get a bad DTB file !\n");
544 		return -EBADF;
545 	}
546 
547 	size = fdt_totalsize(fdt_addr);
548 
549 #ifdef CONFIG_ROCKCHIP_DTB_VERIFY
550 	if (hash_size && fdt_check_hash(fdt_addr, size, hash, hash_size)) {
551 		printf("Get a bad hash of DTB !\n");
552 		return -EBADF;
553 	}
554 #endif
555 	if (!sysmem_alloc_base(MEM_FDT, (phys_addr_t)fdt_addr,
556 			       ALIGN(size, RK_BLK_SIZE) +
557 			       CONFIG_SYS_FDT_PAD))
558 		return -ENOMEM;
559 
560 #if defined(CONFIG_ANDROID_BOOT_IMAGE) && defined(CONFIG_OF_LIBFDT_OVERLAY)
561 	android_fdt_overlay_apply((void *)fdt_addr);
562 #endif
563 
564 	return 0;
565 }
566 #endif
567