nt9856x/BSP/u-boot/board/novatek/common/nvt_pcie_bootep.c
2023-03-28 15:07:53 +08:00

764 lines
22 KiB
C
Executable File

/**
NVT utilities for pice customization
@file nvt_pcie_bootep.c
@ingroup
@note
Copyright Novatek Microelectronics Corp. 2019. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation.
*/
#include <linux/libfdt.h>
#include <asm/nvt-common/nvt_common.h>
#include <asm/arch/IOAddress.h>
#include "nvt_ivot_pack.h"
#include <malloc.h>
#include <mapmem.h>
#include <asm/nvt-common/modelext/bin_info.h>
#include <fs.h>
#include <nand.h>
#include <mmc.h>
#include <spi_flash.h>
#include <fdt_support.h>
#define EP_LOADER_SIZE 0x10000
/* This buffer is a tmperoary buffer for put uboot + eploader */
#define TMP_BUFFER_SIZE 0x100000
#define CMD_BUFFER_SIZE 255
/**************************************************************************
*
*
* Novatek common function
*
*
**************************************************************************/
static int nvt_common_get_linux_mem(const void *fdt_addr, u64 *addr, u64 *size)
{
int nodeoffset, nextoffset;
const char *ptr = NULL;
u32 *val = NULL;
int addr_cells, size_cells;
nodeoffset = fdt_path_offset((void *)fdt_addr, "/memory");
if (nodeoffset > 0) {
addr_cells = fdt_address_cells(fdt_addr, nodeoffset);
size_cells = fdt_size_cells(fdt_addr, nodeoffset);
val = (u32 *)fdt_getprop((const void *)fdt_addr, nodeoffset, "reg", NULL);
if (val != NULL) {
*addr = fdt_read_number(val, addr_cells);
*size = fdt_read_number(val + addr_cells, size_cells);
nvt_dbg(MSG, "EP Linux memory address : 0x%lx, size : 0x%lx\n", *addr, *size);
} else {
nvt_dbg(ERR, "can not find reg on device tree\n");
return -1;
}
}
return 0;
}
/**************************************************************************
*
*
* Novatek RC boot EP Flow
*
*
**************************************************************************/
static int nvt_rc_boot_copy_from_storage(unsigned long dest_addr, unsigned long src_addr, unsigned long size)
{
char cmd[CMD_BUFFER_SIZE];
u32 align_size = 0;
align_size = ALIGN_CEIL(size, _EMBMEM_BLK_SIZE_);
#if defined(CONFIG_NVT_LINUX_SPINAND_BOOT) || (defined(CONFIG_NVT_LINUX_RAMDISK_SUPPORT) && defined(CONFIG_NVT_SPI_NAND))
sprintf(cmd, "nand read 0x%lx 0x%lx 0x%lx", dest_addr, src_addr, align_size);
#elif defined(CONFIG_NVT_LINUX_SPINOR_BOOT) || (defined(CONFIG_NVT_LINUX_RAMDISK_SUPPORT) && defined(CONFIG_NVT_SPI_NOR))
align_size = ALIGN_CEIL(align_size, ARCH_DMA_MINALIGN);
sprintf(cmd, "sf read 0x%lx 0x%lx 0x%lx", dest_addr, src_addr, align_size);
#elif defined(CONFIG_NVT_LINUX_EMMC_BOOT) || (defined(CONFIG_NVT_LINUX_RAMDISK_SUPPORT) && defined(CONFIG_NVT_IVOT_EMMC))
unsigned long align_off;
align_size = ALIGN_CEIL(align_size, MMC_MAX_BLOCK_LEN) / MMC_MAX_BLOCK_LEN;
align_off = ALIGN_CEIL(src_addr, MMC_MAX_BLOCK_LEN) / MMC_MAX_BLOCK_LEN;
sprintf(cmd, "mmc read 0x%lx 0x%lx 0x%lx", dest_addr, align_off, align_size);
#else
nvt_dbg(ERR, "A.bin can not set EMBMEM_NONE on nvt_info.dtsi\n");
#endif
nvt_dbg(MSG, "%s\n", cmd);
run_command(cmd, 0);
flush_cache(round_down((unsigned long)dest_addr, CONFIG_SYS_CACHELINE_SIZE), round_up(align_size, CONFIG_SYS_CACHELINE_SIZE));
return 0;
}
static int nvt_rc_boot_set_ep_ramdisk_addr(void *fdt_addr, unsigned int ep_ramdisk_addr)
{
int nodeoffset, ret = -1;
const char *ptr = NULL;
u64 *val = NULL;
nodeoffset = fdt_path_offset((void *)fdt_addr, "/ep_info");
if (nodeoffset > 0) {
ret = fdt_setprop_u32(fdt_addr, nodeoffset, "ramdisk_addr", ep_ramdisk_addr);
} else {
nvt_dbg(ERR, "can not find /ep_info on device tree\n");
return ret;
}
return ret;
}
static int nvt_rc_boot_get_epfdt(unsigned long *rcfdt_addr, unsigned long *epfdt_addr, unsigned long *epfdt_size)
{
int ret;
ulong rc_size;
/* 1. Verify RC FDT and Get Size firstly */
if ((ret = fdt_check_header((void *)*rcfdt_addr) != 0)) {
nvt_dbg(ERR, "invalid fdt header, addr=0x%08lx er = %d \n", (unsigned long)_BOARD_LINUXTMP_ADDR_, ret);
return ret;
}
rc_size = (ulong)fdt_totalsize((void *)*rcfdt_addr);
if (rc_size <= 0) {
nvt_dbg(ERR, "invalid fdt size, addr=0x%08lx er = %d \n", (unsigned long)_BOARD_LINUXTMP_ADDR_, ret);
return ret;
}
/* 2. Verify EP FDT (fdt address: RC FDT + RC FDT Size) and Get Size */
*epfdt_addr = (unsigned long)((unsigned long)*rcfdt_addr + (unsigned long)rc_size);
if ((ret = fdt_check_header((void *)*epfdt_addr) != 0)) {
nvt_dbg(ERR, "invalid ep fdt header, addr=0x%08lx er = %d\n", epfdt_addr, ret);
return ret;
}
*epfdt_size = (ulong)fdt_totalsize((void *)*epfdt_addr);
if (*epfdt_size <= 0) {
nvt_dbg(ERR, "invalid ep fdt size, addr=0x%08lx er = %d \n", (unsigned long)epfdt_addr, ret);
return ret;
}
return ret;
}
static int nvt_rc_boot_eploader_copy(bool tbin, unsigned long *src_addr, unsigned size)
{
int ret;
HEADINFO *head_info;
char cmd[CMD_BUFFER_SIZE];
unsigned long ep_addr;
char *buffer = malloc(TMP_BUFFER_SIZE);
if (buffer == NULL) {
nvt_dbg(ERR, ": malloc fail\n");
return -1;
}
/* 1. Copy to tmp buffer */
if (tbin) {
if (size > TMP_BUFFER_SIZE) {
nvt_dbg(ERR, "Uboot size(0x%lx) > TMP_BUFFER_SIZE(0x%lx), Stop to boot\n", size, TMP_BUFFER_SIZE);
goto out;
}
memcpy((void *)buffer, src_addr, size);
} else {
size = 2 * _EMBMEM_BLK_SIZE_;
if (size > TMP_BUFFER_SIZE) {
nvt_dbg(ERR, "Uboot size(0x%lx) > TMP_BUFFER_SIZE(0x%lx), Stop to boot\n", size, TMP_BUFFER_SIZE);
goto out;
}
nvt_rc_boot_copy_from_storage((unsigned long)buffer, (unsigned long)src_addr, size);
head_info = (HEADINFO *)(buffer + 0x300);
/* TODO multiple EP flow */
size = head_info->BinLength + EP_LOADER_SIZE;
nvt_rc_boot_copy_from_storage((unsigned long)buffer, (unsigned long)src_addr, size);
if (size > TMP_BUFFER_SIZE) {
nvt_dbg(ERR, "Uboot size(0x%lx) > TMP_BUFFER_SIZE(0x%lx), Stop to boot\n", size, TMP_BUFFER_SIZE);
goto out;
}
}
/* 2. Parsing NVT header to get real image size */
head_info = (HEADINFO *)(buffer + 0x300);
ep_addr = (unsigned long)buffer + head_info->BinLength;
nvt_dbg(MSG, ": EP loader addr = 0x%lx\n", ep_addr);
/* 3. Copy EP Loader to EP SRAM */
sprintf(cmd, "nvt_pcie_copy_sram 0x%lx", ep_addr);
ret = run_command(cmd, 0);
if (ret < 0) {
nvt_dbg(ERR, "Run command : %s fail\n", cmd);
goto out;
}
out:
if (buffer) {
free(buffer);
}
return ret;
}
static int nvt_rc_boot_ep_loader_process_tbin(unsigned int id, NVTPACK_MEM* p_mem, void* p_user_data)
{
EMB_PARTITION* pEmb = (EMB_PARTITION*)p_user_data;
unsigned long src_addr = (unsigned long)p_mem->p_data;
unsigned long size = p_mem->len;
int ret = 0;
switch(pEmb[id].EmbType)
{
case EMBTYPE_UBOOT:
ret = nvt_rc_boot_eploader_copy(true, (unsigned long *)src_addr, size);
break;
default:
break;
}
return ret;
}
static int nvt_rc_boot_ep_loader_process_abin(void* p_user_data)
{
EMB_PARTITION* pEmb = (EMB_PARTITION*)p_user_data;
int ret = -1, id;
for (id = 0; id < EMB_PARTITION_INFO_COUNT; id++) {
if (pEmb[id].EmbType == EMBTYPE_UBOOT) {
unsigned long src_addr = pEmb[id].PartitionOffset;
unsigned long size = pEmb[id].PartitionSize;
ret = nvt_rc_boot_eploader_copy(false, (unsigned long *)src_addr, size);
break;
}
}
return ret;
}
static int nvt_rc_boot_ep_partition_enum_copy_abin(void* p_user_data)
{
int ret = 0, id;
EMB_PARTITION* pEmb = (EMB_PARTITION*)p_user_data;
unsigned long map_base_addr = simple_strtoul(env_get("nvt_pcie_ep0_mau_base"),NULL,16);
unsigned long src_addr;
unsigned long size;
unsigned long pcie_dest_addr;
static unsigned long epfdt_addr = 0;
static unsigned long epfdt_size = 0;
HEADINFO *head_info;
image_header_t *hdr;
char label[CMD_BUFFER_SIZE];
char cmd[CMD_BUFFER_SIZE];
for (id = 0; id < EMB_PARTITION_INFO_COUNT; id++) {
src_addr = pEmb[id].PartitionOffset;
size = pEmb[id].PartitionSize;
switch(pEmb[id].EmbType)
{
case EMBTYPE_FDT:
nvt_dbg(MSG, "Copy EP DTS : \n");
if (size > _BOARD_FDT_SIZE_) {
nvt_dbg(ERR, "FDT Partition size(0x%lx) > BOARD_FDT_SIZE(0x%lx)\n", size, (unsigned long)_BOARD_FDT_SIZE_);
return -1;
}
/* 1. Copy all DTS partition to RC BOARD_FDT_ADDR */
pcie_dest_addr = (unsigned long)_BOARD_FDT_ADDR_;
nvt_rc_boot_copy_from_storage(pcie_dest_addr, src_addr, size);
/* 2. Get EP DTS address and size */
if (nvt_rc_boot_get_epfdt(&pcie_dest_addr, &epfdt_addr, &epfdt_size) < 0)
return -1;
/* 3. Copy to destination */
src_addr = epfdt_addr;
pcie_dest_addr = (unsigned long)_BOARD_FDT_ADDR_ + map_base_addr;
memcpy((void*)pcie_dest_addr, (void*)src_addr, epfdt_size);
break;
case EMBTYPE_ATF:
nvt_dbg(MSG, "Copy EP ATF : \n");
pcie_dest_addr = map_base_addr + (unsigned long)_BOARD_ATF_ADDR_;
size = 2 * _EMBMEM_BLK_SIZE_;
nvt_rc_boot_copy_from_storage(pcie_dest_addr, src_addr, size);
head_info = (HEADINFO *)(pcie_dest_addr + 0x350);
size = head_info->BinLength;
nvt_rc_boot_copy_from_storage(pcie_dest_addr, src_addr, size);
break;
#ifdef CONFIG_NVT_IVOT_OPTEE_SUPPORT
case EMBTYPE_TEEOS:
nvt_dbg(MSG, "Copy EP OPTEE : \n");
pcie_dest_addr = map_base_addr + (unsigned long)_BOARD_TEEOS_ADDR_;
size = 2 * _EMBMEM_BLK_SIZE_;
nvt_rc_boot_copy_from_storage(pcie_dest_addr, src_addr, size);
head_info = (HEADINFO *)(pcie_dest_addr + 0x350);
size = head_info->BinLength;
nvt_rc_boot_copy_from_storage(pcie_dest_addr, src_addr, size);
break;
#endif
case EMBTYPE_UBOOT:
nvt_dbg(MSG, "Copy EP UBOOT : \n");
pcie_dest_addr = map_base_addr + (unsigned long)_BOARD_UBOOT_ADDR_;
size = 2 * _EMBMEM_BLK_SIZE_;
nvt_rc_boot_copy_from_storage(pcie_dest_addr, src_addr, size);
HEADINFO *head_info = (HEADINFO *)(pcie_dest_addr + 0x300);
size = head_info->BinLength;
nvt_rc_boot_copy_from_storage(pcie_dest_addr, src_addr, size);
break;
case EMBTYPE_LINUX:
nvt_dbg(MSG, "Copy EP LINUX : \n");
pcie_dest_addr = map_base_addr + (unsigned long)CONFIG_LINUX_SDRAM_START;
size = sizeof(image_header_t);
nvt_rc_boot_copy_from_storage(pcie_dest_addr, src_addr, size);
hdr = (image_header_t *)pcie_dest_addr;
size = image_get_data_size(hdr) + sizeof(image_header_t);
nvt_rc_boot_copy_from_storage(pcie_dest_addr, src_addr, size);
break;
case EMBTYPE_ROOTFS:
if (nvt_runfw_bin_eprootfs_chk_exist(nvt_fdt_buffer, id) == true) {
nvt_dbg(MSG, "Copy EP-ROOTFS : \n");
/* 1. Get Header from storage */
pcie_dest_addr = map_base_addr + (unsigned long)(_BOARD_LINUX_ADDR_ + _BOARD_LINUX_SIZE_ - 0x10000);
size = sizeof(image_header_t);
nvt_rc_boot_copy_from_storage(pcie_dest_addr, src_addr, size);
/* 2. Get Ramdisk size */
hdr = (image_header_t *)pcie_dest_addr;
size = image_get_data_size(hdr) + sizeof(image_header_t);
size = ALIGN_CEIL(size, 4096);
/* 3. Get EP linux range */
u64 linux_addr, linux_size;
ret = nvt_common_get_linux_mem((void *)epfdt_addr, &linux_addr, &linux_size);
if (ret < 0) {
return ret;
}
/* 4. Set EP Ramdisk address */
ret = nvt_rc_boot_set_ep_ramdisk_addr((void *)epfdt_addr, (unsigned int)(linux_addr + linux_size - size - 0x10000));
if (ret < 0) {
return ret;
}
/* 5. Update EP DTS to EP DRAM */
pcie_dest_addr = (unsigned long)_BOARD_FDT_ADDR_ + map_base_addr;
memcpy((void*)pcie_dest_addr, (void*)epfdt_addr, epfdt_size);
/* 6. Copy EP-rootfs to EP DRAM */
pcie_dest_addr = map_base_addr + (unsigned long)(linux_addr + linux_size - size - 0x10000);
nvt_rc_boot_copy_from_storage(pcie_dest_addr, src_addr, size);
break;
} else {
continue;
}
default:
continue;
}
}
return 0;
}
static int nvt_rc_boot_ep_partition_enum_copy_tbin(unsigned int id, NVTPACK_MEM* p_mem, void* p_user_data)
{
EMB_PARTITION* pEmb = (EMB_PARTITION*)p_user_data;
unsigned long dest_addr;
unsigned long src_addr = (unsigned long)p_mem->p_data;
unsigned long size = p_mem->len;
static unsigned long epfdt_addr = 0;
static unsigned long epfdt_size = 0;
int ret = 0;
char cmd[CMD_BUFFER_SIZE];
switch(pEmb[id].EmbType)
{
case EMBTYPE_FDT:
nvt_dbg(MSG, "Copy EP DTS : 0x%lx\n",src_addr);
if (nvt_rc_boot_get_epfdt(&src_addr, &epfdt_addr, &epfdt_size) < 0)
return -1;
dest_addr = (unsigned long)_BOARD_FDT_ADDR_;
src_addr = epfdt_addr;
size = epfdt_size;
break;
case EMBTYPE_ATF:
nvt_dbg(MSG, "Copy EP ATF : \n");
dest_addr = (unsigned long)_BOARD_ATF_ADDR_;
break;
#ifdef CONFIG_NVT_IVOT_OPTEE_SUPPORT
case EMBTYPE_TEEOS:
nvt_dbg(MSG, "Copy EP OPTEE : \n");
dest_addr = (unsigned long)_BOARD_TEEOS_ADDR_;
break;
#endif
case EMBTYPE_UBOOT:
nvt_dbg(MSG, "Copy EP UBOOT : \n");
dest_addr = (unsigned long)_BOARD_UBOOT_ADDR_;
break;
case EMBTYPE_LINUX:
nvt_dbg(MSG, "Copy EP LINUX : \n");
dest_addr = (unsigned long)CONFIG_LINUX_SDRAM_START;
break;
case EMBTYPE_ROOTFS:
if (nvt_runfw_bin_eprootfs_chk_exist(nvt_fdt_buffer, id) == true) {
nvt_dbg(MSG, "Copy EP-ROOTFS : \n");
#ifdef CONFIG_NVT_BIN_CHKSUM_SUPPORT
src_addr += 64;
#endif
/* 1. Get EP-rootfs size from Header */
image_header_t *hdr = (image_header_t *)src_addr;
size = image_get_data_size(hdr) + sizeof(image_header_t);
size = ALIGN_CEIL(size, 4096);
/* 2. Get EP linux range */
u64 linux_addr, linux_size;
unsigned long map_base_addr = simple_strtoul(env_get("nvt_pcie_ep0_mau_base"),NULL,16);
ret = nvt_common_get_linux_mem((void *)epfdt_addr, &linux_addr, &linux_size);
if (ret < 0) {
return ret;
}
/* 3. Set EP Ramdisk address */
dest_addr = (unsigned long)(linux_addr + linux_size - size - 0x10000);
ret = nvt_rc_boot_set_ep_ramdisk_addr((void *)epfdt_addr, (unsigned int)dest_addr);
if (ret < 0) {
return ret;
}
/* 4. Copy to destination */
unsigned long pcie_dest_addr = (unsigned long)_BOARD_FDT_ADDR_ + map_base_addr;
memcpy((void*)pcie_dest_addr, (void*)epfdt_addr, epfdt_size);
break;
} else {
return 0;
}
default:
return 0;
}
/* Copy to EP DRAM */
sprintf(cmd, "nvt_pcie_copy 0x%lx 0x%lx 0x%lx", src_addr, dest_addr, size);
ret = run_command(cmd, 0);
if (ret < 0) {
nvt_dbg(ERR, "Run command : %s fail\n", cmd);
return ret;
}
}
/**
* nvt_rc_boot_rc_boot_flow - The main flow for RC boot EP
* @tbin: a flag for T.bin
*
* Init PCIE and create mapping table
* Set communication register to idle
* Get EP loader and copy to EP DRAM
* Boot up EP CPU
* Wait EP DRAM config done
* Get all partition and copy to EP DRAM
* Release EP CPU
*
* Returns 0 on success, < 0 otherwise
*/
static int nvt_rc_boot_flow(bool tbin)
{
int ret;
int i;
char cmd[CMD_BUFFER_SIZE];
EMB_PARTITION *pEmbCurr = emb_partition_info_data_curr;
NVTPACK_ENUM_PARTITION_INPUT np_enum_input;
/* Init PCIE and create mapping table */
sprintf(cmd, "nvt_pcie_init");
ret = run_command(cmd, 0);
if (ret < 0) {
nvt_dbg(ERR, "Run command : %s fail\n", cmd);
return ret;
}
/* Set communication register to idle */
sprintf(cmd, "nvt_pcie_epstatus set idle");
ret = run_command(cmd, 0);
if (ret < 0) {
nvt_dbg(ERR, "Run command : %s fail\n", cmd);
return ret;
}
/* 1. Get EP loader and copy to EP SRAM */
if (tbin) {
memset(&np_enum_input, 0, sizeof(np_enum_input));
np_enum_input.mem = (NVTPACK_MEM){(void*)CONFIG_NVT_RUNFW_SDRAM_BASE, 0};;
np_enum_input.p_user_data = pEmbCurr;
np_enum_input.fp_enum = nvt_rc_boot_ep_loader_process_tbin;
if(nvtpack_enum_partition(&np_enum_input) != NVTPACK_ER_SUCCESS) {
printf("failed with rc copy ep loader process.\r\n");
return -1;
}
} else {
ret = nvt_rc_boot_ep_loader_process_abin(pEmbCurr);
if (ret < 0) {
nvt_dbg(ERR, "nvt_rc_boot_ep_loader_process_abin fail\n");
return ret;
}
}
/* 2. Boot up EP CPU */
sprintf(cmd, "nvt_pcie_boot");
ret = run_command(cmd, 0);
if (ret < 0) {
nvt_dbg(ERR, "Run command : %s fail\n", cmd);
return ret;
}
/* 3. Wait EP DRAM config done */
i = 0;
sprintf(cmd, "nvt_pcie_epstatus get");
ret = run_command(cmd, 0);
while ((ret != 1) && (i < 30)) { // 0 = ep not boot, so we should copy ep loader and boot ep cpu
nvt_dbg(MSG, "Wait EP DRAM config done ret = %d\n");
udelay(50000);
ret = run_command(cmd, 0);
i++;
}
if (i >= 30) {
nvt_dbg(ERR, "Wait EP DRAM config done Time out !!!");
return -1;
}
/* 4. Copy all EP image to EP DRAM */
if (tbin) {
memset(&np_enum_input, 0, sizeof(np_enum_input));
np_enum_input.mem = (NVTPACK_MEM){(void*)CONFIG_NVT_RUNFW_SDRAM_BASE, 0};;
np_enum_input.p_user_data = pEmbCurr;
np_enum_input.fp_enum = nvt_rc_boot_ep_partition_enum_copy_tbin;
if(nvtpack_enum_partition(&np_enum_input) != NVTPACK_ER_SUCCESS) {
printf("failed with copy other images.\r\n");
return -1;
}
} else {
ret = nvt_rc_boot_ep_partition_enum_copy_abin(pEmbCurr);
if (ret < 0) {
nvt_dbg(ERR, "nvt_rc_boot_ep_partition_enum_copy_abin fail\n");
return ret;
}
}
/* 5. Issue cmd to EP CPU starting boot */
sprintf(cmd, "nvt_pcie_epstatus set start 0x%lx", _BOARD_FDT_ADDR_);
ret = run_command(cmd, 0);
if (ret < 0) {
nvt_dbg(ERR, "Run command : %s fail\n", cmd);
return ret;
}
return 0;
}
/**************************************************************************
*
*
* Novatek EP Boot Flow
*
*
**************************************************************************/
static int nvt_ep_boot_set_env_by_dts(const void *fdt_addr)
{
int nodeoffset, nextoffset;
const void *val = NULL;
const char *name;
nodeoffset = fdt_path_offset((void *)fdt_addr, "/ep_info");
if (nodeoffset > 0) {
nodeoffset = fdt_first_subnode((const void*)fdt_addr, nodeoffset);
fdt_for_each_property_offset(nextoffset, fdt_addr, nodeoffset) {
val = fdt_getprop_by_offset(fdt_addr, nextoffset, &name, NULL);
if (name != NULL && val != NULL) {
nvt_dbg(MSG, "Set \"%s = %s\" to env\n",name,val);
env_set(name, (void *)val);
}
}
} else {
nvt_dbg(ERR, "can not find /ep_info on device tree\n");
return -1;
}
return 0;
}
static int nvt_ep_boot_get_ep_ramdisk_addr(const void *fdt_addr, unsigned int *ep_ramdisk_addr)
{
int nodeoffset, nextoffset;
const char *ptr = NULL;
u32 *val = NULL;
if (ep_ramdisk_addr == NULL) {
return -1;
}
nodeoffset = fdt_path_offset((void *)fdt_addr, "/ep_info");
if (nodeoffset > 0) {
val = (u32 *)fdt_getprop((const void *)fdt_addr, nodeoffset, "ramdisk_addr", NULL);
if (val != NULL) {
*ep_ramdisk_addr = (unsigned long)fdt32_to_cpu(val[0]);
} else {
nvt_dbg(ERR, "can not find ramdisk_addr on device tree\n");
return -1;
}
} else {
nvt_dbg(ERR, "can not find /ep_info on device tree\n");
return -1;
}
return 0;
}
static int nvt_ep_boot_get_ep_info(const void *fdt_addr, u32 *data)
{
int nodeoffset, nextoffset;
const char *ptr = NULL;
u32 *val = NULL;
if (data == NULL) {
return -1;
}
nodeoffset = fdt_path_offset((void *)fdt_addr, "/ep_info");
if (nodeoffset > 0) {
val = (u32 *)fdt_getprop((const void *)fdt_addr, nodeoffset, "enable", NULL);
if (val != NULL) {
*data = (unsigned int)fdt32_to_cpu(val[0]);
}
} else {
nvt_dbg(ERR, "can not find /ep_info on device tree\n");
return -1;
}
return 0;
}
static int nvt_ep_boot_prepare_env_and_boot(u64 *linux_addr, u64 *linux_size)
{
char buf[CMD_BUFFER_SIZE], cmd[CMD_BUFFER_SIZE];
u64 kernel_size;
unsigned int nvt_ep_boot_ramdisk_addr, nvt_ep_boot_ramdisk_size, size;
image_header_t *hdr;
int ret;
/* To set the uboot env runtime. */
ret = nvt_ep_boot_set_env_by_dts(nvt_fdt_buffer);
if (ret < 0) {
return ret;
}
/* To get the ramdisk address runtime. */
ret = nvt_ep_boot_get_ep_ramdisk_addr(nvt_fdt_buffer, &nvt_ep_boot_ramdisk_addr);
if (ret < 0) {
return ret;
}
/* Get Ramdisk size and address */
hdr = (image_header_t *)(unsigned long)nvt_ep_boot_ramdisk_addr;
size = image_get_data_size(hdr) + sizeof(image_header_t);
nvt_ep_boot_ramdisk_size = ALIGN_CEIL(size, 4096);
sprintf(buf, "0x%08x ", nvt_ep_boot_ramdisk_addr + nvt_ep_boot_ramdisk_size);
env_set("initrd_high", buf);
/* To assign relocated fdt address */
sprintf(buf, "0x%08x ", *linux_addr + *linux_size);
env_set("fdt_high", buf);
/* The following will setup the lmb memory parameters for bootm cmd */
sprintf(buf, "0x%08x ", *linux_addr + *linux_size);
env_set("bootm_size", buf);
env_set("bootm_mapsize", buf);
sprintf(buf, "0x%08x ", *linux_addr);
env_set("bootm_low", buf);
env_set("kernel_comp_addr_r", buf);
/* Get kernel size */
hdr = (image_header_t *)CONFIG_LINUX_SDRAM_START;
kernel_size = image_get_data_size(hdr);
sprintf(buf, "0x%x", kernel_size);
env_set("kernel_comp_size", buf);
run_command("pri", 0);
sprintf(cmd, "booti");
sprintf(cmd, "%s %x %lx %lx", cmd, CONFIG_LINUX_SDRAM_START + sizeof(image_header_t), (unsigned long)nvt_ep_boot_ramdisk_addr, (unsigned long)nvt_fdt_buffer);
printf("%s\n", cmd);
run_command(cmd, 0);
return 0;
}
static int nvt_ep_boot_flow()
{
int ret;
u64 linux_addr, linux_size;
u32 data;
/* Verify EP device tree */
ret = nvt_ep_boot_get_ep_info(nvt_fdt_buffer, &data);
if (ret < 0) {
return ret;
}
if (data == 0) {
nvt_dbg(ERR, "!!! Stop Boot EP !!!\n");
while (1);
} else {
/* normal boot ep */
}
/* Get linux memory address and size from device tree*/
ret = nvt_common_get_linux_mem(nvt_fdt_buffer, &linux_addr, &linux_size);
if (ret != 0) {
return ret;
}
/* Prepare env for boot to linux and boot */
ret = nvt_ep_boot_prepare_env_and_boot(&linux_addr, &linux_size);
return ret;
}
/**************************************************************************
*
*
* Novatek RC Boot EP Entry
*
*
**************************************************************************/
int do_nvt_pcie(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
{
int ret;
ret = run_command("nvt_pcie_getid", 0);
if (ret == 0) {
ret = nvt_ep_boot_flow();
} else {
if (nvt_detect_fw_tbin()) {
ret = nvt_rc_boot_flow(true);
} else {
ret = nvt_rc_boot_flow(false);
}
}
return ret;
}
U_BOOT_CMD(
nvt_pcie, 1, 1, do_nvt_pcie,
"nvt RC boot EP",
""
);