blob: 0c01765db41606a2822d7f5581a5f847d97290c6 [file] [log] [blame]
/*
* Copyright 2018-2020 NXP
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#include <assert.h>
#include <endian.h>
#include <string.h>
#include <common/debug.h>
#include <common/tbbr/tbbr_img_def.h>
#include <drivers/io/io_block.h>
#include <drivers/io/io_driver.h>
#include <drivers/io/io_fip.h>
#include <drivers/io/io_memmap.h>
#include <drivers/io/io_storage.h>
#ifdef FLEXSPI_NOR_BOOT
#include <flexspi_nor.h>
#endif
#if defined(QSPI_BOOT)
#include <qspi.h>
#endif
#if defined(SD_BOOT) || defined(EMMC_BOOT)
#include <sd_mmc.h>
#endif
#include <tools_share/firmware_image_package.h>
#ifdef CONFIG_DDR_FIP_IMAGE
#include <ddr_io_storage.h>
#endif
#ifdef POLICY_FUSE_PROVISION
#include <fuse_io.h>
#endif
#include "plat_common.h"
#include "platform_def.h"
uint32_t fip_device;
/* IO devices */
uintptr_t backend_dev_handle;
static const io_dev_connector_t *fip_dev_con;
static uintptr_t fip_dev_handle;
static const io_dev_connector_t *backend_dev_con;
static io_block_spec_t fip_block_spec = {
.offset = PLAT_FIP_OFFSET,
.length = PLAT_FIP_MAX_SIZE
};
static const io_uuid_spec_t bl2_uuid_spec = {
.uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2,
};
static const io_uuid_spec_t fuse_bl2_uuid_spec = {
.uuid = UUID_SCP_FIRMWARE_SCP_BL2,
};
static const io_uuid_spec_t bl31_uuid_spec = {
.uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31,
};
static const io_uuid_spec_t bl32_uuid_spec = {
.uuid = UUID_SECURE_PAYLOAD_BL32,
};
static const io_uuid_spec_t bl33_uuid_spec = {
.uuid = UUID_NON_TRUSTED_FIRMWARE_BL33,
};
static const io_uuid_spec_t tb_fw_config_uuid_spec = {
.uuid = UUID_TB_FW_CONFIG,
};
static const io_uuid_spec_t hw_config_uuid_spec = {
.uuid = UUID_HW_CONFIG,
};
#if TRUSTED_BOARD_BOOT
static const io_uuid_spec_t tb_fw_cert_uuid_spec = {
.uuid = UUID_TRUSTED_BOOT_FW_CERT,
};
static const io_uuid_spec_t trusted_key_cert_uuid_spec = {
.uuid = UUID_TRUSTED_KEY_CERT,
};
static const io_uuid_spec_t fuse_key_cert_uuid_spec = {
.uuid = UUID_SCP_FW_KEY_CERT,
};
static const io_uuid_spec_t soc_fw_key_cert_uuid_spec = {
.uuid = UUID_SOC_FW_KEY_CERT,
};
static const io_uuid_spec_t tos_fw_key_cert_uuid_spec = {
.uuid = UUID_TRUSTED_OS_FW_KEY_CERT,
};
static const io_uuid_spec_t nt_fw_key_cert_uuid_spec = {
.uuid = UUID_NON_TRUSTED_FW_KEY_CERT,
};
static const io_uuid_spec_t fuse_cert_uuid_spec = {
.uuid = UUID_SCP_FW_CONTENT_CERT,
};
static const io_uuid_spec_t soc_fw_cert_uuid_spec = {
.uuid = UUID_SOC_FW_CONTENT_CERT,
};
static const io_uuid_spec_t tos_fw_cert_uuid_spec = {
.uuid = UUID_TRUSTED_OS_FW_CONTENT_CERT,
};
static const io_uuid_spec_t nt_fw_cert_uuid_spec = {
.uuid = UUID_NON_TRUSTED_FW_CONTENT_CERT,
};
#endif /* TRUSTED_BOARD_BOOT */
static int open_fip(const uintptr_t spec);
struct plat_io_policy {
uintptr_t *dev_handle;
uintptr_t image_spec;
int (*check)(const uintptr_t spec);
};
/* By default, ARM platforms load images from the FIP */
static const struct plat_io_policy policies[] = {
[FIP_IMAGE_ID] = {
&backend_dev_handle,
(uintptr_t)&fip_block_spec,
open_backend
},
[BL2_IMAGE_ID] = {
&fip_dev_handle,
(uintptr_t)&bl2_uuid_spec,
open_fip
},
[SCP_BL2_IMAGE_ID] = {
&fip_dev_handle,
(uintptr_t)&fuse_bl2_uuid_spec,
open_fip
},
[BL31_IMAGE_ID] = {
&fip_dev_handle,
(uintptr_t)&bl31_uuid_spec,
open_fip
},
[BL32_IMAGE_ID] = {
&fip_dev_handle,
(uintptr_t)&bl32_uuid_spec,
open_fip
},
[BL33_IMAGE_ID] = {
&fip_dev_handle,
(uintptr_t)&bl33_uuid_spec,
open_fip
},
[TB_FW_CONFIG_ID] = {
&fip_dev_handle,
(uintptr_t)&tb_fw_config_uuid_spec,
open_fip
},
[HW_CONFIG_ID] = {
&fip_dev_handle,
(uintptr_t)&hw_config_uuid_spec,
open_fip
},
#if TRUSTED_BOARD_BOOT
[TRUSTED_BOOT_FW_CERT_ID] = {
&fip_dev_handle,
(uintptr_t)&tb_fw_cert_uuid_spec,
open_fip
},
[TRUSTED_KEY_CERT_ID] = {
&fip_dev_handle,
(uintptr_t)&trusted_key_cert_uuid_spec,
open_fip
},
[SCP_FW_KEY_CERT_ID] = {
&fip_dev_handle,
(uintptr_t)&fuse_key_cert_uuid_spec,
open_fip
},
[SOC_FW_KEY_CERT_ID] = {
&fip_dev_handle,
(uintptr_t)&soc_fw_key_cert_uuid_spec,
open_fip
},
[TRUSTED_OS_FW_KEY_CERT_ID] = {
&fip_dev_handle,
(uintptr_t)&tos_fw_key_cert_uuid_spec,
open_fip
},
[NON_TRUSTED_FW_KEY_CERT_ID] = {
&fip_dev_handle,
(uintptr_t)&nt_fw_key_cert_uuid_spec,
open_fip
},
[SCP_FW_CONTENT_CERT_ID] = {
&fip_dev_handle,
(uintptr_t)&fuse_cert_uuid_spec,
open_fip
},
[SOC_FW_CONTENT_CERT_ID] = {
&fip_dev_handle,
(uintptr_t)&soc_fw_cert_uuid_spec,
open_fip
},
[TRUSTED_OS_FW_CONTENT_CERT_ID] = {
&fip_dev_handle,
(uintptr_t)&tos_fw_cert_uuid_spec,
open_fip
},
[NON_TRUSTED_FW_CONTENT_CERT_ID] = {
&fip_dev_handle,
(uintptr_t)&nt_fw_cert_uuid_spec,
open_fip
},
#endif /* TRUSTED_BOARD_BOOT */
};
/* Weak definitions may be overridden in specific ARM standard platform */
#pragma weak plat_io_setup
/*
* Return an IO device handle and specification which can be used to access
*/
static int open_fip(const uintptr_t spec)
{
int result;
uintptr_t local_image_handle;
/* See if a Firmware Image Package is available */
result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID);
if (result == 0) {
result = io_open(fip_dev_handle, spec, &local_image_handle);
if (result == 0) {
VERBOSE("Using FIP\n");
io_close(local_image_handle);
}
}
return result;
}
int open_backend(const uintptr_t spec)
{
int result;
uintptr_t local_image_handle;
result = io_dev_init(backend_dev_handle, (uintptr_t)NULL);
if (result == 0) {
result = io_open(backend_dev_handle, spec, &local_image_handle);
if (result == 0) {
io_close(local_image_handle);
}
}
return result;
}
#if defined(SD_BOOT) || defined(EMMC_BOOT)
static int plat_io_block_setup(size_t fip_offset, uintptr_t block_dev_spec)
{
int io_result;
fip_block_spec.offset = fip_offset;
io_result = register_io_dev_block(&backend_dev_con);
assert(io_result == 0);
/* Open connections to devices and cache the handles */
io_result = io_dev_open(backend_dev_con, block_dev_spec,
&backend_dev_handle);
assert(io_result == 0);
return io_result;
}
#endif
#if defined(FLEXSPI_NOR_BOOT) || defined(QSPI_BOOT)
static int plat_io_memmap_setup(size_t fip_offset)
{
int io_result;
fip_block_spec.offset = fip_offset;
io_result = register_io_dev_memmap(&backend_dev_con);
assert(io_result == 0);
/* Open connections to devices and cache the handles */
io_result = io_dev_open(backend_dev_con, (uintptr_t)NULL,
&backend_dev_handle);
assert(io_result == 0);
return io_result;
}
#endif
static int ls_io_fip_setup(unsigned int boot_dev)
{
int io_result;
io_result = register_io_dev_fip(&fip_dev_con);
assert(io_result == 0);
/* Open connections to devices and cache the handles */
io_result = io_dev_open(fip_dev_con, (uintptr_t)&fip_device,
&fip_dev_handle);
assert(io_result == 0);
#ifdef CONFIG_DDR_FIP_IMAGE
/* Open connection to DDR FIP image if available */
io_result = ddr_fip_setup(fip_dev_con, boot_dev);
assert(io_result == 0);
#endif
#ifdef POLICY_FUSE_PROVISION
/* Open connection to FUSE FIP image if available */
io_result = fuse_fip_setup(fip_dev_con, boot_dev);
assert(io_result == 0);
#endif
return io_result;
}
int ls_qspi_io_setup(void)
{
#ifdef QSPI_BOOT
qspi_io_setup(NXP_QSPI_FLASH_ADDR,
NXP_QSPI_FLASH_SIZE,
PLAT_FIP_OFFSET);
return plat_io_memmap_setup(NXP_QSPI_FLASH_ADDR + PLAT_FIP_OFFSET);
#else
ERROR("QSPI driver not present. Check your BUILD\n");
/* Should never reach here */
assert(false);
return -1;
#endif
}
int emmc_sdhc2_io_setup(void)
{
#if defined(EMMC_BOOT) && defined(NXP_ESDHC2_ADDR)
uintptr_t block_dev_spec;
int ret;
ret = sd_emmc_init(&block_dev_spec,
NXP_ESDHC2_ADDR,
NXP_SD_BLOCK_BUF_ADDR,
NXP_SD_BLOCK_BUF_SIZE,
false);
if (ret != 0) {
return ret;
}
return plat_io_block_setup(PLAT_FIP_OFFSET, block_dev_spec);
#else
ERROR("EMMC driver not present. Check your BUILD\n");
/* Should never reach here */
assert(false);
return -1;
#endif
}
int emmc_io_setup(void)
{
/* On the platforms which only has one ESDHC controller,
* eMMC-boot will use the first ESDHC controller.
*/
#if defined(SD_BOOT) || defined(EMMC_BOOT)
uintptr_t block_dev_spec;
int ret;
ret = sd_emmc_init(&block_dev_spec,
NXP_ESDHC_ADDR,
NXP_SD_BLOCK_BUF_ADDR,
NXP_SD_BLOCK_BUF_SIZE,
true);
if (ret != 0) {
return ret;
}
return plat_io_block_setup(PLAT_FIP_OFFSET, block_dev_spec);
#else
ERROR("SD driver not present. Check your BUILD\n");
/* Should never reach here */
assert(false);
return -1;
#endif
}
int ifc_nor_io_setup(void)
{
ERROR("NOR driver not present. Check your BUILD\n");
/* Should never reach here */
assert(false);
return -1;
}
int ifc_nand_io_setup(void)
{
ERROR("NAND driver not present. Check your BUILD\n");
/* Should never reach here */
assert(false);
return -1;
}
int ls_flexspi_nor_io_setup(void)
{
#ifdef FLEXSPI_NOR_BOOT
int ret = 0;
ret = flexspi_nor_io_setup(NXP_FLEXSPI_FLASH_ADDR,
NXP_FLEXSPI_FLASH_SIZE,
NXP_FLEXSPI_ADDR);
if (ret != 0) {
ERROR("FlexSPI NOR driver initialization error.\n");
/* Should never reach here */
assert(0);
panic();
return -1;
}
return plat_io_memmap_setup(NXP_FLEXSPI_FLASH_ADDR + PLAT_FIP_OFFSET);
#else
ERROR("FlexSPI NOR driver not present. Check your BUILD\n");
/* Should never reach here */
assert(false);
return -1;
#endif
}
static int (* const ls_io_setup_table[])(void) = {
[BOOT_DEVICE_IFC_NOR] = ifc_nor_io_setup,
[BOOT_DEVICE_IFC_NAND] = ifc_nand_io_setup,
[BOOT_DEVICE_QSPI] = ls_qspi_io_setup,
[BOOT_DEVICE_EMMC] = emmc_io_setup,
[BOOT_DEVICE_SDHC2_EMMC] = emmc_sdhc2_io_setup,
[BOOT_DEVICE_FLEXSPI_NOR] = ls_flexspi_nor_io_setup,
[BOOT_DEVICE_FLEXSPI_NAND] = ls_flexspi_nor_io_setup,
};
int plat_io_setup(void)
{
int (*io_setup)(void);
unsigned int boot_dev = BOOT_DEVICE_NONE;
int ret;
boot_dev = get_boot_dev();
if (boot_dev == BOOT_DEVICE_NONE) {
ERROR("Boot Device detection failed, Check RCW_SRC\n");
return -EINVAL;
}
io_setup = ls_io_setup_table[boot_dev];
ret = io_setup();
if (ret != 0) {
return ret;
}
ret = ls_io_fip_setup(boot_dev);
if (ret != 0) {
return ret;
}
return 0;
}
/* Return an IO device handle and specification which can be used to access
* an image. Use this to enforce platform load policy
*/
int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle,
uintptr_t *image_spec)
{
int result = -1;
const struct plat_io_policy *policy;
if (image_id < ARRAY_SIZE(policies)) {
policy = &policies[image_id];
result = policy->check(policy->image_spec);
if (result == 0) {
*image_spec = policy->image_spec;
*dev_handle = *(policy->dev_handle);
}
}
#ifdef CONFIG_DDR_FIP_IMAGE
else {
VERBOSE("Trying alternative IO\n");
result = plat_get_ddr_fip_image_source(image_id, dev_handle,
image_spec, open_backend);
}
#endif
#ifdef POLICY_FUSE_PROVISION
if (result != 0) {
VERBOSE("Trying FUSE IO\n");
result = plat_get_fuse_image_source(image_id, dev_handle,
image_spec, open_backend);
}
#endif
return result;
}