xref: /rk3399_rockchip-uboot/arch/arm/mach-rockchip/board.c (revision ee7b0fb8d50f25a5931c44fdb4e6d237e527199a)
138771996SKever Yang /*
238771996SKever Yang  * (C) Copyright 2017 Rockchip Electronics Co., Ltd.
338771996SKever Yang  *
438771996SKever Yang  * SPDX-License-Identifier:     GPL-2.0+
538771996SKever Yang  */
62208cd92SJoseph Chen 
738771996SKever Yang #include <common.h>
850d35c45SJoseph Chen #include <amp.h>
9ac5d8aa9SJoseph Chen #include <android_bootloader.h>
10ac5d8aa9SJoseph Chen #include <android_image.h>
1186f870d6SJoseph Chen #include <bidram.h>
120ed06f16SJoseph Chen #include <boot_rkimg.h>
130ed06f16SJoseph Chen #include <cli.h>
142208cd92SJoseph Chen #include <clk.h>
152208cd92SJoseph Chen #include <console.h>
16575777c5SKever Yang #include <debug_uart.h>
172208cd92SJoseph Chen #include <dm.h>
182208cd92SJoseph Chen #include <dvfs.h>
192208cd92SJoseph Chen #include <io-domain.h>
2003fd0d5bSJoseph Chen #include <image.h>
217397b961SJoseph Chen #include <key.h>
2286f870d6SJoseph Chen #include <memblk.h>
232208cd92SJoseph Chen #include <misc.h>
242208cd92SJoseph Chen #include <of_live.h>
25459f5cb0SJason Zhu #include <mtd_blk.h>
2638771996SKever Yang #include <ram.h>
272208cd92SJoseph Chen #include <rockchip_debugger.h>
2838771996SKever Yang #include <syscon.h>
296929f85bSJoseph Chen #include <sysmem.h>
302208cd92SJoseph Chen #include <video_rockchip.h>
3138771996SKever Yang #include <asm/io.h>
3238771996SKever Yang #include <asm/gpio.h>
333e45175eSJoseph Chen #include <dm/uclass-internal.h>
342208cd92SJoseph Chen #include <dm/root.h>
352208cd92SJoseph Chen #include <power/charge_display.h>
362208cd92SJoseph Chen #include <power/regulator.h>
3703fd0d5bSJoseph Chen #include <optee_include/OpteeClientInterface.h>
38396e3049SElon Zhang #include <optee_include/OpteeClientApiLib.h>
39c29dd8c4SJoseph Chen #include <optee_include/tee_api_defines.h>
402208cd92SJoseph Chen #include <asm/arch/boot_mode.h>
4138771996SKever Yang #include <asm/arch/clock.h>
4260ea26bdSJoseph Chen #include <asm/arch/cpu.h>
43c664909eSJoseph Chen #include <asm/arch/hotkey.h>
446929f85bSJoseph Chen #include <asm/arch/param.h>
452208cd92SJoseph Chen #include <asm/arch/periph.h>
462208cd92SJoseph Chen #include <asm/arch/resource_img.h>
472208cd92SJoseph Chen #include <asm/arch/rk_atags.h>
482208cd92SJoseph Chen #include <asm/arch/vendor.h>
49efeef7e5SWenping Zhang #ifdef CONFIG_ROCKCHIP_EINK_DISPLAY
50efeef7e5SWenping Zhang #include <rk_eink.h>
51efeef7e5SWenping Zhang #endif
5238771996SKever Yang DECLARE_GLOBAL_DATA_PTR;
5338771996SKever Yang 
5438771996SKever Yang __weak int rk_board_late_init(void)
5538771996SKever Yang {
5638771996SKever Yang 	return 0;
5738771996SKever Yang }
5838771996SKever Yang 
5938ce6261SJoseph Chen __weak int rk_board_fdt_fixup(void *blob)
6038ce6261SJoseph Chen {
6138ce6261SJoseph Chen 	return 0;
6238ce6261SJoseph Chen }
6338ce6261SJoseph Chen 
64efdbac34SFinley Xiao __weak int soc_clk_dump(void)
65efdbac34SFinley Xiao {
66efdbac34SFinley Xiao 	return 0;
67efdbac34SFinley Xiao }
68efdbac34SFinley Xiao 
69058e5d94SFinley Xiao __weak int set_armclk_rate(void)
70058e5d94SFinley Xiao {
71058e5d94SFinley Xiao 	return 0;
72058e5d94SFinley Xiao }
73058e5d94SFinley Xiao 
742208cd92SJoseph Chen __weak int rk_board_init(void)
752208cd92SJoseph Chen {
762208cd92SJoseph Chen 	return 0;
772208cd92SJoseph Chen }
782208cd92SJoseph Chen 
792208cd92SJoseph Chen /*
802208cd92SJoseph Chen  * define serialno max length, the max length is 512 Bytes
812208cd92SJoseph Chen  * The remaining bytes are used to ensure that the first 512 bytes
822208cd92SJoseph Chen  * are valid when executing 'env_set("serial#", value)'.
832208cd92SJoseph Chen  */
842208cd92SJoseph Chen #define VENDOR_SN_MAX	513
852208cd92SJoseph Chen #define CPUID_LEN	0x10
862208cd92SJoseph Chen #define CPUID_OFF	0x07
872208cd92SJoseph Chen 
882e32f666SDavid Wu #define MAX_ETHERNET	0x2
892e32f666SDavid Wu 
902208cd92SJoseph Chen static int rockchip_set_ethaddr(void)
912208cd92SJoseph Chen {
922208cd92SJoseph Chen #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION
932e32f666SDavid Wu 	char buf[ARP_HLEN_ASCII + 1], mac[16];
942e32f666SDavid Wu 	u8 ethaddr[ARP_HLEN * MAX_ETHERNET] = {0};
952e32f666SDavid Wu 	int ret, i;
962cde40a1SDavid Wu 	bool need_write = false, randomed = false;
972208cd92SJoseph Chen 
982208cd92SJoseph Chen 	ret = vendor_storage_read(VENDOR_LAN_MAC_ID, ethaddr, sizeof(ethaddr));
992e32f666SDavid Wu 	for (i = 0; i < MAX_ETHERNET; i++) {
1002e32f666SDavid Wu 		if (ret <= 0 || !is_valid_ethaddr(&ethaddr[i * ARP_HLEN])) {
1012cde40a1SDavid Wu 			if (!randomed) {
1022e32f666SDavid Wu 				net_random_ethaddr(&ethaddr[i * ARP_HLEN]);
1032cde40a1SDavid Wu 				randomed = true;
1042cde40a1SDavid Wu 			} else {
1052cde40a1SDavid Wu 				if (i > 0) {
1062cde40a1SDavid Wu 					memcpy(&ethaddr[i * ARP_HLEN],
1072cde40a1SDavid Wu 					       &ethaddr[(i - 1) * ARP_HLEN],
1082cde40a1SDavid Wu 					       ARP_HLEN);
1092cde40a1SDavid Wu 					ethaddr[i * ARP_HLEN] |= 0x02;
1102cde40a1SDavid Wu 					ethaddr[i * ARP_HLEN] += (i << 2);
1112cde40a1SDavid Wu 				}
1122cde40a1SDavid Wu 			}
1132cde40a1SDavid Wu 
1142e32f666SDavid Wu 			need_write = true;
1152e32f666SDavid Wu 		}
1162e32f666SDavid Wu 
1172e32f666SDavid Wu 		if (is_valid_ethaddr(&ethaddr[i * ARP_HLEN])) {
1182e32f666SDavid Wu 			sprintf(buf, "%pM", &ethaddr[i * ARP_HLEN]);
1192e32f666SDavid Wu 			if (i == 0)
1202e32f666SDavid Wu 				memcpy(mac, "ethaddr", sizeof("ethaddr"));
1212e32f666SDavid Wu 			else
1222e32f666SDavid Wu 				sprintf(mac, "eth%daddr", i);
1232e32f666SDavid Wu 			env_set(mac, buf);
1242e32f666SDavid Wu 		}
1252e32f666SDavid Wu 	}
1262e32f666SDavid Wu 
1272e32f666SDavid Wu 	if (need_write) {
1282e32f666SDavid Wu 		ret = vendor_storage_write(VENDOR_LAN_MAC_ID,
1292e32f666SDavid Wu 					   ethaddr, sizeof(ethaddr));
1302e32f666SDavid Wu 		if (ret < 0)
1312e32f666SDavid Wu 			printf("%s: vendor_storage_write failed %d\n",
1322e32f666SDavid Wu 			       __func__, ret);
1332208cd92SJoseph Chen 	}
1342208cd92SJoseph Chen #endif
1352e32f666SDavid Wu 
1362208cd92SJoseph Chen 	return 0;
1372208cd92SJoseph Chen }
1382208cd92SJoseph Chen 
1392208cd92SJoseph Chen static int rockchip_set_serialno(void)
1402208cd92SJoseph Chen {
1412208cd92SJoseph Chen 	u8 low[CPUID_LEN / 2], high[CPUID_LEN / 2];
1422208cd92SJoseph Chen 	u8 cpuid[CPUID_LEN] = {0};
1432208cd92SJoseph Chen 	char serialno_str[VENDOR_SN_MAX];
1442208cd92SJoseph Chen 	int ret = 0, i;
1452208cd92SJoseph Chen 	u64 serialno;
1462208cd92SJoseph Chen 
1472208cd92SJoseph Chen 	/* Read serial number from vendor storage part */
1482208cd92SJoseph Chen 	memset(serialno_str, 0, VENDOR_SN_MAX);
1492208cd92SJoseph Chen 
1502208cd92SJoseph Chen #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION
1512208cd92SJoseph Chen 	ret = vendor_storage_read(VENDOR_SN_ID, serialno_str, (VENDOR_SN_MAX-1));
1522208cd92SJoseph Chen 	if (ret > 0) {
153df197bd2SJason Zhu 		i = strlen(serialno_str);
154df197bd2SJason Zhu 		for (; i > 0; i--) {
155df197bd2SJason Zhu 			if ((serialno_str[i] >= 'a' && serialno_str[i] <= 'z') ||
156df197bd2SJason Zhu 			    (serialno_str[i] >= 'A' && serialno_str[i] <= 'Z') ||
157df197bd2SJason Zhu 			    (serialno_str[i] >= '0' && serialno_str[i] <= '9'))
158df197bd2SJason Zhu 				break;
159df197bd2SJason Zhu 		}
160df197bd2SJason Zhu 
161df197bd2SJason Zhu 		serialno_str[i + 1] = 0x0;
1622208cd92SJoseph Chen 		env_set("serial#", serialno_str);
1632208cd92SJoseph Chen 	} else {
1642208cd92SJoseph Chen #endif
165d3cb8b06SSugar Zhang #if defined(CONFIG_ROCKCHIP_EFUSE) || defined(CONFIG_ROCKCHIP_OTP)
1662208cd92SJoseph Chen 		struct udevice *dev;
1672208cd92SJoseph Chen 
1682208cd92SJoseph Chen 		/* retrieve the device */
169d3cb8b06SSugar Zhang 		if (IS_ENABLED(CONFIG_ROCKCHIP_EFUSE))
1702208cd92SJoseph Chen 			ret = uclass_get_device_by_driver(UCLASS_MISC,
1712208cd92SJoseph Chen 							  DM_GET_DRIVER(rockchip_efuse),
1722208cd92SJoseph Chen 							  &dev);
173d3cb8b06SSugar Zhang 		else
174d3cb8b06SSugar Zhang 			ret = uclass_get_device_by_driver(UCLASS_MISC,
175d3cb8b06SSugar Zhang 							  DM_GET_DRIVER(rockchip_otp),
176d3cb8b06SSugar Zhang 							  &dev);
177d3cb8b06SSugar Zhang 
1782208cd92SJoseph Chen 		if (ret) {
179d3cb8b06SSugar Zhang 			printf("%s: could not find efuse/otp device\n", __func__);
1802208cd92SJoseph Chen 			return ret;
1812208cd92SJoseph Chen 		}
1822208cd92SJoseph Chen 
1832208cd92SJoseph Chen 		/* read the cpu_id range from the efuses */
1842208cd92SJoseph Chen 		ret = misc_read(dev, CPUID_OFF, &cpuid, sizeof(cpuid));
1852208cd92SJoseph Chen 		if (ret) {
186d3cb8b06SSugar Zhang 			printf("%s: read cpuid from efuse/otp failed, ret=%d\n",
1872208cd92SJoseph Chen 			       __func__, ret);
1882208cd92SJoseph Chen 			return ret;
1892208cd92SJoseph Chen 		}
1902208cd92SJoseph Chen #else
1912208cd92SJoseph Chen 		/* generate random cpuid */
1922208cd92SJoseph Chen 		for (i = 0; i < CPUID_LEN; i++)
1932208cd92SJoseph Chen 			cpuid[i] = (u8)(rand());
1942208cd92SJoseph Chen #endif
1952208cd92SJoseph Chen 		/* Generate the serial number based on CPU ID */
1962208cd92SJoseph Chen 		for (i = 0; i < 8; i++) {
1972208cd92SJoseph Chen 			low[i] = cpuid[1 + (i << 1)];
1982208cd92SJoseph Chen 			high[i] = cpuid[i << 1];
1992208cd92SJoseph Chen 		}
2002208cd92SJoseph Chen 
2012208cd92SJoseph Chen 		serialno = crc32_no_comp(0, low, 8);
2022208cd92SJoseph Chen 		serialno |= (u64)crc32_no_comp(serialno, high, 8) << 32;
2032208cd92SJoseph Chen 		snprintf(serialno_str, sizeof(serialno_str), "%llx", serialno);
2042208cd92SJoseph Chen 
2052208cd92SJoseph Chen 		env_set("serial#", serialno_str);
2062208cd92SJoseph Chen #ifdef CONFIG_ROCKCHIP_VENDOR_PARTITION
2072208cd92SJoseph Chen 	}
2082208cd92SJoseph Chen #endif
2092208cd92SJoseph Chen 
2102208cd92SJoseph Chen 	return ret;
2112208cd92SJoseph Chen }
2122208cd92SJoseph Chen 
2132208cd92SJoseph Chen #if defined(CONFIG_USB_FUNCTION_FASTBOOT)
2142208cd92SJoseph Chen int fb_set_reboot_flag(void)
2152208cd92SJoseph Chen {
2162208cd92SJoseph Chen 	printf("Setting reboot to fastboot flag ...\n");
2172208cd92SJoseph Chen 	writel(BOOT_FASTBOOT, CONFIG_ROCKCHIP_BOOT_MODE_REG);
2182208cd92SJoseph Chen 
2192208cd92SJoseph Chen 	return 0;
2202208cd92SJoseph Chen }
2212208cd92SJoseph Chen #endif
2222208cd92SJoseph Chen 
2230ed06f16SJoseph Chen #ifdef CONFIG_ROCKCHIP_USB_BOOT
2240ed06f16SJoseph Chen static int boot_from_udisk(void)
2250ed06f16SJoseph Chen {
2260ed06f16SJoseph Chen 	struct blk_desc *desc;
2270ed06f16SJoseph Chen 	char *devtype;
2280ed06f16SJoseph Chen 	char *devnum;
2290ed06f16SJoseph Chen 
2300ed06f16SJoseph Chen 	devtype = env_get("devtype");
2310ed06f16SJoseph Chen 	devnum = env_get("devnum");
2320ed06f16SJoseph Chen 
2330ed06f16SJoseph Chen 	/* Booting priority: mmc1 > udisk */
2340ed06f16SJoseph Chen 	if (!strcmp(devtype, "mmc") && !strcmp(devnum, "1"))
2350ed06f16SJoseph Chen 		return 0;
2360ed06f16SJoseph Chen 
2370ed06f16SJoseph Chen 	if (!run_command("usb start", -1)) {
2380ed06f16SJoseph Chen 		desc = blk_get_devnum_by_type(IF_TYPE_USB, 0);
2390ed06f16SJoseph Chen 		if (!desc) {
2400ed06f16SJoseph Chen 			printf("No usb device found\n");
2410ed06f16SJoseph Chen 			return -ENODEV;
2420ed06f16SJoseph Chen 		}
2430ed06f16SJoseph Chen 
2440ed06f16SJoseph Chen 		if (!run_command("rkimgtest usb 0", -1)) {
2450ed06f16SJoseph Chen 			rockchip_set_bootdev(desc);
2460ed06f16SJoseph Chen 			env_set("devtype", "usb");
2470ed06f16SJoseph Chen 			env_set("devnum", "0");
2480ed06f16SJoseph Chen 			printf("Boot from usb 0\n");
2490ed06f16SJoseph Chen 		} else {
2500ed06f16SJoseph Chen 			printf("No usb dev 0 found\n");
2510ed06f16SJoseph Chen 			return -ENODEV;
2520ed06f16SJoseph Chen 		}
2530ed06f16SJoseph Chen 	}
2540ed06f16SJoseph Chen 
2550ed06f16SJoseph Chen 	return 0;
2560ed06f16SJoseph Chen }
2570ed06f16SJoseph Chen #endif
2580ed06f16SJoseph Chen 
259c6f0e819SJoseph Chen static void env_fixup(void)
260c6f0e819SJoseph Chen {
261c6f0e819SJoseph Chen 	struct memblock mem;
262c6f0e819SJoseph Chen 	ulong u_addr_r;
263c6f0e819SJoseph Chen 	phys_size_t end;
264c6f0e819SJoseph Chen 	char *addr_r;
265c6f0e819SJoseph Chen 
266c6f0e819SJoseph Chen #ifdef ENV_MEM_LAYOUT_SETTINGS1
267c6f0e819SJoseph Chen 	const char *env_addr0[] = {
268c6f0e819SJoseph Chen 		"scriptaddr", "pxefile_addr_r",
269c6f0e819SJoseph Chen 		"fdt_addr_r", "kernel_addr_r", "ramdisk_addr_r",
270c6f0e819SJoseph Chen 	};
271c6f0e819SJoseph Chen 	const char *env_addr1[] = {
272c6f0e819SJoseph Chen 		"scriptaddr1", "pxefile_addr1_r",
273c6f0e819SJoseph Chen 		"fdt_addr1_r", "kernel_addr1_r", "ramdisk_addr1_r",
274c6f0e819SJoseph Chen 	};
275c6f0e819SJoseph Chen 	int i;
276c6f0e819SJoseph Chen 
277c6f0e819SJoseph Chen 	/* 128M is a typical ram size for most platform, so as default here */
278c6f0e819SJoseph Chen 	if (gd->ram_size <= SZ_128M) {
279c6f0e819SJoseph Chen 		/* Replace orignal xxx_addr_r */
280c6f0e819SJoseph Chen 		for (i = 0; i < ARRAY_SIZE(env_addr1); i++) {
281c6f0e819SJoseph Chen 			addr_r = env_get(env_addr1[i]);
282c6f0e819SJoseph Chen 			if (addr_r)
283c6f0e819SJoseph Chen 				env_set(env_addr0[i], addr_r);
284c6f0e819SJoseph Chen 		}
285c6f0e819SJoseph Chen 	}
286c6f0e819SJoseph Chen #endif
2874175c722SJoseph Chen 	/* If BL32 is disabled, move kernel to lower address. */
288c6f0e819SJoseph Chen 	if (!(gd->flags & GD_FLG_BL32_ENABLED)) {
289c6f0e819SJoseph Chen 		addr_r = env_get("kernel_addr_no_bl32_r");
290c6f0e819SJoseph Chen 		if (addr_r)
291c6f0e819SJoseph Chen 			env_set("kernel_addr_r", addr_r);
2924175c722SJoseph Chen 
2934175c722SJoseph Chen 		/*
2944175c722SJoseph Chen 		 * 0x0a200000 and 0x08400000 are rockchip traditional address
2954175c722SJoseph Chen 		 * of BL32 and ramdisk:
2964175c722SJoseph Chen 		 *
2974175c722SJoseph Chen 		 * |------------|------------|
2984175c722SJoseph Chen 		 * |    BL32    |  ramdisk   |
2994175c722SJoseph Chen 		 * |------------|------------|
3004175c722SJoseph Chen 		 *
3014175c722SJoseph Chen 		 * Move ramdisk to BL32 address to fix sysmem alloc failed
3024175c722SJoseph Chen 		 * issue on the board with critical memory(ie. 256MB).
3034175c722SJoseph Chen 		 */
3044175c722SJoseph Chen 		if (gd->ram_size > SZ_128M && gd->ram_size <= SZ_256M) {
3054175c722SJoseph Chen 			u_addr_r = env_get_ulong("ramdisk_addr_r", 16, 0);
3064175c722SJoseph Chen 			if (u_addr_r == 0x0a200000)
3074175c722SJoseph Chen 				env_set("ramdisk_addr_r", "0x08400000");
3084175c722SJoseph Chen 		}
3094175c722SJoseph Chen 
3104175c722SJoseph Chen 	/* If BL32 is enlarged, move ramdisk right behind it */
311c6f0e819SJoseph Chen 	} else {
312c6f0e819SJoseph Chen 		mem = param_parse_optee_mem();
313c6f0e819SJoseph Chen 		end = mem.base + mem.size;
314c6f0e819SJoseph Chen 		u_addr_r = env_get_ulong("ramdisk_addr_r", 16, 0);
315c6f0e819SJoseph Chen 		if (u_addr_r >= mem.base && u_addr_r < end)
316c6f0e819SJoseph Chen 			env_set_hex("ramdisk_addr_r", end);
317c6f0e819SJoseph Chen 	}
318c6f0e819SJoseph Chen }
319c6f0e819SJoseph Chen 
32083c9bd4bSJoseph Chen static void cmdline_handle(void)
32183c9bd4bSJoseph Chen {
32283c9bd4bSJoseph Chen #ifdef CONFIG_ROCKCHIP_PRELOADER_ATAGS
32383c9bd4bSJoseph Chen 	struct tag *t;
32483c9bd4bSJoseph Chen 
32583c9bd4bSJoseph Chen 	t = atags_get_tag(ATAG_PUB_KEY);
32683c9bd4bSJoseph Chen 	if (t) {
32783c9bd4bSJoseph Chen 		/* Pass if efuse/otp programmed */
32883c9bd4bSJoseph Chen 		if (t->u.pub_key.flag == PUBKEY_FUSE_PROGRAMMED)
32983c9bd4bSJoseph Chen 			env_update("bootargs", "fuse.programmed=1");
33083c9bd4bSJoseph Chen 		else
33183c9bd4bSJoseph Chen 			env_update("bootargs", "fuse.programmed=0");
33283c9bd4bSJoseph Chen 	}
33383c9bd4bSJoseph Chen #endif
33483c9bd4bSJoseph Chen }
33583c9bd4bSJoseph Chen 
33638771996SKever Yang int board_late_init(void)
33738771996SKever Yang {
3382549364dSlanshh 	rockchip_set_ethaddr();
339fc1a5563SJason Zhu 	rockchip_set_serialno();
340d04ada6cSJoseph Chen 	setup_download_mode();
34138771996SKever Yang #if (CONFIG_ROCKCHIP_BOOT_MODE_REG > 0)
34238771996SKever Yang 	setup_boot_mode();
34338771996SKever Yang #endif
3440ed06f16SJoseph Chen #ifdef CONFIG_ROCKCHIP_USB_BOOT
3450ed06f16SJoseph Chen 	boot_from_udisk();
3460ed06f16SJoseph Chen #endif
34738771996SKever Yang #ifdef CONFIG_DM_CHARGE_DISPLAY
34838771996SKever Yang 	charge_display();
34938771996SKever Yang #endif
35038771996SKever Yang #ifdef CONFIG_DRM_ROCKCHIP
35138771996SKever Yang 	rockchip_show_logo();
35238771996SKever Yang #endif
353efeef7e5SWenping Zhang #ifdef CONFIG_ROCKCHIP_EINK_DISPLAY
354efeef7e5SWenping Zhang 	rockchip_eink_show_uboot_logo();
355efeef7e5SWenping Zhang #endif
356c6f0e819SJoseph Chen 	env_fixup();
357efdbac34SFinley Xiao 	soc_clk_dump();
35883c9bd4bSJoseph Chen 	cmdline_handle();
359efdbac34SFinley Xiao 
36038771996SKever Yang 	return rk_board_late_init();
36138771996SKever Yang }
36238771996SKever Yang 
363a7940145SJoseph Chen static void early_download(void)
364644804edSJoseph Chen {
3657397b961SJoseph Chen #if defined(CONFIG_PWRKEY_DNL_TRIGGER_NUM) && \
3667397b961SJoseph Chen 		(CONFIG_PWRKEY_DNL_TRIGGER_NUM > 0)
3677397b961SJoseph Chen 	if (pwrkey_download_init())
3687397b961SJoseph Chen 		printf("Pwrkey download init failed\n");
3697397b961SJoseph Chen #endif
3707397b961SJoseph Chen 
371644804edSJoseph Chen #if (CONFIG_ROCKCHIP_BOOT_MODE_REG > 0)
372c664909eSJoseph Chen 	if (is_hotkey(HK_BROM_DNL)) {
373644804edSJoseph Chen 		printf("Enter bootrom download...");
374363411a1SJoseph Chen 		flushc();
375644804edSJoseph Chen 		writel(BOOT_BROM_DOWNLOAD, CONFIG_ROCKCHIP_BOOT_MODE_REG);
376644804edSJoseph Chen 		do_reset(NULL, 0, 0, NULL);
377644804edSJoseph Chen 		printf("failed!\n");
378644804edSJoseph Chen 	}
379644804edSJoseph Chen #endif
380644804edSJoseph Chen }
381644804edSJoseph Chen 
3825d5f363eSJoseph Chen static void board_debug_init(void)
3835d5f363eSJoseph Chen {
38493586e70SJoseph Chen 	if (!gd->serial.using_pre_serial &&
38593586e70SJoseph Chen 	    !(gd->flags & GD_FLG_DISABLE_CONSOLE))
3867abb254dSJoseph Chen 		debug_uart_init();
38746f61401SJoseph Chen 
38846f61401SJoseph Chen 	if (tstc()) {
38946f61401SJoseph Chen 		gd->console_evt = getc();
39046f61401SJoseph Chen 		if (gd->console_evt <= 0x1a) /* 'z' */
39146f61401SJoseph Chen 			printf("Hotkey: ctrl+%c\n", gd->console_evt + 'a' - 1);
39246f61401SJoseph Chen 	}
3939889a0e0SJoseph Chen 
3949889a0e0SJoseph Chen 	if (IS_ENABLED(CONFIG_CONSOLE_DISABLE_CLI))
39525047d3fSJoseph Chen 		printf("Cmd interface: disabled\n");
3965d5f363eSJoseph Chen }
3975d5f363eSJoseph Chen 
398459f5cb0SJason Zhu #ifdef CONFIG_MTD_BLK
399459f5cb0SJason Zhu static void board_mtd_blk_map_partitions(void)
400459f5cb0SJason Zhu {
401459f5cb0SJason Zhu 	struct blk_desc *dev_desc;
402459f5cb0SJason Zhu 
403459f5cb0SJason Zhu 	dev_desc = rockchip_get_bootdev();
404459f5cb0SJason Zhu 	if (dev_desc)
405459f5cb0SJason Zhu 		mtd_blk_map_partitions(dev_desc);
406459f5cb0SJason Zhu }
407459f5cb0SJason Zhu #endif
408459f5cb0SJason Zhu 
40938771996SKever Yang int board_init(void)
41038771996SKever Yang {
4115d5f363eSJoseph Chen 	board_debug_init();
412ebb6c439SYouMin Chen 
413f0aa8c5dSJason Zhu #ifdef DEBUG
414f0aa8c5dSJason Zhu 	soc_clk_dump();
415f0aa8c5dSJason Zhu #endif
416f0aa8c5dSJason Zhu 
417f8aaa2c2SKever Yang #ifdef CONFIG_USING_KERNEL_DTB
418459f5cb0SJason Zhu #ifdef CONFIG_MTD_BLK
419459f5cb0SJason Zhu 	board_mtd_blk_map_partitions();
420459f5cb0SJason Zhu #endif
421f8aaa2c2SKever Yang 	init_kernel_dtb();
422f8aaa2c2SKever Yang #endif
423a7940145SJoseph Chen 	early_download();
4247397b961SJoseph Chen 
4259f8e13d3SFinley Xiao 	/*
4269f8e13d3SFinley Xiao 	 * pmucru isn't referenced on some platforms, so pmucru driver can't
4279f8e13d3SFinley Xiao 	 * probe that the "assigned-clocks" is unused.
4289f8e13d3SFinley Xiao 	 */
4299f8e13d3SFinley Xiao 	clks_probe();
43038771996SKever Yang #ifdef CONFIG_DM_REGULATOR
431dba9c9e5SJoseph Chen 	if (regulators_enable_boot_on(is_hotkey(HK_REGULATOR)))
4322208cd92SJoseph Chen 		debug("%s: Can't enable boot on regulator\n", __func__);
43338771996SKever Yang #endif
434dae20286SJianqun Xu 
435dae20286SJianqun Xu #ifdef CONFIG_ROCKCHIP_IO_DOMAIN
436dae20286SJianqun Xu 	io_domain_init();
437dae20286SJianqun Xu #endif
438dae20286SJianqun Xu 
439058e5d94SFinley Xiao 	set_armclk_rate();
44038771996SKever Yang 
4413acf4edfSJoseph Chen #ifdef CONFIG_DM_DVFS
4423acf4edfSJoseph Chen 	dvfs_init(true);
4433acf4edfSJoseph Chen #endif
4443acf4edfSJoseph Chen 
44538771996SKever Yang 	return rk_board_init();
44638771996SKever Yang }
44738771996SKever Yang 
448c563adc7SJoseph Chen int interrupt_debugger_init(void)
449c563adc7SJoseph Chen {
450c563adc7SJoseph Chen #ifdef CONFIG_ROCKCHIP_DEBUGGER
4512208cd92SJoseph Chen 	return rockchip_debugger_init();
4522208cd92SJoseph Chen #else
4532208cd92SJoseph Chen 	return 0;
454c563adc7SJoseph Chen #endif
455c563adc7SJoseph Chen }
456c563adc7SJoseph Chen 
457e09b1e4aSJoseph Chen int board_fdt_fixup(void *blob)
458e09b1e4aSJoseph Chen {
4592208cd92SJoseph Chen 	/* Common fixup for DRM */
460e09b1e4aSJoseph Chen #ifdef CONFIG_DRM_ROCKCHIP
461e09b1e4aSJoseph Chen 	rockchip_display_fixup(blob);
462e09b1e4aSJoseph Chen #endif
463e09b1e4aSJoseph Chen 
46438ce6261SJoseph Chen 	return rk_board_fdt_fixup(blob);
465e09b1e4aSJoseph Chen }
466e09b1e4aSJoseph Chen 
467102dfafcSElon Zhang #if defined(CONFIG_ARM64_BOOT_AARCH32) || !defined(CONFIG_ARM64)
468e3fbd280SJoseph Chen /*
469f1d65189SJoseph Chen  * Common for OP-TEE:
470396e3049SElon Zhang  *	64-bit & 32-bit mode: share memory dcache is always enabled;
471e3fbd280SJoseph Chen  *
472f1d65189SJoseph Chen  * Common for U-Boot:
473e3fbd280SJoseph Chen  *	64-bit mode: MMU table is static defined in rkxxx.c file, all memory
474e3fbd280SJoseph Chen  *		     regions are mapped. That's good to match OP-TEE MMU policy.
475e3fbd280SJoseph Chen  *
476e3fbd280SJoseph Chen  *	32-bit mode: MMU table is setup according to gd->bd->bi_dram[..] where
477e3fbd280SJoseph Chen  *		     the OP-TEE region has been reserved, so it can not be
478102dfafcSElon Zhang  *		     mapped(i.e. dcache is disabled). That's *NOT* good to match
479e3fbd280SJoseph Chen  *		     OP-TEE MMU policy.
480e3fbd280SJoseph Chen  *
481e3fbd280SJoseph Chen  * For the data coherence when communication between U-Boot and OP-TEE, U-Boot
482e3fbd280SJoseph Chen  * should follow OP-TEE MMU policy.
483e3fbd280SJoseph Chen  *
484396e3049SElon Zhang  * So 32-bit mode U-Boot should map OP-TEE share memory as dcache enabled.
485e3fbd280SJoseph Chen  */
486e3fbd280SJoseph Chen int board_initr_caches_fixup(void)
487e3fbd280SJoseph Chen {
488396e3049SElon Zhang #ifdef CONFIG_OPTEE_CLIENT
489e3fbd280SJoseph Chen 	struct memblock mem;
490e3fbd280SJoseph Chen 
491396e3049SElon Zhang 	mem.base = 0;
492396e3049SElon Zhang 	mem.size = 0;
493396e3049SElon Zhang 
494396e3049SElon Zhang 	optee_get_shm_config(&mem.base, &mem.size);
495e3fbd280SJoseph Chen 	if (mem.size)
496e3fbd280SJoseph Chen 		mmu_set_region_dcache_behaviour(mem.base, mem.size,
497e3fbd280SJoseph Chen 						DCACHE_WRITEBACK);
498396e3049SElon Zhang #endif
499e3fbd280SJoseph Chen 	return 0;
500e3fbd280SJoseph Chen }
501e3fbd280SJoseph Chen #endif
502e3fbd280SJoseph Chen 
503665be4b0SJoseph Chen void arch_preboot_os(uint32_t bootm_state)
504665be4b0SJoseph Chen {
505665be4b0SJoseph Chen 	if (bootm_state & BOOTM_STATE_OS_PREP)
506665be4b0SJoseph Chen 		hotkey_run(HK_CLI_OS_PRE);
507665be4b0SJoseph Chen }
508665be4b0SJoseph Chen 
50938771996SKever Yang void enable_caches(void)
51038771996SKever Yang {
511567735c8SJoseph Chen 	icache_enable();
51238771996SKever Yang 	dcache_enable();
51338771996SKever Yang }
51438771996SKever Yang 
5152dc2d048SJoseph Chen #ifdef CONFIG_LMB
5162c6a058bSJoseph Chen /*
5172c6a058bSJoseph Chen  * Using last bi_dram[...] to initialize "bootm_low" and "bootm_mapsize".
5182c6a058bSJoseph Chen  * This makes lmb_alloc_base() always alloc from tail of sdram.
5192c6a058bSJoseph Chen  * If we don't assign it, bi_dram[0] is used by default and it may cause
5202c6a058bSJoseph Chen  * lmb_alloc_base() fail when bi_dram[0] range is small.
5212c6a058bSJoseph Chen  */
5222c6a058bSJoseph Chen void board_lmb_reserve(struct lmb *lmb)
5232c6a058bSJoseph Chen {
5242c6a058bSJoseph Chen 	char bootm_mapsize[32];
5252208cd92SJoseph Chen 	char bootm_low[32];
5262208cd92SJoseph Chen 	u64 start, size;
5272c6a058bSJoseph Chen 	int i;
5282c6a058bSJoseph Chen 
5292c6a058bSJoseph Chen 	for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
5302c6a058bSJoseph Chen 		if (!gd->bd->bi_dram[i].size)
5312c6a058bSJoseph Chen 			break;
5322c6a058bSJoseph Chen 	}
5332c6a058bSJoseph Chen 
5342c6a058bSJoseph Chen 	start = gd->bd->bi_dram[i - 1].start;
5352c6a058bSJoseph Chen 	size = gd->bd->bi_dram[i - 1].size;
5362c6a058bSJoseph Chen 
5372c6a058bSJoseph Chen 	/*
5382dc2d048SJoseph Chen 	 * 32-bit kernel: ramdisk/fdt shouldn't be loaded to highmem area(768MB+),
5392dc2d048SJoseph Chen 	 * otherwise "Unable to handle kernel paging request at virtual address ...".
5402dc2d048SJoseph Chen 	 *
5412dc2d048SJoseph Chen 	 * So that we hope limit highest address at 768M, but there comes the the
5422dc2d048SJoseph Chen 	 * problem: ramdisk is a compressed image and it expands after descompress,
5432dc2d048SJoseph Chen 	 * so it accesses 768MB+ and brings the above "Unable to handle kernel ...".
5442dc2d048SJoseph Chen 	 *
5452dc2d048SJoseph Chen 	 * We make a appointment that the highest memory address is 512MB, it
5462dc2d048SJoseph Chen 	 * makes lmb alloc safer.
5472c6a058bSJoseph Chen 	 */
5482dc2d048SJoseph Chen #ifndef CONFIG_ARM64
5492dc2d048SJoseph Chen 	if (start >= ((u64)CONFIG_SYS_SDRAM_BASE + SZ_512M)) {
5502c6a058bSJoseph Chen 		start = gd->bd->bi_dram[i - 2].start;
5512c6a058bSJoseph Chen 		size = gd->bd->bi_dram[i - 2].size;
5522c6a058bSJoseph Chen 	}
5532c6a058bSJoseph Chen 
5542dc2d048SJoseph Chen 	if ((start + size) > ((u64)CONFIG_SYS_SDRAM_BASE + SZ_512M))
5552dc2d048SJoseph Chen 		size = (u64)CONFIG_SYS_SDRAM_BASE + SZ_512M - start;
5562c6a058bSJoseph Chen #endif
5572c6a058bSJoseph Chen 	sprintf(bootm_low, "0x%llx", start);
5582c6a058bSJoseph Chen 	sprintf(bootm_mapsize, "0x%llx", size);
5592c6a058bSJoseph Chen 	env_set("bootm_low", bootm_low);
5602c6a058bSJoseph Chen 	env_set("bootm_mapsize", bootm_mapsize);
5612c6a058bSJoseph Chen }
5622dc2d048SJoseph Chen #endif
5632c6a058bSJoseph Chen 
56486f870d6SJoseph Chen #ifdef CONFIG_BIDRAM
56586f870d6SJoseph Chen int board_bidram_reserve(struct bidram *bidram)
56686f870d6SJoseph Chen {
56786f870d6SJoseph Chen 	struct memblock mem;
56886f870d6SJoseph Chen 	int ret;
56986f870d6SJoseph Chen 
57086f870d6SJoseph Chen 	/* ATF */
57186f870d6SJoseph Chen 	mem = param_parse_atf_mem();
572c01d4489SJoseph Chen 	ret = bidram_reserve(MEM_ATF, mem.base, mem.size);
57386f870d6SJoseph Chen 	if (ret)
57486f870d6SJoseph Chen 		return ret;
57586f870d6SJoseph Chen 
57686f870d6SJoseph Chen 	/* PSTORE/ATAGS/SHM */
57786f870d6SJoseph Chen 	mem = param_parse_common_resv_mem();
578c01d4489SJoseph Chen 	ret = bidram_reserve(MEM_SHM, mem.base, mem.size);
57986f870d6SJoseph Chen 	if (ret)
58086f870d6SJoseph Chen 		return ret;
58186f870d6SJoseph Chen 
58286f870d6SJoseph Chen 	/* OP-TEE */
58386f870d6SJoseph Chen 	mem = param_parse_optee_mem();
584c01d4489SJoseph Chen 	ret = bidram_reserve(MEM_OPTEE, mem.base, mem.size);
58586f870d6SJoseph Chen 	if (ret)
58686f870d6SJoseph Chen 		return ret;
58786f870d6SJoseph Chen 
58886f870d6SJoseph Chen 	return 0;
58986f870d6SJoseph Chen }
59086f870d6SJoseph Chen 
59186f870d6SJoseph Chen parse_fn_t board_bidram_parse_fn(void)
59286f870d6SJoseph Chen {
59386f870d6SJoseph Chen 	return param_parse_ddr_mem;
59486f870d6SJoseph Chen }
59586f870d6SJoseph Chen #endif
59686f870d6SJoseph Chen 
59750d35c45SJoseph Chen #ifdef CONFIG_ROCKCHIP_AMP
59850d35c45SJoseph Chen void cpu_secondary_init_r(void)
59950d35c45SJoseph Chen {
60050d35c45SJoseph Chen 	amp_cpus_on();
60150d35c45SJoseph Chen }
60250d35c45SJoseph Chen #endif
60350d35c45SJoseph Chen 
60493586e70SJoseph Chen int board_init_f_boot_flags(void)
60593586e70SJoseph Chen {
60693586e70SJoseph Chen 	int boot_flags = 0;
60793586e70SJoseph Chen 
60893586e70SJoseph Chen 	/* pre-loader serial */
6094892a977SJoseph Chen #if defined(CONFIG_ROCKCHIP_PRELOADER_SERIAL) && \
6104892a977SJoseph Chen     defined(CONFIG_ROCKCHIP_PRELOADER_ATAGS)
61193586e70SJoseph Chen 	struct tag *t;
612064eb493SJoseph Chen 
61393586e70SJoseph Chen 	t = atags_get_tag(ATAG_SERIAL);
614064eb493SJoseph Chen 	if (t) {
61593586e70SJoseph Chen 		gd->serial.using_pre_serial = 1;
61693586e70SJoseph Chen 		gd->serial.enable = t->u.serial.enable;
617064eb493SJoseph Chen 		gd->serial.baudrate = t->u.serial.baudrate;
6187abb254dSJoseph Chen 		gd->serial.addr = t->u.serial.addr;
619064eb493SJoseph Chen 		gd->serial.id = t->u.serial.id;
62093586e70SJoseph Chen 		gd->baudrate = CONFIG_BAUDRATE;
62193586e70SJoseph Chen 		if (!t->u.serial.enable)
62293586e70SJoseph Chen 			boot_flags |= GD_FLG_DISABLE_CONSOLE;
62393586e70SJoseph Chen 		debug("preloader: enable=%d, addr=0x%lx, baudrate=%d, id=%d\n",
62493586e70SJoseph Chen 		      gd->serial.enable, gd->serial.addr,
62593586e70SJoseph Chen 		      gd->serial.baudrate, gd->serial.id);
62693586e70SJoseph Chen 	} else
627064eb493SJoseph Chen #endif
62893586e70SJoseph Chen 	{
62993586e70SJoseph Chen 		gd->baudrate = CONFIG_BAUDRATE;
63093586e70SJoseph Chen 		gd->serial.baudrate = CONFIG_BAUDRATE;
63193586e70SJoseph Chen 		gd->serial.addr = CONFIG_DEBUG_UART_BASE;
63293586e70SJoseph Chen 	}
63393586e70SJoseph Chen 
63493586e70SJoseph Chen 	/* The highest priority to turn off (override) console */
63593586e70SJoseph Chen #if defined(CONFIG_DISABLE_CONSOLE)
63693586e70SJoseph Chen 	boot_flags |= GD_FLG_DISABLE_CONSOLE;
63793586e70SJoseph Chen #endif
63893586e70SJoseph Chen 
63993586e70SJoseph Chen 	return boot_flags;
64093586e70SJoseph Chen }
641064eb493SJoseph Chen 
64238771996SKever Yang #if defined(CONFIG_USB_GADGET) && defined(CONFIG_USB_GADGET_DWC2_OTG)
6436f7b6465SFrank Wang #include <fdt_support.h>
64438771996SKever Yang #include <usb.h>
64538771996SKever Yang #include <usb/dwc2_udc.h>
64638771996SKever Yang 
64738771996SKever Yang static struct dwc2_plat_otg_data otg_data = {
64838771996SKever Yang 	.rx_fifo_sz	= 512,
64938771996SKever Yang 	.np_tx_fifo_sz	= 16,
65038771996SKever Yang 	.tx_fifo_sz	= 128,
65138771996SKever Yang };
65238771996SKever Yang 
65338771996SKever Yang int board_usb_init(int index, enum usb_init_type init)
65438771996SKever Yang {
65538771996SKever Yang 	const void *blob = gd->fdt_blob;
6562208cd92SJoseph Chen 	const fdt32_t *reg;
6572208cd92SJoseph Chen 	fdt_addr_t addr;
6582208cd92SJoseph Chen 	int node;
65938771996SKever Yang 
66038771996SKever Yang 	/* find the usb_otg node */
661294ad617SWilliam Wu 	node = fdt_node_offset_by_compatible(blob, -1, "snps,dwc2");
66238771996SKever Yang 
663294ad617SWilliam Wu retry:
664294ad617SWilliam Wu 	if (node > 0) {
665294ad617SWilliam Wu 		reg = fdt_getprop(blob, node, "reg", NULL);
666294ad617SWilliam Wu 		if (!reg)
667294ad617SWilliam Wu 			return -EINVAL;
668294ad617SWilliam Wu 
669294ad617SWilliam Wu 		addr = fdt_translate_address(blob, node, reg);
670294ad617SWilliam Wu 		if (addr == OF_BAD_ADDR) {
671294ad617SWilliam Wu 			pr_err("Not found usb_otg address\n");
672294ad617SWilliam Wu 			return -EINVAL;
67338771996SKever Yang 		}
67438771996SKever Yang 
675294ad617SWilliam Wu #if defined(CONFIG_ROCKCHIP_RK3288)
676294ad617SWilliam Wu 		if (addr != 0xff580000) {
67738771996SKever Yang 			node = fdt_node_offset_by_compatible(blob, node,
67838771996SKever Yang 							     "snps,dwc2");
679294ad617SWilliam Wu 			goto retry;
68038771996SKever Yang 		}
681294ad617SWilliam Wu #endif
682294ad617SWilliam Wu 	} else {
683e7b5bb3cSWilliam Wu 		/*
684e7b5bb3cSWilliam Wu 		 * With kernel dtb support, rk3288 dwc2 otg node
685e7b5bb3cSWilliam Wu 		 * use the rockchip legacy dwc2 driver "dwc_otg_310"
686e0b87408SJoseph Chen 		 * with the compatible "rockchip,rk3288_usb20_otg",
687e0b87408SJoseph Chen 		 * and rk3368 also use the "dwc_otg_310" driver with
688e0b87408SJoseph Chen 		 * the compatible "rockchip,rk3368-usb".
689e7b5bb3cSWilliam Wu 		 */
690e0b87408SJoseph Chen #if defined(CONFIG_ROCKCHIP_RK3288)
691e7b5bb3cSWilliam Wu 		node = fdt_node_offset_by_compatible(blob, -1,
692e7b5bb3cSWilliam Wu 				"rockchip,rk3288_usb20_otg");
693e0b87408SJoseph Chen #elif defined(CONFIG_ROCKCHIP_RK3368)
694e0b87408SJoseph Chen 		node = fdt_node_offset_by_compatible(blob, -1,
695e0b87408SJoseph Chen 				"rockchip,rk3368-usb");
696e0b87408SJoseph Chen #endif
697e7b5bb3cSWilliam Wu 		if (node > 0) {
698294ad617SWilliam Wu 			goto retry;
699e7b5bb3cSWilliam Wu 		} else {
700e7b5bb3cSWilliam Wu 			pr_err("Not found usb_otg device\n");
70138771996SKever Yang 			return -ENODEV;
70238771996SKever Yang 		}
703e7b5bb3cSWilliam Wu 	}
7046f7b6465SFrank Wang 
7056f7b6465SFrank Wang 	otg_data.regs_otg = (uintptr_t)addr;
70638771996SKever Yang 
70738771996SKever Yang 	return dwc2_udc_probe(&otg_data);
70838771996SKever Yang }
70938771996SKever Yang 
71038771996SKever Yang int board_usb_cleanup(int index, enum usb_init_type init)
71138771996SKever Yang {
71238771996SKever Yang 	return 0;
71338771996SKever Yang }
71438771996SKever Yang #endif
71585cad72dSJoseph Chen 
71685cad72dSJoseph Chen static void bootm_no_reloc(void)
71785cad72dSJoseph Chen {
71885cad72dSJoseph Chen 	char *ramdisk_high;
71985cad72dSJoseph Chen 	char *fdt_high;
72085cad72dSJoseph Chen 
72185cad72dSJoseph Chen 	if (!env_get_yesno("bootm-no-reloc"))
72285cad72dSJoseph Chen 		return;
72385cad72dSJoseph Chen 
72485cad72dSJoseph Chen 	ramdisk_high = env_get("initrd_high");
72585cad72dSJoseph Chen 	fdt_high = env_get("fdt_high");
72685cad72dSJoseph Chen 
72785cad72dSJoseph Chen 	if (!fdt_high) {
72885cad72dSJoseph Chen 		env_set_hex("fdt_high", -1UL);
72985cad72dSJoseph Chen 		printf("Fdt ");
73085cad72dSJoseph Chen 	}
73185cad72dSJoseph Chen 
73285cad72dSJoseph Chen 	if (!ramdisk_high) {
73385cad72dSJoseph Chen 		env_set_hex("initrd_high", -1UL);
73485cad72dSJoseph Chen 		printf("Ramdisk ");
73585cad72dSJoseph Chen 	}
73685cad72dSJoseph Chen 
73785cad72dSJoseph Chen 	if (!fdt_high || !ramdisk_high)
73885cad72dSJoseph Chen 		printf("skip relocation\n");
73985cad72dSJoseph Chen }
74085cad72dSJoseph Chen 
74185cad72dSJoseph Chen int bootm_board_start(void)
74285cad72dSJoseph Chen {
74385cad72dSJoseph Chen 	/*
74485cad72dSJoseph Chen 	 * print console record data
74585cad72dSJoseph Chen 	 *
74685cad72dSJoseph Chen 	 * On some rockchip platforms, uart debug and sdmmc pin are multiplex.
74785cad72dSJoseph Chen 	 * If boot from sdmmc mode, the console data would be record in buffer,
74885cad72dSJoseph Chen 	 * we switch to uart debug function in order to print it after loading
74985cad72dSJoseph Chen 	 * images.
75085cad72dSJoseph Chen 	 */
75185cad72dSJoseph Chen #if defined(CONFIG_CONSOLE_RECORD)
75285cad72dSJoseph Chen 	if (!strcmp("mmc", env_get("devtype")) &&
75385cad72dSJoseph Chen 	    !strcmp("1", env_get("devnum"))) {
75485cad72dSJoseph Chen 		printf("IOMUX: sdmmc => uart debug");
75585cad72dSJoseph Chen 		pinctrl_select_state(gd->cur_serial_dev, "default");
75685cad72dSJoseph Chen 		console_record_print_purge();
75785cad72dSJoseph Chen 	}
75885cad72dSJoseph Chen #endif
75985cad72dSJoseph Chen 	/* disable bootm relcation to save boot time */
76085cad72dSJoseph Chen 	bootm_no_reloc();
76185cad72dSJoseph Chen 
76285cad72dSJoseph Chen 	/* sysmem */
76385cad72dSJoseph Chen 	hotkey_run(HK_SYSMEM);
76485cad72dSJoseph Chen 	sysmem_overflow_check();
76585cad72dSJoseph Chen 
76685cad72dSJoseph Chen 	return 0;
76785cad72dSJoseph Chen }
768ac5d8aa9SJoseph Chen 
769ac5d8aa9SJoseph Chen /*
770ac5d8aa9SJoseph Chen  * Implement it to support CLI command:
771ac5d8aa9SJoseph Chen  *   - Android: bootm [aosp addr]
772ac5d8aa9SJoseph Chen  *   - FIT:     bootm [fit addr]
773ac5d8aa9SJoseph Chen  *   - uImage:  bootm [uimage addr]
774ac5d8aa9SJoseph Chen  *
775ac5d8aa9SJoseph Chen  * Purpose:
776ac5d8aa9SJoseph Chen  *   - The original bootm command args require fdt addr on AOSP,
777ac5d8aa9SJoseph Chen  *     which is not flexible on rockchip boot/recovery.img.
778ac5d8aa9SJoseph Chen  *   - Take Android/FIT/uImage image into sysmem management to avoid image
779ac5d8aa9SJoseph Chen  *     memory overlap.
780ac5d8aa9SJoseph Chen  */
781ac5d8aa9SJoseph Chen #if defined(CONFIG_ANDROID_BOOTLOADER) ||	\
782ac5d8aa9SJoseph Chen 	defined(CONFIG_ROCKCHIP_FIT_IMAGE) ||	\
783ac5d8aa9SJoseph Chen 	defined(CONFIG_ROCKCHIP_UIMAGE)
784ac5d8aa9SJoseph Chen int board_do_bootm(int argc, char * const argv[])
785ac5d8aa9SJoseph Chen {
786ac5d8aa9SJoseph Chen 	int format;
787ac5d8aa9SJoseph Chen 	void *img;
788ac5d8aa9SJoseph Chen 
789ac5d8aa9SJoseph Chen 	if (argc != 2)
790ac5d8aa9SJoseph Chen 		return 0;
791ac5d8aa9SJoseph Chen 
792ac5d8aa9SJoseph Chen 	img = (void *)simple_strtoul(argv[1], NULL, 16);
793ac5d8aa9SJoseph Chen 	format = (genimg_get_format(img));
794ac5d8aa9SJoseph Chen 
795ac5d8aa9SJoseph Chen 	/* Android */
796ac5d8aa9SJoseph Chen #ifdef CONFIG_ANDROID_BOOT_IMAGE
797ac5d8aa9SJoseph Chen 	if (format == IMAGE_FORMAT_ANDROID) {
798ac5d8aa9SJoseph Chen 		struct andr_img_hdr *hdr;
799ac5d8aa9SJoseph Chen 		ulong load_addr;
800ac5d8aa9SJoseph Chen 		ulong size;
801ac5d8aa9SJoseph Chen 		int ret;
802ac5d8aa9SJoseph Chen 
803ac5d8aa9SJoseph Chen 		hdr = (struct andr_img_hdr *)img;
804ac5d8aa9SJoseph Chen 		printf("BOOTM: transferring to board Android\n");
805ac5d8aa9SJoseph Chen 
806ac5d8aa9SJoseph Chen #ifdef CONFIG_USING_KERNEL_DTB
807ac5d8aa9SJoseph Chen 		sysmem_free((phys_addr_t)gd->fdt_blob);
808ac5d8aa9SJoseph Chen 		/* erase magic */
809ac5d8aa9SJoseph Chen 		fdt_set_magic((void *)gd->fdt_blob, ~0);
810ac5d8aa9SJoseph Chen 		gd->fdt_blob = NULL;
811ac5d8aa9SJoseph Chen #endif
812ac5d8aa9SJoseph Chen 		load_addr = env_get_ulong("kernel_addr_r", 16, 0);
813ac5d8aa9SJoseph Chen 		load_addr -= hdr->page_size;
814ac5d8aa9SJoseph Chen 		size = android_image_get_end(hdr) - (ulong)hdr;
815ac5d8aa9SJoseph Chen 
816ac5d8aa9SJoseph Chen 		if (!sysmem_alloc_base(MEM_ANDROID, (ulong)hdr, size))
817ac5d8aa9SJoseph Chen 			return -ENOMEM;
818ac5d8aa9SJoseph Chen 
819ac5d8aa9SJoseph Chen 		ret = android_image_memcpy_separate(hdr, &load_addr);
820ac5d8aa9SJoseph Chen 		if (ret) {
821ac5d8aa9SJoseph Chen 			printf("board do bootm failed, ret=%d\n", ret);
822ac5d8aa9SJoseph Chen 			return ret;
823ac5d8aa9SJoseph Chen 		}
824ac5d8aa9SJoseph Chen 
825ac5d8aa9SJoseph Chen 		return android_bootloader_boot_kernel(load_addr);
826ac5d8aa9SJoseph Chen 	}
827ac5d8aa9SJoseph Chen #endif
828ac5d8aa9SJoseph Chen 
829ac5d8aa9SJoseph Chen 	/* FIT */
830ac5d8aa9SJoseph Chen #if IMAGE_ENABLE_FIT
831ac5d8aa9SJoseph Chen 	if (format == IMAGE_FORMAT_FIT) {
832ac5d8aa9SJoseph Chen 		char boot_cmd[64];
833ac5d8aa9SJoseph Chen 
834ac5d8aa9SJoseph Chen 		printf("BOOTM: transferring to board FIT\n");
835ac5d8aa9SJoseph Chen 		snprintf(boot_cmd, sizeof(boot_cmd), "boot_fit %s", argv[1]);
836ac5d8aa9SJoseph Chen 		return run_command(boot_cmd, 0);
837ac5d8aa9SJoseph Chen 	}
838ac5d8aa9SJoseph Chen #endif
839ac5d8aa9SJoseph Chen 
840ac5d8aa9SJoseph Chen 	/* uImage */
841ac5d8aa9SJoseph Chen #if defined(CONFIG_IMAGE_FORMAT_LEGACY)
842ac5d8aa9SJoseph Chen 	if (format == IMAGE_FORMAT_LEGACY &&
843ac5d8aa9SJoseph Chen 	    image_get_type(img) == IH_TYPE_MULTI) {
844ac5d8aa9SJoseph Chen 		char boot_cmd[64];
845ac5d8aa9SJoseph Chen 
846ac5d8aa9SJoseph Chen 		printf("BOOTM: transferring to board uImage\n");
847ac5d8aa9SJoseph Chen 		snprintf(boot_cmd, sizeof(boot_cmd), "boot_uimage %s", argv[1]);
848ac5d8aa9SJoseph Chen 		return run_command(boot_cmd, 0);
849ac5d8aa9SJoseph Chen 	}
850ac5d8aa9SJoseph Chen #endif
851ac5d8aa9SJoseph Chen 
852ac5d8aa9SJoseph Chen 	return 0;
853ac5d8aa9SJoseph Chen }
854ac5d8aa9SJoseph Chen #endif
8554ab50248SJoseph Chen 
8564ab50248SJoseph Chen void autoboot_command_fail_handle(void)
8574ab50248SJoseph Chen {
8584ab50248SJoseph Chen #ifdef CONFIG_AVB_VBMETA_PUBLIC_KEY_VALIDATE
8594ab50248SJoseph Chen #ifdef CONFIG_ANDROID_AB
8604ab50248SJoseph Chen 	run_command("fastboot usb 0;", 0);  /* use fastboot to ative slot */
8614ab50248SJoseph Chen #else
8624ab50248SJoseph Chen 	run_command("rockusb 0 ${devtype} ${devnum}", 0);
8634ab50248SJoseph Chen 	run_command("fastboot usb 0;", 0);
8644ab50248SJoseph Chen #endif
8654ab50248SJoseph Chen #endif
8664ab50248SJoseph Chen }
867346c39b3SJoseph Chen 
868c29dd8c4SJoseph Chen #ifdef CONFIG_FIT_ROLLBACK_PROTECT
869c29dd8c4SJoseph Chen 
870c29dd8c4SJoseph Chen #define FIT_ROLLBACK_INDEX_LOCATION	0x66697472	/* "fitr" */
871c29dd8c4SJoseph Chen 
872c29dd8c4SJoseph Chen int fit_read_otp_rollback_index(uint32_t fit_index, uint32_t *otp_index)
873c29dd8c4SJoseph Chen {
874c29dd8c4SJoseph Chen #ifdef CONFIG_OPTEE_CLIENT
875c29dd8c4SJoseph Chen 	u64 index;
876c29dd8c4SJoseph Chen 	int ret;
877c29dd8c4SJoseph Chen 
878c29dd8c4SJoseph Chen 	ret = trusty_read_rollback_index(FIT_ROLLBACK_INDEX_LOCATION, &index);
879c29dd8c4SJoseph Chen 	if (ret) {
880c29dd8c4SJoseph Chen 		if (ret != TEE_ERROR_ITEM_NOT_FOUND)
881c29dd8c4SJoseph Chen 			return ret;
882c29dd8c4SJoseph Chen 
883*ee7b0fb8SJason Zhu 		index = 0;
884c29dd8c4SJoseph Chen 		printf("Initial otp index as %d\n", fit_index);
885bcec4579SZain Wang 	}
886*ee7b0fb8SJason Zhu 
887*ee7b0fb8SJason Zhu 	*otp_index = (uint32_t)index;
888c29dd8c4SJoseph Chen #else
889c29dd8c4SJoseph Chen 	*otp_index = 0;
890c29dd8c4SJoseph Chen #endif
891c29dd8c4SJoseph Chen 
892c29dd8c4SJoseph Chen 	return 0;
893c29dd8c4SJoseph Chen }
894c29dd8c4SJoseph Chen 
895c29dd8c4SJoseph Chen static int fit_write_trusty_rollback_index(u32 trusty_index)
896c29dd8c4SJoseph Chen {
897c29dd8c4SJoseph Chen 	if (!trusty_index)
898c29dd8c4SJoseph Chen 		return 0;
899c29dd8c4SJoseph Chen 
9008d26d4b3SJoseph Chen 	return trusty_write_rollback_index(FIT_ROLLBACK_INDEX_LOCATION,
901c29dd8c4SJoseph Chen 					   (u64)trusty_index);
902c29dd8c4SJoseph Chen }
903c29dd8c4SJoseph Chen #endif
904c29dd8c4SJoseph Chen 
905189c0d68SJoseph Chen void board_quiesce_devices(void *images)
906189c0d68SJoseph Chen {
907189c0d68SJoseph Chen 	hotkey_run(HK_CMDLINE);
908189c0d68SJoseph Chen 	hotkey_run(HK_CLI_OS_GO);
909189c0d68SJoseph Chen 
910189c0d68SJoseph Chen #ifdef CONFIG_ROCKCHIP_PRELOADER_ATAGS
911189c0d68SJoseph Chen 	/* Destroy atags makes next warm boot safer */
912189c0d68SJoseph Chen 	atags_destroy();
913189c0d68SJoseph Chen #endif
914189c0d68SJoseph Chen 
915189c0d68SJoseph Chen #ifdef CONFIG_FIT_ROLLBACK_PROTECT
9168d26d4b3SJoseph Chen 	int ret;
9178d26d4b3SJoseph Chen 
9188d26d4b3SJoseph Chen 	ret = fit_write_trusty_rollback_index(gd->rollback_index);
9198d26d4b3SJoseph Chen 	if (ret) {
9208d26d4b3SJoseph Chen 		panic("Failed to write fit rollback index %d, ret=%d",
9218d26d4b3SJoseph Chen 		      gd->rollback_index, ret);
9228d26d4b3SJoseph Chen 	}
923189c0d68SJoseph Chen #endif
924a5401a9dSJoseph Chen 
925a5401a9dSJoseph Chen #ifdef CONFIG_ROCKCHIP_HW_DECOMPRESS
926a5401a9dSJoseph Chen 	misc_decompress_cleanup();
927a5401a9dSJoseph Chen #endif
928189c0d68SJoseph Chen }
929