xref: /rk3399_rockchip-uboot/arch/arm/mach-rockchip/spl.c (revision b6bda7d5f40f8df92d3195bfab2b7ecbabd3e740)
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>
12*b6bda7d5SXuhui Lin #include <envf.h>
132323b257SJason Zhu #include <key.h>
14f0daa6c1SJason Zhu #include <led.h>
15a5373663SJason Zhu #include <misc.h>
16*b6bda7d5SXuhui Lin #include <mtd_blk.h>
1738771996SKever Yang #include <ram.h>
1838771996SKever Yang #include <spl.h>
19*b6bda7d5SXuhui Lin #include <spl_ab.h>
206afcbf88SJoseph Chen #include <optee_include/OpteeClientInterface.h>
21c90ee5c7SJason Zhu #include <power/fuel_gauge.h>
2238771996SKever Yang #include <asm/arch/bootrom.h>
2310dd5e8cSJason Zhu #ifdef CONFIG_ROCKCHIP_PRELOADER_ATAGS
2410dd5e8cSJason Zhu #include <asm/arch/rk_atags.h>
2510dd5e8cSJason Zhu #endif
264c8e468bSKever Yang #include <asm/arch/pcie_ep_boot.h>
27e1f97ec3SYouMin Chen #include <asm/arch/sdram.h>
282323b257SJason Zhu #include <asm/arch/boot_mode.h>
2952f7b21dSZhihuan He #include <asm/arch-rockchip/sys_proto.h>
3038771996SKever Yang #include <asm/io.h>
31ad771a9cSHuibin Hong #include <asm/arch/param.h>
3244f37eaaSXuhui Lin #include <asm/arch/rk_hwid.h>
33*b6bda7d5SXuhui Lin #include <asm/arch/rk_meta.h>
3438771996SKever Yang 
3538771996SKever Yang DECLARE_GLOBAL_DATA_PTR;
3638771996SKever Yang 
board_return_to_bootrom(void)3738771996SKever Yang void board_return_to_bootrom(void)
3838771996SKever Yang {
3938771996SKever Yang 	back_to_bootrom(BROM_BOOT_NEXTSTAGE);
4038771996SKever Yang }
4138771996SKever Yang 
4238771996SKever Yang __weak const char * const boot_devices[BROM_LAST_BOOTSOURCE + 1] = {
4338771996SKever Yang };
4438771996SKever Yang 
spl_rk_board_prepare_for_jump(struct spl_image_info * spl_image)4552c8858eSJoseph Chen __weak void spl_rk_board_prepare_for_jump(struct spl_image_info *spl_image)
4652c8858eSJoseph Chen {
4752c8858eSJoseph Chen }
4852c8858eSJoseph Chen 
board_spl_was_booted_from(void)4938771996SKever Yang const char *board_spl_was_booted_from(void)
5038771996SKever Yang {
5138771996SKever Yang 	u32  bootdevice_brom_id = readl(BROM_BOOTSOURCE_ID_ADDR);
5238771996SKever Yang 	const char *bootdevice_ofpath = NULL;
5338771996SKever Yang 
54b2b4c2f5SYifeng Zhao 	if ((bootdevice_brom_id & BROM_DOWNLOAD_MASK) == BROM_DOWNLOAD_MASK)
55b2b4c2f5SYifeng Zhao 		bootdevice_brom_id = BROM_BOOTSOURCE_USB;
56b2b4c2f5SYifeng Zhao 
57b2b4c2f5SYifeng Zhao 	bootdevice_brom_id = bootdevice_brom_id & BROM_BOOTSOURCE_MASK;
5838771996SKever Yang 	if (bootdevice_brom_id < ARRAY_SIZE(boot_devices))
5938771996SKever Yang 		bootdevice_ofpath = boot_devices[bootdevice_brom_id];
6038771996SKever Yang 
6138771996SKever Yang 	if (bootdevice_ofpath)
6238771996SKever Yang 		debug("%s: brom_bootdevice_id %x maps to '%s'\n",
6338771996SKever Yang 		      __func__, bootdevice_brom_id, bootdevice_ofpath);
6438771996SKever Yang 	else
6538771996SKever Yang 		debug("%s: failed to resolve brom_bootdevice_id %x\n",
6638771996SKever Yang 		      __func__, bootdevice_brom_id);
6738771996SKever Yang 
6838771996SKever Yang 	return bootdevice_ofpath;
6938771996SKever Yang }
7038771996SKever Yang 
spl_boot_device(void)7138771996SKever Yang u32 spl_boot_device(void)
7238771996SKever Yang {
7338771996SKever Yang 	u32 boot_device = BOOT_DEVICE_MMC1;
7438771996SKever Yang 
7538771996SKever Yang #if defined(CONFIG_TARGET_CHROMEBOOK_JERRY) || \
7638771996SKever Yang 		defined(CONFIG_TARGET_CHROMEBIT_MICKEY) || \
7738771996SKever Yang 		defined(CONFIG_TARGET_CHROMEBOOK_MINNIE)
7838771996SKever Yang 	return BOOT_DEVICE_SPI;
7938771996SKever Yang #endif
8038771996SKever Yang 	if (CONFIG_IS_ENABLED(ROCKCHIP_BACK_TO_BROM))
8138771996SKever Yang 		return BOOT_DEVICE_BOOTROM;
8238771996SKever Yang 
8338771996SKever Yang 	return boot_device;
8438771996SKever Yang }
8538771996SKever Yang 
spl_boot_mode(const u32 boot_device)8638771996SKever Yang u32 spl_boot_mode(const u32 boot_device)
8738771996SKever Yang {
8838771996SKever Yang 	return MMCSD_MODE_RAW;
8938771996SKever Yang }
9038771996SKever Yang 
rockchip_stimer_init(void)9138771996SKever Yang __weak void rockchip_stimer_init(void)
9238771996SKever Yang {
93d74e8763SKever Yang 	/* If Timer already enabled, don't re-init it */
94d74e8763SKever Yang 	u32 reg = readl(CONFIG_ROCKCHIP_STIMER_BASE + 0x10);
95d74e8763SKever Yang 	if ( reg & 0x1 )
96d74e8763SKever Yang 		return;
9713ceb2afSXuhui Lin #ifdef COUNTER_FREQUENCY
98a09afa08SKever Yang #ifndef CONFIG_ARM64
99a09afa08SKever Yang 	asm volatile("mcr p15, 0, %0, c14, c0, 0"
100a09afa08SKever Yang 		     : : "r"(COUNTER_FREQUENCY));
101a09afa08SKever Yang #endif
10213ceb2afSXuhui Lin #endif
10338771996SKever Yang 	writel(0, CONFIG_ROCKCHIP_STIMER_BASE + 0x10);
10438771996SKever Yang 	writel(0xffffffff, CONFIG_ROCKCHIP_STIMER_BASE);
10538771996SKever Yang 	writel(0xffffffff, CONFIG_ROCKCHIP_STIMER_BASE + 4);
10638771996SKever Yang 	writel(1, CONFIG_ROCKCHIP_STIMER_BASE + 0x10);
10738771996SKever Yang }
10838771996SKever Yang 
arch_cpu_init(void)10938771996SKever Yang __weak int arch_cpu_init(void)
11038771996SKever Yang {
11138771996SKever Yang 	return 0;
11238771996SKever Yang }
11338771996SKever Yang 
rk_board_init_f(void)11438771996SKever Yang __weak int rk_board_init_f(void)
11538771996SKever Yang {
11638771996SKever Yang 	return 0;
11738771996SKever Yang }
11838771996SKever Yang 
119e62c13b9SZhihuan He #ifndef CONFIG_SPL_LIBGENERIC_SUPPORT
udelay(unsigned long usec)120e62c13b9SZhihuan He void udelay(unsigned long usec)
121e62c13b9SZhihuan He {
122e62c13b9SZhihuan He 	__udelay(usec);
123e62c13b9SZhihuan He }
124e62c13b9SZhihuan He 
hang(void)125e62c13b9SZhihuan He void hang(void)
126e62c13b9SZhihuan He {
127e62c13b9SZhihuan He 	bootstage_error(BOOTSTAGE_ID_NEED_RESET);
128e62c13b9SZhihuan He 	for (;;)
129e62c13b9SZhihuan He 		;
130e62c13b9SZhihuan He }
131e62c13b9SZhihuan He 
132e62c13b9SZhihuan He /**
133e62c13b9SZhihuan He  * memset - Fill a region of memory with the given value
134e62c13b9SZhihuan He  * @s: Pointer to the start of the area.
135e62c13b9SZhihuan He  * @c: The byte to fill the area with
136e62c13b9SZhihuan He  * @count: The size of the area.
137e62c13b9SZhihuan He  *
138e62c13b9SZhihuan He  * Do not use memset() to access IO space, use memset_io() instead.
139e62c13b9SZhihuan He  */
memset(void * s,int c,size_t count)140e62c13b9SZhihuan He void *memset(void *s, int c, size_t count)
141e62c13b9SZhihuan He {
142e62c13b9SZhihuan He 	unsigned long *sl = (unsigned long *)s;
143e62c13b9SZhihuan He 	char *s8;
144e62c13b9SZhihuan He 
145e62c13b9SZhihuan He #if !CONFIG_IS_ENABLED(TINY_MEMSET)
146e62c13b9SZhihuan He 	unsigned long cl = 0;
147e62c13b9SZhihuan He 	int i;
148e62c13b9SZhihuan He 
149e62c13b9SZhihuan He 	/* do it one word at a time (32 bits or 64 bits) while possible */
150e62c13b9SZhihuan He 	if (((ulong)s & (sizeof(*sl) - 1)) == 0) {
151e62c13b9SZhihuan He 		for (i = 0; i < sizeof(*sl); i++) {
152e62c13b9SZhihuan He 			cl <<= 8;
153e62c13b9SZhihuan He 			cl |= c & 0xff;
154e62c13b9SZhihuan He 		}
155e62c13b9SZhihuan He 		while (count >= sizeof(*sl)) {
156e62c13b9SZhihuan He 			*sl++ = cl;
157e62c13b9SZhihuan He 			count -= sizeof(*sl);
158e62c13b9SZhihuan He 		}
159e62c13b9SZhihuan He 	}
160e62c13b9SZhihuan He #endif /* fill 8 bits at a time */
161e62c13b9SZhihuan He 	s8 = (char *)sl;
162e62c13b9SZhihuan He 	while (count--)
163e62c13b9SZhihuan He 		*s8++ = c;
164e62c13b9SZhihuan He 
165e62c13b9SZhihuan He 	return s;
166e62c13b9SZhihuan He }
167e62c13b9SZhihuan He #endif
168e62c13b9SZhihuan He 
1694fcb4a04SJoseph Chen #ifdef CONFIG_SPL_DM_RESET
brom_download(void)1704fcb4a04SJoseph Chen static void brom_download(void)
1714fcb4a04SJoseph Chen {
172b1f7fc03SXuhui Lin 	if (gd->console_evt == 0x02) {
1734fcb4a04SJoseph Chen 		printf("ctrl+b: Bootrom download!\n");
1744fcb4a04SJoseph Chen 		writel(BOOT_BROM_DOWNLOAD, CONFIG_ROCKCHIP_BOOT_MODE_REG);
1754fcb4a04SJoseph Chen 		do_reset(NULL, 0, 0, NULL);
1764fcb4a04SJoseph Chen 	}
1774fcb4a04SJoseph Chen }
1784fcb4a04SJoseph Chen #endif
1794fcb4a04SJoseph Chen 
spl_hotkey_init(void)180b1f7fc03SXuhui Lin static void spl_hotkey_init(void)
181b1f7fc03SXuhui Lin {
182b1f7fc03SXuhui Lin 	/* If disable console, skip getting uart reg */
183b1f7fc03SXuhui Lin 	if (!gd || gd->flags & GD_FLG_DISABLE_CONSOLE)
184b1f7fc03SXuhui Lin 		return;
185b1f7fc03SXuhui Lin 	if (!gd->have_console)
186b1f7fc03SXuhui Lin 		return;
187b1f7fc03SXuhui Lin 
188b1f7fc03SXuhui Lin 	/* serial uclass only exists when enable CONFIG_SPL_FRAMEWORK */
189b1f7fc03SXuhui Lin #ifdef CONFIG_SPL_FRAMEWORK
190b1f7fc03SXuhui Lin 	if (serial_tstc()) {
191b1f7fc03SXuhui Lin 		gd->console_evt = serial_getc();
192b1f7fc03SXuhui Lin #else
193b1f7fc03SXuhui Lin 	if (debug_uart_tstc()) {
194b1f7fc03SXuhui Lin 		gd->console_evt = debug_uart_getc();
195b1f7fc03SXuhui Lin #endif
196b1f7fc03SXuhui Lin 		if (gd->console_evt <= 0x1a) /* 'z' */
197b1f7fc03SXuhui Lin 			printf("SPL Hotkey: ctrl+%c\n",
198b1f7fc03SXuhui Lin 				gd->console_evt + 'a' - 1);
199b1f7fc03SXuhui Lin 	}
200b1f7fc03SXuhui Lin 
201b1f7fc03SXuhui Lin 	return;
202b1f7fc03SXuhui Lin }
203b1f7fc03SXuhui Lin 
20438771996SKever Yang void board_init_f(ulong dummy)
20538771996SKever Yang {
20638771996SKever Yang #ifdef CONFIG_SPL_FRAMEWORK
20738771996SKever Yang 	int ret;
20838771996SKever Yang #if !defined(CONFIG_SUPPORT_TPL)
20938771996SKever Yang 	struct udevice *dev;
21038771996SKever Yang #endif
21138771996SKever Yang #endif
2127d536d43SJoseph Chen 	gd->flags = dummy;
213a09afa08SKever Yang 	rockchip_stimer_init();
21438771996SKever Yang #define EARLY_UART
21538771996SKever Yang #if defined(EARLY_UART) && defined(CONFIG_DEBUG_UART)
21638771996SKever Yang 	/*
21738771996SKever Yang 	 * Debug UART can be used from here if required:
21838771996SKever Yang 	 *
21938771996SKever Yang 	 * debug_uart_init();
22038771996SKever Yang 	 * printch('a');
22138771996SKever Yang 	 * printhex8(0x1234);
22238771996SKever Yang 	 * printascii("string");
22338771996SKever Yang 	 */
22481e837faSJoseph Chen 	if (!gd->serial.using_pre_serial &&
22581e837faSJoseph Chen 	    !(gd->flags & GD_FLG_DISABLE_CONSOLE))
22638771996SKever Yang 		debug_uart_init();
22738771996SKever Yang 	printascii("U-Boot SPL board init");
22838771996SKever Yang #endif
229e220d757SJoseph Chen 	gd->sys_start_tick = get_ticks();
2304c8e468bSKever Yang #ifdef CONFIG_SPL_PCIE_EP_SUPPORT
2314c8e468bSKever Yang 	rockchip_pcie_ep_init();
2324c8e468bSKever Yang #endif
23338771996SKever Yang #ifdef CONFIG_SPL_FRAMEWORK
23438771996SKever Yang 	ret = spl_early_init();
23538771996SKever Yang 	if (ret) {
23638771996SKever Yang 		printf("spl_early_init() failed: %d\n", ret);
23738771996SKever Yang 		hang();
23838771996SKever Yang 	}
23938771996SKever Yang #if !defined(CONFIG_SUPPORT_TPL)
24038771996SKever Yang 	debug("\nspl:init dram\n");
24138771996SKever Yang 	ret = uclass_get_device(UCLASS_RAM, 0, &dev);
24238771996SKever Yang 	if (ret) {
24338771996SKever Yang 		printf("DRAM init failed: %d\n", ret);
24438771996SKever Yang 		return;
24538771996SKever Yang 	}
24638771996SKever Yang #endif
24738771996SKever Yang 	preloader_console_init();
24838771996SKever Yang #else
24938771996SKever Yang 	/* Some SoCs like rk3036 does not use any frame work */
25038771996SKever Yang 	sdram_init();
25138771996SKever Yang #endif
252b1f7fc03SXuhui Lin 	/* Get hotkey and store in gd */
253b1f7fc03SXuhui Lin 	spl_hotkey_init();
2544fcb4a04SJoseph Chen #ifdef CONFIG_SPL_DM_RESET
2554fcb4a04SJoseph Chen 	brom_download();
2564fcb4a04SJoseph Chen #endif
257ddc9405dSKever Yang 	arch_cpu_init();
25838771996SKever Yang 	rk_board_init_f();
2596f80b298SXuhui Lin #if defined(CONFIG_SPL_RAM_DEVICE) && defined(CONFIG_SPL_PCIE_EP_SUPPORT)
2604c8e468bSKever Yang 	rockchip_pcie_ep_get_firmware();
2614c8e468bSKever Yang #endif
26238771996SKever Yang #if CONFIG_IS_ENABLED(ROCKCHIP_BACK_TO_BROM) && !defined(CONFIG_SPL_BOARD_INIT)
26338771996SKever Yang 	back_to_bootrom(BROM_BOOT_NEXTSTAGE);
26438771996SKever Yang #endif
26538771996SKever Yang 
26638771996SKever Yang }
26738771996SKever Yang 
26838771996SKever Yang #ifdef CONFIG_SPL_LOAD_FIT
26938771996SKever Yang int board_fit_config_name_match(const char *name)
27038771996SKever Yang {
27138771996SKever Yang 	/* Just empty function now - can't decide what to choose */
27238771996SKever Yang 	debug("%s: %s\n", __func__, name);
27338771996SKever Yang 
27438771996SKever Yang 	return 0;
27538771996SKever Yang }
27638771996SKever Yang #endif
27738771996SKever Yang 
27893586e70SJoseph Chen int board_init_f_boot_flags(void)
27993586e70SJoseph Chen {
28093586e70SJoseph Chen 	int boot_flags = 0;
28193586e70SJoseph Chen 
28213ceb2afSXuhui Lin #ifdef CONFIG_ARM64
28313ceb2afSXuhui Lin 	asm volatile("mrs %0, cntfrq_el0" : "=r" (gd->arch.timer_rate_hz));
28413ceb2afSXuhui Lin #else
28513ceb2afSXuhui Lin 	asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (gd->arch.timer_rate_hz));
28613ceb2afSXuhui Lin #endif
28713ceb2afSXuhui Lin 
288dfe45d3eSJoseph Chen #if CONFIG_IS_ENABLED(FPGA_ROCKCHIP)
2899f68846bSJoseph Chen 	arch_fpga_init();
2909f68846bSJoseph Chen #endif
291ad771a9cSHuibin Hong #ifdef CONFIG_PSTORE
292ad771a9cSHuibin Hong 	param_parse_pstore();
293ad771a9cSHuibin Hong #endif
29493586e70SJoseph Chen 	/* pre-loader serial */
29593586e70SJoseph Chen #if defined(CONFIG_ROCKCHIP_PRELOADER_SERIAL) && \
29693586e70SJoseph Chen     defined(CONFIG_ROCKCHIP_PRELOADER_ATAGS)
29793586e70SJoseph Chen 	struct tag *t;
29893586e70SJoseph Chen 
29993586e70SJoseph Chen 	t = atags_get_tag(ATAG_SERIAL);
30093586e70SJoseph Chen 	if (t) {
30193586e70SJoseph Chen 		gd->serial.using_pre_serial = 1;
30293586e70SJoseph Chen 		gd->serial.enable = t->u.serial.enable;
30393586e70SJoseph Chen 		gd->serial.baudrate = t->u.serial.baudrate;
30493586e70SJoseph Chen 		gd->serial.addr = t->u.serial.addr;
30593586e70SJoseph Chen 		gd->serial.id = t->u.serial.id;
30693586e70SJoseph Chen 		gd->baudrate = t->u.serial.baudrate;
30793586e70SJoseph Chen 		if (!t->u.serial.enable)
30893586e70SJoseph Chen 			boot_flags |= GD_FLG_DISABLE_CONSOLE;
30993586e70SJoseph Chen 		debug("preloader: enable=%d, addr=0x%x, baudrate=%d, id=%d\n",
31093586e70SJoseph Chen 		      t->u.serial.enable, (u32)t->u.serial.addr,
31193586e70SJoseph Chen 		      t->u.serial.baudrate, t->u.serial.id);
31293586e70SJoseph Chen 	} else
31393586e70SJoseph Chen #endif
31493586e70SJoseph Chen 	{
31593586e70SJoseph Chen 		gd->baudrate = CONFIG_BAUDRATE;
31693586e70SJoseph Chen 		gd->serial.baudrate = CONFIG_BAUDRATE;
31793586e70SJoseph Chen 		gd->serial.addr = CONFIG_DEBUG_UART_BASE;
31893586e70SJoseph Chen 	}
31993586e70SJoseph Chen 
32093586e70SJoseph Chen 	/* The highest priority to turn off (override) console */
32193586e70SJoseph Chen #if defined(CONFIG_DISABLE_CONSOLE)
32293586e70SJoseph Chen 	boot_flags |= GD_FLG_DISABLE_CONSOLE;
32393586e70SJoseph Chen #endif
32493586e70SJoseph Chen 
32593586e70SJoseph Chen 	return boot_flags;
32693586e70SJoseph Chen }
32793586e70SJoseph Chen 
32838771996SKever Yang #ifdef CONFIG_SPL_BOARD_INIT
32938771996SKever Yang __weak int rk_spl_board_init(void)
33038771996SKever Yang {
33138771996SKever Yang 	return 0;
33238771996SKever Yang }
33338771996SKever Yang 
33438771996SKever Yang static int setup_led(void)
33538771996SKever Yang {
33638771996SKever Yang #ifdef CONFIG_SPL_LED
33738771996SKever Yang 	struct udevice *dev;
33838771996SKever Yang 	char *led_name;
33938771996SKever Yang 	int ret;
34038771996SKever Yang 
34138771996SKever Yang 	led_name = fdtdec_get_config_string(gd->fdt_blob, "u-boot,boot-led");
34238771996SKever Yang 	if (!led_name)
34338771996SKever Yang 		return 0;
34438771996SKever Yang 	ret = led_get_by_label(led_name, &dev);
34538771996SKever Yang 	if (ret) {
34638771996SKever Yang 		debug("%s: get=%d\n", __func__, ret);
34738771996SKever Yang 		return ret;
34838771996SKever Yang 	}
349f0daa6c1SJason Zhu 	ret = led_set_state(dev, LEDST_ON);
35038771996SKever Yang 	if (ret)
35138771996SKever Yang 		return ret;
35238771996SKever Yang #endif
35338771996SKever Yang 
35438771996SKever Yang 	return 0;
35538771996SKever Yang }
35638771996SKever Yang 
35738771996SKever Yang void spl_board_init(void)
35838771996SKever Yang {
35938771996SKever Yang 	int ret;
36038771996SKever Yang 
36138771996SKever Yang 	ret = setup_led();
36238771996SKever Yang 
36338771996SKever Yang 	if (ret) {
36438771996SKever Yang 		debug("LED ret=%d\n", ret);
36538771996SKever Yang 		hang();
36638771996SKever Yang 	}
36738771996SKever Yang 
36838771996SKever Yang 	rk_spl_board_init();
36938771996SKever Yang #if CONFIG_IS_ENABLED(ROCKCHIP_BACK_TO_BROM)
37038771996SKever Yang 	back_to_bootrom(BROM_BOOT_NEXTSTAGE);
37138771996SKever Yang #endif
37238771996SKever Yang 	return;
37338771996SKever Yang }
37438771996SKever Yang #endif
37510dd5e8cSJason Zhu 
3762323b257SJason Zhu #ifdef CONFIG_SPL_KERNEL_BOOT
3772323b257SJason Zhu static int spl_rockchip_dnl_key_pressed(void)
3782323b257SJason Zhu {
37952387546SJoseph Chen #if defined(CONFIG_SPL_INPUT)
38052387546SJoseph Chen 	return key_read(KEY_VOLUMEUP);
3812323b257SJason Zhu #else
38252387546SJoseph Chen 	return 0;
3832323b257SJason Zhu #endif
3842323b257SJason Zhu }
3852323b257SJason Zhu 
386c90ee5c7SJason Zhu #ifdef CONFIG_SPL_DM_FUEL_GAUGE
387c90ee5c7SJason Zhu bool spl_is_low_power(void)
388c90ee5c7SJason Zhu {
389c90ee5c7SJason Zhu 	struct udevice *dev;
390c90ee5c7SJason Zhu 	int ret, voltage;
391c90ee5c7SJason Zhu 
392c90ee5c7SJason Zhu 	ret = uclass_get_device(UCLASS_FG, 0, &dev);
393c90ee5c7SJason Zhu 	if (ret) {
394c90ee5c7SJason Zhu 		debug("Get charge display failed, ret=%d\n", ret);
395c90ee5c7SJason Zhu 		return false;
396c90ee5c7SJason Zhu 	}
397c90ee5c7SJason Zhu 
398c90ee5c7SJason Zhu 	voltage = fuel_gauge_get_voltage(dev);
399c90ee5c7SJason Zhu 	if (voltage >= CONFIG_SPL_POWER_LOW_VOLTAGE_THRESHOLD)
400c90ee5c7SJason Zhu 		return false;
401c90ee5c7SJason Zhu 
402c90ee5c7SJason Zhu 	return true;
403c90ee5c7SJason Zhu }
404c90ee5c7SJason Zhu #endif
405c90ee5c7SJason Zhu 
4062323b257SJason Zhu void spl_next_stage(struct spl_image_info *spl)
4072323b257SJason Zhu {
408c07b486eSXuhui Lin 	const char *reason[] = { "Recovery key", "Ctrl+c", "LowPwr", "Other" };
4092323b257SJason Zhu 	uint32_t reg_boot_mode;
410c5d340afSXuhui Lin 	int i = 0;
4112323b257SJason Zhu 
4122323b257SJason Zhu 	if (spl_rockchip_dnl_key_pressed()) {
413c5d340afSXuhui Lin 		i = 0;
4142323b257SJason Zhu 		spl->next_stage = SPL_NEXT_STAGE_UBOOT;
415c5d340afSXuhui Lin 		goto out;
4162323b257SJason Zhu 	}
417c5d340afSXuhui Lin 
418c5d340afSXuhui Lin 	if (gd->console_evt == 0x03) {
419c5d340afSXuhui Lin 		i = 1;
420c5d340afSXuhui Lin 		spl->next_stage = SPL_NEXT_STAGE_UBOOT;
421c5d340afSXuhui Lin 		goto out;
422c5d340afSXuhui Lin 	}
423c5d340afSXuhui Lin 
424c90ee5c7SJason Zhu #ifdef CONFIG_SPL_DM_FUEL_GAUGE
425c90ee5c7SJason Zhu 	if (spl_is_low_power()) {
426c5d340afSXuhui Lin 		i = 2;
427c90ee5c7SJason Zhu 		spl->next_stage = SPL_NEXT_STAGE_UBOOT;
428c5d340afSXuhui Lin 		goto out;
429c90ee5c7SJason Zhu 	}
430c90ee5c7SJason Zhu #endif
4312323b257SJason Zhu 
4322323b257SJason Zhu 	reg_boot_mode = readl((void *)CONFIG_ROCKCHIP_BOOT_MODE_REG);
4332323b257SJason Zhu 	switch (reg_boot_mode) {
434c07b486eSXuhui Lin 	case BOOT_LOADER:
435c07b486eSXuhui Lin 	case BOOT_FASTBOOT:
436c07b486eSXuhui Lin 	case BOOT_CHARGING:
437c07b486eSXuhui Lin 	case BOOT_UMS:
438c07b486eSXuhui Lin 	case BOOT_DFU:
439c5d340afSXuhui Lin 		i = 3;
4402323b257SJason Zhu 		spl->next_stage = SPL_NEXT_STAGE_UBOOT;
441bff96653SXuhui Lin 		break;
442c07b486eSXuhui Lin 	default:
443c07b486eSXuhui Lin 		spl->next_stage = SPL_NEXT_STAGE_KERNEL;
4442323b257SJason Zhu 	}
445c5d340afSXuhui Lin 
446c5d340afSXuhui Lin out:
447c5d340afSXuhui Lin 	if (spl->next_stage == SPL_NEXT_STAGE_UBOOT)
448c5d340afSXuhui Lin 		printf("Enter uboot reason: %s\n", reason[i]);
449c5d340afSXuhui Lin 
450c5d340afSXuhui Lin 	return;
451c5d340afSXuhui Lin }
4526afcbf88SJoseph Chen 
4534484e03eSJoseph Chen const char *spl_kernel_partition(struct spl_image_info *spl,
4544484e03eSJoseph Chen 				 struct spl_load_info *info)
4554484e03eSJoseph Chen {
4564484e03eSJoseph Chen 	struct bootloader_message *bmsg = NULL;
4574484e03eSJoseph Chen 	u32 boot_mode;
4584484e03eSJoseph Chen 	int ret, cnt;
4594484e03eSJoseph Chen 	u32 sector = 0;
4604484e03eSJoseph Chen 
4614484e03eSJoseph Chen #ifdef CONFIG_SPL_LIBDISK_SUPPORT
4624484e03eSJoseph Chen 	disk_partition_t part_info;
4634484e03eSJoseph Chen 
4644484e03eSJoseph Chen 	ret = part_get_info_by_name(info->dev, PART_MISC, &part_info);
4654484e03eSJoseph Chen 	if (ret >= 0)
4664484e03eSJoseph Chen 		sector = part_info.start;
4674484e03eSJoseph Chen #else
4684484e03eSJoseph Chen 	sector = CONFIG_SPL_MISC_SECTOR;
4694484e03eSJoseph Chen #endif
4704484e03eSJoseph Chen 	if (sector) {
4714484e03eSJoseph Chen 		cnt = DIV_ROUND_UP(sizeof(*bmsg), info->bl_len);
4724484e03eSJoseph Chen 		bmsg = memalign(ARCH_DMA_MINALIGN, cnt * info->bl_len);
4734484e03eSJoseph Chen 		ret = info->read(info, sector + BCB_MESSAGE_BLK_OFFSET,
4744484e03eSJoseph Chen 				 cnt, bmsg);
4754484e03eSJoseph Chen 		if (ret == cnt && !strcmp(bmsg->command, "boot-recovery")) {
4764484e03eSJoseph Chen 			free(bmsg);
4774484e03eSJoseph Chen 			return PART_RECOVERY;
4784484e03eSJoseph Chen 		} else {
4794484e03eSJoseph Chen 			free(bmsg);
4804484e03eSJoseph Chen 		}
4814484e03eSJoseph Chen 	}
4824484e03eSJoseph Chen 
4834484e03eSJoseph Chen 	boot_mode = readl((void *)CONFIG_ROCKCHIP_BOOT_MODE_REG);
4844484e03eSJoseph Chen 
4854484e03eSJoseph Chen 	return (boot_mode == BOOT_RECOVERY) ? PART_RECOVERY : PART_BOOT;
4864484e03eSJoseph Chen }
4870d7b3963SXuhui Lin 
488b37add71SXuhui Lin __weak void spl_fdt_fixup_memory(struct spl_image_info *spl_image)
4890d7b3963SXuhui Lin {
4900d7b3963SXuhui Lin 	void *blob = spl_image->fdt_addr;
4910d7b3963SXuhui Lin 	struct tag *t;
4920d7b3963SXuhui Lin 	u64 start[CONFIG_NR_DRAM_BANKS];
4930d7b3963SXuhui Lin 	u64 size[CONFIG_NR_DRAM_BANKS];
4940d7b3963SXuhui Lin 	int i, count, err;
4950d7b3963SXuhui Lin 
4960d7b3963SXuhui Lin 	err = fdt_check_header(blob);
4970d7b3963SXuhui Lin 	if (err < 0) {
4980d7b3963SXuhui Lin 		printf("Invalid dtb\n");
4990d7b3963SXuhui Lin 		return;
5000d7b3963SXuhui Lin 	}
5010d7b3963SXuhui Lin 
5020d7b3963SXuhui Lin 	/* Fixup memory node based on ddr_mem atags */
5030d7b3963SXuhui Lin 	t = atags_get_tag(ATAG_DDR_MEM);
5040d7b3963SXuhui Lin 	if (t && t->u.ddr_mem.count) {
5050d7b3963SXuhui Lin 		count = t->u.ddr_mem.count;
5060d7b3963SXuhui Lin 		for (i = 0; i < count; i++) {
5070d7b3963SXuhui Lin 			start[i] = t->u.ddr_mem.bank[i];
5080d7b3963SXuhui Lin 			size[i] = t->u.ddr_mem.bank[i + count];
509be1263cbSXuhui Lin #ifdef SPL_RESV_MEM_SIZE
510be1263cbSXuhui Lin 			if ((start[i] == CONFIG_SYS_SDRAM_BASE) &&
511be1263cbSXuhui Lin 			    (start[i] + size[i] > CONFIG_SYS_SDRAM_BASE + SPL_RESV_MEM_SIZE))
512be1263cbSXuhui Lin 				start[i] += SPL_RESV_MEM_SIZE;
513be1263cbSXuhui Lin #endif
5140d7b3963SXuhui Lin 			if (size[i] == 0)
5150d7b3963SXuhui Lin 				continue;
5160d7b3963SXuhui Lin 			debug("Adding bank: 0x%08llx - 0x%08llx (size: 0x%08llx)\n",
5170d7b3963SXuhui Lin 			       start[i], start[i] + size[i], size[i]);
5180d7b3963SXuhui Lin 		}
5195c9a04ecSXuhui Lin 
5205c9a04ecSXuhui Lin 		fdt_increase_size(blob, 512);
5215c9a04ecSXuhui Lin 
5220d7b3963SXuhui Lin 		err = fdt_fixup_memory_banks(blob, start, size, count);
5230d7b3963SXuhui Lin 		if (err < 0) {
5240d7b3963SXuhui Lin 			printf("Fixup kernel dtb memory node failed: %s\n", fdt_strerror(err));
5250d7b3963SXuhui Lin 			return;
5260d7b3963SXuhui Lin 		}
5270d7b3963SXuhui Lin 	}
5280d7b3963SXuhui Lin 
5290d7b3963SXuhui Lin 	return;
5300d7b3963SXuhui Lin }
53144f37eaaSXuhui Lin 
53244f37eaaSXuhui Lin #if defined(CONFIG_SPL_ROCKCHIP_HWID_DTB)
53344f37eaaSXuhui Lin int spl_find_hwid_dtb(const char *fdt_name)
53444f37eaaSXuhui Lin {
53544f37eaaSXuhui Lin 	hwid_init_data();
53644f37eaaSXuhui Lin 
53744f37eaaSXuhui Lin 	return hwid_dtb_is_available(fdt_name);
53844f37eaaSXuhui Lin }
53944f37eaaSXuhui Lin #endif
540*b6bda7d5SXuhui Lin 
541*b6bda7d5SXuhui Lin int spl_fdt_chosen_bootargs(struct spl_load_info *info, void *fdt)
542*b6bda7d5SXuhui Lin {
543*b6bda7d5SXuhui Lin 	__maybe_unused struct blk_desc *desc = info->dev;
544*b6bda7d5SXuhui Lin 
545*b6bda7d5SXuhui Lin #ifdef CONFIG_SPL_AB
546*b6bda7d5SXuhui Lin 	char slot_suffix[3] = {0};
547*b6bda7d5SXuhui Lin 
548*b6bda7d5SXuhui Lin 	if (!spl_get_current_slot(desc, "misc", slot_suffix))
549*b6bda7d5SXuhui Lin 		spl_ab_bootargs_append_slot(fdt, slot_suffix);
550*b6bda7d5SXuhui Lin #endif
551*b6bda7d5SXuhui Lin 
552*b6bda7d5SXuhui Lin #ifdef CONFIG_SPL_ENVF
553*b6bda7d5SXuhui Lin 	char *part_type[] = { "mtdparts", "blkdevparts" };
554*b6bda7d5SXuhui Lin 	char *env = NULL;
555*b6bda7d5SXuhui Lin 	char *part_list;
556*b6bda7d5SXuhui Lin 	int id = 0, ret = 0;
557*b6bda7d5SXuhui Lin 
558*b6bda7d5SXuhui Lin 	env = envf_get(desc, part_type[id]);
559*b6bda7d5SXuhui Lin 	if (!env)
560*b6bda7d5SXuhui Lin 		env = envf_get(desc, part_type[++id]);
561*b6bda7d5SXuhui Lin 	if (env) {
562*b6bda7d5SXuhui Lin 		if (!strstr(env, part_type[id])) {
563*b6bda7d5SXuhui Lin 			part_list = calloc(1, strlen(env) + strlen(part_type[id]) + 2);
564*b6bda7d5SXuhui Lin 			if (part_list) {
565*b6bda7d5SXuhui Lin 				strcat(part_list, part_type[id]);
566*b6bda7d5SXuhui Lin 				strcat(part_list, "=");
567*b6bda7d5SXuhui Lin 				strcat(part_list, env);
568*b6bda7d5SXuhui Lin 			}
569*b6bda7d5SXuhui Lin 		} else {
570*b6bda7d5SXuhui Lin 			part_list = env;
571*b6bda7d5SXuhui Lin 		}
572*b6bda7d5SXuhui Lin 		ret = fdt_bootargs_append(fdt, part_list);
573*b6bda7d5SXuhui Lin 		if (ret) {
574*b6bda7d5SXuhui Lin 			printf("Append parts info to bootargs fail");
575*b6bda7d5SXuhui Lin 			return ret;
576*b6bda7d5SXuhui Lin 		}
577*b6bda7d5SXuhui Lin 		debug("## parts: %s\n\n", part_list);
578*b6bda7d5SXuhui Lin 
579*b6bda7d5SXuhui Lin 		env = envf_get(desc, "sys_bootargs");
580*b6bda7d5SXuhui Lin 		env = env + strlen("sys_bootargs=");
581*b6bda7d5SXuhui Lin 		if (env) {
582*b6bda7d5SXuhui Lin 			ret = fdt_bootargs_append(fdt, env);
583*b6bda7d5SXuhui Lin 			if (ret) {
584*b6bda7d5SXuhui Lin 				printf("Append sys_bootargs to bootargs fail");
585*b6bda7d5SXuhui Lin 				return ret;
586*b6bda7d5SXuhui Lin 			}
587*b6bda7d5SXuhui Lin 			debug("## sys_bootargs: %s\n\n", env);
588*b6bda7d5SXuhui Lin 		}
589*b6bda7d5SXuhui Lin 	}
590*b6bda7d5SXuhui Lin #endif
591*b6bda7d5SXuhui Lin #ifdef CONFIG_MTD_BLK
592*b6bda7d5SXuhui Lin 	if (!env && desc->if_type == IF_TYPE_MTD) {
593*b6bda7d5SXuhui Lin 		char *mtd_par_info = mtd_part_parse(desc);
594*b6bda7d5SXuhui Lin 
595*b6bda7d5SXuhui Lin 		ret = fdt_bootargs_append(fdt, mtd_par_info);
596*b6bda7d5SXuhui Lin 		if (ret) {
597*b6bda7d5SXuhui Lin 			printf("Append mtdparts info to bootargs fail");
598*b6bda7d5SXuhui Lin 			return ret;
599*b6bda7d5SXuhui Lin 		}
600*b6bda7d5SXuhui Lin 		debug("## mtdparts: %s\n\n", mtd_par_info);
601*b6bda7d5SXuhui Lin 	}
602*b6bda7d5SXuhui Lin #endif
603*b6bda7d5SXuhui Lin #ifdef CONFIG_ROCKCHIP_META
604*b6bda7d5SXuhui Lin 	rk_meta_bootargs_append(fdt);
605*b6bda7d5SXuhui Lin #endif
606*b6bda7d5SXuhui Lin 
607*b6bda7d5SXuhui Lin 	return 0;
608*b6bda7d5SXuhui Lin }
6094484e03eSJoseph Chen #endif
6104484e03eSJoseph Chen 
6110d7b3963SXuhui Lin void spl_perform_fixups(struct spl_image_info *spl_image)
6120d7b3963SXuhui Lin {
6130d7b3963SXuhui Lin #ifdef CONFIG_ROCKCHIP_PRELOADER_ATAGS
6140d7b3963SXuhui Lin 	atags_set_bootdev_by_spl_bootdevice(spl_image->boot_device);
6150d7b3963SXuhui Lin   #ifdef BUILD_SPL_TAG
6160d7b3963SXuhui Lin 	atags_set_shared_fwver(FW_SPL, "spl-"BUILD_SPL_TAG);
6170d7b3963SXuhui Lin   #endif
6180d7b3963SXuhui Lin #endif
6190d7b3963SXuhui Lin #if defined(CONFIG_SPL_KERNEL_BOOT)
6200d7b3963SXuhui Lin 	if (spl_image->next_stage == SPL_NEXT_STAGE_KERNEL)
6210d7b3963SXuhui Lin 		spl_fdt_fixup_memory(spl_image);
6220d7b3963SXuhui Lin #endif
6230d7b3963SXuhui Lin 	return;
6240d7b3963SXuhui Lin }
6250d7b3963SXuhui Lin 
626cead3ab8SJason Zhu void spl_hang_reset(void)
627cead3ab8SJason Zhu {
628cead3ab8SJason Zhu 	printf("# Reset the board to bootrom #\n");
629cead3ab8SJason Zhu #if defined(CONFIG_SPL_SYSRESET) && defined(CONFIG_SPL_DRIVERS_MISC_SUPPORT)
6305ead1aa0SJoseph Chen 	/* reset is available after dm setup */
6315ead1aa0SJoseph Chen 	if (gd->flags & GD_FLG_SPL_EARLY_INIT) {
632cead3ab8SJason Zhu 		writel(BOOT_BROM_DOWNLOAD, CONFIG_ROCKCHIP_BOOT_MODE_REG);
633cead3ab8SJason Zhu 		do_reset(NULL, 0, 0, NULL);
6345ead1aa0SJoseph Chen 	}
635cead3ab8SJason Zhu #endif
636cead3ab8SJason Zhu }
637a5373663SJason Zhu 
638cf13b784SJoseph Chen #ifdef CONFIG_SPL_FIT_ROLLBACK_PROTECT
639cf13b784SJoseph Chen int fit_read_otp_rollback_index(uint32_t fit_index, uint32_t *otp_index)
640cf13b784SJoseph Chen {
641cf13b784SJoseph Chen 	int ret = 0;
642cf13b784SJoseph Chen 
643cf13b784SJoseph Chen 	*otp_index = 0;
644299f09a0SJason Zhu #if defined(CONFIG_SPL_ROCKCHIP_SECURE_OTP)
645cf13b784SJoseph Chen 	struct udevice *dev;
646cf13b784SJoseph Chen 	u32 index, i, otp_version;
647cf13b784SJoseph Chen 	u32 bit_count;
648cf13b784SJoseph Chen 
649cf13b784SJoseph Chen 	dev = misc_otp_get_device(OTP_S);
650cf13b784SJoseph Chen 	if (!dev)
651cf13b784SJoseph Chen 		return -ENODEV;
652cf13b784SJoseph Chen 
653cf13b784SJoseph Chen 	otp_version = 0;
654cf13b784SJoseph Chen 	for (i = 0; i < OTP_UBOOT_ROLLBACK_WORDS; i++) {
655bf39446fSJason Zhu 		if (misc_otp_read(dev, OTP_UBOOT_ROLLBACK_OFFSET + i * 4,
656cf13b784SJoseph Chen 		    &index,
657cf13b784SJoseph Chen 		    4)) {
658cf13b784SJoseph Chen 			printf("Can't read rollback index\n");
659cf13b784SJoseph Chen 			return -EIO;
660cf13b784SJoseph Chen 		}
661bf39446fSJason Zhu 
662cf13b784SJoseph Chen 		bit_count = fls(index);
663cf13b784SJoseph Chen 		otp_version += bit_count;
664cf13b784SJoseph Chen 	}
665cf13b784SJoseph Chen 	*otp_index = otp_version;
666cf13b784SJoseph Chen #endif
667cf13b784SJoseph Chen 
668cf13b784SJoseph Chen 	return ret;
669cf13b784SJoseph Chen }
670cf13b784SJoseph Chen 
671cf13b784SJoseph Chen static int fit_write_otp_rollback_index(u32 fit_index)
672cf13b784SJoseph Chen {
673299f09a0SJason Zhu #if defined(CONFIG_SPL_ROCKCHIP_SECURE_OTP)
674cf13b784SJoseph Chen 	struct udevice *dev;
675cf13b784SJoseph Chen 	u32 index, i, otp_index;
676cf13b784SJoseph Chen 
677d5989feaSJoseph Chen 	if (!fit_index)
678d5989feaSJoseph Chen 		return 0;
679d5989feaSJoseph Chen 
680d5989feaSJoseph Chen 	if (fit_index > OTP_UBOOT_ROLLBACK_WORDS * 32)
681cf13b784SJoseph Chen 		return -EINVAL;
682cf13b784SJoseph Chen 
683cf13b784SJoseph Chen 	dev = misc_otp_get_device(OTP_S);
684cf13b784SJoseph Chen 	if (!dev)
685cf13b784SJoseph Chen 		return -ENODEV;
686cf13b784SJoseph Chen 
687cf13b784SJoseph Chen 	if (fit_read_otp_rollback_index(fit_index, &otp_index))
688cf13b784SJoseph Chen 		return -EIO;
689cf13b784SJoseph Chen 
690cf13b784SJoseph Chen 	if (otp_index < fit_index) {
691cf13b784SJoseph Chen 		/* Write new SW version to otp */
692cf13b784SJoseph Chen 		for (i = 0; i < OTP_UBOOT_ROLLBACK_WORDS; i++) {
693bf39446fSJason Zhu 			/*
694bf39446fSJason Zhu 			 * If fit_index is equal to 0, then execute 0xffffffff >> 32.
695bf39446fSJason Zhu 			 * But the operand can only be 0 - 31. The "0xffffffff >> 32" is
696bf39446fSJason Zhu 			 * actually be "0xffffffff >> 0".
697bf39446fSJason Zhu 			 */
698bf39446fSJason Zhu 			if (!fit_index)
699bf39446fSJason Zhu 				break;
700cf13b784SJoseph Chen 			/* convert to base-1 representation */
701cf13b784SJoseph Chen 			index = 0xffffffff >> (OTP_ALL_ONES_NUM_BITS -
702cf13b784SJoseph Chen 				min(fit_index, (u32)OTP_ALL_ONES_NUM_BITS));
703cf13b784SJoseph Chen 			fit_index -= min(fit_index,
704cf13b784SJoseph Chen 					  (u32)OTP_ALL_ONES_NUM_BITS);
705cf13b784SJoseph Chen 			if (index) {
706bf39446fSJason Zhu 				if (misc_otp_write(dev, OTP_UBOOT_ROLLBACK_OFFSET + i * 4,
707cf13b784SJoseph Chen 				    &index,
708cf13b784SJoseph Chen 				    4)) {
709cf13b784SJoseph Chen 					printf("Can't write rollback index\n");
710cf13b784SJoseph Chen 					return -EIO;
711cf13b784SJoseph Chen 				}
712cf13b784SJoseph Chen 			}
713cf13b784SJoseph Chen 		}
714cf13b784SJoseph Chen 	}
715cf13b784SJoseph Chen #endif
716cf13b784SJoseph Chen 
717cf13b784SJoseph Chen 	return 0;
718cf13b784SJoseph Chen }
719cf13b784SJoseph Chen #endif
720cf13b784SJoseph Chen 
721ed5a55baSJoseph Chen int spl_board_prepare_for_jump(struct spl_image_info *spl_image)
722ed5a55baSJoseph Chen {
723cf13b784SJoseph Chen #ifdef CONFIG_SPL_FIT_ROLLBACK_PROTECT
7248d26d4b3SJoseph Chen 	int ret;
7258d26d4b3SJoseph Chen 
7268d26d4b3SJoseph Chen 	ret = fit_write_otp_rollback_index(gd->rollback_index);
7278d26d4b3SJoseph Chen 	if (ret) {
7288d26d4b3SJoseph Chen 		panic("Failed to write fit rollback index %d, ret=%d",
7298d26d4b3SJoseph Chen 		      gd->rollback_index, ret);
7308d26d4b3SJoseph Chen 	}
731ed5a55baSJoseph Chen #endif
732a5401a9dSJoseph Chen 
733a5401a9dSJoseph Chen #ifdef CONFIG_SPL_ROCKCHIP_HW_DECOMPRESS
734a5401a9dSJoseph Chen 	misc_decompress_cleanup();
735a5401a9dSJoseph Chen #endif
73652c8858eSJoseph Chen 	spl_rk_board_prepare_for_jump(spl_image);
73752c8858eSJoseph Chen 
738ed5a55baSJoseph Chen 	return 0;
739ed5a55baSJoseph Chen }
740