You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
459 lines
9.6 KiB
459 lines
9.6 KiB
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <dm.h>
|
|
#include <ram.h>
|
|
#include <asm/io.h>
|
|
#include <asm/arch/rk_atags.h>
|
|
#include <asm/arch/param.h>
|
|
|
|
DECLARE_GLOBAL_DATA_PTR;
|
|
|
|
#define SZ_4GB 0x100000000ULL
|
|
|
|
#ifndef CONFIG_SPL_BUILD
|
|
#define SDRAM_OFFSET(offset) (CONFIG_SYS_SDRAM_BASE + (offset))
|
|
#define PARAM_DRAM_INFO_OFFSET (SZ_32M)
|
|
#define PARAM_OPTEE_INFO_OFFSET (SZ_32M + SZ_2M)
|
|
|
|
struct tos_param_t {
|
|
u32 version;
|
|
u32 checksum;
|
|
struct {
|
|
char name[8];
|
|
s64 phy_addr;
|
|
u32 size;
|
|
u32 flags;
|
|
} tee_mem;
|
|
struct {
|
|
char name[8];
|
|
s64 phy_addr;
|
|
u32 size;
|
|
u32 flags;
|
|
} drm_mem;
|
|
s64 reserve[8];
|
|
};
|
|
|
|
static uint16_t trust_checksum(const uint8_t *buf, uint16_t len)
|
|
{
|
|
uint16_t i, checksum = 0;
|
|
|
|
for (i = 0; i < len; i++) {
|
|
if (i % 2)
|
|
checksum += buf[i] << 8;
|
|
else
|
|
checksum += buf[i];
|
|
}
|
|
checksum = ~checksum;
|
|
|
|
return checksum;
|
|
}
|
|
|
|
struct memblock param_parse_atf_mem(void)
|
|
{
|
|
struct memblock mem;
|
|
|
|
mem.base = 0;
|
|
mem.size = 0;
|
|
|
|
#ifdef CONFIG_ROCKCHIP_PRELOADER_ATAGS
|
|
struct tag *t = NULL;
|
|
|
|
/*
|
|
* Get memory region of ATF
|
|
*
|
|
* 1. New way: atags info;
|
|
* 2. Leagcy way: 2MB size and start from ddr 0x0 offset;
|
|
*/
|
|
t = atags_get_tag(ATAG_ATF_MEM);
|
|
if (t && t->u.atf_mem.size) {
|
|
mem.base = t->u.atf_mem.phy_addr;
|
|
mem.size = t->u.atf_mem.size;
|
|
/* Sanity */
|
|
if (mem.base + mem.size > SDRAM_OFFSET(SZ_1M)) {
|
|
printf("%s: ATF reserved region is not within 0-1MB "
|
|
"offset(0x%08llx-0x%08llx)!\n",
|
|
__func__, (u64)mem.base, (u64)mem.base + mem.size);
|
|
return mem;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* Legacy */
|
|
if (!mem.size) {
|
|
if (IS_ENABLED(CONFIG_ARM64) ||
|
|
IS_ENABLED(CONFIG_ARM64_BOOT_AARCH32)) {
|
|
mem.base = SDRAM_OFFSET(0);
|
|
mem.size = SZ_1M;
|
|
}
|
|
}
|
|
|
|
debug("ATF: 0x%llx - 0x%llx\n", (u64)mem.base, (u64)mem.base + mem.size);
|
|
|
|
return mem;
|
|
}
|
|
|
|
struct memblock param_parse_optee_mem(void)
|
|
{
|
|
struct tos_param_t *tos_parameter;
|
|
struct memblock mem;
|
|
u32 checksum;
|
|
|
|
mem.base = 0;
|
|
mem.size = 0;
|
|
|
|
#ifdef CONFIG_ROCKCHIP_PRELOADER_ATAGS
|
|
struct tag *t = NULL;
|
|
|
|
/*
|
|
* Get memory region of OP-TEE
|
|
*
|
|
* 1. New way: atags info;
|
|
* 2. Leagcy way: info in ddr 34M offset;
|
|
*/
|
|
t = atags_get_tag(ATAG_TOS_MEM);
|
|
if (t && (t->u.tos_mem.tee_mem.flags == 1)) {
|
|
mem.base = t->u.tos_mem.tee_mem.phy_addr;
|
|
mem.size = t->u.tos_mem.tee_mem.size;
|
|
}
|
|
#endif
|
|
|
|
/* Legacy */
|
|
if (!mem.size) {
|
|
tos_parameter =
|
|
(struct tos_param_t *)(SDRAM_OFFSET(PARAM_OPTEE_INFO_OFFSET));
|
|
checksum =
|
|
trust_checksum((uint8_t *)(unsigned long)tos_parameter + 8,
|
|
sizeof(struct tos_param_t) - 8);
|
|
if ((checksum == tos_parameter->checksum) &&
|
|
(tos_parameter->tee_mem.flags == 1)) {
|
|
mem.base = tos_parameter->tee_mem.phy_addr;
|
|
mem.size = tos_parameter->tee_mem.size;
|
|
}
|
|
}
|
|
|
|
if (mem.size)
|
|
gd->flags |= GD_FLG_BL32_ENABLED;
|
|
|
|
debug("TOS: 0x%llx - 0x%llx\n", (u64)mem.base, (u64)mem.base + mem.size);
|
|
|
|
return mem;
|
|
}
|
|
|
|
struct memblock param_parse_common_resv_mem(void)
|
|
{
|
|
struct memblock mem;
|
|
|
|
#if defined(CONFIG_ARM64)
|
|
mem.base = SDRAM_OFFSET(SZ_1M);
|
|
mem.size = SZ_1M;
|
|
/*
|
|
* The ARMv8 platform enabling AArch32 mode should reserve memory the same
|
|
* as AArch64 mode(because there is no difference about ATF), only some
|
|
* platform has special request, they are: RK3308.
|
|
*/
|
|
#elif defined(CONFIG_ARM64_BOOT_AARCH32) && !defined(CONFIG_ROCKCHIP_RK3308)
|
|
mem.base = SDRAM_OFFSET(SZ_1M);
|
|
mem.size = SZ_1M;
|
|
#else
|
|
mem.size = 0;
|
|
#endif
|
|
return mem;
|
|
}
|
|
|
|
int param_parse_assign_bootdev(char **devtype, char **devnum)
|
|
{
|
|
char *bootdev_str = CONFIG_ROCKCHIP_BOOTDEV;
|
|
char *type, *num;
|
|
|
|
num = strchr(bootdev_str, ' ');
|
|
if (!num)
|
|
return -ENODEV;
|
|
|
|
type = strdup(bootdev_str);
|
|
type[num - bootdev_str] = 0;
|
|
num++;
|
|
|
|
*devtype = type;
|
|
*devnum = num;
|
|
|
|
return 0;
|
|
}
|
|
|
|
int param_parse_atags_bootdev(char **devtype, char **devnum)
|
|
{
|
|
#ifdef CONFIG_ROCKCHIP_PRELOADER_ATAGS
|
|
struct tag *t;
|
|
|
|
t = atags_get_tag(ATAG_BOOTDEV);
|
|
if (t) {
|
|
switch (t->u.bootdev.devtype) {
|
|
#ifdef CONFIG_DM_MMC
|
|
case BOOT_TYPE_EMMC:
|
|
*devtype = "mmc";
|
|
*devnum = "0";
|
|
break;
|
|
case BOOT_TYPE_SD0:
|
|
case BOOT_TYPE_SD1:
|
|
*devtype = "mmc";
|
|
*devnum = "1";
|
|
/*
|
|
* If preloader does not pass sdupdate value, we treat it
|
|
* as a unknown card and call the rkimgtest cmd to find
|
|
* out what it is.
|
|
*
|
|
* If preloader pass sdupdate value as an update card,
|
|
* we just set "sdfwupdate" to bootargs instead of
|
|
* calling rkimgtest cmd which consumes time.
|
|
*/
|
|
if (t->u.bootdev.sdupdate == SD_UNKNOWN_CARD) {
|
|
run_command("mmc dev 1", 0);
|
|
run_command("rkimgtest mmc 1", 0);
|
|
} else if (t->u.bootdev.sdupdate == SD_UPDATE_CARD) {
|
|
env_update("bootargs", "sdfwupdate");
|
|
}
|
|
break;
|
|
#endif
|
|
#if defined(CONFIG_RKNAND) || defined(CONFIG_RKNANDC_NAND)
|
|
case BOOT_TYPE_NAND:
|
|
*devtype = "rknand";
|
|
*devnum = "0";
|
|
break;
|
|
#endif
|
|
#ifdef CONFIG_RKSFC_NAND
|
|
case BOOT_TYPE_SPI_NAND:
|
|
*devtype = "spinand";
|
|
*devnum = "0";
|
|
break;
|
|
#endif
|
|
#ifdef CONFIG_RKSFC_NOR
|
|
case BOOT_TYPE_SPI_NOR:
|
|
*devtype = "spinor";
|
|
*devnum = "1";
|
|
break;
|
|
#endif
|
|
#ifdef CONFIG_DM_RAMDISK
|
|
case BOOT_TYPE_RAM:
|
|
*devtype = "ramdisk";
|
|
*devnum = "0";
|
|
break;
|
|
#endif
|
|
#ifdef CONFIG_NAND
|
|
case BOOT_TYPE_MTD_BLK_NAND:
|
|
*devtype = "mtd";
|
|
*devnum = "0";
|
|
break;
|
|
#endif
|
|
#ifdef CONFIG_MTD_SPI_NAND
|
|
case BOOT_TYPE_MTD_BLK_SPI_NAND:
|
|
*devtype = "mtd";
|
|
*devnum = "1";
|
|
break;
|
|
#endif
|
|
#ifdef CONFIG_SPI_FLASH_MTD
|
|
case BOOT_TYPE_MTD_BLK_SPI_NOR:
|
|
*devtype = "mtd";
|
|
*devnum = "2";
|
|
break;
|
|
#endif
|
|
default:
|
|
printf("Unknown bootdev type: 0x%x\n",
|
|
t->u.bootdev.devtype);
|
|
return -EINVAL;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
return -ENOSYS;
|
|
}
|
|
#endif
|
|
|
|
static phys_size_t ddr_mem_get_usable_size(u64 base, u64 size)
|
|
{
|
|
return (base + size >= CONFIG_SYS_SDRAM_BASE + SDRAM_MAX_SIZE) ?
|
|
(CONFIG_SYS_SDRAM_BASE + SDRAM_MAX_SIZE - base) : size;
|
|
}
|
|
|
|
struct memblock *param_parse_ddr_mem(int *out_count)
|
|
{
|
|
struct udevice *dev;
|
|
struct memblock *mem;
|
|
struct ram_info ram;
|
|
int i, ret, count;
|
|
|
|
/*
|
|
* Get memory region of DDR
|
|
*
|
|
* 1. New: atags info;
|
|
* 2. Leagcy: os register;
|
|
*/
|
|
#ifdef CONFIG_ROCKCHIP_PRELOADER_ATAGS
|
|
struct tag *t;
|
|
u64 base, size;
|
|
int n;
|
|
|
|
t = atags_get_tag(ATAG_DDR_MEM);
|
|
if (t && t->u.ddr_mem.count) {
|
|
/* extend top ram size */
|
|
if (t->u.ddr_mem.flags & DDR_MEM_FLG_EXT_TOP)
|
|
gd->ram_top_ext_size = t->u.ddr_mem.data[0];
|
|
|
|
/* normal ram size */
|
|
count = t->u.ddr_mem.count;
|
|
mem = calloc(count + MEM_RESV_COUNT, sizeof(*mem));
|
|
if (!mem) {
|
|
printf("Calloc ddr memory failed\n");
|
|
return 0;
|
|
}
|
|
|
|
for (i = 0, n = 0; i < count; i++, n++) {
|
|
base = t->u.ddr_mem.bank[i];
|
|
size = t->u.ddr_mem.bank[i + count];
|
|
|
|
/* 0~4GB */
|
|
if (base < SZ_4GB) {
|
|
mem[n].base = base;
|
|
mem[n].size = ddr_mem_get_usable_size(base, size);
|
|
if (base + size > SZ_4GB) {
|
|
n++;
|
|
mem[n].base_u64 = SZ_4GB;
|
|
mem[n].size_u64 = base + size - SZ_4GB;
|
|
}
|
|
} else {
|
|
/* 4GB+ */
|
|
mem[n].base_u64 = base;
|
|
mem[n].size_u64 = size;
|
|
}
|
|
|
|
assert(n < count + MEM_RESV_COUNT);
|
|
}
|
|
|
|
*out_count = n;
|
|
return mem;
|
|
}
|
|
#endif
|
|
|
|
/* Leagcy */
|
|
ret = uclass_get_device(UCLASS_RAM, 0, &dev);
|
|
if (ret) {
|
|
debug("DRAM init failed: %d\n", ret);
|
|
return NULL;
|
|
}
|
|
ret = ram_get_info(dev, &ram);
|
|
if (ret) {
|
|
debug("Cannot get DRAM size: %d\n", ret);
|
|
return NULL;
|
|
}
|
|
|
|
debug("SDRAM base=%lx, size=%lx\n",
|
|
(unsigned long)ram.base, (unsigned long)ram.size);
|
|
|
|
count = 1;
|
|
mem = calloc(1, sizeof(*mem));
|
|
if (!mem) {
|
|
printf("Calloc ddr memory failed\n");
|
|
return 0;
|
|
}
|
|
|
|
for (i = 0; i < count; i++) {
|
|
mem[i].base = CONFIG_SYS_SDRAM_BASE;
|
|
mem[i].size = ddr_mem_get_usable_size(mem[i].base, ram.size);
|
|
}
|
|
|
|
*out_count = count;
|
|
return mem;
|
|
}
|
|
|
|
#ifndef CONFIG_BIDRAM
|
|
/*
|
|
* init_bank=0: called from dram_init_banksize()
|
|
* init_bank=0: called from dram_init()
|
|
*/
|
|
phys_size_t param_simple_parse_ddr_mem(int init_bank)
|
|
{
|
|
struct memblock *list;
|
|
int i, count;
|
|
|
|
list = param_parse_ddr_mem(&count);
|
|
if (!list) {
|
|
printf("Can't get dram banks\n");
|
|
return 0;
|
|
}
|
|
|
|
if (count > CONFIG_NR_DRAM_BANKS) {
|
|
printf("Dram banks num=%d, over %d\n", count, CONFIG_NR_DRAM_BANKS);
|
|
return 0;
|
|
}
|
|
|
|
if (!init_bank) {
|
|
i = count - 1;
|
|
return ddr_mem_get_usable_size(list[i].base, list[i].size);
|
|
}
|
|
|
|
for (i = 0; i < count; i++) {
|
|
gd->bd->bi_dram[i].start = list[i].base;
|
|
gd->bd->bi_dram[i].size =
|
|
ddr_mem_get_usable_size(list[i].base, list[i].size);
|
|
debug("bank[%d]: 0x%08lx - 0x%08lx\n", i,
|
|
(ulong)gd->bd->bi_dram[i].start,
|
|
(ulong)gd->bd->bi_dram[i].start +
|
|
(ulong)gd->bd->bi_dram[i].size);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
int param_parse_pre_serial(int *flags)
|
|
{
|
|
#if defined(CONFIG_ROCKCHIP_PRELOADER_SERIAL) && \
|
|
defined(CONFIG_ROCKCHIP_PRELOADER_ATAGS)
|
|
struct tag *t;
|
|
|
|
t = atags_get_tag(ATAG_SERIAL);
|
|
if (t) {
|
|
gd->serial.using_pre_serial = 1;
|
|
gd->serial.enable = t->u.serial.enable;
|
|
gd->serial.baudrate = t->u.serial.baudrate;
|
|
gd->serial.addr = t->u.serial.addr;
|
|
gd->serial.id = t->u.serial.id;
|
|
gd->baudrate = CONFIG_BAUDRATE;
|
|
if (!gd->serial.enable && flags)
|
|
*flags |= GD_FLG_DISABLE_CONSOLE;
|
|
debug("preloader: enable=%d, addr=0x%lx, baudrate=%d, id=%d\n",
|
|
gd->serial.enable, gd->serial.addr,
|
|
gd->serial.baudrate, gd->serial.id);
|
|
} else
|
|
#endif
|
|
{
|
|
gd->baudrate = CONFIG_BAUDRATE;
|
|
gd->serial.baudrate = CONFIG_BAUDRATE;
|
|
gd->serial.addr = CONFIG_DEBUG_UART_BASE;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int param_parse_pubkey_fuse_programmed(void)
|
|
{
|
|
#ifdef CONFIG_ROCKCHIP_PRELOADER_ATAGS
|
|
struct tag *t;
|
|
|
|
t = atags_get_tag(ATAG_PUB_KEY);
|
|
if (t) {
|
|
/* Pass if efuse/otp programmed */
|
|
if (t->u.pub_key.flag == PUBKEY_FUSE_PROGRAMMED)
|
|
env_update("bootargs", "fuse.programmed=1");
|
|
else
|
|
env_update("bootargs", "fuse.programmed=0");
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|