rockchip: add rk atags support

The atags information is deliverd among rockchip pre-loaders,
i.e. ddr, miniloader, atf, tos and U-boot, etc.

Notice: the first pre-loader who creates the atags must call
atags_destroy() before atags_set_tag(), because atags_set_tag()
may detect last valid and existence ATAG_CORE tag in memory and
lead a wrong setup, that is not what we expect.

Change-Id: I6c2bf7633699af14afd472f2069e7d3ed91f5196
Signed-off-by: Joseph Chen <chenjh@rock-chips.com>
This commit is contained in:
Joseph Chen 2018-08-23 17:43:13 +08:00 committed by Kever Yang
parent 45a3782ab4
commit dc490422b6
4 changed files with 413 additions and 0 deletions

View File

@ -0,0 +1,145 @@
/* SPDX-License-Identifier: GPL-2.0+ */
/*
* (C) Copyright 2018 Rockchip Electronics Co., Ltd
*
*/
#ifndef __RK_ATAGS_H_
#define __RK_ATAGS_H_
/* Tag magic */
#define ATAG_CORE 0x54410001
#define ATAG_NONE 0x00000000
#define ATAG_SERIAL 0x54410050
#define ATAG_BOOTDEV 0x54410051
#define ATAG_DDR_MEM 0x54410052
#define ATAG_TOS_MEM 0x54410053
/* Tag size and offset */
#define ATAGS_SIZE (0x2000) /* 8K */
#define ATAGS_OFFSET (0x200000 - ATAGS_SIZE)/* [2M-8K, 2M] */
/* Tag sdram position!! */
#define ATAGS_PHYS_BASE (CONFIG_SYS_SDRAM_BASE + ATAGS_OFFSET)
#ifndef ATAGS_PHYS_BASE
"ERROR: ATAGS_PHYS_BASE is not defined!!"
#endif
/* tag_bootdev.devtype */
#define BOOT_TYPE_EMMC 0x0
#define BOOT_TYPE_NAND 0x1
#define BOOT_TYPE_SDCARD 0x2
#define BOOT_TYPE_SPI_NOR 0x3
#define BOOT_TYPE_SPI_NAND 0x4
/* tag_serial.m_mode */
#define SERIAL_M_MODE_M0 0x0
#define SERIAL_M_MODE_M1 0x1
#define SERIAL_M_MODE_M2 0x2
struct tag_serial {
u32 version;
u32 enable;
u64 addr;
u32 baudrate;
u32 m_mode;
u32 reserved[4];
} __packed;
struct tag_bootdev {
u32 version;
u32 devtype;
u32 devnum;
u32 mode;
u32 reserved[8];
} __packed;
struct tag_ddr_mem {
u32 count;
u32 version;
u64 bank[20];
u32 reserved[4];
} __packed;
struct tag_tos_mem {
u32 version;
struct {
char name[8];
u64 phy_addr;
u32 size;
u32 flags;
} tee_mem;
struct {
char name[8];
u64 phy_addr;
u32 size;
u32 flags;
} drm_mem;
u64 reserved[8];
} __packed;
struct tag_core {
u32 flags;
u32 pagesize;
u32 rootdev;
} __packed;
struct tag_header {
u32 size; /* bytes = size * 4 */
u32 magic;
} __packed;
/* Must be 4 bytes align */
struct tag {
struct tag_header hdr;
union {
struct tag_core core;
struct tag_serial serial;
struct tag_bootdev bootdev;
struct tag_ddr_mem ddr_mem;
struct tag_tos_mem tos_mem;
} u;
} __aligned(4);
/*
* Destroy atags
*
* first pre-loader who creates atags must call it before atags_set_tag(),
* because atags_set_tag() may detect last valid and existence ATAG_CORE
* tag in memory and lead a wrong setup, that is not what we expect.
*/
void atags_destroy(void);
/*
* atags_set_tag - set tag data
*
* @magic: tag magic, i.e. ATAG_SERIAL, ATAG_BOOTDEV, ....
* @tagdata: core data of struct, i.e. struct tag_serial/tag_bootdev ...
*
* return: 0 on success, others failed.
*/
int atags_set_tag(u32 magic, void *tagdata);
/*
* atags_get_tag - get tag by tag magic
*
* @magic: tag magic, i.e. ATAG_SERIAL, ATAG_BOOTDEV, ...
*
* return: NULL on failed, otherwise return the tag that we want.
*/
struct tag *atags_get_tag(u32 magic);
/* Print only one tag */
void atags_print_tag(struct tag *t);
/* Print all tags */
void atags_print_all_tags(void);
/* An atags example test */
void atags_test(void);
#endif

View File

@ -483,6 +483,15 @@ config ROCKCHIP_CRASH_DUMP
This enable dump registers when system crash, the registers you would like
to dump can be added in show_regs().
config ROCKCHIP_PRELOADER_ATAGS
bool "Rockchip pre-loader atags"
default y if ARCH_ROCKCHIP
help
This enable support Rockchip atags among pre-loaders, i.e. ddr, miniloader, ATF,
tos, U-Boot, etc. It delivers boot and configure information, shared with pre-loaders
and finally ends with U-Boot.
config GICV2
bool "ARM GICv2"

View File

@ -56,3 +56,5 @@ obj-spl-$(CONFIG_TPL_BUILD) =
# Now add SPL/TPL objects back into the main build
obj-$(CONFIG_SPL_BUILD) += $(obj-spl-y)
obj-$(CONFIG_TPL_BUILD) += $(obj-tpl-y)
obj-$(CONFIG_ROCKCHIP_PRELOADER_ATAGS) += rk_atags.o

View File

@ -0,0 +1,257 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* (C) Copyright 2018 Rockchip Electronics Co., Ltd.
*
*/
#include <common.h>
#include <asm/arch/rk_atags.h>
#define tag_next(t) ((struct tag *)((u32 *)(t) + (t)->hdr.size))
#define tag_size(type) ((sizeof(struct tag_header) + sizeof(struct type)) >> 2)
#define for_each_tag(t, base) \
for (t = base; t->hdr.size; t = tag_next(t))
static int inline bad_magic(u32 magic)
{
return ((magic != ATAG_CORE) &&
(magic != ATAG_NONE) &&
(magic != ATAG_SERIAL) &&
(magic != ATAG_BOOTDEV) &&
(magic != ATAG_DDR_MEM) &&
(magic != ATAG_TOS_MEM));
}
static int inline atags_size_overflow(struct tag *t, u32 tag_size)
{
return (unsigned long)t + (tag_size << 2) - ATAGS_PHYS_BASE > ATAGS_SIZE;
}
int atags_set_tag(u32 magic, void *tagdata)
{
u32 length, size = 0;
struct tag *t = (struct tag *)ATAGS_PHYS_BASE;
if (!tagdata)
return -ENODATA;
if (bad_magic(magic)) {
printf("%s: magic(%x) is not support\n", __func__, magic);
return -EINVAL;
}
/* Not allowed to be set by user directly, so do nothing */
if ((magic == ATAG_CORE) || (magic == ATAG_NONE))
return -EPERM;
/* If not initialized, setup now! */
if (t->hdr.magic != ATAG_CORE) {
t->hdr.magic = ATAG_CORE;
t->hdr.size = tag_size(tag_core);
t->u.core.flags = 0;
t->u.core.pagesize = 0;
t->u.core.rootdev = 0;
t = tag_next(t);
} else {
/* Find the end, and use it as a new tag */
for_each_tag(t, (struct tag *)ATAGS_PHYS_BASE) {
/*
* We had better check magic to avoid traversing an
* unknown tag, in case of atags has been damaged by
* some unknown reason.
*/
if (bad_magic(t->hdr.magic)) {
printf("%s: find unknown magic(%x)\n",
__func__, t->hdr.magic);
return -EINVAL;
}
if (t->hdr.magic == ATAG_NONE)
break;
}
}
/* Initialize new tag */
switch (magic) {
case ATAG_SERIAL:
size = tag_size(tag_serial);
break;
case ATAG_BOOTDEV:
size = tag_size(tag_bootdev);
break;
case ATAG_TOS_MEM:
size = tag_size(tag_tos_mem);
break;
case ATAG_DDR_MEM:
size = tag_size(tag_ddr_mem);
break;
};
if (atags_size_overflow(t, size)) {
printf("%s: failed! no memory to setup magic(%x), max_mem=0x%x\n",
__func__, magic, ATAGS_SIZE);
return -ENOMEM;
}
/* It's okay to setup a new tag */
t->hdr.magic = magic;
t->hdr.size = size;
length = (t->hdr.size << 2) - sizeof(struct tag_header);
memcpy(&t->u, (char *)tagdata, length);
/* Next tag */
t = tag_next(t);
/* Setup done */
t->hdr.magic = ATAG_NONE;
t->hdr.size = 0;
return 0;
}
struct tag *atags_get_tag(u32 magic)
{
struct tag *t;
for_each_tag(t, (struct tag *)ATAGS_PHYS_BASE) {
if (bad_magic(t->hdr.magic)) {
printf("%s: find unknown magic(%x)\n",
__func__, t->hdr.magic);
return NULL;
}
if (t->hdr.magic == magic)
return t;
}
return NULL;
}
void atags_destroy(void)
{
memset((char *)ATAGS_PHYS_BASE, 0, sizeof(struct tag));
}
#ifdef DEBUG_ATAGS
void atags_print_tag(struct tag *t)
{
u32 i;
if (!t)
return;
switch (t->hdr.magic) {
case ATAG_SERIAL:
printf("[serial]:\n");
printf(" magic = 0x%x\n", t->hdr.magic);
printf(" size = 0x%x\n\n", t->hdr.size << 2);
printf(" version = 0x%x\n", t->u.serial.version);
printf(" enable = 0x%x\n", t->u.serial.enable);
printf(" addr = 0x%llx\n", t->u.serial.addr);
printf(" baudrate = 0x%x\n", t->u.serial.baudrate);
printf(" m_mode = 0x%x\n", t->u.serial.m_mode);
for (i = 0; i < ARRAY_SIZE(t->u.serial.reserved); i++)
printf(" res[%d] = 0x%x\n", i, t->u.serial.reserved[i]);
break;
case ATAG_BOOTDEV:
printf("[bootdev]:\n");
printf(" magic = 0x%x\n", t->hdr.magic);
printf(" size = 0x%x\n\n", t->hdr.size << 2);
printf(" version = 0x%x\n", t->u.bootdev.version);
printf(" devtype = 0x%x\n", t->u.bootdev.devtype);
printf(" devnum = 0x%x\n", t->u.bootdev.devnum);
printf(" mode = 0x%x\n", t->u.bootdev.mode);
for (i = 0; i < ARRAY_SIZE(t->u.bootdev.reserved); i++)
printf(" res[%d] = 0x%x\n",
i, t->u.bootdev.reserved[i]);
break;
case ATAG_TOS_MEM:
printf("[tos_mem]:\n");
printf(" magic = 0x%x\n", t->hdr.magic);
printf(" size = 0x%x\n\n", t->hdr.size << 2);
printf(" version = 0x%x\n", t->u.tos_mem.version);
printf(" tee_mem:\n");
printf(" name = %s\n", t->u.tos_mem.tee_mem.name);
printf(" phy_addr = 0x%llx\n", t->u.tos_mem.tee_mem.phy_addr);
printf(" size = 0x%x\n", t->u.tos_mem.tee_mem.size);
printf(" flags = 0x%x\n", t->u.tos_mem.tee_mem.flags);
printf(" drm_mem:\n");
printf(" name = %s\n", t->u.tos_mem.drm_mem.name);
printf(" phy_addr = 0x%llx\n", t->u.tos_mem.drm_mem.phy_addr);
printf(" size = 0x%x\n", t->u.tos_mem.drm_mem.size);
printf(" flags = 0x%x\n", t->u.tos_mem.drm_mem.flags);
for (i = 0; i < ARRAY_SIZE(t->u.tos_mem.reserved); i++)
printf(" res[%d] = 0x%llx\n", i, t->u.tos_mem.reserved[i]);
break;
case ATAG_DDR_MEM:
printf("[ddr_mem]:\n");
printf(" magic = 0x%x\n", t->hdr.magic);
printf(" size = 0x%x\n\n", t->hdr.size << 2);
printf(" count = 0x%x\n", t->u.ddr_mem.count);
printf(" version = 0x%x\n", t->u.ddr_mem.version);
for (i = 0; i < ARRAY_SIZE(t->u.ddr_mem.bank); i++)
printf(" bank[%d] = 0x%llx\n", i, t->u.ddr_mem.bank[i]);
for (i = 0; i < ARRAY_SIZE(t->u.ddr_mem.reserved); i++)
printf(" res[%d] = 0x%x\n", i, t->u.ddr_mem.reserved[i]);
break;
case ATAG_CORE:
printf("[core]:\n");
printf(" magic = 0x%x\n", t->hdr.magic);
printf(" size = 0x%x\n\n", t->hdr.size << 2);
printf(" flags = 0x%x\n", t->u.core.flags);
printf(" pagesize = 0x%x\n", t->u.core.pagesize);
printf(" rootdev = 0x%x\n", t->u.core.rootdev);
break;
default:
printf("%s: magic(%x) is not support\n", __func__, t->hdr.magic);
}
printf("\n");
}
void atags_print_all_tags(void)
{
struct tag *t;
for_each_tag(t, (struct tag *)ATAGS_PHYS_BASE) {
if (bad_magic(t->hdr.magic)) {
printf("%s: find unknown magic(%x)\n",
__func__, t->hdr.magic);
return;
}
atags_print_tag(t);
}
}
void atags_test(void)
{
struct tag_serial t_serial;
struct tag_bootdev t_bootdev;
struct tag_ddr_mem t_ddr_mem;
struct tag_tos_mem t_tos_mem;
memset(&t_serial, 0x1, sizeof(t_serial));
memset(&t_bootdev, 0x2, sizeof(t_bootdev));
memset(&t_ddr_mem, 0x3, sizeof(t_ddr_mem));
memset(&t_tos_mem, 0x4, sizeof(t_tos_mem));
memcpy(&t_tos_mem.tee_mem.name, "tee_mem", 8);
memcpy(&t_tos_mem.drm_mem.name, "drm_mem", 8);
/* First pre-loader must call it before atags_set_tag() */
atags_destroy();
atags_set_tag(ATAG_SERIAL, &t_serial);
atags_set_tag(ATAG_BOOTDEV, &t_bootdev);
atags_set_tag(ATAG_DDR_MEM, &t_ddr_mem);
atags_set_tag(ATAG_TOS_MEM, &t_tos_mem);
atags_print_all_tags();
}
#else
void inline atags_print_tag(struct tag *t) {}
void inline atags_print_all_tags(void) {}
void inline atags_test(void) {}
#endif