2018-01-22 06:49:12 +00:00
|
|
|
/*
|
|
|
|
|
* (C) Copyright 2018 Rockchip Electronics Co., Ltd
|
|
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: GPL-2.0+
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <common.h>
|
|
|
|
|
#include <debug_uart.h>
|
|
|
|
|
#include <dm.h>
|
2020-03-21 09:11:18 +00:00
|
|
|
#include <key.h>
|
2020-04-24 01:44:00 +00:00
|
|
|
#include <misc.h>
|
2018-01-22 06:49:12 +00:00
|
|
|
#include <ram.h>
|
|
|
|
|
#include <spl.h>
|
2020-04-02 11:59:12 +00:00
|
|
|
#include <optee_include/OpteeClientInterface.h>
|
2018-01-22 06:49:12 +00:00
|
|
|
#include <asm/arch/bootrom.h>
|
2019-07-26 07:57:13 +00:00
|
|
|
#ifdef CONFIG_ROCKCHIP_PRELOADER_ATAGS
|
|
|
|
|
#include <asm/arch/rk_atags.h>
|
|
|
|
|
#endif
|
2019-03-07 09:31:43 +00:00
|
|
|
#include <asm/arch/sdram.h>
|
2020-03-21 09:11:18 +00:00
|
|
|
#include <asm/arch/boot_mode.h>
|
2018-02-01 07:40:55 +00:00
|
|
|
#include <asm/arch-rockchip/sys_proto.h>
|
2018-01-22 06:49:12 +00:00
|
|
|
#include <asm/io.h>
|
|
|
|
|
|
|
|
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
|
|
|
|
|
|
void board_return_to_bootrom(void)
|
|
|
|
|
{
|
|
|
|
|
back_to_bootrom(BROM_BOOT_NEXTSTAGE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
__weak const char * const boot_devices[BROM_LAST_BOOTSOURCE + 1] = {
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const char *board_spl_was_booted_from(void)
|
|
|
|
|
{
|
|
|
|
|
u32 bootdevice_brom_id = readl(BROM_BOOTSOURCE_ID_ADDR);
|
|
|
|
|
const char *bootdevice_ofpath = NULL;
|
|
|
|
|
|
|
|
|
|
if (bootdevice_brom_id < ARRAY_SIZE(boot_devices))
|
|
|
|
|
bootdevice_ofpath = boot_devices[bootdevice_brom_id];
|
|
|
|
|
|
|
|
|
|
if (bootdevice_ofpath)
|
|
|
|
|
debug("%s: brom_bootdevice_id %x maps to '%s'\n",
|
|
|
|
|
__func__, bootdevice_brom_id, bootdevice_ofpath);
|
|
|
|
|
else
|
|
|
|
|
debug("%s: failed to resolve brom_bootdevice_id %x\n",
|
|
|
|
|
__func__, bootdevice_brom_id);
|
|
|
|
|
|
|
|
|
|
return bootdevice_ofpath;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u32 spl_boot_device(void)
|
|
|
|
|
{
|
|
|
|
|
u32 boot_device = BOOT_DEVICE_MMC1;
|
|
|
|
|
|
|
|
|
|
#if defined(CONFIG_TARGET_CHROMEBOOK_JERRY) || \
|
|
|
|
|
defined(CONFIG_TARGET_CHROMEBIT_MICKEY) || \
|
|
|
|
|
defined(CONFIG_TARGET_CHROMEBOOK_MINNIE)
|
|
|
|
|
return BOOT_DEVICE_SPI;
|
|
|
|
|
#endif
|
|
|
|
|
if (CONFIG_IS_ENABLED(ROCKCHIP_BACK_TO_BROM))
|
|
|
|
|
return BOOT_DEVICE_BOOTROM;
|
|
|
|
|
|
|
|
|
|
return boot_device;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u32 spl_boot_mode(const u32 boot_device)
|
|
|
|
|
{
|
|
|
|
|
return MMCSD_MODE_RAW;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
__weak void rockchip_stimer_init(void)
|
|
|
|
|
{
|
2019-03-26 08:10:35 +00:00
|
|
|
/* If Timer already enabled, don't re-init it */
|
|
|
|
|
u32 reg = readl(CONFIG_ROCKCHIP_STIMER_BASE + 0x10);
|
|
|
|
|
if ( reg & 0x1 )
|
|
|
|
|
return;
|
2018-03-15 07:43:59 +00:00
|
|
|
#ifndef CONFIG_ARM64
|
|
|
|
|
asm volatile("mcr p15, 0, %0, c14, c0, 0"
|
|
|
|
|
: : "r"(COUNTER_FREQUENCY));
|
|
|
|
|
#endif
|
2018-01-22 06:49:12 +00:00
|
|
|
writel(0, CONFIG_ROCKCHIP_STIMER_BASE + 0x10);
|
|
|
|
|
writel(0xffffffff, CONFIG_ROCKCHIP_STIMER_BASE);
|
|
|
|
|
writel(0xffffffff, CONFIG_ROCKCHIP_STIMER_BASE + 4);
|
|
|
|
|
writel(1, CONFIG_ROCKCHIP_STIMER_BASE + 0x10);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
__weak int arch_cpu_init(void)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
__weak int rk_board_init_f(void)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-25 10:11:24 +00:00
|
|
|
#ifndef CONFIG_SPL_LIBGENERIC_SUPPORT
|
|
|
|
|
void udelay(unsigned long usec)
|
|
|
|
|
{
|
|
|
|
|
__udelay(usec);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void hang(void)
|
|
|
|
|
{
|
|
|
|
|
bootstage_error(BOOTSTAGE_ID_NEED_RESET);
|
|
|
|
|
for (;;)
|
|
|
|
|
;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* memset - Fill a region of memory with the given value
|
|
|
|
|
* @s: Pointer to the start of the area.
|
|
|
|
|
* @c: The byte to fill the area with
|
|
|
|
|
* @count: The size of the area.
|
|
|
|
|
*
|
|
|
|
|
* Do not use memset() to access IO space, use memset_io() instead.
|
|
|
|
|
*/
|
|
|
|
|
void *memset(void *s, int c, size_t count)
|
|
|
|
|
{
|
|
|
|
|
unsigned long *sl = (unsigned long *)s;
|
|
|
|
|
char *s8;
|
|
|
|
|
|
|
|
|
|
#if !CONFIG_IS_ENABLED(TINY_MEMSET)
|
|
|
|
|
unsigned long cl = 0;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
/* do it one word at a time (32 bits or 64 bits) while possible */
|
|
|
|
|
if (((ulong)s & (sizeof(*sl) - 1)) == 0) {
|
|
|
|
|
for (i = 0; i < sizeof(*sl); i++) {
|
|
|
|
|
cl <<= 8;
|
|
|
|
|
cl |= c & 0xff;
|
|
|
|
|
}
|
|
|
|
|
while (count >= sizeof(*sl)) {
|
|
|
|
|
*sl++ = cl;
|
|
|
|
|
count -= sizeof(*sl);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif /* fill 8 bits at a time */
|
|
|
|
|
s8 = (char *)sl;
|
|
|
|
|
while (count--)
|
|
|
|
|
*s8++ = c;
|
|
|
|
|
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2018-01-22 06:49:12 +00:00
|
|
|
void board_init_f(ulong dummy)
|
|
|
|
|
{
|
|
|
|
|
#ifdef CONFIG_SPL_FRAMEWORK
|
|
|
|
|
int ret;
|
|
|
|
|
#if !defined(CONFIG_SUPPORT_TPL)
|
|
|
|
|
struct udevice *dev;
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
2018-03-15 07:43:59 +00:00
|
|
|
rockchip_stimer_init();
|
2018-01-22 06:49:12 +00:00
|
|
|
#define EARLY_UART
|
|
|
|
|
#if defined(EARLY_UART) && defined(CONFIG_DEBUG_UART)
|
|
|
|
|
/*
|
|
|
|
|
* Debug UART can be used from here if required:
|
|
|
|
|
*
|
|
|
|
|
* debug_uart_init();
|
|
|
|
|
* printch('a');
|
|
|
|
|
* printhex8(0x1234);
|
|
|
|
|
* printascii("string");
|
|
|
|
|
*/
|
|
|
|
|
debug_uart_init();
|
|
|
|
|
printascii("U-Boot SPL board init");
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_SPL_FRAMEWORK
|
|
|
|
|
ret = spl_early_init();
|
|
|
|
|
if (ret) {
|
|
|
|
|
printf("spl_early_init() failed: %d\n", ret);
|
|
|
|
|
hang();
|
|
|
|
|
}
|
|
|
|
|
#if !defined(CONFIG_SUPPORT_TPL)
|
|
|
|
|
debug("\nspl:init dram\n");
|
|
|
|
|
ret = uclass_get_device(UCLASS_RAM, 0, &dev);
|
|
|
|
|
if (ret) {
|
|
|
|
|
printf("DRAM init failed: %d\n", ret);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
preloader_console_init();
|
|
|
|
|
#else
|
|
|
|
|
/* Some SoCs like rk3036 does not use any frame work */
|
|
|
|
|
sdram_init();
|
|
|
|
|
#endif
|
|
|
|
|
|
2019-03-25 10:10:06 +00:00
|
|
|
arch_cpu_init();
|
2018-01-22 06:49:12 +00:00
|
|
|
rk_board_init_f();
|
|
|
|
|
#if CONFIG_IS_ENABLED(ROCKCHIP_BACK_TO_BROM) && !defined(CONFIG_SPL_BOARD_INIT)
|
|
|
|
|
back_to_bootrom(BROM_BOOT_NEXTSTAGE);
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_SPL_LOAD_FIT
|
|
|
|
|
int board_fit_config_name_match(const char *name)
|
|
|
|
|
{
|
|
|
|
|
/* Just empty function now - can't decide what to choose */
|
|
|
|
|
debug("%s: %s\n", __func__, name);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef CONFIG_SPL_BOARD_INIT
|
|
|
|
|
__weak int rk_spl_board_init(void)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int setup_led(void)
|
|
|
|
|
{
|
|
|
|
|
#ifdef CONFIG_SPL_LED
|
|
|
|
|
struct udevice *dev;
|
|
|
|
|
char *led_name;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
led_name = fdtdec_get_config_string(gd->fdt_blob, "u-boot,boot-led");
|
|
|
|
|
if (!led_name)
|
|
|
|
|
return 0;
|
|
|
|
|
ret = led_get_by_label(led_name, &dev);
|
|
|
|
|
if (ret) {
|
|
|
|
|
debug("%s: get=%d\n", __func__, ret);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
ret = led_set_on(dev, 1);
|
|
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void spl_board_init(void)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
ret = setup_led();
|
|
|
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
|
debug("LED ret=%d\n", ret);
|
|
|
|
|
hang();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rk_spl_board_init();
|
|
|
|
|
#if CONFIG_IS_ENABLED(ROCKCHIP_BACK_TO_BROM)
|
|
|
|
|
back_to_bootrom(BROM_BOOT_NEXTSTAGE);
|
|
|
|
|
#endif
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2019-07-26 07:57:13 +00:00
|
|
|
|
|
|
|
|
void spl_perform_fixups(struct spl_image_info *spl_image)
|
|
|
|
|
{
|
|
|
|
|
#ifdef CONFIG_ROCKCHIP_PRELOADER_ATAGS
|
|
|
|
|
atags_set_bootdev_by_spl_bootdevice(spl_image->boot_device);
|
|
|
|
|
#endif
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-21 09:11:18 +00:00
|
|
|
#ifdef CONFIG_SPL_KERNEL_BOOT
|
|
|
|
|
static int spl_rockchip_dnl_key_pressed(void)
|
|
|
|
|
{
|
2020-04-17 03:04:56 +00:00
|
|
|
#if defined(CONFIG_SPL_INPUT)
|
|
|
|
|
return key_read(KEY_VOLUMEUP);
|
2020-03-21 09:11:18 +00:00
|
|
|
#else
|
2020-04-17 03:04:56 +00:00
|
|
|
return 0;
|
2020-03-21 09:11:18 +00:00
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void spl_next_stage(struct spl_image_info *spl)
|
|
|
|
|
{
|
|
|
|
|
uint32_t reg_boot_mode;
|
|
|
|
|
|
|
|
|
|
if (spl_rockchip_dnl_key_pressed()) {
|
|
|
|
|
spl->next_stage = SPL_NEXT_STAGE_UBOOT;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
reg_boot_mode = readl((void *)CONFIG_ROCKCHIP_BOOT_MODE_REG);
|
|
|
|
|
switch (reg_boot_mode) {
|
2020-06-02 10:06:39 +00:00
|
|
|
case BOOT_COLD:
|
2020-03-21 09:11:18 +00:00
|
|
|
case BOOT_PANIC:
|
|
|
|
|
case BOOT_WATCHDOG:
|
|
|
|
|
case BOOT_NORMAL:
|
|
|
|
|
spl->next_stage = SPL_NEXT_STAGE_KERNEL;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
spl->next_stage = SPL_NEXT_STAGE_UBOOT;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
2020-04-02 11:59:12 +00:00
|
|
|
|
2020-04-15 07:34:19 +00:00
|
|
|
void spl_hang_reset(void)
|
|
|
|
|
{
|
|
|
|
|
printf("# Reset the board to bootrom #\n");
|
|
|
|
|
#if defined(CONFIG_SPL_SYSRESET) && defined(CONFIG_SPL_DRIVERS_MISC_SUPPORT)
|
|
|
|
|
writel(BOOT_BROM_DOWNLOAD, CONFIG_ROCKCHIP_BOOT_MODE_REG);
|
|
|
|
|
do_reset(NULL, 0, 0, NULL);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
2020-04-24 01:44:00 +00:00
|
|
|
|
2020-06-23 06:52:39 +00:00
|
|
|
#ifdef CONFIG_SPL_FIT_ROLLBACK_PROTECT
|
|
|
|
|
int fit_read_otp_rollback_index(uint32_t fit_index, uint32_t *otp_index)
|
|
|
|
|
{
|
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
|
|
*otp_index = 0;
|
|
|
|
|
#if defined(CONFIG_SPL_ROCKCHIP_SECURE_OTP_V2)
|
|
|
|
|
struct udevice *dev;
|
|
|
|
|
u32 index, i, otp_version;
|
|
|
|
|
u32 bit_count;
|
|
|
|
|
|
|
|
|
|
dev = misc_otp_get_device(OTP_S);
|
|
|
|
|
if (!dev)
|
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
|
|
otp_version = 0;
|
|
|
|
|
for (i = 0; i < OTP_UBOOT_ROLLBACK_WORDS; i++) {
|
|
|
|
|
if (misc_otp_read(dev, 4 *
|
|
|
|
|
(OTP_UBOOT_ROLLBACK_OFFSET + i),
|
|
|
|
|
&index,
|
|
|
|
|
4)) {
|
|
|
|
|
printf("Can't read rollback index\n");
|
|
|
|
|
return -EIO;
|
|
|
|
|
}
|
|
|
|
|
bit_count = fls(index);
|
|
|
|
|
otp_version += bit_count;
|
|
|
|
|
}
|
|
|
|
|
*otp_index = otp_version;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int fit_write_otp_rollback_index(u32 fit_index)
|
|
|
|
|
{
|
|
|
|
|
#if defined(CONFIG_SPL_ROCKCHIP_SECURE_OTP_V2)
|
|
|
|
|
struct udevice *dev;
|
|
|
|
|
u32 index, i, otp_index;
|
|
|
|
|
|
|
|
|
|
if (!fit_index || fit_index > OTP_UBOOT_ROLLBACK_WORDS * 32)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
dev = misc_otp_get_device(OTP_S);
|
|
|
|
|
if (!dev)
|
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
|
|
if (fit_read_otp_rollback_index(fit_index, &otp_index))
|
|
|
|
|
return -EIO;
|
|
|
|
|
|
|
|
|
|
if (otp_index < fit_index) {
|
|
|
|
|
/* Write new SW version to otp */
|
|
|
|
|
for (i = 0; i < OTP_UBOOT_ROLLBACK_WORDS; i++) {
|
|
|
|
|
/* convert to base-1 representation */
|
|
|
|
|
index = 0xffffffff >> (OTP_ALL_ONES_NUM_BITS -
|
|
|
|
|
min(fit_index, (u32)OTP_ALL_ONES_NUM_BITS));
|
|
|
|
|
fit_index -= min(fit_index,
|
|
|
|
|
(u32)OTP_ALL_ONES_NUM_BITS);
|
|
|
|
|
if (index) {
|
|
|
|
|
if (misc_otp_write(dev, 4 *
|
|
|
|
|
(OTP_UBOOT_ROLLBACK_OFFSET + i),
|
|
|
|
|
&index,
|
|
|
|
|
4)) {
|
|
|
|
|
printf("Can't write rollback index\n");
|
|
|
|
|
return -EIO;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2020-06-28 02:50:50 +00:00
|
|
|
int spl_board_prepare_for_jump(struct spl_image_info *spl_image)
|
|
|
|
|
{
|
2020-06-23 06:52:39 +00:00
|
|
|
#ifdef CONFIG_SPL_FIT_ROLLBACK_PROTECT
|
|
|
|
|
return fit_write_otp_rollback_index(gd->rollback_index);
|
2020-06-28 02:50:50 +00:00
|
|
|
#endif
|
|
|
|
|
return 0;
|
|
|
|
|
}
|