xref: /rk3399_rockchip-uboot/arch/arm/mach-rockchip/spl.c (revision dfe45d3e7e8abc8fcabff66135bf69b9671c19a4)
138771996SKever Yang /*
238771996SKever Yang  * (C) Copyright 2018 Rockchip Electronics Co., Ltd
338771996SKever Yang  *
438771996SKever Yang  * SPDX-License-Identifier:     GPL-2.0+
538771996SKever Yang  */
638771996SKever Yang 
738771996SKever Yang #include <common.h>
8de77dbbbSJoseph Chen #include <version.h>
94484e03eSJoseph Chen #include <boot_rkimg.h>
1038771996SKever Yang #include <debug_uart.h>
1138771996SKever Yang #include <dm.h>
122323b257SJason Zhu #include <key.h>
13f0daa6c1SJason Zhu #include <led.h>
14a5373663SJason Zhu #include <misc.h>
1538771996SKever Yang #include <ram.h>
1638771996SKever Yang #include <spl.h>
176afcbf88SJoseph Chen #include <optee_include/OpteeClientInterface.h>
18c90ee5c7SJason Zhu #include <power/fuel_gauge.h>
1938771996SKever Yang #include <asm/arch/bootrom.h>
2010dd5e8cSJason Zhu #ifdef CONFIG_ROCKCHIP_PRELOADER_ATAGS
2110dd5e8cSJason Zhu #include <asm/arch/rk_atags.h>
2210dd5e8cSJason Zhu #endif
234c8e468bSKever Yang #include <asm/arch/pcie_ep_boot.h>
24e1f97ec3SYouMin Chen #include <asm/arch/sdram.h>
252323b257SJason Zhu #include <asm/arch/boot_mode.h>
2652f7b21dSZhihuan He #include <asm/arch-rockchip/sys_proto.h>
2738771996SKever Yang #include <asm/io.h>
28ad771a9cSHuibin Hong #include <asm/arch/param.h>
2938771996SKever Yang 
3038771996SKever Yang DECLARE_GLOBAL_DATA_PTR;
3138771996SKever Yang 
3238771996SKever Yang void board_return_to_bootrom(void)
3338771996SKever Yang {
3438771996SKever Yang 	back_to_bootrom(BROM_BOOT_NEXTSTAGE);
3538771996SKever Yang }
3638771996SKever Yang 
3738771996SKever Yang __weak const char * const boot_devices[BROM_LAST_BOOTSOURCE + 1] = {
3838771996SKever Yang };
3938771996SKever Yang 
4038771996SKever Yang const char *board_spl_was_booted_from(void)
4138771996SKever Yang {
4238771996SKever Yang 	u32  bootdevice_brom_id = readl(BROM_BOOTSOURCE_ID_ADDR);
4338771996SKever Yang 	const char *bootdevice_ofpath = NULL;
4438771996SKever Yang 
45b2b4c2f5SYifeng Zhao 	if ((bootdevice_brom_id & BROM_DOWNLOAD_MASK) == BROM_DOWNLOAD_MASK)
46b2b4c2f5SYifeng Zhao 		bootdevice_brom_id = BROM_BOOTSOURCE_USB;
47b2b4c2f5SYifeng Zhao 
48b2b4c2f5SYifeng Zhao 	bootdevice_brom_id = bootdevice_brom_id & BROM_BOOTSOURCE_MASK;
4938771996SKever Yang 	if (bootdevice_brom_id < ARRAY_SIZE(boot_devices))
5038771996SKever Yang 		bootdevice_ofpath = boot_devices[bootdevice_brom_id];
5138771996SKever Yang 
5238771996SKever Yang 	if (bootdevice_ofpath)
5338771996SKever Yang 		debug("%s: brom_bootdevice_id %x maps to '%s'\n",
5438771996SKever Yang 		      __func__, bootdevice_brom_id, bootdevice_ofpath);
5538771996SKever Yang 	else
5638771996SKever Yang 		debug("%s: failed to resolve brom_bootdevice_id %x\n",
5738771996SKever Yang 		      __func__, bootdevice_brom_id);
5838771996SKever Yang 
5938771996SKever Yang 	return bootdevice_ofpath;
6038771996SKever Yang }
6138771996SKever Yang 
6238771996SKever Yang u32 spl_boot_device(void)
6338771996SKever Yang {
6438771996SKever Yang 	u32 boot_device = BOOT_DEVICE_MMC1;
6538771996SKever Yang 
6638771996SKever Yang #if defined(CONFIG_TARGET_CHROMEBOOK_JERRY) || \
6738771996SKever Yang 		defined(CONFIG_TARGET_CHROMEBIT_MICKEY) || \
6838771996SKever Yang 		defined(CONFIG_TARGET_CHROMEBOOK_MINNIE)
6938771996SKever Yang 	return BOOT_DEVICE_SPI;
7038771996SKever Yang #endif
7138771996SKever Yang 	if (CONFIG_IS_ENABLED(ROCKCHIP_BACK_TO_BROM))
7238771996SKever Yang 		return BOOT_DEVICE_BOOTROM;
7338771996SKever Yang 
7438771996SKever Yang 	return boot_device;
7538771996SKever Yang }
7638771996SKever Yang 
7738771996SKever Yang u32 spl_boot_mode(const u32 boot_device)
7838771996SKever Yang {
7938771996SKever Yang 	return MMCSD_MODE_RAW;
8038771996SKever Yang }
8138771996SKever Yang 
8238771996SKever Yang __weak void rockchip_stimer_init(void)
8338771996SKever Yang {
84d74e8763SKever Yang 	/* If Timer already enabled, don't re-init it */
85d74e8763SKever Yang 	u32 reg = readl(CONFIG_ROCKCHIP_STIMER_BASE + 0x10);
86d74e8763SKever Yang 	if ( reg & 0x1 )
87d74e8763SKever Yang 		return;
88a09afa08SKever Yang #ifndef CONFIG_ARM64
89a09afa08SKever Yang 	asm volatile("mcr p15, 0, %0, c14, c0, 0"
90a09afa08SKever Yang 		     : : "r"(COUNTER_FREQUENCY));
91a09afa08SKever Yang #endif
9238771996SKever Yang 	writel(0, CONFIG_ROCKCHIP_STIMER_BASE + 0x10);
9338771996SKever Yang 	writel(0xffffffff, CONFIG_ROCKCHIP_STIMER_BASE);
9438771996SKever Yang 	writel(0xffffffff, CONFIG_ROCKCHIP_STIMER_BASE + 4);
9538771996SKever Yang 	writel(1, CONFIG_ROCKCHIP_STIMER_BASE + 0x10);
9638771996SKever Yang }
9738771996SKever Yang 
9838771996SKever Yang __weak int arch_cpu_init(void)
9938771996SKever Yang {
10038771996SKever Yang 	return 0;
10138771996SKever Yang }
10238771996SKever Yang 
10338771996SKever Yang __weak int rk_board_init_f(void)
10438771996SKever Yang {
10538771996SKever Yang 	return 0;
10638771996SKever Yang }
10738771996SKever Yang 
108e62c13b9SZhihuan He #ifndef CONFIG_SPL_LIBGENERIC_SUPPORT
109e62c13b9SZhihuan He void udelay(unsigned long usec)
110e62c13b9SZhihuan He {
111e62c13b9SZhihuan He 	__udelay(usec);
112e62c13b9SZhihuan He }
113e62c13b9SZhihuan He 
114e62c13b9SZhihuan He void hang(void)
115e62c13b9SZhihuan He {
116e62c13b9SZhihuan He 	bootstage_error(BOOTSTAGE_ID_NEED_RESET);
117e62c13b9SZhihuan He 	for (;;)
118e62c13b9SZhihuan He 		;
119e62c13b9SZhihuan He }
120e62c13b9SZhihuan He 
121e62c13b9SZhihuan He /**
122e62c13b9SZhihuan He  * memset - Fill a region of memory with the given value
123e62c13b9SZhihuan He  * @s: Pointer to the start of the area.
124e62c13b9SZhihuan He  * @c: The byte to fill the area with
125e62c13b9SZhihuan He  * @count: The size of the area.
126e62c13b9SZhihuan He  *
127e62c13b9SZhihuan He  * Do not use memset() to access IO space, use memset_io() instead.
128e62c13b9SZhihuan He  */
129e62c13b9SZhihuan He void *memset(void *s, int c, size_t count)
130e62c13b9SZhihuan He {
131e62c13b9SZhihuan He 	unsigned long *sl = (unsigned long *)s;
132e62c13b9SZhihuan He 	char *s8;
133e62c13b9SZhihuan He 
134e62c13b9SZhihuan He #if !CONFIG_IS_ENABLED(TINY_MEMSET)
135e62c13b9SZhihuan He 	unsigned long cl = 0;
136e62c13b9SZhihuan He 	int i;
137e62c13b9SZhihuan He 
138e62c13b9SZhihuan He 	/* do it one word at a time (32 bits or 64 bits) while possible */
139e62c13b9SZhihuan He 	if (((ulong)s & (sizeof(*sl) - 1)) == 0) {
140e62c13b9SZhihuan He 		for (i = 0; i < sizeof(*sl); i++) {
141e62c13b9SZhihuan He 			cl <<= 8;
142e62c13b9SZhihuan He 			cl |= c & 0xff;
143e62c13b9SZhihuan He 		}
144e62c13b9SZhihuan He 		while (count >= sizeof(*sl)) {
145e62c13b9SZhihuan He 			*sl++ = cl;
146e62c13b9SZhihuan He 			count -= sizeof(*sl);
147e62c13b9SZhihuan He 		}
148e62c13b9SZhihuan He 	}
149e62c13b9SZhihuan He #endif /* fill 8 bits at a time */
150e62c13b9SZhihuan He 	s8 = (char *)sl;
151e62c13b9SZhihuan He 	while (count--)
152e62c13b9SZhihuan He 		*s8++ = c;
153e62c13b9SZhihuan He 
154e62c13b9SZhihuan He 	return s;
155e62c13b9SZhihuan He }
156e62c13b9SZhihuan He #endif
157e62c13b9SZhihuan He 
1584fcb4a04SJoseph Chen #ifdef CONFIG_SPL_DM_RESET
1594fcb4a04SJoseph Chen static void brom_download(void)
1604fcb4a04SJoseph Chen {
161b1f7fc03SXuhui Lin 	if (gd->console_evt == 0x02) {
1624fcb4a04SJoseph Chen 		printf("ctrl+b: Bootrom download!\n");
1634fcb4a04SJoseph Chen 		writel(BOOT_BROM_DOWNLOAD, CONFIG_ROCKCHIP_BOOT_MODE_REG);
1644fcb4a04SJoseph Chen 		do_reset(NULL, 0, 0, NULL);
1654fcb4a04SJoseph Chen 	}
1664fcb4a04SJoseph Chen }
1674fcb4a04SJoseph Chen #endif
1684fcb4a04SJoseph Chen 
169b1f7fc03SXuhui Lin static void spl_hotkey_init(void)
170b1f7fc03SXuhui Lin {
171b1f7fc03SXuhui Lin 	/* If disable console, skip getting uart reg */
172b1f7fc03SXuhui Lin 	if (!gd || gd->flags & GD_FLG_DISABLE_CONSOLE)
173b1f7fc03SXuhui Lin 		return;
174b1f7fc03SXuhui Lin 	if (!gd->have_console)
175b1f7fc03SXuhui Lin 		return;
176b1f7fc03SXuhui Lin 
177b1f7fc03SXuhui Lin 	/* serial uclass only exists when enable CONFIG_SPL_FRAMEWORK */
178b1f7fc03SXuhui Lin #ifdef CONFIG_SPL_FRAMEWORK
179b1f7fc03SXuhui Lin 	if (serial_tstc()) {
180b1f7fc03SXuhui Lin 		gd->console_evt = serial_getc();
181b1f7fc03SXuhui Lin #else
182b1f7fc03SXuhui Lin 	if (debug_uart_tstc()) {
183b1f7fc03SXuhui Lin 		gd->console_evt = debug_uart_getc();
184b1f7fc03SXuhui Lin #endif
185b1f7fc03SXuhui Lin 		if (gd->console_evt <= 0x1a) /* 'z' */
186b1f7fc03SXuhui Lin 			printf("SPL Hotkey: ctrl+%c\n",
187b1f7fc03SXuhui Lin 				gd->console_evt + 'a' - 1);
188b1f7fc03SXuhui Lin 	}
189b1f7fc03SXuhui Lin 
190b1f7fc03SXuhui Lin 	return;
191b1f7fc03SXuhui Lin }
192b1f7fc03SXuhui Lin 
19338771996SKever Yang void board_init_f(ulong dummy)
19438771996SKever Yang {
19538771996SKever Yang #ifdef CONFIG_SPL_FRAMEWORK
19638771996SKever Yang 	int ret;
19738771996SKever Yang #if !defined(CONFIG_SUPPORT_TPL)
19838771996SKever Yang 	struct udevice *dev;
19938771996SKever Yang #endif
20038771996SKever Yang #endif
2017d536d43SJoseph Chen 	gd->flags = dummy;
202a09afa08SKever Yang 	rockchip_stimer_init();
20338771996SKever Yang #define EARLY_UART
20438771996SKever Yang #if defined(EARLY_UART) && defined(CONFIG_DEBUG_UART)
20538771996SKever Yang 	/*
20638771996SKever Yang 	 * Debug UART can be used from here if required:
20738771996SKever Yang 	 *
20838771996SKever Yang 	 * debug_uart_init();
20938771996SKever Yang 	 * printch('a');
21038771996SKever Yang 	 * printhex8(0x1234);
21138771996SKever Yang 	 * printascii("string");
21238771996SKever Yang 	 */
21381e837faSJoseph Chen 	if (!gd->serial.using_pre_serial &&
21481e837faSJoseph Chen 	    !(gd->flags & GD_FLG_DISABLE_CONSOLE))
21538771996SKever Yang 		debug_uart_init();
21638771996SKever Yang 	printascii("U-Boot SPL board init");
21738771996SKever Yang #endif
218e220d757SJoseph Chen 	gd->sys_start_tick = get_ticks();
2194c8e468bSKever Yang #ifdef CONFIG_SPL_PCIE_EP_SUPPORT
2204c8e468bSKever Yang 	rockchip_pcie_ep_init();
2214c8e468bSKever Yang #endif
22238771996SKever Yang #ifdef CONFIG_SPL_FRAMEWORK
22338771996SKever Yang 	ret = spl_early_init();
22438771996SKever Yang 	if (ret) {
22538771996SKever Yang 		printf("spl_early_init() failed: %d\n", ret);
22638771996SKever Yang 		hang();
22738771996SKever Yang 	}
22838771996SKever Yang #if !defined(CONFIG_SUPPORT_TPL)
22938771996SKever Yang 	debug("\nspl:init dram\n");
23038771996SKever Yang 	ret = uclass_get_device(UCLASS_RAM, 0, &dev);
23138771996SKever Yang 	if (ret) {
23238771996SKever Yang 		printf("DRAM init failed: %d\n", ret);
23338771996SKever Yang 		return;
23438771996SKever Yang 	}
23538771996SKever Yang #endif
23638771996SKever Yang 	preloader_console_init();
23738771996SKever Yang #else
23838771996SKever Yang 	/* Some SoCs like rk3036 does not use any frame work */
23938771996SKever Yang 	sdram_init();
24038771996SKever Yang #endif
241b1f7fc03SXuhui Lin 	/* Get hotkey and store in gd */
242b1f7fc03SXuhui Lin 	spl_hotkey_init();
2434fcb4a04SJoseph Chen #ifdef CONFIG_SPL_DM_RESET
2444fcb4a04SJoseph Chen 	brom_download();
2454fcb4a04SJoseph Chen #endif
246ddc9405dSKever Yang 	arch_cpu_init();
24738771996SKever Yang 	rk_board_init_f();
2486f80b298SXuhui Lin #if defined(CONFIG_SPL_RAM_DEVICE) && defined(CONFIG_SPL_PCIE_EP_SUPPORT)
2494c8e468bSKever Yang 	rockchip_pcie_ep_get_firmware();
2504c8e468bSKever Yang #endif
25138771996SKever Yang #if CONFIG_IS_ENABLED(ROCKCHIP_BACK_TO_BROM) && !defined(CONFIG_SPL_BOARD_INIT)
25238771996SKever Yang 	back_to_bootrom(BROM_BOOT_NEXTSTAGE);
25338771996SKever Yang #endif
25438771996SKever Yang 
25538771996SKever Yang }
25638771996SKever Yang 
25738771996SKever Yang #ifdef CONFIG_SPL_LOAD_FIT
25838771996SKever Yang int board_fit_config_name_match(const char *name)
25938771996SKever Yang {
26038771996SKever Yang 	/* Just empty function now - can't decide what to choose */
26138771996SKever Yang 	debug("%s: %s\n", __func__, name);
26238771996SKever Yang 
26338771996SKever Yang 	return 0;
26438771996SKever Yang }
26538771996SKever Yang #endif
26638771996SKever Yang 
26793586e70SJoseph Chen int board_init_f_boot_flags(void)
26893586e70SJoseph Chen {
26993586e70SJoseph Chen 	int boot_flags = 0;
27093586e70SJoseph Chen 
271*dfe45d3eSJoseph Chen #if CONFIG_IS_ENABLED(FPGA_ROCKCHIP)
2729f68846bSJoseph Chen 	arch_fpga_init();
2739f68846bSJoseph Chen #endif
274ad771a9cSHuibin Hong #ifdef CONFIG_PSTORE
275ad771a9cSHuibin Hong 	param_parse_pstore();
276ad771a9cSHuibin Hong #endif
27793586e70SJoseph Chen 	/* pre-loader serial */
27893586e70SJoseph Chen #if defined(CONFIG_ROCKCHIP_PRELOADER_SERIAL) && \
27993586e70SJoseph Chen     defined(CONFIG_ROCKCHIP_PRELOADER_ATAGS)
28093586e70SJoseph Chen 	struct tag *t;
28193586e70SJoseph Chen 
28293586e70SJoseph Chen 	t = atags_get_tag(ATAG_SERIAL);
28393586e70SJoseph Chen 	if (t) {
28493586e70SJoseph Chen 		gd->serial.using_pre_serial = 1;
28593586e70SJoseph Chen 		gd->serial.enable = t->u.serial.enable;
28693586e70SJoseph Chen 		gd->serial.baudrate = t->u.serial.baudrate;
28793586e70SJoseph Chen 		gd->serial.addr = t->u.serial.addr;
28893586e70SJoseph Chen 		gd->serial.id = t->u.serial.id;
28993586e70SJoseph Chen 		gd->baudrate = t->u.serial.baudrate;
29093586e70SJoseph Chen 		if (!t->u.serial.enable)
29193586e70SJoseph Chen 			boot_flags |= GD_FLG_DISABLE_CONSOLE;
29293586e70SJoseph Chen 		debug("preloader: enable=%d, addr=0x%x, baudrate=%d, id=%d\n",
29393586e70SJoseph Chen 		      t->u.serial.enable, (u32)t->u.serial.addr,
29493586e70SJoseph Chen 		      t->u.serial.baudrate, t->u.serial.id);
29593586e70SJoseph Chen 	} else
29693586e70SJoseph Chen #endif
29793586e70SJoseph Chen 	{
29893586e70SJoseph Chen 		gd->baudrate = CONFIG_BAUDRATE;
29993586e70SJoseph Chen 		gd->serial.baudrate = CONFIG_BAUDRATE;
30093586e70SJoseph Chen 		gd->serial.addr = CONFIG_DEBUG_UART_BASE;
30193586e70SJoseph Chen 	}
30293586e70SJoseph Chen 
30393586e70SJoseph Chen 	/* The highest priority to turn off (override) console */
30493586e70SJoseph Chen #if defined(CONFIG_DISABLE_CONSOLE)
30593586e70SJoseph Chen 	boot_flags |= GD_FLG_DISABLE_CONSOLE;
30693586e70SJoseph Chen #endif
30793586e70SJoseph Chen 
30893586e70SJoseph Chen 	return boot_flags;
30993586e70SJoseph Chen }
31093586e70SJoseph Chen 
31138771996SKever Yang #ifdef CONFIG_SPL_BOARD_INIT
31238771996SKever Yang __weak int rk_spl_board_init(void)
31338771996SKever Yang {
31438771996SKever Yang 	return 0;
31538771996SKever Yang }
31638771996SKever Yang 
31738771996SKever Yang static int setup_led(void)
31838771996SKever Yang {
31938771996SKever Yang #ifdef CONFIG_SPL_LED
32038771996SKever Yang 	struct udevice *dev;
32138771996SKever Yang 	char *led_name;
32238771996SKever Yang 	int ret;
32338771996SKever Yang 
32438771996SKever Yang 	led_name = fdtdec_get_config_string(gd->fdt_blob, "u-boot,boot-led");
32538771996SKever Yang 	if (!led_name)
32638771996SKever Yang 		return 0;
32738771996SKever Yang 	ret = led_get_by_label(led_name, &dev);
32838771996SKever Yang 	if (ret) {
32938771996SKever Yang 		debug("%s: get=%d\n", __func__, ret);
33038771996SKever Yang 		return ret;
33138771996SKever Yang 	}
332f0daa6c1SJason Zhu 	ret = led_set_state(dev, LEDST_ON);
33338771996SKever Yang 	if (ret)
33438771996SKever Yang 		return ret;
33538771996SKever Yang #endif
33638771996SKever Yang 
33738771996SKever Yang 	return 0;
33838771996SKever Yang }
33938771996SKever Yang 
34038771996SKever Yang void spl_board_init(void)
34138771996SKever Yang {
34238771996SKever Yang 	int ret;
34338771996SKever Yang 
34438771996SKever Yang 	ret = setup_led();
34538771996SKever Yang 
34638771996SKever Yang 	if (ret) {
34738771996SKever Yang 		debug("LED ret=%d\n", ret);
34838771996SKever Yang 		hang();
34938771996SKever Yang 	}
35038771996SKever Yang 
35138771996SKever Yang 	rk_spl_board_init();
35238771996SKever Yang #if CONFIG_IS_ENABLED(ROCKCHIP_BACK_TO_BROM)
35338771996SKever Yang 	back_to_bootrom(BROM_BOOT_NEXTSTAGE);
35438771996SKever Yang #endif
35538771996SKever Yang 	return;
35638771996SKever Yang }
35738771996SKever Yang #endif
35810dd5e8cSJason Zhu 
35910dd5e8cSJason Zhu void spl_perform_fixups(struct spl_image_info *spl_image)
36010dd5e8cSJason Zhu {
36110dd5e8cSJason Zhu #ifdef CONFIG_ROCKCHIP_PRELOADER_ATAGS
36210dd5e8cSJason Zhu 	atags_set_bootdev_by_spl_bootdevice(spl_image->boot_device);
363de77dbbbSJoseph Chen   #ifdef BUILD_SPL_TAG
364e4e12492SJoseph Chen 	atags_set_shared_fwver(FW_SPL, "spl-"BUILD_SPL_TAG);
365de77dbbbSJoseph Chen   #endif
36610dd5e8cSJason Zhu #endif
36710dd5e8cSJason Zhu 	return;
36810dd5e8cSJason Zhu }
36910dd5e8cSJason Zhu 
3702323b257SJason Zhu #ifdef CONFIG_SPL_KERNEL_BOOT
3712323b257SJason Zhu static int spl_rockchip_dnl_key_pressed(void)
3722323b257SJason Zhu {
37352387546SJoseph Chen #if defined(CONFIG_SPL_INPUT)
37452387546SJoseph Chen 	return key_read(KEY_VOLUMEUP);
3752323b257SJason Zhu #else
37652387546SJoseph Chen 	return 0;
3772323b257SJason Zhu #endif
3782323b257SJason Zhu }
3792323b257SJason Zhu 
380c90ee5c7SJason Zhu #ifdef CONFIG_SPL_DM_FUEL_GAUGE
381c90ee5c7SJason Zhu bool spl_is_low_power(void)
382c90ee5c7SJason Zhu {
383c90ee5c7SJason Zhu 	struct udevice *dev;
384c90ee5c7SJason Zhu 	int ret, voltage;
385c90ee5c7SJason Zhu 
386c90ee5c7SJason Zhu 	ret = uclass_get_device(UCLASS_FG, 0, &dev);
387c90ee5c7SJason Zhu 	if (ret) {
388c90ee5c7SJason Zhu 		debug("Get charge display failed, ret=%d\n", ret);
389c90ee5c7SJason Zhu 		return false;
390c90ee5c7SJason Zhu 	}
391c90ee5c7SJason Zhu 
392c90ee5c7SJason Zhu 	voltage = fuel_gauge_get_voltage(dev);
393c90ee5c7SJason Zhu 	if (voltage >= CONFIG_SPL_POWER_LOW_VOLTAGE_THRESHOLD)
394c90ee5c7SJason Zhu 		return false;
395c90ee5c7SJason Zhu 
396c90ee5c7SJason Zhu 	return true;
397c90ee5c7SJason Zhu }
398c90ee5c7SJason Zhu #endif
399c90ee5c7SJason Zhu 
4002323b257SJason Zhu void spl_next_stage(struct spl_image_info *spl)
4012323b257SJason Zhu {
402c07b486eSXuhui Lin 	const char *reason[] = { "Recovery key", "Ctrl+c", "LowPwr", "Other" };
4032323b257SJason Zhu 	uint32_t reg_boot_mode;
404c5d340afSXuhui Lin 	int i = 0;
4052323b257SJason Zhu 
4062323b257SJason Zhu 	if (spl_rockchip_dnl_key_pressed()) {
407c5d340afSXuhui Lin 		i = 0;
4082323b257SJason Zhu 		spl->next_stage = SPL_NEXT_STAGE_UBOOT;
409c5d340afSXuhui Lin 		goto out;
4102323b257SJason Zhu 	}
411c5d340afSXuhui Lin 
412c5d340afSXuhui Lin 	if (gd->console_evt == 0x03) {
413c5d340afSXuhui Lin 		i = 1;
414c5d340afSXuhui Lin 		spl->next_stage = SPL_NEXT_STAGE_UBOOT;
415c5d340afSXuhui Lin 		goto out;
416c5d340afSXuhui Lin 	}
417c5d340afSXuhui Lin 
418c90ee5c7SJason Zhu #ifdef CONFIG_SPL_DM_FUEL_GAUGE
419c90ee5c7SJason Zhu 	if (spl_is_low_power()) {
420c5d340afSXuhui Lin 		i = 2;
421c90ee5c7SJason Zhu 		spl->next_stage = SPL_NEXT_STAGE_UBOOT;
422c5d340afSXuhui Lin 		goto out;
423c90ee5c7SJason Zhu 	}
424c90ee5c7SJason Zhu #endif
4252323b257SJason Zhu 
4262323b257SJason Zhu 	reg_boot_mode = readl((void *)CONFIG_ROCKCHIP_BOOT_MODE_REG);
4272323b257SJason Zhu 	switch (reg_boot_mode) {
428c07b486eSXuhui Lin 	case BOOT_LOADER:
429c07b486eSXuhui Lin 	case BOOT_FASTBOOT:
430c07b486eSXuhui Lin 	case BOOT_CHARGING:
431c07b486eSXuhui Lin 	case BOOT_UMS:
432c07b486eSXuhui Lin 	case BOOT_DFU:
433c5d340afSXuhui Lin 		i = 3;
4342323b257SJason Zhu 		spl->next_stage = SPL_NEXT_STAGE_UBOOT;
435bff96653SXuhui Lin 		break;
436c07b486eSXuhui Lin 	default:
437c07b486eSXuhui Lin 		spl->next_stage = SPL_NEXT_STAGE_KERNEL;
4382323b257SJason Zhu 	}
439c5d340afSXuhui Lin 
440c5d340afSXuhui Lin out:
441c5d340afSXuhui Lin 	if (spl->next_stage == SPL_NEXT_STAGE_UBOOT)
442c5d340afSXuhui Lin 		printf("Enter uboot reason: %s\n", reason[i]);
443c5d340afSXuhui Lin 
444c5d340afSXuhui Lin 	return;
445c5d340afSXuhui Lin }
4462323b257SJason Zhu #endif
4476afcbf88SJoseph Chen 
448c1c74825SJoseph Chen #ifdef CONFIG_SPL_KERNEL_BOOT
4494484e03eSJoseph Chen const char *spl_kernel_partition(struct spl_image_info *spl,
4504484e03eSJoseph Chen 				 struct spl_load_info *info)
4514484e03eSJoseph Chen {
4524484e03eSJoseph Chen 	struct bootloader_message *bmsg = NULL;
4534484e03eSJoseph Chen 	u32 boot_mode;
4544484e03eSJoseph Chen 	int ret, cnt;
4554484e03eSJoseph Chen 	u32 sector = 0;
4564484e03eSJoseph Chen 
4574484e03eSJoseph Chen #ifdef CONFIG_SPL_LIBDISK_SUPPORT
4584484e03eSJoseph Chen 	disk_partition_t part_info;
4594484e03eSJoseph Chen 
4604484e03eSJoseph Chen 	ret = part_get_info_by_name(info->dev, PART_MISC, &part_info);
4614484e03eSJoseph Chen 	if (ret >= 0)
4624484e03eSJoseph Chen 		sector = part_info.start;
4634484e03eSJoseph Chen #else
4644484e03eSJoseph Chen 	sector = CONFIG_SPL_MISC_SECTOR;
4654484e03eSJoseph Chen #endif
4664484e03eSJoseph Chen 	if (sector) {
4674484e03eSJoseph Chen 		cnt = DIV_ROUND_UP(sizeof(*bmsg), info->bl_len);
4684484e03eSJoseph Chen 		bmsg = memalign(ARCH_DMA_MINALIGN, cnt * info->bl_len);
4694484e03eSJoseph Chen 		ret = info->read(info, sector + BCB_MESSAGE_BLK_OFFSET,
4704484e03eSJoseph Chen 				 cnt, bmsg);
4714484e03eSJoseph Chen 		if (ret == cnt && !strcmp(bmsg->command, "boot-recovery")) {
4724484e03eSJoseph Chen 			free(bmsg);
4734484e03eSJoseph Chen 			return PART_RECOVERY;
4744484e03eSJoseph Chen 		} else {
4754484e03eSJoseph Chen 			free(bmsg);
4764484e03eSJoseph Chen 		}
4774484e03eSJoseph Chen 	}
4784484e03eSJoseph Chen 
4794484e03eSJoseph Chen 	boot_mode = readl((void *)CONFIG_ROCKCHIP_BOOT_MODE_REG);
4804484e03eSJoseph Chen 
4814484e03eSJoseph Chen 	return (boot_mode == BOOT_RECOVERY) ? PART_RECOVERY : PART_BOOT;
4824484e03eSJoseph Chen }
4834484e03eSJoseph Chen #endif
4844484e03eSJoseph Chen 
485cead3ab8SJason Zhu void spl_hang_reset(void)
486cead3ab8SJason Zhu {
487cead3ab8SJason Zhu 	printf("# Reset the board to bootrom #\n");
488cead3ab8SJason Zhu #if defined(CONFIG_SPL_SYSRESET) && defined(CONFIG_SPL_DRIVERS_MISC_SUPPORT)
4895ead1aa0SJoseph Chen 	/* reset is available after dm setup */
4905ead1aa0SJoseph Chen 	if (gd->flags & GD_FLG_SPL_EARLY_INIT) {
491cead3ab8SJason Zhu 		writel(BOOT_BROM_DOWNLOAD, CONFIG_ROCKCHIP_BOOT_MODE_REG);
492cead3ab8SJason Zhu 		do_reset(NULL, 0, 0, NULL);
4935ead1aa0SJoseph Chen 	}
494cead3ab8SJason Zhu #endif
495cead3ab8SJason Zhu }
496a5373663SJason Zhu 
497cf13b784SJoseph Chen #ifdef CONFIG_SPL_FIT_ROLLBACK_PROTECT
498cf13b784SJoseph Chen int fit_read_otp_rollback_index(uint32_t fit_index, uint32_t *otp_index)
499cf13b784SJoseph Chen {
500cf13b784SJoseph Chen 	int ret = 0;
501cf13b784SJoseph Chen 
502cf13b784SJoseph Chen 	*otp_index = 0;
503299f09a0SJason Zhu #if defined(CONFIG_SPL_ROCKCHIP_SECURE_OTP)
504cf13b784SJoseph Chen 	struct udevice *dev;
505cf13b784SJoseph Chen 	u32 index, i, otp_version;
506cf13b784SJoseph Chen 	u32 bit_count;
507cf13b784SJoseph Chen 
508cf13b784SJoseph Chen 	dev = misc_otp_get_device(OTP_S);
509cf13b784SJoseph Chen 	if (!dev)
510cf13b784SJoseph Chen 		return -ENODEV;
511cf13b784SJoseph Chen 
512cf13b784SJoseph Chen 	otp_version = 0;
513cf13b784SJoseph Chen 	for (i = 0; i < OTP_UBOOT_ROLLBACK_WORDS; i++) {
514bf39446fSJason Zhu 		if (misc_otp_read(dev, OTP_UBOOT_ROLLBACK_OFFSET + i * 4,
515cf13b784SJoseph Chen 		    &index,
516cf13b784SJoseph Chen 		    4)) {
517cf13b784SJoseph Chen 			printf("Can't read rollback index\n");
518cf13b784SJoseph Chen 			return -EIO;
519cf13b784SJoseph Chen 		}
520bf39446fSJason Zhu 
521cf13b784SJoseph Chen 		bit_count = fls(index);
522cf13b784SJoseph Chen 		otp_version += bit_count;
523cf13b784SJoseph Chen 	}
524cf13b784SJoseph Chen 	*otp_index = otp_version;
525cf13b784SJoseph Chen #endif
526cf13b784SJoseph Chen 
527cf13b784SJoseph Chen 	return ret;
528cf13b784SJoseph Chen }
529cf13b784SJoseph Chen 
530cf13b784SJoseph Chen static int fit_write_otp_rollback_index(u32 fit_index)
531cf13b784SJoseph Chen {
532299f09a0SJason Zhu #if defined(CONFIG_SPL_ROCKCHIP_SECURE_OTP)
533cf13b784SJoseph Chen 	struct udevice *dev;
534cf13b784SJoseph Chen 	u32 index, i, otp_index;
535cf13b784SJoseph Chen 
536d5989feaSJoseph Chen 	if (!fit_index)
537d5989feaSJoseph Chen 		return 0;
538d5989feaSJoseph Chen 
539d5989feaSJoseph Chen 	if (fit_index > OTP_UBOOT_ROLLBACK_WORDS * 32)
540cf13b784SJoseph Chen 		return -EINVAL;
541cf13b784SJoseph Chen 
542cf13b784SJoseph Chen 	dev = misc_otp_get_device(OTP_S);
543cf13b784SJoseph Chen 	if (!dev)
544cf13b784SJoseph Chen 		return -ENODEV;
545cf13b784SJoseph Chen 
546cf13b784SJoseph Chen 	if (fit_read_otp_rollback_index(fit_index, &otp_index))
547cf13b784SJoseph Chen 		return -EIO;
548cf13b784SJoseph Chen 
549cf13b784SJoseph Chen 	if (otp_index < fit_index) {
550cf13b784SJoseph Chen 		/* Write new SW version to otp */
551cf13b784SJoseph Chen 		for (i = 0; i < OTP_UBOOT_ROLLBACK_WORDS; i++) {
552bf39446fSJason Zhu 			/*
553bf39446fSJason Zhu 			 * If fit_index is equal to 0, then execute 0xffffffff >> 32.
554bf39446fSJason Zhu 			 * But the operand can only be 0 - 31. The "0xffffffff >> 32" is
555bf39446fSJason Zhu 			 * actually be "0xffffffff >> 0".
556bf39446fSJason Zhu 			 */
557bf39446fSJason Zhu 			if (!fit_index)
558bf39446fSJason Zhu 				break;
559cf13b784SJoseph Chen 			/* convert to base-1 representation */
560cf13b784SJoseph Chen 			index = 0xffffffff >> (OTP_ALL_ONES_NUM_BITS -
561cf13b784SJoseph Chen 				min(fit_index, (u32)OTP_ALL_ONES_NUM_BITS));
562cf13b784SJoseph Chen 			fit_index -= min(fit_index,
563cf13b784SJoseph Chen 					  (u32)OTP_ALL_ONES_NUM_BITS);
564cf13b784SJoseph Chen 			if (index) {
565bf39446fSJason Zhu 				if (misc_otp_write(dev, OTP_UBOOT_ROLLBACK_OFFSET + i * 4,
566cf13b784SJoseph Chen 				    &index,
567cf13b784SJoseph Chen 				    4)) {
568cf13b784SJoseph Chen 					printf("Can't write rollback index\n");
569cf13b784SJoseph Chen 					return -EIO;
570cf13b784SJoseph Chen 				}
571cf13b784SJoseph Chen 			}
572cf13b784SJoseph Chen 		}
573cf13b784SJoseph Chen 	}
574cf13b784SJoseph Chen #endif
575cf13b784SJoseph Chen 
576cf13b784SJoseph Chen 	return 0;
577cf13b784SJoseph Chen }
578cf13b784SJoseph Chen #endif
579cf13b784SJoseph Chen 
580ed5a55baSJoseph Chen int spl_board_prepare_for_jump(struct spl_image_info *spl_image)
581ed5a55baSJoseph Chen {
582cf13b784SJoseph Chen #ifdef CONFIG_SPL_FIT_ROLLBACK_PROTECT
5838d26d4b3SJoseph Chen 	int ret;
5848d26d4b3SJoseph Chen 
5858d26d4b3SJoseph Chen 	ret = fit_write_otp_rollback_index(gd->rollback_index);
5868d26d4b3SJoseph Chen 	if (ret) {
5878d26d4b3SJoseph Chen 		panic("Failed to write fit rollback index %d, ret=%d",
5888d26d4b3SJoseph Chen 		      gd->rollback_index, ret);
5898d26d4b3SJoseph Chen 	}
590ed5a55baSJoseph Chen #endif
591a5401a9dSJoseph Chen 
592a5401a9dSJoseph Chen #ifdef CONFIG_SPL_ROCKCHIP_HW_DECOMPRESS
593a5401a9dSJoseph Chen 	misc_decompress_cleanup();
594a5401a9dSJoseph Chen #endif
595ed5a55baSJoseph Chen 	return 0;
596ed5a55baSJoseph Chen }
597