xref: /rk3399_rockchip-uboot/arch/arm/mach-rockchip/boot_rkimg.c (revision 3a00cba2d05061ed8f5f4308972fe59b252933da)
1aa1eec08SJoseph Chen /*
2aa1eec08SJoseph Chen  * (C) Copyright 2017 Rockchip Electronics Co., Ltd
3aa1eec08SJoseph Chen  *
4aa1eec08SJoseph Chen  * SPDX-License-Identifier:     GPL-2.0+
5aa1eec08SJoseph Chen  */
6aa1eec08SJoseph Chen 
7aa1eec08SJoseph Chen #include <common.h>
8aa1eec08SJoseph Chen #include <adc.h>
9bc4ccd53SJoseph Chen #include <android_bootloader.h>
10bc4ccd53SJoseph Chen #include <android_image.h>
11aa1eec08SJoseph Chen #include <bidram.h>
12aa1eec08SJoseph Chen #include <bootm.h>
13aa1eec08SJoseph Chen #include <boot_rkimg.h>
14aa1eec08SJoseph Chen #include <cli.h>
15bc4ccd53SJoseph Chen #include <crypto.h>
16aa1eec08SJoseph Chen #include <dm.h>
17bc4ccd53SJoseph Chen #include <fs.h>
18aa1eec08SJoseph Chen #include <image.h>
19aa1eec08SJoseph Chen #include <key.h>
20aa1eec08SJoseph Chen #include <mmc.h>
21aa1eec08SJoseph Chen #include <malloc.h>
2236c449feSJoseph Chen #include <mp_boot.h>
23ed2db57eSJoseph Chen #include <mtd_blk.h>
2431120150SJon Lin #include <nvme.h>
255029b474SJoseph Chen #include <scsi.h>
26aa1eec08SJoseph Chen #include <stdlib.h>
27aa1eec08SJoseph Chen #include <sysmem.h>
28aa1eec08SJoseph Chen #include <asm/io.h>
29aa1eec08SJoseph Chen #include <asm/arch/boot_mode.h>
30c5b23954SJoseph Chen #include <asm/arch/fit.h>
31aa1eec08SJoseph Chen #include <asm/arch/hotkey.h>
32aa1eec08SJoseph Chen #include <asm/arch/param.h>
33aa1eec08SJoseph Chen #include <asm/arch/resource_img.h>
34c5b23954SJoseph Chen #include <asm/arch/uimage.h>
35bc4ccd53SJoseph Chen #include <dm/ofnode.h>
36bc4ccd53SJoseph Chen #include <linux/list.h>
37bc4ccd53SJoseph Chen #include <u-boot/sha1.h>
38bc4ccd53SJoseph Chen #include <u-boot/sha256.h>
3973a9beaaSJianing Ren #include <linux/usb/phy-rockchip-usb2.h>
40aa1eec08SJoseph Chen 
41aa1eec08SJoseph Chen DECLARE_GLOBAL_DATA_PTR;
42aa1eec08SJoseph Chen 
rk_board_early_fdt_fixup(void * blob)43e3f2a979SJoseph Chen __weak int rk_board_early_fdt_fixup(void *blob)
44e3f2a979SJoseph Chen {
45e3f2a979SJoseph Chen 	return 0;
46e3f2a979SJoseph Chen }
47e3f2a979SJoseph Chen 
rk_board_scan_bootdev(void)4886826528SJoseph Chen __weak int rk_board_scan_bootdev(void)
49aa1eec08SJoseph Chen {
50aa1eec08SJoseph Chen 	const char *devtype_num_set = "run rkimg_bootdev";
5186826528SJoseph Chen 
5286826528SJoseph Chen 	return run_command_list(devtype_num_set, -1, 0);
5386826528SJoseph Chen }
5486826528SJoseph Chen 
bootdev_init(const char * devtype,const char * devnum)555029b474SJoseph Chen static int bootdev_init(const char *devtype, const char *devnum)
565029b474SJoseph Chen {
575029b474SJoseph Chen #ifdef CONFIG_MMC
585029b474SJoseph Chen 	if (!strcmp("mmc", devtype))
595029b474SJoseph Chen 		mmc_initialize(gd->bd);
605029b474SJoseph Chen #endif
615029b474SJoseph Chen #ifdef CONFIG_NVME
625029b474SJoseph Chen 	if (!strcmp("nvme", devtype)) {
635029b474SJoseph Chen 		pci_init();
645029b474SJoseph Chen 		if (nvme_scan_namespace())
655029b474SJoseph Chen 			return -ENODEV;
665029b474SJoseph Chen 	}
675029b474SJoseph Chen #endif
68*f749a034SYifeng Zhao #if defined(CONFIG_SCSI) && defined(CONFIG_CMD_SCSI) && (defined(CONFIG_AHCI) || defined(CONFIG_UFS))
695029b474SJoseph Chen 	if (!strcmp("scsi", devtype)) {
705029b474SJoseph Chen 		if (scsi_scan(true))
715029b474SJoseph Chen 			return -ENODEV;
725029b474SJoseph Chen 	}
735029b474SJoseph Chen #endif
745029b474SJoseph Chen 	/* Ok, let's test whether we can get the expected boot device or not */
755029b474SJoseph Chen 	if (!blk_get_devnum_by_typename(devtype, atoi(devnum)))
765029b474SJoseph Chen 		return -ENODEV;
775029b474SJoseph Chen 
785029b474SJoseph Chen 	env_set("devtype", devtype);
795029b474SJoseph Chen 	env_set("devnum", devnum);
805029b474SJoseph Chen 
815029b474SJoseph Chen 	return 0;
825029b474SJoseph Chen }
835029b474SJoseph Chen 
845029b474SJoseph Chen /*
855029b474SJoseph Chen  * Priority: configuration > atags > scan list.
865029b474SJoseph Chen  */
boot_devtype_init(void)8786826528SJoseph Chen static void boot_devtype_init(void)
8886826528SJoseph Chen {
89aa1eec08SJoseph Chen 	char *devtype = NULL, *devnum = NULL;
905029b474SJoseph Chen 	char *src = "scan";
91aa1eec08SJoseph Chen 	static int done;	/* static */
92aa1eec08SJoseph Chen 	int ret;
93aa1eec08SJoseph Chen 
94aa1eec08SJoseph Chen 	if (done)
95aa1eec08SJoseph Chen 		return;
96aa1eec08SJoseph Chen 
9736c449feSJoseph Chen #ifdef CONFIG_MP_BOOT
9836c449feSJoseph Chen 	mpb_post(0);
9936c449feSJoseph Chen #endif
10036c449feSJoseph Chen 
1015029b474SJoseph Chen 	/* configuration */
1025029b474SJoseph Chen 	if (!param_parse_assign_bootdev(&devtype, &devnum)) {
1035029b474SJoseph Chen 		if (!bootdev_init(devtype, devnum)) {
1045029b474SJoseph Chen 			src = "assign";
1055d68fdf1SYifeng Zhao 			goto finish;
1065d68fdf1SYifeng Zhao 		}
1075d68fdf1SYifeng Zhao 	}
1085d68fdf1SYifeng Zhao 
1095029b474SJoseph Chen 	/* atags */
110982d40b6SJoseph Chen #ifdef CONFIG_ROCKCHIP_PRELOADER_ATAGS
1115029b474SJoseph Chen 	if (!param_parse_atags_bootdev(&devtype, &devnum)) {
1125029b474SJoseph Chen 		if (!bootdev_init(devtype, devnum)) {
1135029b474SJoseph Chen 			src = "atags";
114aa1eec08SJoseph Chen 			goto finish;
115aa1eec08SJoseph Chen 		}
1165029b474SJoseph Chen 	}
117982d40b6SJoseph Chen #endif
118aa1eec08SJoseph Chen 
1195029b474SJoseph Chen 	/* scan list */
120589d4a88SJason Zhu #ifdef CONFIG_MMC
121aa1eec08SJoseph Chen 	mmc_initialize(gd->bd);
122aa1eec08SJoseph Chen #endif
12386826528SJoseph Chen 	ret = rk_board_scan_bootdev();
124aa1eec08SJoseph Chen 	if (ret) {
1255029b474SJoseph Chen 		/* Set default if all failed */
126aa1eec08SJoseph Chen 		devtype = "mmc";
127aa1eec08SJoseph Chen 		devnum = "0";
128aa1eec08SJoseph Chen 		env_set("devtype", devtype);
129aa1eec08SJoseph Chen 		env_set("devnum", devnum);
130aa1eec08SJoseph Chen 	}
131aa1eec08SJoseph Chen finish:
132aa1eec08SJoseph Chen 	done = 1;
1335029b474SJoseph Chen 	printf("Bootdev(%s): %s %s\n", src,
134aa1eec08SJoseph Chen 	       env_get("devtype"), env_get("devnum"));
135aa1eec08SJoseph Chen }
136aa1eec08SJoseph Chen 
get_bootdev_type(void)137aa1eec08SJoseph Chen static int get_bootdev_type(void)
138aa1eec08SJoseph Chen {
139aa1eec08SJoseph Chen 	char *boot_media = NULL, *devtype = NULL;
140aa1eec08SJoseph Chen 	char boot_options[128] = {0};
141aa1eec08SJoseph Chen 	static int appended;
142aa1eec08SJoseph Chen 	ulong devnum = 0;
143aa1eec08SJoseph Chen 	int type = 0;
144aa1eec08SJoseph Chen 
145aa1eec08SJoseph Chen 	devtype = env_get("devtype");
146aa1eec08SJoseph Chen 	devnum = env_get_ulong("devnum", 10, 0);
147aa1eec08SJoseph Chen 
148aa1eec08SJoseph Chen 	/* For current use(Only EMMC support!) */
149aa1eec08SJoseph Chen 	if (!devtype) {
150aa1eec08SJoseph Chen 		devtype = "mmc";
151aa1eec08SJoseph Chen 		printf("Use emmc as default boot media\n");
152aa1eec08SJoseph Chen 	}
153aa1eec08SJoseph Chen 
154aa1eec08SJoseph Chen 	if (!strcmp(devtype, "mmc")) {
155aa1eec08SJoseph Chen 		type = IF_TYPE_MMC;
156aa1eec08SJoseph Chen 		if (devnum == 1)
157aa1eec08SJoseph Chen 			boot_media = "sd";
158aa1eec08SJoseph Chen 		else
159aa1eec08SJoseph Chen 			boot_media = "emmc";
160aa1eec08SJoseph Chen 	} else if (!strcmp(devtype, "rknand")) {
161aa1eec08SJoseph Chen 		type = IF_TYPE_RKNAND;
162aa1eec08SJoseph Chen 		boot_media = "nand";
163aa1eec08SJoseph Chen 	} else if (!strcmp(devtype, "spinand")) {
164aa1eec08SJoseph Chen 		type = IF_TYPE_SPINAND;
165aa1eec08SJoseph Chen 		boot_media = "nand"; /* kernel treat sfc nand as nand device */
166aa1eec08SJoseph Chen 	} else if (!strcmp(devtype, "spinor")) {
167aa1eec08SJoseph Chen 		type = IF_TYPE_SPINOR;
168aa1eec08SJoseph Chen 		boot_media = "nor";
169aa1eec08SJoseph Chen 	} else if (!strcmp(devtype, "ramdisk")) {
170aa1eec08SJoseph Chen 		type = IF_TYPE_RAMDISK;
171aa1eec08SJoseph Chen 		boot_media = "ramdisk";
172aa1eec08SJoseph Chen 	} else if (!strcmp(devtype, "mtd")) {
173aa1eec08SJoseph Chen 		type = IF_TYPE_MTD;
174aa1eec08SJoseph Chen 		boot_media = "mtd";
1755d68fdf1SYifeng Zhao 	} else if (!strcmp(devtype, "scsi")) {
1765d68fdf1SYifeng Zhao 		type = IF_TYPE_SCSI;
1775d68fdf1SYifeng Zhao 		boot_media = "scsi";
17831120150SJon Lin 	} else if (!strcmp(devtype, "nvme")) {
17931120150SJon Lin 		type = IF_TYPE_NVME;
18031120150SJon Lin 		boot_media = "nvme";
181aa1eec08SJoseph Chen 	} else {
182aa1eec08SJoseph Chen 		/* Add new to support */
183aa1eec08SJoseph Chen 	}
184aa1eec08SJoseph Chen 
185aa1eec08SJoseph Chen 	if (!appended && boot_media) {
186aa1eec08SJoseph Chen 		appended = 1;
187aa1eec08SJoseph Chen 
188aa1eec08SJoseph Chen 	/*
189aa1eec08SJoseph Chen 	 * The legacy rockchip Android (SDK < 8.1) requires "androidboot.mode="
190aa1eec08SJoseph Chen 	 * to be "charger" or boot media which is a rockchip private solution.
191aa1eec08SJoseph Chen 	 *
192aa1eec08SJoseph Chen 	 * The official Android rule (SDK >= 8.1) is:
193aa1eec08SJoseph Chen 	 * "androidboot.mode=normal" or "androidboot.mode=charger".
194aa1eec08SJoseph Chen 	 *
195aa1eec08SJoseph Chen 	 * Now that this U-Boot is usually working with higher version
196aa1eec08SJoseph Chen 	 * Android (SDK >= 8.1), we follow the official rules.
197aa1eec08SJoseph Chen 	 *
198aa1eec08SJoseph Chen 	 * Common: androidboot.mode=charger has higher priority, don't override;
199aa1eec08SJoseph Chen 	 */
200aa1eec08SJoseph Chen #ifdef CONFIG_RKIMG_ANDROID_BOOTMODE_LEGACY
201aa1eec08SJoseph Chen 		/* rknand doesn't need "androidboot.mode="; */
202aa1eec08SJoseph Chen 		if (env_exist("bootargs", "androidboot.mode=charger") ||
203aa1eec08SJoseph Chen 		    (type == IF_TYPE_RKNAND) ||
204aa1eec08SJoseph Chen 		    (type == IF_TYPE_SPINAND) ||
205aa1eec08SJoseph Chen 		    (type == IF_TYPE_SPINOR))
206aa1eec08SJoseph Chen 			snprintf(boot_options, sizeof(boot_options),
207aa1eec08SJoseph Chen 				 "storagemedia=%s", boot_media);
208aa1eec08SJoseph Chen 		else
209aa1eec08SJoseph Chen 			snprintf(boot_options, sizeof(boot_options),
210aa1eec08SJoseph Chen 				 "storagemedia=%s androidboot.mode=%s",
211aa1eec08SJoseph Chen 				 boot_media, boot_media);
212aa1eec08SJoseph Chen #else
213aa1eec08SJoseph Chen 		/*
214aa1eec08SJoseph Chen 		 * 1. "storagemedia": This is a legacy variable to indicate board
215aa1eec08SJoseph Chen 		 *    storage media for kernel and android.
216aa1eec08SJoseph Chen 		 *
217aa1eec08SJoseph Chen 		 * 2. "androidboot.storagemedia": The same purpose as "storagemedia",
218aa1eec08SJoseph Chen 		 *    but the android framework will auto create property by
219aa1eec08SJoseph Chen 		 *    variable with format "androidboot.xxx", eg:
220aa1eec08SJoseph Chen 		 *
221aa1eec08SJoseph Chen 		 *    "androidboot.storagemedia" => "ro.boot.storagemedia".
222aa1eec08SJoseph Chen 		 *
223aa1eec08SJoseph Chen 		 *    So, U-Boot pass this new variable is only for the convenience
224aa1eec08SJoseph Chen 		 *    to Android.
225aa1eec08SJoseph Chen 		 */
226aa1eec08SJoseph Chen 		if (env_exist("bootargs", "androidboot.mode=charger"))
227aa1eec08SJoseph Chen 			snprintf(boot_options, sizeof(boot_options),
228aa1eec08SJoseph Chen 				 "storagemedia=%s androidboot.storagemedia=%s",
229aa1eec08SJoseph Chen 				 boot_media, boot_media);
230aa1eec08SJoseph Chen 		else
231aa1eec08SJoseph Chen 			snprintf(boot_options, sizeof(boot_options),
232aa1eec08SJoseph Chen 				 "storagemedia=%s androidboot.storagemedia=%s "
233aa1eec08SJoseph Chen 				 "androidboot.mode=normal ",
234aa1eec08SJoseph Chen 				 boot_media, boot_media);
235aa1eec08SJoseph Chen #endif
236aa1eec08SJoseph Chen 		env_update("bootargs", boot_options);
237aa1eec08SJoseph Chen 	}
238aa1eec08SJoseph Chen 
239aa1eec08SJoseph Chen 	return type;
240aa1eec08SJoseph Chen }
241aa1eec08SJoseph Chen 
242aa1eec08SJoseph Chen static struct blk_desc *dev_desc;
243aa1eec08SJoseph Chen 
rockchip_get_bootdev(void)244aa1eec08SJoseph Chen struct blk_desc *rockchip_get_bootdev(void)
245aa1eec08SJoseph Chen {
246aa1eec08SJoseph Chen 	int dev_type;
247aa1eec08SJoseph Chen 	int devnum;
248aa1eec08SJoseph Chen 
249aa1eec08SJoseph Chen 	if (dev_desc)
250aa1eec08SJoseph Chen 		return dev_desc;
251aa1eec08SJoseph Chen 
252aa1eec08SJoseph Chen 	boot_devtype_init();
253aa1eec08SJoseph Chen 	dev_type = get_bootdev_type();
254aa1eec08SJoseph Chen 	devnum = env_get_ulong("devnum", 10, 0);
255aa1eec08SJoseph Chen 
256aa1eec08SJoseph Chen 	dev_desc = blk_get_devnum_by_type(dev_type, devnum);
257aa1eec08SJoseph Chen 	if (!dev_desc) {
258aa1eec08SJoseph Chen 		printf("%s: Can't find dev_desc!\n", __func__);
259aa1eec08SJoseph Chen 		return NULL;
260aa1eec08SJoseph Chen 	}
261aa1eec08SJoseph Chen 
262aa1eec08SJoseph Chen #ifdef CONFIG_MMC
263aa1eec08SJoseph Chen 	if (dev_type == IF_TYPE_MMC) {
264aa1eec08SJoseph Chen 		struct mmc *mmc;
265aa1eec08SJoseph Chen 		const char *timing[] = {
266aa1eec08SJoseph Chen 			"Legacy", "High Speed", "High Speed", "SDR12",
267aa1eec08SJoseph Chen 			"SDR25", "SDR50", "SDR104", "DDR50",
268aa1eec08SJoseph Chen 			"DDR52", "HS200", "HS400", "HS400 Enhanced Strobe"};
269aa1eec08SJoseph Chen 
270aa1eec08SJoseph Chen 		mmc = find_mmc_device(devnum);
271aa1eec08SJoseph Chen 		printf("MMC%d: %s, %dMhz\n", devnum,
272aa1eec08SJoseph Chen 		       timing[mmc->timing], mmc->clock / 1000000);
273aa1eec08SJoseph Chen 	}
274aa1eec08SJoseph Chen #endif
275aa1eec08SJoseph Chen 
276aa1eec08SJoseph Chen 	printf("PartType: %s\n", part_get_type(dev_desc));
277aa1eec08SJoseph Chen 
278ed2db57eSJoseph Chen #ifdef CONFIG_MTD_BLK
279ed2db57eSJoseph Chen 	mtd_blk_map_partitions(dev_desc);
280ed2db57eSJoseph Chen #endif
281aa1eec08SJoseph Chen 	return dev_desc;
282aa1eec08SJoseph Chen }
283aa1eec08SJoseph Chen 
rockchip_set_bootdev(struct blk_desc * desc)284aa1eec08SJoseph Chen void rockchip_set_bootdev(struct blk_desc *desc)
285aa1eec08SJoseph Chen {
286aa1eec08SJoseph Chen 	dev_desc = desc;
287aa1eec08SJoseph Chen }
288aa1eec08SJoseph Chen 
289aa1eec08SJoseph Chen /*
290aa1eec08SJoseph Chen  * detect download key status by adc, most rockchip
291aa1eec08SJoseph Chen  * based boards use adc sample the download key status,
292aa1eec08SJoseph Chen  * but there are also some use gpio. So it's better to
293aa1eec08SJoseph Chen  * make this a weak function that can be override by
294aa1eec08SJoseph Chen  * some special boards.
295aa1eec08SJoseph Chen  */
296aa1eec08SJoseph Chen #define KEY_DOWN_MIN_VAL	0
297aa1eec08SJoseph Chen #define KEY_DOWN_MAX_VAL	30
298aa1eec08SJoseph Chen 
rockchip_dnl_key_pressed(void)299aa1eec08SJoseph Chen __weak int rockchip_dnl_key_pressed(void)
300aa1eec08SJoseph Chen {
301aa1eec08SJoseph Chen #if defined(CONFIG_DM_KEY)
302aa1eec08SJoseph Chen 	return key_is_pressed(key_read(KEY_VOLUMEUP));
303aa1eec08SJoseph Chen 
304aa1eec08SJoseph Chen #elif defined(CONFIG_ADC)
305aa1eec08SJoseph Chen 	const void *blob = gd->fdt_blob;
306aa1eec08SJoseph Chen 	int node, ret, channel = 1;
307aa1eec08SJoseph Chen 	u32 val, chns[2];
308aa1eec08SJoseph Chen 
309aa1eec08SJoseph Chen 	node = fdt_node_offset_by_compatible(blob, 0, "adc-keys");
310aa1eec08SJoseph Chen 	if (node >= 0) {
311aa1eec08SJoseph Chen 		if (!fdtdec_get_int_array(blob, node, "io-channels", chns, 2))
312aa1eec08SJoseph Chen 			channel = chns[1];
313aa1eec08SJoseph Chen 	}
314aa1eec08SJoseph Chen 
315aa1eec08SJoseph Chen 	ret = adc_channel_single_shot("saradc", channel, &val);
316a6c9ff86SJoseph Chen 	if (ret)
317a6c9ff86SJoseph Chen 		ret = adc_channel_single_shot("adc", channel, &val);
318aa1eec08SJoseph Chen 	if (ret) {
319aa1eec08SJoseph Chen 		printf("%s: Failed to read saradc, ret=%d\n", __func__, ret);
320aa1eec08SJoseph Chen 		return 0;
321aa1eec08SJoseph Chen 	}
322aa1eec08SJoseph Chen 
323aa1eec08SJoseph Chen 	return ((val >= KEY_DOWN_MIN_VAL) && (val <= KEY_DOWN_MAX_VAL));
324aa1eec08SJoseph Chen #endif
325aa1eec08SJoseph Chen 
326aa1eec08SJoseph Chen 	return 0;
327aa1eec08SJoseph Chen }
328aa1eec08SJoseph Chen 
setup_download_mode(void)329aa1eec08SJoseph Chen void setup_download_mode(void)
330aa1eec08SJoseph Chen {
331702e26daSJoseph Chen 	int vbus = 1; /* Assumed 1 in case of no rockusb */
3323017074fSJoseph Chen 
333aa1eec08SJoseph Chen 	boot_devtype_init();
334aa1eec08SJoseph Chen 
335aa1eec08SJoseph Chen 	if (rockchip_dnl_key_pressed() || is_hotkey(HK_ROCKUSB_DNL)) {
336497d7897SJoseph Chen 		printf("download %skey pressed... ",
337497d7897SJoseph Chen 		       is_hotkey(HK_ROCKUSB_DNL) ? "hot" : "");
3383017074fSJoseph Chen #ifdef CONFIG_CMD_ROCKUSB
3393017074fSJoseph Chen 		vbus = rockchip_u2phy_vbus_detect();
3403017074fSJoseph Chen #endif
3413017074fSJoseph Chen 		if (vbus > 0) {
3423017074fSJoseph Chen 			printf("%sentering download mode...\n",
3433017074fSJoseph Chen 			       IS_ENABLED(CONFIG_CMD_ROCKUSB) ?
3443017074fSJoseph Chen 			       "" : "no rockusb, ");
3453017074fSJoseph Chen 
346aa1eec08SJoseph Chen 			/* try rockusb download and brom download */
347aa1eec08SJoseph Chen 			run_command("download", 0);
348aa1eec08SJoseph Chen 		} else {
349aa1eec08SJoseph Chen 			printf("entering recovery mode!\n");
350aa1eec08SJoseph Chen 			env_set("reboot_mode", "recovery-key");
351aa1eec08SJoseph Chen 		}
352aa1eec08SJoseph Chen 	} else if (is_hotkey(HK_FASTBOOT)) {
353aa1eec08SJoseph Chen 		env_set("reboot_mode", "fastboot");
354aa1eec08SJoseph Chen 	}
355aa1eec08SJoseph Chen }
356aa1eec08SJoseph Chen 
board_run_recovery_wipe_data(void)357aa1eec08SJoseph Chen void board_run_recovery_wipe_data(void)
358aa1eec08SJoseph Chen {
359aa1eec08SJoseph Chen 	struct bootloader_message bmsg;
360aa1eec08SJoseph Chen 	struct blk_desc *dev_desc;
361aa1eec08SJoseph Chen 	disk_partition_t part_info;
362aa1eec08SJoseph Chen #ifdef CONFIG_ANDROID_BOOT_IMAGE
363aa1eec08SJoseph Chen 	u32 bcb_offset = android_bcb_msg_sector_offset();
364aa1eec08SJoseph Chen #else
365aa1eec08SJoseph Chen 	u32 bcb_offset = BCB_MESSAGE_BLK_OFFSET;
366aa1eec08SJoseph Chen #endif
367aa1eec08SJoseph Chen 	int cnt, ret;
368aa1eec08SJoseph Chen 
369aa1eec08SJoseph Chen 	printf("Rebooting into recovery to do wipe_data\n");
370aa1eec08SJoseph Chen 	dev_desc = rockchip_get_bootdev();
371aa1eec08SJoseph Chen 	if (!dev_desc) {
372aa1eec08SJoseph Chen 		printf("%s: dev_desc is NULL!\n", __func__);
373aa1eec08SJoseph Chen 		return;
374aa1eec08SJoseph Chen 	}
375aa1eec08SJoseph Chen 
376aa1eec08SJoseph Chen 	ret = part_get_info_by_name(dev_desc, PART_MISC, &part_info);
377aa1eec08SJoseph Chen 	if (ret < 0) {
378aa1eec08SJoseph Chen 		printf("%s: Could not found misc partition, just run recovery\n",
379aa1eec08SJoseph Chen 		       __func__);
380aa1eec08SJoseph Chen 		goto out;
381aa1eec08SJoseph Chen 	}
382aa1eec08SJoseph Chen 
383aa1eec08SJoseph Chen 	memset((char *)&bmsg, 0, sizeof(struct bootloader_message));
384aa1eec08SJoseph Chen 	strcpy(bmsg.command, "boot-recovery");
385aa1eec08SJoseph Chen 	strcpy(bmsg.recovery, "recovery\n--wipe_data");
386aa1eec08SJoseph Chen 	bmsg.status[0] = 0;
387aa1eec08SJoseph Chen 	cnt = DIV_ROUND_UP(sizeof(struct bootloader_message), dev_desc->blksz);
388aa1eec08SJoseph Chen 	ret = blk_dwrite(dev_desc, part_info.start + bcb_offset, cnt, &bmsg);
389aa1eec08SJoseph Chen 	if (ret != cnt)
390aa1eec08SJoseph Chen 		printf("Wipe data failed, ret=%d\n", ret);
391aa1eec08SJoseph Chen out:
392aa1eec08SJoseph Chen 	/* now reboot to recovery */
393aa1eec08SJoseph Chen 	env_set("reboot_mode", "recovery");
394aa1eec08SJoseph Chen 	run_command("run bootcmd", 0);
395aa1eec08SJoseph Chen }
396bc4ccd53SJoseph Chen 
39750c37953SJoseph Chen #if defined(CONFIG_USING_KERNEL_DTB) || defined(CONFIG_CMD_BOOTM) || \
39850c37953SJoseph Chen     defined(CONFIG_CMD_BOOTZ) || defined(CONFIG_CMD_BOOTI)
399bc4ccd53SJoseph Chen #ifdef CONFIG_ROCKCHIP_DTB_VERIFY
fdt_check_hash(void * fdt_addr,u32 fdt_size,char * hash_cmp,u32 hash_size)400bc4ccd53SJoseph Chen static int fdt_check_hash(void *fdt_addr, u32 fdt_size,
401bc4ccd53SJoseph Chen 			  char *hash_cmp, u32 hash_size)
402bc4ccd53SJoseph Chen {
403bc4ccd53SJoseph Chen 	uchar hash[32];
40454e2fee2SJoseph Chen #ifdef CONFIG_ARMV8_CRYPTO
40554e2fee2SJoseph Chen 	char *engine = "ce";
40654e2fee2SJoseph Chen #elif defined(CONFIG_DM_CRYPTO)
40754e2fee2SJoseph Chen 	char *engine = "c";
408bc4ccd53SJoseph Chen #else
40954e2fee2SJoseph Chen 	char *engine = "s";
41054e2fee2SJoseph Chen #endif
411bc4ccd53SJoseph Chen 
412bc4ccd53SJoseph Chen 	if (!hash_size)
413bc4ccd53SJoseph Chen 		return 0;
414bc4ccd53SJoseph Chen 
415bc4ccd53SJoseph Chen 	if (hash_size == 20)
416bc4ccd53SJoseph Chen 		sha1_csum((const uchar *)fdt_addr, fdt_size, hash);
417bc4ccd53SJoseph Chen 	else if (hash_size == 32)
418bc4ccd53SJoseph Chen 		sha256_csum((const uchar *)fdt_addr, fdt_size, hash);
419bc4ccd53SJoseph Chen 	else
420bc4ccd53SJoseph Chen 		return -EINVAL;
421bc4ccd53SJoseph Chen 
42254e2fee2SJoseph Chen 	printf("HASH(%s): ", engine);
423bc4ccd53SJoseph Chen 	if (memcmp(hash, hash_cmp, hash_size)) {
424bc4ccd53SJoseph Chen 		printf("error\n");
425bc4ccd53SJoseph Chen 		return -EBADF;
426bc4ccd53SJoseph Chen 	}
427bc4ccd53SJoseph Chen 
428bc4ccd53SJoseph Chen 	printf("OK\n");
429bc4ccd53SJoseph Chen 
430bc4ccd53SJoseph Chen 	return 0;
431bc4ccd53SJoseph Chen }
432bc4ccd53SJoseph Chen #endif	/* CONFIG_ROCKCHIP_DTB_VERIFY */
433bc4ccd53SJoseph Chen 
434bc4ccd53SJoseph Chen #if defined(CONFIG_ROCKCHIP_EARLY_DISTRO_DTB)
rockchip_read_distro_dtb(void * fdt_addr)435bc4ccd53SJoseph Chen static int rockchip_read_distro_dtb(void *fdt_addr)
436bc4ccd53SJoseph Chen {
437bc4ccd53SJoseph Chen 	const char *cmd = "part list ${devtype} ${devnum} -bootable devplist";
438bc4ccd53SJoseph Chen 	char *devnum, *devtype, *devplist;
439bc4ccd53SJoseph Chen 	char devnum_part[12];
440bc4ccd53SJoseph Chen 	char fdt_hex_str[19];
441bc4ccd53SJoseph Chen 	char *fs_argv[5];
442bc4ccd53SJoseph Chen 
443bc4ccd53SJoseph Chen 	if (!rockchip_get_bootdev() || !fdt_addr)
444bc4ccd53SJoseph Chen 		return -ENODEV;
445bc4ccd53SJoseph Chen 
446bc4ccd53SJoseph Chen 	if (run_command_list(cmd, -1, 0)) {
447bc4ccd53SJoseph Chen 		printf("Failed to find -bootable\n");
448bc4ccd53SJoseph Chen 		return -EINVAL;
449bc4ccd53SJoseph Chen 	}
450bc4ccd53SJoseph Chen 
451bc4ccd53SJoseph Chen 	devplist = env_get("devplist");
452bc4ccd53SJoseph Chen 	if (!devplist)
45384774875SJoseph Chen 		devplist = "1";
454bc4ccd53SJoseph Chen 
455bc4ccd53SJoseph Chen 	devtype = env_get("devtype");
456bc4ccd53SJoseph Chen 	devnum = env_get("devnum");
457bc4ccd53SJoseph Chen 	sprintf(devnum_part, "%s:%s", devnum, devplist);
458bc4ccd53SJoseph Chen 	sprintf(fdt_hex_str, "0x%lx", (ulong)fdt_addr);
459bc4ccd53SJoseph Chen 
460bc4ccd53SJoseph Chen 	fs_argv[0] = "load";
461bc4ccd53SJoseph Chen 	fs_argv[1] = devtype,
462bc4ccd53SJoseph Chen 	fs_argv[2] = devnum_part;
463bc4ccd53SJoseph Chen 	fs_argv[3] = fdt_hex_str;
464bc4ccd53SJoseph Chen 	fs_argv[4] = CONFIG_ROCKCHIP_EARLY_DISTRO_DTB_PATH;
465bc4ccd53SJoseph Chen 
466bc4ccd53SJoseph Chen 	if (do_load(NULL, 0, 5, fs_argv, FS_TYPE_ANY))
467bc4ccd53SJoseph Chen 		return -EIO;
468bc4ccd53SJoseph Chen 
469bc4ccd53SJoseph Chen 	if (fdt_check_header(fdt_addr))
470bc4ccd53SJoseph Chen 		return -EBADF;
471bc4ccd53SJoseph Chen 
472bc4ccd53SJoseph Chen 	printf("DTB(Distro): %s\n", CONFIG_ROCKCHIP_EARLY_DISTRO_DTB_PATH);
473bc4ccd53SJoseph Chen 
474bc4ccd53SJoseph Chen 	return 0;
475bc4ccd53SJoseph Chen }
476bc4ccd53SJoseph Chen #endif
477bc4ccd53SJoseph Chen 
47825a706d2SJoseph Chen enum {
47925a706d2SJoseph Chen 	LOCATE_DISTRO,
48025a706d2SJoseph Chen 	LOCATE_RESOURCE,
48125a706d2SJoseph Chen 	LOCATE_FIT,
48225a706d2SJoseph Chen 	LOCATE_END,
48325a706d2SJoseph Chen };
48425a706d2SJoseph Chen 
dtb_scan(void * fdt,int where)4856ea28a6cSJoseph Chen static int dtb_scan(void *fdt, int where)
486bc4ccd53SJoseph Chen {
48725a706d2SJoseph Chen 	if (where == LOCATE_DISTRO) {
488bc4ccd53SJoseph Chen #ifdef CONFIG_ROCKCHIP_EARLY_DISTRO_DTB
48925a706d2SJoseph Chen 		return rockchip_read_distro_dtb(fdt);
490bc4ccd53SJoseph Chen #endif
49125a706d2SJoseph Chen 	} else if (where == LOCATE_RESOURCE) {
49225a706d2SJoseph Chen #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE
49325a706d2SJoseph Chen 		int hash_size = 0;
49425a706d2SJoseph Chen 		char *hash;
49525a706d2SJoseph Chen 		u32 ret;
49625a706d2SJoseph Chen 
49725a706d2SJoseph Chen 		ret = rockchip_read_resource_dtb(fdt, &hash, &hash_size);
498bc4ccd53SJoseph Chen 		if (ret) {
4997bcb4b0dSJoseph Chen 			printf("Failed to load DTB, ret=%d\n", ret);
500bc4ccd53SJoseph Chen 			return ret;
501bc4ccd53SJoseph Chen 		}
502bc4ccd53SJoseph Chen 
50325a706d2SJoseph Chen 		if (fdt_check_header(fdt)) {
5047bcb4b0dSJoseph Chen 			printf("Invalid DTB magic !\n");
505bc4ccd53SJoseph Chen 			return -EBADF;
506bc4ccd53SJoseph Chen 		}
507bc4ccd53SJoseph Chen #ifdef CONFIG_ROCKCHIP_DTB_VERIFY
50825a706d2SJoseph Chen 		if (hash_size && fdt_check_hash(fdt,
50925a706d2SJoseph Chen 			fdt_totalsize(fdt), hash, hash_size)) {
5107bcb4b0dSJoseph Chen 			printf("Invalid DTB hash !\n");
511bc4ccd53SJoseph Chen 			return -EBADF;
512bc4ccd53SJoseph Chen 		}
513bc4ccd53SJoseph Chen #endif
51425a706d2SJoseph Chen 		return 0;
51525a706d2SJoseph Chen #endif
51625a706d2SJoseph Chen 	} else if (where == LOCATE_FIT) {
51725a706d2SJoseph Chen #if defined(CONFIG_ROCKCHIP_FIT_IMAGE) && !defined(CONFIG_ROCKCHIP_RESOURCE_IMAGE)
51825a706d2SJoseph Chen 		return fit_image_read_dtb(fdt);
51925a706d2SJoseph Chen #endif
52025a706d2SJoseph Chen 	}
52125a706d2SJoseph Chen 
52225a706d2SJoseph Chen 	return -EINVAL;
52325a706d2SJoseph Chen }
52425a706d2SJoseph Chen 
rockchip_read_dtb_file(void * fdt)52525a706d2SJoseph Chen int rockchip_read_dtb_file(void *fdt)
52625a706d2SJoseph Chen {
52725a706d2SJoseph Chen 	int locate, ret;
52825a706d2SJoseph Chen 	int size;
52925a706d2SJoseph Chen 
53025a706d2SJoseph Chen 	for (locate = 0; locate < LOCATE_END; locate++) {
5316ea28a6cSJoseph Chen 		ret = dtb_scan(fdt, locate);
53225a706d2SJoseph Chen 		if (!ret)
53325a706d2SJoseph Chen 			break;
53425a706d2SJoseph Chen 	}
53525a706d2SJoseph Chen 	if (ret) {
5366ea28a6cSJoseph Chen 		printf("No valid DTB, ret=%d\n", ret);
53725a706d2SJoseph Chen 		return ret;
53825a706d2SJoseph Chen 	}
53925a706d2SJoseph Chen 
54025a706d2SJoseph Chen 	/* reserved memory */
54125a706d2SJoseph Chen 	size = fdt_totalsize(fdt);
54225a706d2SJoseph Chen 	if (!sysmem_alloc_base(MEM_FDT, (phys_addr_t)fdt,
54325a706d2SJoseph Chen 		ALIGN(size, RK_BLK_SIZE) + CONFIG_SYS_FDT_PAD))
544bc4ccd53SJoseph Chen 		return -ENOMEM;
545bc4ccd53SJoseph Chen 
54625a706d2SJoseph Chen 	/* fixup/overlay */
54725a706d2SJoseph Chen 	rk_board_early_fdt_fixup(fdt);
548bc4ccd53SJoseph Chen #if defined(CONFIG_ANDROID_BOOT_IMAGE) && defined(CONFIG_OF_LIBFDT_OVERLAY)
54925a706d2SJoseph Chen 	android_fdt_overlay_apply((void *)fdt);
550bc4ccd53SJoseph Chen #endif
551bc4ccd53SJoseph Chen 
552bc4ccd53SJoseph Chen 	return 0;
553bc4ccd53SJoseph Chen }
55450c37953SJoseph Chen #endif
55525a706d2SJoseph Chen 
rockchip_ram_read_dtb_file(void * img,void * fdt)55625a706d2SJoseph Chen int rockchip_ram_read_dtb_file(void *img, void *fdt)
55725a706d2SJoseph Chen {
55825a706d2SJoseph Chen 	int format;
55925a706d2SJoseph Chen 	int ret;
56025a706d2SJoseph Chen 
56125a706d2SJoseph Chen 	format = (genimg_get_format(img));
56225a706d2SJoseph Chen #ifdef CONFIG_ANDROID_BOOT_IMAGE
56325a706d2SJoseph Chen 	if (format == IMAGE_FORMAT_ANDROID) {
56425a706d2SJoseph Chen 		struct andr_img_hdr *hdr = img;
56525a706d2SJoseph Chen 		struct blk_desc *dev_desc;
56625a706d2SJoseph Chen 		ulong offset;
56725a706d2SJoseph Chen 
56825a706d2SJoseph Chen 		dev_desc = rockchip_get_bootdev();
56925a706d2SJoseph Chen 		if (!dev_desc)
57025a706d2SJoseph Chen 			return -ENODEV;
57125a706d2SJoseph Chen 
57225a706d2SJoseph Chen 		offset = hdr->page_size + ALIGN(hdr->kernel_size, hdr->page_size) +
57325a706d2SJoseph Chen 			ALIGN(hdr->ramdisk_size, hdr->page_size);
57425a706d2SJoseph Chen #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE
5756ea28a6cSJoseph Chen 		ret = resource_setup_ram_list(dev_desc, (void *)hdr + offset);
57625a706d2SJoseph Chen 		if (ret)
57725a706d2SJoseph Chen 			return ret;
57825a706d2SJoseph Chen 
57925a706d2SJoseph Chen 		return rockchip_read_dtb_file((void *)fdt);
58025a706d2SJoseph Chen #else
58125a706d2SJoseph Chen 		if (fdt_check_header((void *)offset))
58225a706d2SJoseph Chen 			return -EINVAL;
58325a706d2SJoseph Chen 
58425a706d2SJoseph Chen 		memcpy(fdt, (char *)offset, fdt_totalsize(offset));
58525a706d2SJoseph Chen 		if (!sysmem_alloc_base(MEM_FDT, (phys_addr_t)fdt,
58625a706d2SJoseph Chen 			ALIGN(fdt_totalsize(fdt), RK_BLK_SIZE) + CONFIG_SYS_FDT_PAD))
58725a706d2SJoseph Chen 			return -ENOMEM;
58825a706d2SJoseph Chen 
58925a706d2SJoseph Chen 		return 0;
59025a706d2SJoseph Chen #endif
59125a706d2SJoseph Chen 	}
59225a706d2SJoseph Chen #endif
59325a706d2SJoseph Chen #if IMAGE_ENABLE_FIT
59425a706d2SJoseph Chen 	if (format == IMAGE_FORMAT_FIT) {
59525a706d2SJoseph Chen 		const void *data;
59625a706d2SJoseph Chen 		size_t size;
59725a706d2SJoseph Chen 		int noffset;
59825a706d2SJoseph Chen #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE
59925a706d2SJoseph Chen 		const char *path = "/images/resource";
60025a706d2SJoseph Chen #else
60125a706d2SJoseph Chen 		const char *path = "/images/fdt";
60225a706d2SJoseph Chen #endif
60325a706d2SJoseph Chen 
60425a706d2SJoseph Chen 		noffset = fdt_path_offset(img, path);
60525a706d2SJoseph Chen 		if (noffset < 0)
60625a706d2SJoseph Chen 			return noffset;
60725a706d2SJoseph Chen 
60825a706d2SJoseph Chen #ifdef CONFIG_ROCKCHIP_RESOURCE_IMAGE
60925a706d2SJoseph Chen 		ret = fit_image_get_data(img, noffset, &data, &size);
61025a706d2SJoseph Chen 		if (ret < 0)
61125a706d2SJoseph Chen 			return ret;
61225a706d2SJoseph Chen 
61325a706d2SJoseph Chen 		dev_desc = rockchip_get_bootdev();
61425a706d2SJoseph Chen 		if (!dev_desc)
61525a706d2SJoseph Chen 			return -ENODEV;
61625a706d2SJoseph Chen 
6176ea28a6cSJoseph Chen 		ret = resource_setup_ram_list(dev_desc, (void *)data);
61825a706d2SJoseph Chen 		if (ret) {
6196ea28a6cSJoseph Chen 			printf("resource_setup_ram_list fail, ret=%d\n", ret);
62025a706d2SJoseph Chen 			return ret;
62125a706d2SJoseph Chen 		}
62225a706d2SJoseph Chen 
62325a706d2SJoseph Chen 		return rockchip_read_dtb_file((void *)fdt);
62425a706d2SJoseph Chen #else
62525a706d2SJoseph Chen 
62625a706d2SJoseph Chen 		ret = fit_image_get_data(img, noffset, &data, &size);
62725a706d2SJoseph Chen 		if (ret)
62825a706d2SJoseph Chen 			return ret;
62925a706d2SJoseph Chen 
63025a706d2SJoseph Chen 		if (fdt_check_header(data))
63125a706d2SJoseph Chen 			return -EINVAL;
63225a706d2SJoseph Chen 
63325a706d2SJoseph Chen 		memcpy(fdt, data, size);
63425a706d2SJoseph Chen 		if (!sysmem_alloc_base(MEM_FDT, (phys_addr_t)fdt,
63525a706d2SJoseph Chen 			ALIGN(fdt_totalsize(fdt), RK_BLK_SIZE) + CONFIG_SYS_FDT_PAD))
63625a706d2SJoseph Chen 			return -ENOMEM;
63725a706d2SJoseph Chen 
63825a706d2SJoseph Chen 		printf("Load DTB from 'images/fdt'\n");
63925a706d2SJoseph Chen 
64025a706d2SJoseph Chen 		return 0;
64125a706d2SJoseph Chen #endif
64225a706d2SJoseph Chen 	}
64325a706d2SJoseph Chen #endif
64425a706d2SJoseph Chen 
64525a706d2SJoseph Chen 	return -EINVAL;
64625a706d2SJoseph Chen }
647