linuxOS_D21X/source/uboot-2021.10/board/artinchip/d211/d211.c
2025-06-05 14:33:02 +08:00

1102 lines
23 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2020 ArtInChip Technology Co.,Ltd
* Author: Dehuang Wu <dehuang.wu@artinchip.com>
*/
#include <common.h>
#include <cpu_func.h>
#include <dm.h>
#include <dm/uclass.h>
#include <dm/uclass-internal.h>
#include <dm/device-internal.h>
#include <video.h>
#include <artinchip/artinchip_fb.h>
#include <artinchip_ve.h>
#include <mmc.h>
#include <env.h>
#include <spl.h>
#include <hang.h>
#include <init.h>
#include <spi.h>
#include <spi_flash.h>
#include <linux/io.h>
#include <debug_uart.h>
#include <fdt_support.h>
#include <asm/arch/boot_param.h>
#include <asm/arch/usb_detect.h>
#include <serial.h>
#include <linux/delay.h>
#include <linux/ctype.h>
#include <asm/unaligned.h>
#include <userid.h>
#include <log_buf.h>
#define usleep_range(a, b) udelay((b))
#define RTC_CMU_REG ((void *)0x18020908)
#define RTC_CMU_BUS_EN_MSK (0x1000)
#define BASE_RTC ((void *)0x19030000)
#define RTC_WRITE_KEY_REG (BASE_RTC + 0x0FC)
#define RTC_WRITE_KEY_VALUE (0xAC)
#define RTC_BOOTINFO1_REG (BASE_RTC + 0x100)
#define BOOTINFO1_REASON_OFF (4)
#define BOOTINFO1_REASON_MSK (0xF << 4)
#define RTC_REBOOT_REASON_UPGRADE (4)
#define RTC_REBOOT_REASON_BL_UPGRADE (5)
#define RTC_SYS_BAK_BASE (BASE_RTC + 0x104)
#define RTC_SYS_BAK_REG(id) (RTC_SYS_BAK_BASE + (id) * 0x04)
#ifdef CONFIG_SPL_SPI_NAND_TINY
#include <artinchip_spinand.h>
#endif
#ifdef CONFIG_AUTO_CALCULATE_PART_CONFIG
#include <generated/image_cfg_part_config.h>
#endif
DECLARE_GLOBAL_DATA_PTR;
#define MAX_MTDIDS 64
#define MAX_MTDPARTS 256
#define EFUSE_CMU_REG ((void *)0x18020904)
#define EFUSE_SHADOW_FEATURE_REG ((void *)0x19010224)
#define DDR2_32MB 0xA
#define DDR2_64MB 0xB
#define DDR3_128MB 0xC
#define DDR3_256MB 0xD
#ifdef CONFIG_DEBUG_UART_BOARD_INIT
#define USE_UART0
#define GPIO_CMU_CFG_REG ((void *)(0x1802083C))
#define CMU_PLL_INT1_CFG_REG ((void *)(0x18020004))
#ifdef USE_UART1
#define UART1_CMU_CFG_REG ((void *)(0x18020844))
#define UART1_LSR_REG ((void *)(0x18711014))
#define UART1_IER_REG ((void *)(0x18711004))
#define GPIO_PA4_PIN_CFG_REG ((void *)0x18700090)
#define GPIO_PA5_PIN_CFG_REG ((void *)0x18700094)
#endif
#ifdef USE_UART0
#define UART0_CMU_CFG_REG ((void *)(0x18020840))
#define UART0_LSR_REG ((void *)(0x18710014))
#define UART0_IER_REG ((void *)(0x18710004))
#define GPIO_PN0_PIN_CFG_REG ((void *)0x18700E80)
#define GPIO_PN1_PIN_CFG_REG ((void *)0x18700E84)
#endif
#define LSR_TX_EMP_BIT BIT(6)
void board_debug_uart_init(void)
{
u32 val = 0;
/* Reset and Gating GPIO */
writel(0x3100, GPIO_CMU_CFG_REG);
writel(0x88153100, CMU_PLL_INT1_CFG_REG);
#ifdef USE_UART1
writel(0x325, GPIO_PA4_PIN_CFG_REG);
writel(0x325, GPIO_PA5_PIN_CFG_REG);
val = readl(UART1_CMU_CFG_REG);
if (val & 0x3100) {
/* Wait for UART Tx FIFO to be empty, if UART already enabled */
while ((readl(UART1_LSR_REG) & LSR_TX_EMP_BIT) == 0)
;
writel(0, UART1_CMU_CFG_REG);
};
/* Reset and Gating UART */
writel(0x3118, UART1_CMU_CFG_REG);
#endif
#ifdef USE_UART0
writel(0x324, GPIO_PN0_PIN_CFG_REG);
writel(0x324, GPIO_PN1_PIN_CFG_REG);
val = readl(UART0_CMU_CFG_REG);
if (val & 0x3100) {
/* Wait for UART Tx FIFO to be empty, if UART already enabled */
while ((readl(UART0_LSR_REG) & LSR_TX_EMP_BIT) == 0)
;
writel(0, UART0_CMU_CFG_REG);
};
/* Reset and Gating UART */
writel(0x3118, UART0_CMU_CFG_REG);
#endif
}
#endif
#if defined(CONFIG_SPL_BUILD)
void board_init_f(ulong dummy)
{
int ret;
#ifdef CONFIG_ARTINCHIP_DEBUG_BOOT_TIME
u32 *p = (u32 *)BOOT_TIME_SPL_START;
/* SPL start time */
*p = aic_timer_get_us();
#endif
log_buf_init();
#ifdef CONFIG_DEBUG_UART
/*
* For SPL, Use DEBUG UART to enable serial output,
* don't use dm serial driver, because it spend too much time to
* initialize driver.
*/
log_notice("\nspl:debug uart enabled in %s\n", __func__);
#endif
ret = spl_early_init();
if (ret)
panic("spl_early_init() failed: %d\n", ret);
riscv_cpu_setup(NULL, NULL);
preloader_console_init();
ret = spl_board_init_f();
if (ret)
panic("spl_board_init_f() failed: %d\n", ret);
}
void spl_board_init(void)
{
enable_caches();
}
void spl_board_prepare_for_linux(void)
{
usb_dev_connection_check_end(0);
}
#endif
int board_init(void)
{
return 0;
}
static void setup_boot_device(void)
{
enum boot_device bd;
/*
* Boot ROM detects Boot device and pass it to SPL,
* SPL pass it to U-Boot.
*/
bd = aic_get_boot_device();
switch (bd) {
case BD_SDMC0:
env_set("boot_device", "mmc");
env_set("boot_devnum", "0");
debug("Booting from eMMC...\n");
break;
case BD_SDMC1:
env_set("boot_device", "mmc");
env_set("boot_devnum", "1");
debug("Booting from SD Card...\n");
break;
case BD_SDFAT32:
env_set("boot_device", "fat");
env_set("boot_devnum", "1");
debug("Booting from SD Card FATFS...\n");
break;
case BD_SPINOR:
env_set("boot_device", "nor");
env_set("boot_devnum", "0");
debug("Booting from SPI NOR...\n");
break;
case BD_SPINAND:
env_set("boot_device", "nand");
env_set("boot_devnum", "0");
debug("Booting from SPI NAND...\n");
break;
case BD_USB:
env_set("boot_device", "usb");
env_set("boot_devnum", "0");
debug("Booting from USBUPG...\n");
break;
default:
pr_err("Unknown boot device id %d...\n", (int)bd);
break;
}
}
#if CONFIG_IS_ENABLED(OF_CONTROL) && defined(CONFIG_FIT_SIGNATURE)
static int set_dev_part(const void *blob, char *propname)
{
struct disk_partition info;
struct blk_desc *desc;
char *media, *devnum, dev_name[16];
const char *part_name;
int part, ret;
media = env_get("boot_device");
devnum = env_get("boot_devnum");
/* get part name */
part_name = fdtdec_get_chosen_prop(blob, propname);
if (part_name) {
/* get dev desc */
ret = blk_get_device_by_str(media, devnum, &desc);
if (ret < 0)
return ret;
/* get part number */
part = part_get_info_by_name(desc, part_name, &info);
if (part < 0)
return -1;
snprintf(dev_name, sizeof(dev_name), "/dev/mmcblk%sp%d",
devnum, part);
env_set(propname, dev_name);
}
return 0;
}
static int setup_dm_verity_part(void)
{
int ret;
ret = set_dev_part(gd->fdt_blob, "root_part");
if (ret < 0)
return ret;
ret = set_dev_part(gd->fdt_blob, "hash_part");
if (ret < 0)
return ret;
return 0;
}
#endif
#ifdef CONFIG_VIDEO_ARTINCHIP
static int board_prepare_logo(struct udevice *dev)
{
enum boot_device bd;
int ret = -EINVAL;
bd = aic_get_boot_device();
switch (bd) {
case BD_SDMC0:
case BD_SDMC1:
case BD_SPINAND:
case BD_SPINOR:
ret = aic_disp_logo("boot", bd);
break;
case BD_SDFAT32:
#ifdef CONFIG_PROGRESS_BAR
ret = 0;
#else
ret = aic_disp_logo("sdburn", bd);
#endif
break;
case BD_BOOTROM:
ret = aic_disp_logo("usbburn", bd);
break;
default:
pr_err("Unknown boot device id %d...\n", (int)bd);
return ret;
}
return ret;
}
static int board_show_logo(void)
{
struct udevice *dev;
int ret;
ret = uclass_first_device(UCLASS_VIDEO, &dev);
if (ret) {
pr_err("Failed to find aicfb udevice\n");
return ret;
}
#ifdef CONFIG_PROGRESS_BAR
struct video_priv *priv = dev_get_uclass_priv(dev);
memset(priv->fb, 0xffffff, priv->fb_size);
flush_dcache_range((uintptr_t)&priv->fb, (uintptr_t)(&priv->fb_size));
#endif
ret = board_prepare_logo(dev);
if (!ret) {
aicfb_update_ui_layer(dev);
aicfb_startup_panel(dev);
}
return ret;
}
#endif /* CONFIG_VIDEO_ARTINCHIP */
static u64 efuse_get_ddr_size(void)
{
u32 val, mem;
u64 size = 0;
writel(0x1100, EFUSE_CMU_REG);
val = readl(EFUSE_SHADOW_FEATURE_REG);
mem = (val >> 20) & 0xF;
switch (mem) {
case DDR2_32MB:
pr_info("DDR2 32MB\n");
size = 0x2000000;
break;
case DDR2_64MB:
pr_info("DDR2 64MB\n");
size = 0x4000000;
break;
case DDR3_128MB:
pr_info("DDR3 128MB\n");
size = 0x8000000;
break;
case DDR3_256MB:
pr_info("DDR3 256MB\n");
size = 0x10000000;
break;
default:
pr_info("No DDR info\n");
}
return size;
}
static u64 get_dram_size(void)
{
const fdt64_t *val;
u64 size = 0;
int offset;
int len;
size = efuse_get_ddr_size();
if (size > 0)
return size;
offset = fdt_path_offset(gd->fdt_blob, "/memory");
if (offset < 0) {
pr_err("Get memory node from DTS failed.\n");
return size;
}
val = fdt_getprop(gd->fdt_blob, offset, "reg", &len);
if (len < sizeof(*val) * 2) {
pr_err("Get memory size from DTS failed.\n");
return size;
}
size = (u64)get_unaligned_be64(&val[1]);
return size;
}
int dram_init(void)
{
gd->ram_size = get_dram_size();
if (gd->ram_size == 0) {
pr_err("Get DRAM size failed.\n");
}
return 0;
}
void fdt_fix_mem_size(void *blob)
{
int len, nodeoffset;
const u64 *reg;
u64 start[1], size[1];
char *node = "/memory@40000000";
nodeoffset = fdt_path_offset(blob, node);
reg = fdt_getprop(blob, nodeoffset, "reg", &len);
if (reg) {
start[0] = fdt64_to_cpu(reg[0]);
size[0] = efuse_get_ddr_size();
if (size[0]) {
fdt_fix_memory(blob, start, size, node);
}
}
}
#if defined(CONFIG_FIT_SIGNATURE)
static int replace_first_str(char *src, char *match_str, char *replace_str)
{
int str_len;
char newstring[1024] = {0};
char *find_pos;
if (!match_str || !replace_str)
return -1;
find_pos = strstr(src, match_str);
if (!find_pos)
return -1;
while (find_pos) {
str_len = find_pos - src;
strncpy(newstring, src, str_len);
strcat(newstring, replace_str);
strcat(newstring, find_pos + strlen(match_str));
strcpy(src, newstring);
return 0;
}
return 0;
}
static int fdt_get_cmdline(void *fdt, char *console, char *cmdline)
{
int nodeoffset;
const char *create, *waitfor, *bootargs, *args;
char buf[1024];
/* find or create "/chosen" node. */
nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen");
if (nodeoffset < 0)
return nodeoffset;
debug("Get bootargs parameters.\n");
create = fdt_getprop(fdt, nodeoffset, "dm-mod.create", NULL);
waitfor = fdt_getprop(fdt, nodeoffset, "dm-mod.waitfor", NULL);
bootargs = fdt_getprop(fdt, nodeoffset, "bootargs", NULL);
args = fdt_getprop(fdt, nodeoffset, "args", NULL);
if (!create || !waitfor || !bootargs || !args) {
printf("Get bootargs parameters failed!\n");
printf("If secure boot is not used, ");
printf("CONFIG_FIT_SIGNATURE should be disabled!\n");
return -EINVAL;
}
strcpy(buf, create);
if (replace_first_str(buf, "data_dev", env_get("root_part")))
printf("Set data dev failed.\n");
if (replace_first_str(buf, "hash_dev", env_get("hash_part")))
printf("Set hash dev failed.\n");
/* Don't add console= if user already set it */
if (strstr(bootargs, "console="))
snprintf(cmdline, 1024, "%s %s %s %s", bootargs, args, buf,
waitfor);
else
snprintf(cmdline, 1024, "%s %s %s %s %s", console, bootargs,
args, buf, waitfor);
return 0;
}
#endif
#ifdef CONFIG_OF_BOARD_SETUP
char *board_fdt_chosen_bootargs(void)
{
/* Set up chosen bootargs in ft_board_setup */
return NULL;
}
static int ft_board_setup_chosen_bootargs(void *fdt)
{
int err, idx;
int nodeoffset;
char *str, *s;
char cmdline[1024], console[32];
/* find or create "/chosen" node. */
nodeoffset = fdt_find_or_add_subnode(fdt, 0, "chosen");
if (nodeoffset < 0)
return nodeoffset;
err = 0;
str = (char *)fdtdec_get_chosen_prop(fdt, "stdout-path");
if (str) {
for (s = str; *s; s++)
if (isdigit(*s) || *s == ':')
break;
idx = simple_strtoul(s, NULL, 10);
s = strchr(str, ':');
s++;
} else {
idx = 0;
s = "115200n8";
}
snprintf(console, 32, "console=ttyS%d,%s", idx, s);
#if defined(CONFIG_FIT_SIGNATURE)
err = fdt_get_cmdline(fdt, console, cmdline);
if (err)
return err;
#else
str = env_get("bootargs");
/* Don't add console= if user already set it */
if (strstr(str, "console="))
snprintf(cmdline, 1024, "%s", str);
else
snprintf(cmdline, 1024, "%s %s", console, str);
#endif
if (str) {
err = fdt_setprop(fdt, nodeoffset, "bootargs", cmdline,
strlen(cmdline) + 1);
if (err < 0) {
printf("WARNING: could not set bootargs %s.\n",
fdt_strerror(err));
return err;
}
}
return err;
}
static int fdt_fix_aic_logo_reserved_memory(void *blob)
{
int ret = 0;
#ifdef CONFIG_VIDEO_ARTINCHIP
struct fdt_memory logo;
struct video_priv *priv;
struct udevice *dev;
ret = uclass_find_first_device(UCLASS_VIDEO, &dev);
if (ret) {
pr_err("%s: failed to find aicfb udevice\n", __func__);
return ret;
}
priv = dev_get_uclass_priv(dev);
if (IS_ERR_OR_NULL(priv)) {
pr_warn("%s: failed to find aic-logo info\n", __func__);
return 0;
}
logo.start = (phys_addr_t)priv->fb;
logo.end = (phys_addr_t)priv->fb + priv->fb_size - 1;
ret = fdtdec_add_reserved_memory(blob, "aic-logo", &logo, NULL, 0, NULL, false);
if (ret < 0 && ret != -FDT_ERR_EXISTS) {
pr_err("%s: failed to add reserved memory\n", __func__);
return ret;
}
#endif
return ret;
}
int ft_board_setup(void *blob, struct bd_info *bd)
{
fdt_fix_mem_size(blob);
ft_board_setup_chosen_bootargs(blob);
fdt_fix_aic_logo_reserved_memory(blob);
return 0;
}
#endif /* CONFIG_OF_BOARD_SETUP */
int board_late_init(void)
{
setup_boot_device();
#if defined(CONFIG_FIT_SIGNATURE)
setup_dm_verity_part();
#endif
#ifdef CONFIG_VIDEO_ARTINCHIP
board_show_logo();
#endif
#ifdef CONFIG_USERID_SUPPORT
enum boot_device bd;
bd = aic_get_boot_device();
if (bd != BD_USB && bd != BD_SDFAT32)
userid_init();
#endif
return 0;
}
void board_mtdparts_default(const char **mtdids, const char **mtdparts)
{
static char ids[MAX_MTDIDS];
static char parts[MAX_MTDPARTS];
struct mtd_info *mtd = get_mtd_device(NULL, 0);
struct udevice *dev;
int pos, ret, cnt;
char *p;
if (IS_ERR_OR_NULL(mtd)) {
ret = uclass_first_device(UCLASS_MTD, &dev);
if (ret && !dev) {
pr_err("Find MTD device failed.\n");
goto out;
}
device_probe(dev);
mtd = get_mtd_device(NULL, 0);
}
if (IS_ERR_OR_NULL(mtd)) {
pr_err("There is no mtd device.\n");
goto out;
}
if ((gd->flags & GD_FLG_ENV_READY) == 0) {
pr_warn("env is not loaded.\n");
goto out;
}
p = env_get("MTD");
if (!p) {
pr_warn("Get MTD partition table from env failed.\n");
goto out;
}
memset(ids, 0, MAX_MTDIDS);
snprintf(ids, MAX_MTDIDS, "%s=", mtd->name);
for (pos = 0; pos < strlen(p); pos++) {
if (p[pos] == ':')
break;
}
if (pos == strlen(p)) {
pr_err("There is no mtd ids in partition table.\n");
return;
}
if ((pos + strlen(ids)) >= MAX_MTDIDS) {
pr_err("mtd ids is too long.\n");
return;
}
if (strlen(p) >= MAX_MTDPARTS) {
pr_err("mtd partition table is too long\n");
return;
}
memcpy(ids + strlen(ids), p, pos);
strcpy(parts, p);
/* Check if it is set minimal boot mtdparts number */
p = env_get("nand_boot_mtdparts_cnt");
if (p) {
cnt = simple_strtoul(p, NULL, 10);
if (!cnt)
goto all;
/* Filter minimal parts */
p = parts;
while (*p != '\0') {
p++;
if (*p == ',')
cnt--;
if (cnt == 0)
break;
}
/* OK, drop not relative mtdparts for u-boot */
if (!cnt && *p == ',')
*p = '\0';
}
all:
*mtdids = ids;
*mtdparts = parts;
pr_info("U-Boot stage mtdparts: %s\n", parts);
return;
out:
/* ENV is not ready, use default configuratioin if it is provided.*/
#ifdef CONFIG_MTDIDS_DEFAULT
*mtdids = CONFIG_MTDIDS_DEFAULT;
#endif
#ifdef CONFIG_MTDPARTS_DEFAULT
*mtdparts = CONFIG_MTDPARTS_DEFAULT;
#endif
return;
}
int dram_init_banksize(void)
{
gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
gd->bd->bi_dram[0].size = gd->ram_size;
return 0;
}
#ifdef CONFIG_SPL_OS_BOOT
static int search_boot_os(u8 *env_ram, int len)
{
int i = 0, cnt = 0;
while (i < len) {
if (env_ram[i] != 0)
cnt = 0;
if ((env_ram[i] == 'b') &&
!memcmp(&env_ram[i], "boot_os=yes", 11))
return 1;
else if (env_ram[i] == 0)
cnt++;
if (cnt >= 2)
break;
i++;
}
return 0;
}
#ifdef CONFIG_SPL_MMC_SUPPORT
static int mmc_load_env_simple(int dev, u8 *env_ram)
{
static struct mmc *mmc;
unsigned long count, sector_start, sector_cnt;
int err = -1;
mmc = find_mmc_device(dev);
if (!mmc)
return err;
sector_start = CONFIG_ENV_OFFSET / mmc->read_bl_len;
sector_cnt = CONFIG_ENV_SIZE / mmc->read_bl_len;
count = blk_dread(mmc_get_blk_desc(mmc), sector_start, sector_cnt,
env_ram);
if (count != sector_cnt)
return -1;
return CONFIG_ENV_SIZE;
}
#endif
#ifdef CONFIG_SPL_SPI_NAND_TINY
static int spinand_load_env_simple(u8 *env_ram)
{
struct spinand_device *spinand;
unsigned long offset, remain;
size_t rdlen;
spinand = spl_spinand_init();
if (IS_ERR_OR_NULL(spinand)) {
pr_err("Tiny SPI NAND init failed. ret = %ld\n",
PTR_ERR(spinand));
return -1;
}
offset = CONFIG_ENV_OFFSET;
remain = (uint32_t)CONFIG_ENV_SIZE;
#ifndef CONFIG_SYS_REDUNDAND_ENVIRONMENT
spl_spi_nand_read(spinand, offset, remain, &rdlen, (void *)env_ram);
if (remain != rdlen) {
pr_err("Tiny SPI NAND read failed.\n");
return -1;
}
return CONFIG_ENV_SIZE;
#else
int read1_fail = 0, read2_fail = 0;
u8 *buf = env_ram;
u8 *buf_redund = (u8 *)CONFIG_ENV_RAM_ADDR + CONFIG_ENV_SIZE;
char tmp_env1_flags, tmp_env2_flags;
read1_fail = spl_spi_nand_read(spinand, CONFIG_ENV_OFFSET, remain,
&rdlen, (void *)buf);
read2_fail = spl_spi_nand_read(spinand, CONFIG_ENV_OFFSET_REDUND,
remain, &rdlen, (void *)buf_redund);
if (read1_fail && read2_fail) {
pr_err("Tiny SPI NAND read failed.\n");
return -1;
}
tmp_env1_flags = buf[4];
tmp_env2_flags = buf_redund[4];
if (tmp_env1_flags == 255 && tmp_env2_flags == 0)
memcpy(env_ram, buf_redund, CONFIG_ENV_SIZE);
else if (tmp_env2_flags > tmp_env1_flags)
memcpy(env_ram, buf_redund, CONFIG_ENV_SIZE);
return CONFIG_ENV_SIZE;
#endif
}
#endif
#ifdef CONFIG_SPL_SPI_LOAD
static int spinor_load_env_simple(u8 *env_ram)
{
unsigned int bus = CONFIG_SF_DEFAULT_BUS;
unsigned int cs = CONFIG_SF_DEFAULT_CS;
struct udevice *new, *bus_dev;
struct spi_flash *flash;
int ret;
ret = spi_find_bus_and_cs(bus, cs, &bus_dev, &new);
if (ret) {
pr_err("Failed to find a spi device\n");
return -EINVAL;
}
flash = dev_get_uclass_priv(new);
ret = spi_flash_read(flash, CONFIG_ENV_OFFSET, CONFIG_ENV_SIZE,
(void *)env_ram);
if (ret) {
pr_err("Failed to read env from SPINOR.\n");
return -1;
}
return CONFIG_ENV_SIZE;
}
#endif
static int env_boot_os_flag(enum boot_device bd)
{
u8 *env_ram = (u8 *)CONFIG_ENV_RAM_ADDR;
int size = 0;
switch (bd) {
#ifdef CONFIG_SPL_MMC_SUPPORT
case BD_SDMC0:
size = mmc_load_env_simple(0, env_ram);
break;
case BD_SDMC1:
size = mmc_load_env_simple(1, env_ram);
break;
#endif
case BD_SPINAND:
#ifdef CONFIG_SPL_SPI_NAND_TINY
size = spinand_load_env_simple(env_ram);
#endif
break;
case BD_SPINOR:
#ifdef CONFIG_SPL_SPI_LOAD
size = spinor_load_env_simple(env_ram);
#endif
break;
default:
break;
}
if (size > 0)
return search_boot_os(env_ram, size);
return 0;
}
#ifdef CONFIG_USERID_SUPPORT
static int userid_lock_flag(enum boot_device bd)
{
int ret = 0;
u32 flag = 0;
ret = userid_init();
if (ret) {
return 0;
}
ret = userid_read("lock", 0, (void *)&flag, 4);
if (ret <= 0)
return 0;
return (flag != 0);
}
#endif
#define START_UNKNOWN -1
#define START_KERNEL 0
#define START_UBOOT 1
extern int aic_upg_mode_detect(void);
/*
* This API will be called multi-times
*/
int spl_start_uboot(void)
{
#ifndef CONFIG_SPL_OS_BOOT
/* Falcon mode is not enabled, run u-boot directly */
return START_UBOOT;
#else
static int start = START_UNKNOWN;
static int usb_dev_check;
enum boot_device bd;
int userid_lock = 0;
if (start == START_UBOOT)
return start;
/* UNKNOWN, START_KERNEL: still need to check */
bd = aic_get_boot_device();
if (bd == BD_USB || bd == BD_SDFAT32) {
/* If Boot for image upgrading, force to start U-Boot. */
start = START_UBOOT;
puts("Run U-Boot: upgrading mode\n");
goto out;
}
#ifdef CONFIG_SPL_SERIAL_SUPPORT
/* break into full u-boot with CTRL + c/C */
if (serial_tstc() && serial_getc() == CTRL('C')) {
start = START_UBOOT;
puts("Run U-Boot: got CTRL+C\n");
goto out;
}
#endif
if (start == START_UNKNOWN) {
#ifdef CONFIG_CMD_AICUPG
if (aic_upg_mode_detect()) {
start = START_UBOOT;
puts("Run U-Boot: Software reset to enter UPG mode\n");
goto out;
}
#endif
if (env_boot_os_flag(bd) != 1) {
start = START_UBOOT;
puts("Run U-Boot: boot_os=no in ENV, don't boot os\n");
goto out;
}
#ifdef CONFIG_UPDATE_UDISK_FATFS_ARTINCHIP
/* Check udisk upgrading:
* Only check when userid is locked
*/
if (usb_host_udisk_connection_check()) {
/* Device is connecting to UDISK, goto uboot to check
* whether it is going to perform UDISK upgrading
*/
start = START_UBOOT;
puts("Run U-Boot: try UDISK upgrading\n");
goto out;
}
#endif
usb_dev_check = 0;
#ifdef CONFIG_USERID_SUPPORT
userid_lock = userid_lock_flag(bd);
#else
userid_lock = 1;
#endif
/*
* When userid partition is locked, it is no needed to check
* usb connection for userid
*/
if (!userid_lock)
usb_dev_check++;
#ifdef CONFIG_AICUPG_FORCE_USBUPG_SUPPORT
usb_dev_check++;
#endif
/*
* Switch to Device mode, and check whether USB connecting to PC.
* This function should be called once.
*/
if (usb_dev_check)
usb_dev_connection_check_start(0);
}
/*
* Check usb connecton status every time spl_start_uboot is called.
*/
if (usb_dev_check && usb_dev_connection_check_status(0)) {
start = START_UBOOT;
usb_dev_connection_check_end(0);
puts("Run U-Boot: Device is connecting to PC with USB, try to burn userid\n");
goto out;
}
start = START_KERNEL;
out:
return start;
#endif
}
#endif
ulong board_spl_fit_size_align(ulong size)
{
size = ALIGN(size, 0x20);
return size;
}
/* Get the top of usable RAM */
ulong board_get_usable_ram_top(ulong total_size)
{
u64 dram_size;
phys_addr_t top;
dram_size = get_dram_size();
top = CONFIG_SYS_SDRAM_BASE + dram_size;
/* last region is for OpenSBI */
top = top - CONFIG_SPL_OPENSBI_SIZE;
return top;
}
int board_load_opensbi_to_ram_top(void)
{
return 1;
}
void aic_upg_flag_clear(void)
{
u32 val;
val = readl(RTC_CMU_REG);
if (!(val & RTC_CMU_BUS_EN_MSK))
writel(RTC_CMU_BUS_EN_MSK, RTC_CMU_REG);
writel(RTC_WRITE_KEY_VALUE, RTC_WRITE_KEY_REG);
val = readl(RTC_BOOTINFO1_REG);
val &= ~BOOTINFO1_REASON_MSK;
writel(val, RTC_BOOTINFO1_REG);
writel(0, RTC_WRITE_KEY_REG);
}
static int rtc_upg_flag_check(void)
{
u32 val;
val = readl((void *)RTC_BOOTINFO1_REG);
val = (val & BOOTINFO1_REASON_MSK) >> BOOTINFO1_REASON_OFF;
if ((val == RTC_REBOOT_REASON_UPGRADE) ||
(val == RTC_REBOOT_REASON_BL_UPGRADE)) {
printf("Software reboot to enter upgrading mode.\n");
return 1;
}
return 0;
}
void aic_upg_succ_cnt(void)
{
u32 val;
val = readl(RTC_CMU_REG);
if (!(val & RTC_CMU_BUS_EN_MSK))
writel(RTC_CMU_BUS_EN_MSK, RTC_CMU_REG);
writel(RTC_WRITE_KEY_VALUE, RTC_WRITE_KEY_REG);
val = readl(RTC_SYS_BAK_REG(14));
val += 1;
writel(val, RTC_SYS_BAK_REG(14));
writel(0, RTC_WRITE_KEY_REG);
printf("Successfully burned %d times.\n", val);
}
int aic_upg_mode_detect(void)
{
int ret;
ret = rtc_upg_flag_check();
return ret;
}
#ifndef CONFIG_SPL_BUILD
extern int do_reset(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]);
void do_brom_upg(char *upg_mode)
{
u32 val;
writel(RTC_WRITE_KEY_VALUE, RTC_WRITE_KEY_REG);
val = readl((void *)RTC_BOOTINFO1_REG);
val &= ~BOOTINFO1_REASON_MSK;
val |= (RTC_REBOOT_REASON_UPGRADE << BOOTINFO1_REASON_OFF);
writel(val, (void *)RTC_BOOTINFO1_REG);
writel(0, RTC_WRITE_KEY_REG);
do_reset(NULL, 0, 0, 0);
}
#endif