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