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