GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <common/debug.h>
|
||||
#include <drivers/console.h>
|
||||
#include <drivers/ti/uart/uart_16550.h>
|
||||
|
||||
#include <platform_def.h>
|
||||
|
||||
/*******************************************************************************
|
||||
* Functions that set up the console
|
||||
******************************************************************************/
|
||||
static console_t bcm_boot_console;
|
||||
static console_t bcm_runtime_console;
|
||||
|
||||
/* Initialize the console to provide early debug support */
|
||||
void bcm_console_boot_init(void)
|
||||
{
|
||||
int rc = console_16550_register(PLAT_BRCM_BOOT_UART_BASE,
|
||||
PLAT_BRCM_BOOT_UART_CLK_IN_HZ,
|
||||
BRCM_CONSOLE_BAUDRATE,
|
||||
&bcm_boot_console);
|
||||
if (rc == 0) {
|
||||
/*
|
||||
* The crash console doesn't use the multi console API, it uses
|
||||
* the core console functions directly. It is safe to call panic
|
||||
* and let it print debug information.
|
||||
*/
|
||||
panic();
|
||||
}
|
||||
|
||||
console_set_scope(&bcm_boot_console, CONSOLE_FLAG_BOOT);
|
||||
}
|
||||
|
||||
void bcm_console_boot_end(void)
|
||||
{
|
||||
console_flush();
|
||||
|
||||
(void)console_unregister(&bcm_boot_console);
|
||||
}
|
||||
|
||||
/* Initialize the runtime console */
|
||||
void bcm_console_runtime_init(void)
|
||||
{
|
||||
int rc = console_16550_register(PLAT_BRCM_BL31_RUN_UART_BASE,
|
||||
PLAT_BRCM_BL31_RUN_UART_CLK_IN_HZ,
|
||||
BRCM_CONSOLE_BAUDRATE,
|
||||
&bcm_runtime_console);
|
||||
if (rc == 0)
|
||||
panic();
|
||||
|
||||
console_set_scope(&bcm_runtime_console, CONSOLE_FLAG_RUNTIME);
|
||||
}
|
||||
|
||||
void bcm_console_runtime_end(void)
|
||||
{
|
||||
console_flush();
|
||||
|
||||
(void)console_unregister(&bcm_runtime_console);
|
||||
}
|
||||
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
* Copyright (c) 2018 - 2020, Broadcom
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <arch_helpers.h>
|
||||
#include <common/debug.h>
|
||||
#include <plat/common/platform.h>
|
||||
|
||||
#include <bcm_elog.h>
|
||||
|
||||
/* error logging signature */
|
||||
#define BCM_ELOG_SIG_OFFSET 0x0000
|
||||
#define BCM_ELOG_SIG_VAL 0x75767971
|
||||
|
||||
/* current logging offset that points to where new logs should be added */
|
||||
#define BCM_ELOG_OFF_OFFSET 0x0004
|
||||
|
||||
/* current logging length (excluding header) */
|
||||
#define BCM_ELOG_LEN_OFFSET 0x0008
|
||||
|
||||
#define BCM_ELOG_HEADER_LEN 12
|
||||
|
||||
/*
|
||||
* @base: base address of memory where log is saved
|
||||
* @max_size: max size of memory reserved for logging
|
||||
* @is_active: indicates logging is currently active
|
||||
* @level: current logging level
|
||||
*/
|
||||
struct bcm_elog {
|
||||
uintptr_t base;
|
||||
uint32_t max_size;
|
||||
unsigned int is_active;
|
||||
unsigned int level;
|
||||
};
|
||||
|
||||
static struct bcm_elog global_elog;
|
||||
|
||||
extern void memcpy16(void *dst, const void *src, unsigned int len);
|
||||
|
||||
/*
|
||||
* Log one character
|
||||
*/
|
||||
static void elog_putchar(struct bcm_elog *elog, unsigned char c)
|
||||
{
|
||||
uint32_t offset, len;
|
||||
|
||||
offset = mmio_read_32(elog->base + BCM_ELOG_OFF_OFFSET);
|
||||
len = mmio_read_32(elog->base + BCM_ELOG_LEN_OFFSET);
|
||||
mmio_write_8(elog->base + offset, c);
|
||||
offset++;
|
||||
|
||||
/* log buffer is now full and need to wrap around */
|
||||
if (offset >= elog->max_size)
|
||||
offset = BCM_ELOG_HEADER_LEN;
|
||||
|
||||
/* only increment length when log buffer is not full */
|
||||
if (len < elog->max_size - BCM_ELOG_HEADER_LEN)
|
||||
len++;
|
||||
|
||||
mmio_write_32(elog->base + BCM_ELOG_OFF_OFFSET, offset);
|
||||
mmio_write_32(elog->base + BCM_ELOG_LEN_OFFSET, len);
|
||||
}
|
||||
|
||||
static void elog_unsigned_num(struct bcm_elog *elog, unsigned long unum,
|
||||
unsigned int radix)
|
||||
{
|
||||
/* Just need enough space to store 64 bit decimal integer */
|
||||
unsigned char num_buf[20];
|
||||
int i = 0, rem;
|
||||
|
||||
do {
|
||||
rem = unum % radix;
|
||||
if (rem < 0xa)
|
||||
num_buf[i++] = '0' + rem;
|
||||
else
|
||||
num_buf[i++] = 'a' + (rem - 0xa);
|
||||
} while (unum /= radix);
|
||||
|
||||
while (--i >= 0)
|
||||
elog_putchar(elog, num_buf[i]);
|
||||
}
|
||||
|
||||
static void elog_string(struct bcm_elog *elog, const char *str)
|
||||
{
|
||||
while (*str)
|
||||
elog_putchar(elog, *str++);
|
||||
}
|
||||
|
||||
/*
|
||||
* Routine to initialize error logging
|
||||
*/
|
||||
int bcm_elog_init(void *base, uint32_t size, unsigned int level)
|
||||
{
|
||||
struct bcm_elog *elog = &global_elog;
|
||||
uint32_t val;
|
||||
|
||||
elog->base = (uintptr_t)base;
|
||||
elog->max_size = size;
|
||||
elog->is_active = 1;
|
||||
elog->level = level / 10;
|
||||
|
||||
/*
|
||||
* If a valid signature can be found, it means logs have been copied
|
||||
* into designated memory by another software. In this case, we should
|
||||
* not re-initialize the entry header in the designated memory
|
||||
*/
|
||||
val = mmio_read_32(elog->base + BCM_ELOG_SIG_OFFSET);
|
||||
if (val != BCM_ELOG_SIG_VAL) {
|
||||
mmio_write_32(elog->base + BCM_ELOG_SIG_OFFSET,
|
||||
BCM_ELOG_SIG_VAL);
|
||||
mmio_write_32(elog->base + BCM_ELOG_OFF_OFFSET,
|
||||
BCM_ELOG_HEADER_LEN);
|
||||
mmio_write_32(elog->base + BCM_ELOG_LEN_OFFSET, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Routine to disable error logging
|
||||
*/
|
||||
void bcm_elog_exit(void)
|
||||
{
|
||||
struct bcm_elog *elog = &global_elog;
|
||||
|
||||
if (!elog->is_active)
|
||||
return;
|
||||
|
||||
elog->is_active = 0;
|
||||
|
||||
flush_dcache_range(elog->base, elog->max_size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Routine to copy error logs from current memory to 'dst' memory and continue
|
||||
* logging from the new 'dst' memory.
|
||||
* dst and base addresses must be 16-bytes aligned.
|
||||
*/
|
||||
int bcm_elog_copy_log(void *dst, uint32_t max_size)
|
||||
{
|
||||
struct bcm_elog *elog = &global_elog;
|
||||
uint32_t offset, len;
|
||||
|
||||
if (!elog->is_active || ((uintptr_t)dst == elog->base))
|
||||
return -1;
|
||||
|
||||
/* flush cache before copying logs */
|
||||
flush_dcache_range(elog->base, max_size);
|
||||
|
||||
/*
|
||||
* If current offset exceeds the new max size, then that is considered
|
||||
* as a buffer overflow situation. In this case, we reset the offset
|
||||
* back to the beginning
|
||||
*/
|
||||
offset = mmio_read_32(elog->base + BCM_ELOG_OFF_OFFSET);
|
||||
if (offset >= max_size) {
|
||||
offset = BCM_ELOG_HEADER_LEN;
|
||||
mmio_write_32(elog->base + BCM_ELOG_OFF_OFFSET, offset);
|
||||
}
|
||||
|
||||
/* note payload length does not include header */
|
||||
len = mmio_read_32(elog->base + BCM_ELOG_LEN_OFFSET);
|
||||
if (len > max_size - BCM_ELOG_HEADER_LEN) {
|
||||
len = max_size - BCM_ELOG_HEADER_LEN;
|
||||
mmio_write_32(elog->base + BCM_ELOG_LEN_OFFSET, len);
|
||||
}
|
||||
|
||||
/* Need to copy everything including the header. */
|
||||
memcpy16(dst, (const void *)elog->base, len + BCM_ELOG_HEADER_LEN);
|
||||
elog->base = (uintptr_t)dst;
|
||||
elog->max_size = max_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Main routine to save logs into memory
|
||||
*/
|
||||
void bcm_elog(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
const char *prefix_str;
|
||||
int bit64;
|
||||
int64_t num;
|
||||
uint64_t unum;
|
||||
char *str;
|
||||
struct bcm_elog *elog = &global_elog;
|
||||
|
||||
/* We expect the LOG_MARKER_* macro as the first character */
|
||||
unsigned int level = fmt[0];
|
||||
|
||||
if (!elog->is_active || level > elog->level)
|
||||
return;
|
||||
|
||||
prefix_str = plat_log_get_prefix(level);
|
||||
|
||||
while (*prefix_str != '\0') {
|
||||
elog_putchar(elog, *prefix_str);
|
||||
prefix_str++;
|
||||
}
|
||||
|
||||
va_start(args, fmt);
|
||||
fmt++;
|
||||
while (*fmt) {
|
||||
bit64 = 0;
|
||||
|
||||
if (*fmt == '%') {
|
||||
fmt++;
|
||||
/* Check the format specifier */
|
||||
loop:
|
||||
switch (*fmt) {
|
||||
case 'i': /* Fall through to next one */
|
||||
case 'd':
|
||||
if (bit64)
|
||||
num = va_arg(args, int64_t);
|
||||
else
|
||||
num = va_arg(args, int32_t);
|
||||
|
||||
if (num < 0) {
|
||||
elog_putchar(elog, '-');
|
||||
unum = (unsigned long)-num;
|
||||
} else
|
||||
unum = (unsigned long)num;
|
||||
|
||||
elog_unsigned_num(elog, unum, 10);
|
||||
break;
|
||||
case 's':
|
||||
str = va_arg(args, char *);
|
||||
elog_string(elog, str);
|
||||
break;
|
||||
case 'x':
|
||||
if (bit64)
|
||||
unum = va_arg(args, uint64_t);
|
||||
else
|
||||
unum = va_arg(args, uint32_t);
|
||||
|
||||
elog_unsigned_num(elog, unum, 16);
|
||||
break;
|
||||
case 'l':
|
||||
bit64 = 1;
|
||||
fmt++;
|
||||
goto loop;
|
||||
case 'u':
|
||||
if (bit64)
|
||||
unum = va_arg(args, uint64_t);
|
||||
else
|
||||
unum = va_arg(args, uint32_t);
|
||||
|
||||
elog_unsigned_num(elog, unum, 10);
|
||||
break;
|
||||
default:
|
||||
/* Exit on any other format specifier */
|
||||
goto exit;
|
||||
}
|
||||
fmt++;
|
||||
continue;
|
||||
}
|
||||
elog_putchar(elog, *fmt++);
|
||||
}
|
||||
exit:
|
||||
va_end(args);
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Broadcom.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <arch_helpers.h>
|
||||
#include <common/debug.h>
|
||||
|
||||
#include <ddr_init.h>
|
||||
#include <scp_cmd.h>
|
||||
#include <scp_utils.h>
|
||||
#include <platform_def.h>
|
||||
|
||||
#include "bcm_elog_ddr.h"
|
||||
#include "m0_cfg.h"
|
||||
#include "m0_ipc.h"
|
||||
|
||||
void elog_init_ddr_log(void)
|
||||
{
|
||||
struct elog_setup setup = {0};
|
||||
struct elog_global_header global;
|
||||
struct elog_meta_record rec;
|
||||
unsigned int rec_idx = 0;
|
||||
uint32_t log_offset;
|
||||
uintptr_t metadata;
|
||||
char *rec_desc[ELOG_SUPPORTED_REC_CNT] = {"SYSRESET", "THERMAL",
|
||||
"DDR_ECC", "APBOOTLG",
|
||||
"IDM"};
|
||||
|
||||
/*
|
||||
* If this is warm boot, return immediately.
|
||||
* We expect metadata to be initialized already
|
||||
*/
|
||||
if (is_warmboot()) {
|
||||
WARN("Warmboot detected, skip ELOG metadata initialization\n");
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&global, 0, sizeof(global));
|
||||
|
||||
global.sector_size = ELOG_SECTOR_SIZE;
|
||||
global.signature = ELOG_GLOBAL_META_HDR_SIG;
|
||||
global.rec_count = ELOG_SUPPORTED_REC_CNT;
|
||||
|
||||
/* Start of logging area in DDR memory */
|
||||
log_offset = ELOG_STORE_OFFSET;
|
||||
|
||||
/* Shift to the first RECORD header */
|
||||
log_offset += 2 * global.sector_size;
|
||||
|
||||
/* Temporary place to hold metadata */
|
||||
metadata = TMP_ELOG_METADATA_BASE;
|
||||
|
||||
memcpy((void *)metadata, &global, sizeof(global));
|
||||
metadata += sizeof(global);
|
||||
|
||||
while (rec_idx < global.rec_count) {
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
|
||||
rec.type = rec_idx;
|
||||
if (rec_idx == ELOG_REC_UART_LOG) {
|
||||
rec.format = ELOG_REC_FMT_ASCII;
|
||||
rec.src_mem_type = ELOG_SRC_MEM_TYPE_DDR;
|
||||
rec.alt_src_mem_type = ELOG_SRC_MEM_TYPE_FS4_SCRATCH;
|
||||
rec.src_mem_addr = BCM_ELOG_BL31_BASE;
|
||||
rec.alt_src_mem_addr = BCM_ELOG_BL2_BASE;
|
||||
rec.rec_size = ELOG_APBOOTLG_REC_SIZE;
|
||||
} else if (rec_idx == ELOG_REC_IDM_LOG) {
|
||||
rec.type = IDM_ELOG_REC_TYPE;
|
||||
rec.format = ELOG_REC_FMT_CUSTOM;
|
||||
rec.src_mem_type = ELOG_SRC_MEM_TYPE_DDR;
|
||||
rec.alt_src_mem_type = ELOG_SRC_MEM_TYPE_CRMU_SCRATCH;
|
||||
rec.src_mem_addr = ELOG_IDM_SRC_MEM_ADDR;
|
||||
rec.alt_src_mem_addr = 0x0;
|
||||
rec.rec_size = ELOG_DEFAULT_REC_SIZE;
|
||||
} else {
|
||||
rec.format = ELOG_REC_FMT_CUSTOM;
|
||||
rec.src_mem_type = ELOG_SRC_MEM_TYPE_CRMU_SCRATCH;
|
||||
rec.alt_src_mem_type = ELOG_SRC_MEM_TYPE_CRMU_SCRATCH;
|
||||
rec.src_mem_addr = ELOG_USE_DEFAULT_MEM_ADDR;
|
||||
rec.alt_src_mem_addr = ELOG_USE_DEFAULT_MEM_ADDR;
|
||||
rec.rec_size = ELOG_DEFAULT_REC_SIZE;
|
||||
}
|
||||
|
||||
rec.nvm_type = LOG_MEDIA_DDR;
|
||||
rec.sector_size = ELOG_SECTOR_SIZE;
|
||||
|
||||
rec.rec_addr = (uint64_t)log_offset;
|
||||
log_offset += rec.rec_size;
|
||||
|
||||
/* Sanity checks */
|
||||
if (rec.type > ELOG_MAX_REC_COUNT ||
|
||||
rec.format > ELOG_MAX_REC_FORMAT ||
|
||||
(rec.nvm_type > ELOG_MAX_NVM_TYPE &&
|
||||
rec.nvm_type != ELOG_NVM_DEFAULT) ||
|
||||
!rec.rec_size ||
|
||||
!rec.sector_size ||
|
||||
rec_idx >= ELOG_SUPPORTED_REC_CNT) {
|
||||
ERROR("Invalid ELOG record(%u) detected\n", rec_idx);
|
||||
return;
|
||||
}
|
||||
|
||||
memset(rec.rec_desc, ' ', sizeof(rec.rec_desc));
|
||||
|
||||
memcpy(rec.rec_desc, rec_desc[rec_idx],
|
||||
strlen(rec_desc[rec_idx]));
|
||||
|
||||
memcpy((void *)metadata, &rec, sizeof(rec));
|
||||
metadata += sizeof(rec);
|
||||
|
||||
rec_idx++;
|
||||
}
|
||||
|
||||
setup.params[0] = TMP_ELOG_METADATA_BASE;
|
||||
setup.params[1] = (sizeof(global) + global.rec_count * sizeof(rec));
|
||||
setup.cmd = ELOG_SETUP_CMD_WRITE_META;
|
||||
|
||||
flush_dcache_range((uintptr_t)&setup, sizeof(struct elog_setup));
|
||||
flush_dcache_range((uintptr_t)setup.params[0], setup.params[1]);
|
||||
|
||||
/* initialize DDR Logging METADATA if this is NOT warmboot */
|
||||
if (!is_warmboot()) {
|
||||
if (scp_send_cmd(MCU_IPC_MCU_CMD_ELOG_SETUP,
|
||||
(uint32_t)(uintptr_t)(&setup),
|
||||
SCP_CMD_DEFAULT_TIMEOUT_US)) {
|
||||
ERROR("scp_send_cmd: timeout/error for elog setup\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
NOTICE("MCU Error logging initialized\n");
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Broadcom
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef BCM_ELOG_DDR_H
|
||||
#define BCM_ELOG_DDR_H
|
||||
|
||||
#define ELOG_GLOBAL_META_HDR_SIG 0x45524c47
|
||||
#define ELOG_MAX_REC_COUNT 13
|
||||
#define ELOG_MAX_REC_FORMAT 1
|
||||
#define ELOG_MAX_NVM_TYPE 4
|
||||
/* Use a default NVM, set by m0 configuration */
|
||||
#define ELOG_NVM_DEFAULT 0xff
|
||||
|
||||
/* Max. number of cmd parameters per elog spec */
|
||||
#define ELOG_PARAM_COUNT 3
|
||||
/*
|
||||
* Number of supported RECORD Types-
|
||||
* SYSRESET, THERMAL, DDR_ECC, APBOOTLG, IDM
|
||||
*/
|
||||
#define ELOG_SUPPORTED_REC_CNT 5
|
||||
|
||||
#define ELOG_REC_DESC_LENGTH 8
|
||||
|
||||
#define ELOG_SECTOR_SIZE 0x1000
|
||||
|
||||
/* Default Record size for all record types except APBOOTLOG */
|
||||
#define ELOG_DEFAULT_REC_SIZE 0x10000
|
||||
|
||||
/* Default record size for APBOOTLOG record */
|
||||
#define ELOG_APBOOTLG_REC_SIZE 0x60000
|
||||
|
||||
/* Use default CRMU provided mem address */
|
||||
#define ELOG_USE_DEFAULT_MEM_ADDR 0x0
|
||||
|
||||
/* Temporary place to hold metadata */
|
||||
#define TMP_ELOG_METADATA_BASE (ELOG_AP_UART_LOG_BASE + \
|
||||
BCM_ELOG_BL2_SIZE)
|
||||
/* IDM ELOG source memory address */
|
||||
#define ELOG_IDM_SRC_MEM_ADDR 0x8f213000
|
||||
|
||||
#define IDM_ELOG_REC_TYPE 5
|
||||
|
||||
enum elog_record_type {
|
||||
ELOG_REC_SYS_RESET_EVT = 0,
|
||||
ELOG_REC_THERMAL_EVT,
|
||||
ELOG_REC_DDR_ECC,
|
||||
ELOG_REC_UART_LOG,
|
||||
ELOG_REC_IDM_LOG,
|
||||
ELOG_REC_MAX
|
||||
};
|
||||
|
||||
enum elog_record_format {
|
||||
ELOG_REC_FMT_ASCII = 0,
|
||||
ELOG_REC_FMT_CUSTOM
|
||||
};
|
||||
|
||||
enum elog_src_memory_type {
|
||||
ELOG_SRC_MEM_TYPE_CRMU_SCRATCH = 0,
|
||||
ELOG_SRC_MEM_TYPE_FS4_SCRATCH,
|
||||
ELOG_SRC_MEM_TYPE_DDR,
|
||||
ELOG_SRC_MEM_TYPE_CHIMP_SCRATCH
|
||||
};
|
||||
|
||||
enum elog_setup_cmd {
|
||||
ELOG_SETUP_CMD_VALIDATE_META,
|
||||
ELOG_SETUP_CMD_WRITE_META,
|
||||
ELOG_SETUP_CMD_ERASE,
|
||||
ELOG_SETUP_CMD_READ,
|
||||
ELOG_SETUP_CMD_CHECK
|
||||
};
|
||||
|
||||
struct elog_setup {
|
||||
uint32_t cmd;
|
||||
uint32_t params[ELOG_PARAM_COUNT];
|
||||
uint32_t result;
|
||||
uint32_t ret_code;
|
||||
};
|
||||
|
||||
struct elog_meta_record {
|
||||
uint8_t type;
|
||||
uint8_t format;
|
||||
uint8_t src_mem_type;
|
||||
uint8_t alt_src_mem_type;
|
||||
uint8_t nvm_type;
|
||||
char rec_desc[ELOG_REC_DESC_LENGTH];
|
||||
uint64_t src_mem_addr;
|
||||
uint64_t alt_src_mem_addr;
|
||||
uint64_t rec_addr;
|
||||
uint32_t rec_size;
|
||||
uint32_t sector_size;
|
||||
uint8_t padding[3];
|
||||
} __packed;
|
||||
|
||||
struct elog_global_header {
|
||||
uint32_t signature;
|
||||
uint32_t sector_size;
|
||||
uint8_t revision;
|
||||
uint8_t rec_count;
|
||||
uint16_t padding;
|
||||
} __packed;
|
||||
|
||||
void elog_init_ddr_log(void);
|
||||
|
||||
#endif /* BCM_ELOG_DDR_H */
|
||||
+625
@@ -0,0 +1,625 @@
|
||||
/*
|
||||
* Copyright 2015 - 2020 Broadcom
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <common/debug.h>
|
||||
#include <lib/mmio.h>
|
||||
#include <plat/common/platform.h>
|
||||
#include <tools_share/tbbr_oid.h>
|
||||
|
||||
#include <sbl_util.h>
|
||||
#include <sotp.h>
|
||||
|
||||
/* Weak definition may be overridden in specific platform */
|
||||
#pragma weak plat_match_rotpk
|
||||
#pragma weak plat_get_nv_ctr
|
||||
#pragma weak plat_set_nv_ctr
|
||||
|
||||
/* SHA256 algorithm */
|
||||
#define SHA256_BYTES 32
|
||||
|
||||
/* ROTPK locations */
|
||||
#define ARM_ROTPK_REGS_ID 1
|
||||
#define ARM_ROTPK_DEVEL_RSA_ID 2
|
||||
#define BRCM_ROTPK_SOTP_RSA_ID 3
|
||||
|
||||
#if !ARM_ROTPK_LOCATION_ID
|
||||
#error "ARM_ROTPK_LOCATION_ID not defined"
|
||||
#endif
|
||||
|
||||
static const unsigned char rotpk_hash_hdr[] =
|
||||
"\x30\x31\x30\x0D\x06\x09\x60\x86\x48"
|
||||
"\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20";
|
||||
static const unsigned int rotpk_hash_hdr_len = sizeof(rotpk_hash_hdr) - 1;
|
||||
static unsigned char rotpk_hash_der[sizeof(rotpk_hash_hdr) - 1 + SHA256_BYTES];
|
||||
|
||||
#if (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_DEVEL_RSA_ID)
|
||||
static const unsigned char arm_devel_rotpk_hash[] =
|
||||
"\xB0\xF3\x82\x09\x12\x97\xD8\x3A"
|
||||
"\x37\x7A\x72\x47\x1B\xEC\x32\x73"
|
||||
"\xE9\x92\x32\xE2\x49\x59\xF6\x5E"
|
||||
"\x8B\x4A\x4A\x46\xD8\x22\x9A\xDA";
|
||||
#endif
|
||||
|
||||
#pragma weak plat_rotpk_hash
|
||||
const unsigned char plat_rotpk_hash[] =
|
||||
"\xdb\x06\x67\x95\x4f\x88\x2b\x88"
|
||||
"\x49\xbf\x70\x3f\xde\x50\x4a\x96"
|
||||
"\xd8\x17\x69\xd4\xa0\x6c\xba\xee"
|
||||
"\x66\x3e\x71\x82\x2d\x95\x69\xe4";
|
||||
|
||||
#pragma weak rom_slice
|
||||
const unsigned char rom_slice[] =
|
||||
"\x77\x06\xbc\x98\x40\xbe\xfd\xab"
|
||||
"\x60\x4b\x74\x3c\x9a\xb3\x80\x75"
|
||||
"\x39\xb6\xda\x27\x07\x2e\x5b\xbf"
|
||||
"\x5c\x47\x91\xc9\x95\x26\x26\x0c";
|
||||
|
||||
#if (ARM_ROTPK_LOCATION_ID == BRCM_ROTPK_SOTP_RSA_ID)
|
||||
static int plat_is_trusted_boot(void)
|
||||
{
|
||||
uint64_t section3_row0_data;
|
||||
|
||||
section3_row0_data = sotp_mem_read(SOTP_DEVICE_SECURE_CFG0_ROW, 0);
|
||||
|
||||
if ((section3_row0_data & SOTP_DEVICE_SECURE_CFG0_AB_MASK) == 0) {
|
||||
INFO("NOT AB\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
INFO("AB\n");
|
||||
return TRUSTED_BOARD_BOOT;
|
||||
}
|
||||
|
||||
/*
|
||||
* FAST AUTH is enabled if all following conditions are met:
|
||||
* - AB part
|
||||
* - SOTP.DEV != 0
|
||||
* - SOTP.CID != 0
|
||||
* - SOTP.ENC_DEV_TYPE = ENC_AB_DEV
|
||||
* - Manuf_debug strap set high
|
||||
*/
|
||||
static int plat_fast_auth_enabled(void)
|
||||
{
|
||||
uint32_t chip_state;
|
||||
uint64_t section3_row0_data;
|
||||
uint64_t section3_row1_data;
|
||||
|
||||
section3_row0_data =
|
||||
sotp_mem_read(SOTP_DEVICE_SECURE_CFG0_ROW, 0);
|
||||
section3_row1_data =
|
||||
sotp_mem_read(SOTP_DEVICE_SECURE_CFG1_ROW, 0);
|
||||
|
||||
chip_state = mmio_read_32(SOTP_REGS_SOTP_CHIP_STATES);
|
||||
|
||||
if (plat_is_trusted_boot() &&
|
||||
(section3_row0_data & SOTP_DEVICE_SECURE_CFG0_DEV_MASK) &&
|
||||
(section3_row0_data & SOTP_DEVICE_SECURE_CFG0_CID_MASK) &&
|
||||
((section3_row1_data & SOTP_ENC_DEV_TYPE_MASK) ==
|
||||
SOTP_ENC_DEV_TYPE_AB_DEV) &&
|
||||
(chip_state & SOTP_CHIP_STATES_MANU_DEBUG_MASK))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Return the ROTPK hash in the following ASN.1 structure in DER format:
|
||||
*
|
||||
* AlgorithmIdentifier ::= SEQUENCE {
|
||||
* algorithm OBJECT IDENTIFIER,
|
||||
* parameters ANY DEFINED BY algorithm OPTIONAL
|
||||
* }
|
||||
*
|
||||
* DigestInfo ::= SEQUENCE {
|
||||
* digestAlgorithm AlgorithmIdentifier,
|
||||
* digest OCTET STRING
|
||||
* }
|
||||
*/
|
||||
int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len,
|
||||
unsigned int *flags)
|
||||
{
|
||||
uint8_t *dst;
|
||||
|
||||
assert(key_ptr != NULL);
|
||||
assert(key_len != NULL);
|
||||
assert(flags != NULL);
|
||||
|
||||
*flags = 0;
|
||||
|
||||
/* Copy the DER header */
|
||||
memcpy(rotpk_hash_der, rotpk_hash_hdr, rotpk_hash_hdr_len);
|
||||
dst = (uint8_t *)&rotpk_hash_der[rotpk_hash_hdr_len];
|
||||
|
||||
#if (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_DEVEL_RSA_ID)
|
||||
memcpy(dst, arm_devel_rotpk_hash, SHA256_BYTES);
|
||||
#elif (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_REGS_ID)
|
||||
uint32_t *src, tmp;
|
||||
unsigned int words, i;
|
||||
|
||||
/*
|
||||
* Append the hash from Trusted Root-Key Storage registers. The hash has
|
||||
* not been written linearly into the registers, so we have to do a bit
|
||||
* of byte swapping:
|
||||
*
|
||||
* 0x00 0x04 0x08 0x0C 0x10 0x14 0x18 0x1C
|
||||
* +---------------------------------------------------------------+
|
||||
* | Reg0 | Reg1 | Reg2 | Reg3 | Reg4 | Reg5 | Reg6 | Reg7 |
|
||||
* +---------------------------------------------------------------+
|
||||
* | ... ... | | ... ... |
|
||||
* | +--------------------+ | +-------+
|
||||
* | | | |
|
||||
* +----------------------------+ +----------------------------+
|
||||
* | | | |
|
||||
* +-------+ | +--------------------+ |
|
||||
* | | | |
|
||||
* v v v v
|
||||
* +---------------------------------------------------------------+
|
||||
* | | |
|
||||
* +---------------------------------------------------------------+
|
||||
* 0 15 16 31
|
||||
*
|
||||
* Additionally, we have to access the registers in 32-bit words
|
||||
*/
|
||||
words = SHA256_BYTES >> 3;
|
||||
|
||||
/* Swap bytes 0-15 (first four registers) */
|
||||
src = (uint32_t *)TZ_PUB_KEY_HASH_BASE;
|
||||
for (i = 0 ; i < words ; i++) {
|
||||
tmp = src[words - 1 - i];
|
||||
/* Words are read in little endian */
|
||||
*dst++ = (uint8_t)((tmp >> 24) & 0xFF);
|
||||
*dst++ = (uint8_t)((tmp >> 16) & 0xFF);
|
||||
*dst++ = (uint8_t)((tmp >> 8) & 0xFF);
|
||||
*dst++ = (uint8_t)(tmp & 0xFF);
|
||||
}
|
||||
|
||||
/* Swap bytes 16-31 (last four registers) */
|
||||
src = (uint32_t *)(TZ_PUB_KEY_HASH_BASE + SHA256_BYTES / 2);
|
||||
for (i = 0 ; i < words ; i++) {
|
||||
tmp = src[words - 1 - i];
|
||||
*dst++ = (uint8_t)((tmp >> 24) & 0xFF);
|
||||
*dst++ = (uint8_t)((tmp >> 16) & 0xFF);
|
||||
*dst++ = (uint8_t)((tmp >> 8) & 0xFF);
|
||||
*dst++ = (uint8_t)(tmp & 0xFF);
|
||||
}
|
||||
#elif (ARM_ROTPK_LOCATION_ID == BRCM_ROTPK_SOTP_RSA_ID)
|
||||
{
|
||||
int i;
|
||||
int ret = -1;
|
||||
|
||||
/*
|
||||
* In non-AB mode, we do not read the key.
|
||||
* In AB mode:
|
||||
* - The Dauth is in BL11 if SBL is enabled
|
||||
* - The Dauth is in SOTP if SBL is disabled.
|
||||
*/
|
||||
if (plat_is_trusted_boot() == 0) {
|
||||
|
||||
INFO("NON-AB: Do not read DAUTH!\n");
|
||||
*flags = ROTPK_NOT_DEPLOYED;
|
||||
ret = 0;
|
||||
|
||||
} else if ((sbl_status() == SBL_ENABLED) &&
|
||||
(mmio_read_32(BL11_DAUTH_BASE) == BL11_DAUTH_ID)) {
|
||||
|
||||
/* Read hash from BL11 */
|
||||
INFO("readKeys (DAUTH) from BL11\n");
|
||||
|
||||
memcpy(dst,
|
||||
(void *)(BL11_DAUTH_BASE + sizeof(uint32_t)),
|
||||
SHA256_BYTES);
|
||||
|
||||
for (i = 0; i < SHA256_BYTES; i++)
|
||||
if (dst[i] != 0)
|
||||
break;
|
||||
|
||||
if (i >= SHA256_BYTES)
|
||||
ERROR("Hash not valid from BL11\n");
|
||||
else
|
||||
ret = 0;
|
||||
|
||||
} else if (sotp_key_erased()) {
|
||||
|
||||
memcpy(dst, plat_rotpk_hash, SHA256_BYTES);
|
||||
|
||||
INFO("SOTP erased, Use internal key hash.\n");
|
||||
ret = 0;
|
||||
|
||||
} else if (plat_fast_auth_enabled()) {
|
||||
|
||||
INFO("AB DEV: FAST AUTH!\n");
|
||||
*flags = ROTPK_NOT_DEPLOYED;
|
||||
ret = 0;
|
||||
|
||||
} else if (!(mmio_read_32(SOTP_STATUS_1) & SOTP_DAUTH_ECC_ERROR_MASK)) {
|
||||
|
||||
/* Read hash from SOTP */
|
||||
ret = sotp_read_key(dst,
|
||||
SHA256_BYTES,
|
||||
SOTP_DAUTH_ROW,
|
||||
SOTP_K_HMAC_ROW-1);
|
||||
|
||||
INFO("sotp_read_key (DAUTH): %i\n", ret);
|
||||
|
||||
} else {
|
||||
|
||||
uint64_t row_data;
|
||||
uint32_t k;
|
||||
|
||||
for (k = 0; k < (SOTP_K_HMAC_ROW - SOTP_DAUTH_ROW); k++) {
|
||||
row_data = sotp_mem_read(SOTP_DAUTH_ROW + k,
|
||||
SOTP_ROW_NO_ECC);
|
||||
|
||||
if (row_data != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (k == (SOTP_K_HMAC_ROW - SOTP_DAUTH_ROW)) {
|
||||
INFO("SOTP NOT PROGRAMMED: Do not use DAUTH!\n");
|
||||
|
||||
if (sotp_mem_read(SOTP_ATF2_CFG_ROW_ID,
|
||||
SOTP_ROW_NO_ECC) & SOTP_ROMKEY_MASK) {
|
||||
memcpy(dst, plat_rotpk_hash, SHA256_BYTES);
|
||||
|
||||
INFO("Use internal key hash.\n");
|
||||
ret = 0;
|
||||
} else {
|
||||
*flags = ROTPK_NOT_DEPLOYED;
|
||||
ret = 0;
|
||||
}
|
||||
} else {
|
||||
INFO("No hash found in SOTP\n");
|
||||
}
|
||||
}
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
*key_ptr = (void *)rotpk_hash_der;
|
||||
*key_len = (unsigned int)sizeof(rotpk_hash_der);
|
||||
*flags |= ROTPK_IS_HASH;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define SOTP_NUM_BITS_PER_ROW 41
|
||||
#define SOTP_NVCTR_ROW_ALL_ONES 0x1ffffffffff
|
||||
#define SOTP_NVCTR_TRUSTED_IN_USE \
|
||||
((uint64_t)0x3 << (SOTP_NUM_BITS_PER_ROW-2))
|
||||
#define SOTP_NVCTR_NON_TRUSTED_IN_USE ((uint64_t)0x3)
|
||||
#define SOTP_NVCTR_TRUSTED_NEAR_END SOTP_NVCTR_NON_TRUSTED_IN_USE
|
||||
#define SOTP_NVCTR_NON_TRUSTED_NEAR_END SOTP_NVCTR_TRUSTED_IN_USE
|
||||
|
||||
#define SOTP_NVCTR_ROW_START 64
|
||||
#define SOTP_NVCTR_ROW_END 75
|
||||
|
||||
/*
|
||||
* SOTP NVCTR are stored in section 10 of SOTP (rows 64-75).
|
||||
* Each row of SOTP is 41 bits.
|
||||
* NVCTR's are stored in a bitstream format.
|
||||
* We are tolerant to consecutive bit errors.
|
||||
* Trusted NVCTR starts at the top of row 64 in bitstream format.
|
||||
* Non Trusted NVCTR starts at the bottom of row 75 in reverse bitstream.
|
||||
* Each row can only be used by 1 of the 2 counters. This is determined
|
||||
* by 2 zeros remaining at the beginning or end of the last available row.
|
||||
* If one counter has already starting using a row, the other will be
|
||||
* prevent from writing to that row.
|
||||
*
|
||||
* Example counter values for SOTP programmed below:
|
||||
* Trusted Counter (rows64-69) = 5 * 41 + 40 = 245
|
||||
* NonTrusted Counter (row75-71) = 3 * 41 + 4 = 127
|
||||
* 40 39 38 37 36 ..... 5 4 3 2 1 0
|
||||
* row 64 1 1 1 1 1 1 1 1 1 1 1
|
||||
* row 65 1 1 1 1 1 1 1 1 1 1 1
|
||||
* row 66 1 1 1 1 1 1 1 1 1 1 1
|
||||
* row 67 1 1 1 1 1 1 1 1 1 1 1
|
||||
* row 68 1 1 1 1 1 1 1 1 1 1 1
|
||||
* row 69 1 1 1 1 1 1 1 1 1 1 0
|
||||
* row 71 0 0 0 0 0 0 0 0 0 0 0
|
||||
* row 71 0 0 0 0 0 0 0 0 0 0 0
|
||||
* row 71 0 0 0 0 0 0 0 1 1 1 1
|
||||
* row 73 1 1 1 1 1 1 1 1 1 1 1
|
||||
* row 74 1 1 1 1 1 1 1 1 1 1 1
|
||||
* row 75 1 1 1 1 1 1 1 1 1 1 1
|
||||
*
|
||||
*/
|
||||
|
||||
#if (DEBUG == 1)
|
||||
/*
|
||||
* Dump sotp rows
|
||||
*/
|
||||
void sotp_dump_rows(uint32_t start_row, uint32_t end_row)
|
||||
{
|
||||
int32_t rownum;
|
||||
uint64_t rowdata;
|
||||
|
||||
for (rownum = start_row; rownum <= end_row; rownum++) {
|
||||
rowdata = sotp_mem_read(rownum, SOTP_ROW_NO_ECC);
|
||||
INFO("%d 0x%" PRIx64 "\n", rownum, rowdata);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Get SOTP Trusted nvctr
|
||||
*/
|
||||
unsigned int sotp_get_trusted_nvctr(void)
|
||||
{
|
||||
uint64_t rowdata;
|
||||
uint64_t nextrowdata;
|
||||
uint32_t rownum;
|
||||
unsigned int nvctr;
|
||||
|
||||
rownum = SOTP_NVCTR_ROW_START;
|
||||
nvctr = SOTP_NUM_BITS_PER_ROW;
|
||||
|
||||
/*
|
||||
* Determine what row has last valid data for trusted ctr
|
||||
*/
|
||||
rowdata = sotp_mem_read(rownum, SOTP_ROW_NO_ECC);
|
||||
while ((rowdata & SOTP_NVCTR_TRUSTED_IN_USE) &&
|
||||
(rowdata & SOTP_NVCTR_TRUSTED_NEAR_END) &&
|
||||
(rownum < SOTP_NVCTR_ROW_END)) {
|
||||
/*
|
||||
* Current row in use and has data in last 2 bits as well.
|
||||
* Check if next row also has data for this counter
|
||||
*/
|
||||
nextrowdata = sotp_mem_read(rownum+1, SOTP_ROW_NO_ECC);
|
||||
if (nextrowdata & SOTP_NVCTR_TRUSTED_IN_USE) {
|
||||
/* Next row also has data so increment rownum */
|
||||
rownum++;
|
||||
nvctr += SOTP_NUM_BITS_PER_ROW;
|
||||
rowdata = nextrowdata;
|
||||
} else {
|
||||
/* Next row does not have data */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rowdata & SOTP_NVCTR_TRUSTED_IN_USE) {
|
||||
while ((rowdata & 0x1) == 0) {
|
||||
nvctr--;
|
||||
rowdata >>= 1;
|
||||
}
|
||||
} else
|
||||
nvctr -= SOTP_NUM_BITS_PER_ROW;
|
||||
|
||||
INFO("CTR %i\n", nvctr);
|
||||
return nvctr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get SOTP NonTrusted nvctr
|
||||
*/
|
||||
unsigned int sotp_get_nontrusted_nvctr(void)
|
||||
{
|
||||
uint64_t rowdata;
|
||||
uint64_t nextrowdata;
|
||||
uint32_t rownum;
|
||||
unsigned int nvctr;
|
||||
|
||||
nvctr = SOTP_NUM_BITS_PER_ROW;
|
||||
rownum = SOTP_NVCTR_ROW_END;
|
||||
|
||||
/*
|
||||
* Determine what row has last valid data for nontrusted ctr
|
||||
*/
|
||||
rowdata = sotp_mem_read(rownum, SOTP_ROW_NO_ECC);
|
||||
while ((rowdata & SOTP_NVCTR_NON_TRUSTED_NEAR_END) &&
|
||||
(rowdata & SOTP_NVCTR_NON_TRUSTED_IN_USE) &&
|
||||
(rownum > SOTP_NVCTR_ROW_START)) {
|
||||
/*
|
||||
* Current row in use and has data in last 2 bits as well.
|
||||
* Check if next row also has data for this counter
|
||||
*/
|
||||
nextrowdata = sotp_mem_read(rownum-1, SOTP_ROW_NO_ECC);
|
||||
if (nextrowdata & SOTP_NVCTR_NON_TRUSTED_IN_USE) {
|
||||
/* Next row also has data so decrement rownum */
|
||||
rownum--;
|
||||
nvctr += SOTP_NUM_BITS_PER_ROW;
|
||||
rowdata = nextrowdata;
|
||||
} else {
|
||||
/* Next row does not have data */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rowdata & SOTP_NVCTR_NON_TRUSTED_IN_USE) {
|
||||
while ((rowdata & ((uint64_t)0x1 << (SOTP_NUM_BITS_PER_ROW-1)))
|
||||
==
|
||||
0) {
|
||||
nvctr--;
|
||||
rowdata <<= 1;
|
||||
}
|
||||
} else
|
||||
nvctr -= SOTP_NUM_BITS_PER_ROW;
|
||||
|
||||
INFO("NCTR %i\n", nvctr);
|
||||
return nvctr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set SOTP Trusted nvctr
|
||||
*/
|
||||
int sotp_set_trusted_nvctr(unsigned int nvctr)
|
||||
{
|
||||
int numrows_available;
|
||||
uint32_t nontrusted_rownum;
|
||||
uint32_t trusted_rownum;
|
||||
uint64_t rowdata;
|
||||
unsigned int maxnvctr;
|
||||
|
||||
/*
|
||||
* Read SOTP to find out how many rows are used by the
|
||||
* NON Trusted nvctr
|
||||
*/
|
||||
nontrusted_rownum = SOTP_NVCTR_ROW_END;
|
||||
do {
|
||||
rowdata = sotp_mem_read(nontrusted_rownum, SOTP_ROW_NO_ECC);
|
||||
if (rowdata & SOTP_NVCTR_NON_TRUSTED_IN_USE)
|
||||
nontrusted_rownum--;
|
||||
else
|
||||
break;
|
||||
} while (nontrusted_rownum >= SOTP_NVCTR_ROW_START);
|
||||
|
||||
/*
|
||||
* Calculate maximum value we can have for nvctr based on
|
||||
* number of available rows.
|
||||
*/
|
||||
numrows_available = nontrusted_rownum - SOTP_NVCTR_ROW_START + 1;
|
||||
maxnvctr = numrows_available * SOTP_NUM_BITS_PER_ROW;
|
||||
if (maxnvctr) {
|
||||
/*
|
||||
* Last 2 bits of counter can't be written or it will
|
||||
* overflow with nontrusted counter
|
||||
*/
|
||||
maxnvctr -= 2;
|
||||
}
|
||||
|
||||
if (nvctr > maxnvctr) {
|
||||
/* Error - not enough room */
|
||||
WARN("tctr not set\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* It is safe to write the nvctr, fill all 1's up to the
|
||||
* last row and then fill the last row with partial bitstream
|
||||
*/
|
||||
trusted_rownum = SOTP_NVCTR_ROW_START;
|
||||
rowdata = SOTP_NVCTR_ROW_ALL_ONES;
|
||||
|
||||
while (nvctr >= SOTP_NUM_BITS_PER_ROW) {
|
||||
sotp_mem_write(trusted_rownum, SOTP_ROW_NO_ECC, rowdata);
|
||||
nvctr -= SOTP_NUM_BITS_PER_ROW;
|
||||
trusted_rownum++;
|
||||
}
|
||||
rowdata <<= (SOTP_NUM_BITS_PER_ROW - nvctr);
|
||||
sotp_mem_write(trusted_rownum, SOTP_ROW_NO_ECC, rowdata);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set SOTP NonTrusted nvctr
|
||||
*/
|
||||
int sotp_set_nontrusted_nvctr(unsigned int nvctr)
|
||||
{
|
||||
int numrows_available;
|
||||
uint32_t nontrusted_rownum;
|
||||
uint32_t trusted_rownum;
|
||||
uint64_t rowdata;
|
||||
unsigned int maxnvctr;
|
||||
|
||||
/*
|
||||
* Read SOTP to find out how many rows are used by the
|
||||
* Trusted nvctr
|
||||
*/
|
||||
trusted_rownum = SOTP_NVCTR_ROW_START;
|
||||
do {
|
||||
rowdata = sotp_mem_read(trusted_rownum, SOTP_ROW_NO_ECC);
|
||||
if (rowdata & SOTP_NVCTR_TRUSTED_IN_USE)
|
||||
trusted_rownum++;
|
||||
else
|
||||
break;
|
||||
} while (trusted_rownum <= SOTP_NVCTR_ROW_END);
|
||||
|
||||
/*
|
||||
* Calculate maximum value we can have for nvctr based on
|
||||
* number of available rows.
|
||||
*/
|
||||
numrows_available = SOTP_NVCTR_ROW_END - trusted_rownum + 1;
|
||||
maxnvctr = numrows_available * SOTP_NUM_BITS_PER_ROW;
|
||||
if (maxnvctr) {
|
||||
/*
|
||||
* Last 2 bits of counter can't be written or it will
|
||||
* overflow with nontrusted counter
|
||||
*/
|
||||
maxnvctr -= 2;
|
||||
}
|
||||
|
||||
if (nvctr > maxnvctr) {
|
||||
/* Error - not enough room */
|
||||
WARN("nctr not set\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* It is safe to write the nvctr, fill all 1's up to the
|
||||
* last row and then fill the last row with partial bitstream
|
||||
*/
|
||||
nontrusted_rownum = SOTP_NVCTR_ROW_END;
|
||||
rowdata = SOTP_NVCTR_ROW_ALL_ONES;
|
||||
|
||||
while (nvctr >= SOTP_NUM_BITS_PER_ROW) {
|
||||
sotp_mem_write(nontrusted_rownum, SOTP_ROW_NO_ECC, rowdata);
|
||||
nvctr -= SOTP_NUM_BITS_PER_ROW;
|
||||
nontrusted_rownum--;
|
||||
}
|
||||
rowdata >>= (SOTP_NUM_BITS_PER_ROW - nvctr);
|
||||
sotp_mem_write(nontrusted_rownum, SOTP_ROW_NO_ECC, rowdata);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the non-volatile counter value stored in the platform. The cookie
|
||||
* will contain the OID of the counter in the certificate.
|
||||
*
|
||||
* Return: 0 = success, Otherwise = error
|
||||
*/
|
||||
int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr)
|
||||
{
|
||||
const char *oid;
|
||||
|
||||
assert(cookie != NULL);
|
||||
assert(nv_ctr != NULL);
|
||||
|
||||
*nv_ctr = 0;
|
||||
if ((sotp_mem_read(SOTP_ATF_CFG_ROW_ID, SOTP_ROW_NO_ECC) &
|
||||
SOTP_ATF_NVCOUNTER_ENABLE_MASK)) {
|
||||
oid = (const char *)cookie;
|
||||
if (strcmp(oid, TRUSTED_FW_NVCOUNTER_OID) == 0)
|
||||
*nv_ctr = sotp_get_trusted_nvctr();
|
||||
else if (strcmp(oid, NON_TRUSTED_FW_NVCOUNTER_OID) == 0)
|
||||
*nv_ctr = sotp_get_nontrusted_nvctr();
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Store a new non-volatile counter value.
|
||||
*
|
||||
* Return: 0 = success, Otherwise = error
|
||||
*/
|
||||
int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr)
|
||||
{
|
||||
const char *oid;
|
||||
|
||||
if (sotp_mem_read(SOTP_ATF_CFG_ROW_ID, SOTP_ROW_NO_ECC) &
|
||||
SOTP_ATF_NVCOUNTER_ENABLE_MASK) {
|
||||
INFO("set CTR %i\n", nv_ctr);
|
||||
oid = (const char *)cookie;
|
||||
if (strcmp(oid, TRUSTED_FW_NVCOUNTER_OID) == 0)
|
||||
return sotp_set_trusted_nvctr(nv_ctr);
|
||||
else if (strcmp(oid, NON_TRUSTED_FW_NVCOUNTER_OID) == 0)
|
||||
return sotp_set_nontrusted_nvctr(nv_ctr);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size)
|
||||
{
|
||||
return get_mbedtls_heap_helper(heap_addr, heap_size);
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2016 - 2020, Broadcom
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <brcm_def.h>
|
||||
#include <plat_brcm.h>
|
||||
|
||||
#if IMAGE_BL2
|
||||
const mmap_region_t plat_brcm_mmap[] = {
|
||||
HSLS_REGION,
|
||||
BRCM_MAP_SHARED_RAM,
|
||||
BRCM_MAP_NAND_RO,
|
||||
BRCM_MAP_QSPI_RO,
|
||||
#ifdef PERIPH0_REGION
|
||||
PERIPH0_REGION,
|
||||
#endif
|
||||
#ifdef PERIPH1_REGION
|
||||
PERIPH1_REGION,
|
||||
#endif
|
||||
#ifdef USE_DDR
|
||||
BRCM_MAP_NS_DRAM1,
|
||||
#if BRCM_BL31_IN_DRAM
|
||||
BRCM_MAP_BL31_SEC_DRAM,
|
||||
#endif
|
||||
#else
|
||||
#ifdef BRCM_MAP_EXT_SRAM
|
||||
BRCM_MAP_EXT_SRAM,
|
||||
#endif
|
||||
#endif
|
||||
#if defined(USE_CRMU_SRAM) && defined(CRMU_SRAM_BASE)
|
||||
CRMU_SRAM_REGION,
|
||||
#endif
|
||||
{0}
|
||||
};
|
||||
#endif
|
||||
|
||||
#if IMAGE_BL31
|
||||
const mmap_region_t plat_brcm_mmap[] = {
|
||||
HSLS_REGION,
|
||||
#ifdef PERIPH0_REGION
|
||||
PERIPH0_REGION,
|
||||
#endif
|
||||
#ifdef PERIPH1_REGION
|
||||
PERIPH1_REGION,
|
||||
#endif
|
||||
#ifdef PERIPH2_REGION
|
||||
PERIPH2_REGION,
|
||||
#endif
|
||||
#ifdef USB_REGION
|
||||
USB_REGION,
|
||||
#endif
|
||||
#ifdef USE_DDR
|
||||
BRCM_MAP_NS_DRAM1,
|
||||
#ifdef BRCM_MAP_NS_SHARED_DRAM
|
||||
BRCM_MAP_NS_SHARED_DRAM,
|
||||
#endif
|
||||
#else
|
||||
#ifdef BRCM_MAP_EXT_SRAM
|
||||
BRCM_MAP_EXT_SRAM,
|
||||
#endif
|
||||
#endif
|
||||
#if defined(USE_CRMU_SRAM) && defined(CRMU_SRAM_BASE)
|
||||
CRMU_SRAM_REGION,
|
||||
#endif
|
||||
{0}
|
||||
};
|
||||
#endif
|
||||
|
||||
CASSERT((ARRAY_SIZE(plat_brcm_mmap) - 1) <= PLAT_BRCM_MMAP_ENTRIES,
|
||||
assert_plat_brcm_mmap_mismatch);
|
||||
CASSERT((PLAT_BRCM_MMAP_ENTRIES + BRCM_BL_REGIONS) <= MAX_MMAP_REGIONS,
|
||||
assert_max_mmap_regions);
|
||||
+294
@@ -0,0 +1,294 @@
|
||||
#
|
||||
# Copyright (c) 2015 - 2021, Broadcom
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
||||
|
||||
PLAT_BL_COMMON_SOURCES += plat/brcm/board/common/board_common.c
|
||||
|
||||
# If no board config makefile, do not include it
|
||||
ifneq (${BOARD_CFG},)
|
||||
BOARD_CFG_MAKE := $(shell find plat/brcm/board/${PLAT} -name '${BOARD_CFG}.mk')
|
||||
$(eval $(call add_define,BOARD_CFG))
|
||||
ifneq (${BOARD_CFG_MAKE},)
|
||||
$(info Including ${BOARD_CFG_MAKE})
|
||||
include ${BOARD_CFG_MAKE}
|
||||
else
|
||||
$(error Error: File ${BOARD_CFG}.mk not found in plat/brcm/board/${PLAT})
|
||||
endif
|
||||
endif
|
||||
|
||||
# To compile with highest log level (VERBOSE) set value to 50
|
||||
LOG_LEVEL := 40
|
||||
|
||||
# Use custom generic timer clock
|
||||
ifneq (${GENTIMER_ACTUAL_CLOCK},)
|
||||
$(info Using GENTIMER_ACTUAL_CLOCK=$(GENTIMER_ACTUAL_CLOCK))
|
||||
SYSCNT_FREQ := $(GENTIMER_ACTUAL_CLOCK)
|
||||
$(eval $(call add_define,SYSCNT_FREQ))
|
||||
endif
|
||||
|
||||
ifeq (${DRIVER_EMMC_ENABLE},)
|
||||
DRIVER_EMMC_ENABLE :=1
|
||||
endif
|
||||
|
||||
ifeq (${DRIVER_SPI_ENABLE},)
|
||||
DRIVER_SPI_ENABLE := 0
|
||||
endif
|
||||
|
||||
ifeq (${DRIVER_I2C_ENABLE},)
|
||||
DRIVER_I2C_ENABLE := 0
|
||||
endif
|
||||
|
||||
# By default, Trusted Watchdog is always enabled unless SPIN_ON_BL1_EXIT is set
|
||||
ifeq (${BRCM_DISABLE_TRUSTED_WDOG},)
|
||||
BRCM_DISABLE_TRUSTED_WDOG := 0
|
||||
endif
|
||||
ifeq (${SPIN_ON_BL1_EXIT}, 1)
|
||||
BRCM_DISABLE_TRUSTED_WDOG := 1
|
||||
endif
|
||||
|
||||
$(eval $(call assert_boolean,BRCM_DISABLE_TRUSTED_WDOG))
|
||||
$(eval $(call add_define,BRCM_DISABLE_TRUSTED_WDOG))
|
||||
|
||||
# Process ARM_BL31_IN_DRAM flag
|
||||
ifeq (${ARM_BL31_IN_DRAM},)
|
||||
ARM_BL31_IN_DRAM := 0
|
||||
endif
|
||||
$(eval $(call assert_boolean,ARM_BL31_IN_DRAM))
|
||||
$(eval $(call add_define,ARM_BL31_IN_DRAM))
|
||||
|
||||
ifeq (${STANDALONE_BL2},yes)
|
||||
BL2_LOG_LEVEL := 40
|
||||
$(eval $(call add_define,MMU_DISABLED))
|
||||
endif
|
||||
|
||||
# BL2 XIP from QSPI
|
||||
RUN_BL2_FROM_QSPI := 0
|
||||
ifeq (${RUN_BL2_FROM_QSPI},1)
|
||||
$(eval $(call add_define,RUN_BL2_FROM_QSPI))
|
||||
endif
|
||||
|
||||
# BL2 XIP from NAND
|
||||
RUN_BL2_FROM_NAND := 0
|
||||
ifeq (${RUN_BL2_FROM_NAND},1)
|
||||
$(eval $(call add_define,RUN_BL2_FROM_NAND))
|
||||
endif
|
||||
|
||||
ifneq (${ELOG_AP_UART_LOG_BASE},)
|
||||
$(eval $(call add_define,ELOG_AP_UART_LOG_BASE))
|
||||
endif
|
||||
|
||||
ifeq (${ELOG_SUPPORT},1)
|
||||
ifeq (${ELOG_STORE_MEDIA},DDR)
|
||||
$(eval $(call add_define,ELOG_STORE_MEDIA_DDR))
|
||||
ifneq (${ELOG_STORE_OFFSET},)
|
||||
$(eval $(call add_define,ELOG_STORE_OFFSET))
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq (${BL2_LOG_LEVEL},)
|
||||
$(eval $(call add_define,BL2_LOG_LEVEL))
|
||||
endif
|
||||
|
||||
ifneq (${BL31_LOG_LEVEL},)
|
||||
$(eval $(call add_define,BL31_LOG_LEVEL))
|
||||
endif
|
||||
|
||||
# Use CRMU SRAM from iHOST
|
||||
ifneq (${USE_CRMU_SRAM},)
|
||||
$(eval $(call add_define,USE_CRMU_SRAM))
|
||||
endif
|
||||
|
||||
# Use PIO mode if DDR is not used
|
||||
ifeq (${USE_DDR},yes)
|
||||
EMMC_USE_DMA := 1
|
||||
else
|
||||
EMMC_USE_DMA := 0
|
||||
endif
|
||||
$(eval $(call add_define,EMMC_USE_DMA))
|
||||
|
||||
# On BRCM platforms, separate the code and read-only data sections to allow
|
||||
# mapping the former as executable and the latter as execute-never.
|
||||
SEPARATE_CODE_AND_RODATA := 1
|
||||
|
||||
# Use generic OID definition (tbbr_oid.h)
|
||||
USE_TBBR_DEFS := 1
|
||||
|
||||
PLAT_INCLUDES += -Iplat/brcm/board/common \
|
||||
-Iinclude/drivers/brcm \
|
||||
-Iinclude/drivers/brcm/emmc \
|
||||
-Iinclude/drivers/brcm/mdio
|
||||
|
||||
PLAT_BL_COMMON_SOURCES += plat/brcm/common/brcm_common.c \
|
||||
plat/brcm/board/common/cmn_sec.c \
|
||||
plat/brcm/board/common/bcm_console.c \
|
||||
plat/brcm/board/common/brcm_mbedtls.c \
|
||||
plat/brcm/board/common/plat_setup.c \
|
||||
plat/brcm/board/common/platform_common.c \
|
||||
drivers/arm/sp804/sp804_delay_timer.c \
|
||||
drivers/brcm/sotp.c \
|
||||
drivers/delay_timer/delay_timer.c \
|
||||
drivers/io/io_fip.c \
|
||||
drivers/io/io_memmap.c \
|
||||
drivers/io/io_storage.c \
|
||||
plat/brcm/common/brcm_io_storage.c \
|
||||
plat/brcm/board/common/err.c \
|
||||
plat/brcm/board/common/sbl_util.c \
|
||||
drivers/arm/sp805/sp805.c
|
||||
|
||||
# Add RNG driver
|
||||
DRIVER_RNG_ENABLE := 1
|
||||
ifeq (${DRIVER_RNG_ENABLE},1)
|
||||
PLAT_BL_COMMON_SOURCES += drivers/brcm/rng.c
|
||||
endif
|
||||
|
||||
# Add eMMC driver
|
||||
ifeq (${DRIVER_EMMC_ENABLE},1)
|
||||
$(eval $(call add_define,DRIVER_EMMC_ENABLE))
|
||||
|
||||
EMMC_SOURCES += drivers/brcm/emmc/emmc_chal_sd.c \
|
||||
drivers/brcm/emmc/emmc_csl_sdcard.c \
|
||||
drivers/brcm/emmc/emmc_csl_sdcmd.c \
|
||||
drivers/brcm/emmc/emmc_pboot_hal_memory_drv.c
|
||||
|
||||
PLAT_BL_COMMON_SOURCES += ${EMMC_SOURCES}
|
||||
|
||||
ifeq (${DRIVER_EMMC_ENABLE_DATA_WIDTH_8BIT},)
|
||||
$(eval $(call add_define,DRIVER_EMMC_ENABLE_DATA_WIDTH_8BIT))
|
||||
endif
|
||||
endif
|
||||
|
||||
BL2_SOURCES += plat/brcm/common/brcm_bl2_mem_params_desc.c \
|
||||
plat/brcm/common/brcm_image_load.c \
|
||||
common/desc_image_load.c
|
||||
|
||||
BL2_SOURCES += plat/brcm/common/brcm_bl2_setup.c
|
||||
|
||||
BL31_SOURCES += plat/brcm/common/brcm_bl31_setup.c
|
||||
|
||||
ifeq (${BCM_ELOG},yes)
|
||||
ELOG_SOURCES += plat/brcm/board/common/bcm_elog.c
|
||||
BL2_SOURCES += ${ELOG_SOURCES}
|
||||
BL31_SOURCES += ${ELOG_SOURCES}
|
||||
endif
|
||||
|
||||
# Add spi driver
|
||||
ifeq (${DRIVER_SPI_ENABLE},1)
|
||||
PLAT_BL_COMMON_SOURCES += drivers/brcm/spi/iproc_spi.c \
|
||||
drivers/brcm/spi/iproc_qspi.c
|
||||
endif
|
||||
|
||||
# Add spi nor/flash driver
|
||||
ifeq (${DRIVER_SPI_NOR_ENABLE},1)
|
||||
PLAT_BL_COMMON_SOURCES += drivers/brcm/spi_sf.c \
|
||||
drivers/brcm/spi_flash.c
|
||||
endif
|
||||
|
||||
ifeq (${DRIVER_I2C_ENABLE},1)
|
||||
$(eval $(call add_define,DRIVER_I2C_ENABLE))
|
||||
BL2_SOURCES += drivers/brcm/i2c/i2c.c
|
||||
PLAT_INCLUDES += -Iinclude/drivers/brcm/i2c
|
||||
endif
|
||||
|
||||
ifeq (${DRIVER_OCOTP_ENABLE},1)
|
||||
$(eval $(call add_define,DRIVER_OCOTP_ENABLE))
|
||||
BL2_SOURCES += drivers/brcm/ocotp.c
|
||||
endif
|
||||
|
||||
# Enable FRU table support
|
||||
ifeq (${USE_FRU},yes)
|
||||
$(eval $(call add_define,USE_FRU))
|
||||
BL2_SOURCES += drivers/brcm/fru.c
|
||||
endif
|
||||
|
||||
# Enable GPIO support
|
||||
ifeq (${USE_GPIO},yes)
|
||||
$(eval $(call add_define,USE_GPIO))
|
||||
BL2_SOURCES += drivers/gpio/gpio.c
|
||||
BL2_SOURCES += drivers/brcm/iproc_gpio.c
|
||||
ifeq (${GPIO_SUPPORT_FLOAT_DETECTION},yes)
|
||||
$(eval $(call add_define,GPIO_SUPPORT_FLOAT_DETECTION))
|
||||
endif
|
||||
endif
|
||||
|
||||
# Include mbedtls if it can be located
|
||||
MBEDTLS_DIR ?= mbedtls
|
||||
MBEDTLS_CHECK := $(shell find ${MBEDTLS_DIR}/include -name '$(notdir ${MBEDTLS_DIR})')
|
||||
|
||||
ifneq (${MBEDTLS_CHECK},)
|
||||
$(info Found mbedTLS at ${MBEDTLS_DIR})
|
||||
PLAT_INCLUDES += -I${MBEDTLS_DIR}/include/mbedtls
|
||||
|
||||
# By default, use RSA keys
|
||||
KEY_ALG := rsa_1_5
|
||||
|
||||
# Include common TBB sources
|
||||
AUTH_SOURCES += drivers/auth/auth_mod.c \
|
||||
drivers/auth/crypto_mod.c \
|
||||
drivers/auth/img_parser_mod.c \
|
||||
drivers/auth/tbbr/tbbr_cot_common.c \
|
||||
drivers/auth/tbbr/tbbr_cot_bl2.c
|
||||
|
||||
BL2_SOURCES += ${AUTH_SOURCES}
|
||||
|
||||
# Use ATF framework for MBEDTLS
|
||||
TRUSTED_BOARD_BOOT := 1
|
||||
CRYPTO_LIB_MK := drivers/auth/mbedtls/mbedtls_crypto.mk
|
||||
IMG_PARSER_LIB_MK := drivers/auth/mbedtls/mbedtls_x509.mk
|
||||
$(info Including ${CRYPTO_LIB_MK})
|
||||
include ${CRYPTO_LIB_MK}
|
||||
$(info Including ${IMG_PARSER_LIB_MK})
|
||||
include ${IMG_PARSER_LIB_MK}
|
||||
|
||||
# Use ATF secure boot functions
|
||||
# Use Hardcoded hash for devel
|
||||
|
||||
ARM_ROTPK_LOCATION=arm_rsa
|
||||
ifeq (${ARM_ROTPK_LOCATION}, arm_rsa)
|
||||
ARM_ROTPK_LOCATION_ID=ARM_ROTPK_DEVEL_RSA_ID
|
||||
ROT_KEY=plat/arm/board/common/rotpk/arm_rotprivk_rsa.pem
|
||||
else ifeq (${ARM_ROTPK_LOCATION}, brcm_rsa)
|
||||
ARM_ROTPK_LOCATION_ID=BRCM_ROTPK_SOTP_RSA_ID
|
||||
ifeq (${ROT_KEY},)
|
||||
ROT_KEY=plat/brcm/board/common/rotpk/rsa_dauth2048_key.pem
|
||||
endif
|
||||
KEY_FIND := $(shell m="${ROT_KEY}"; [ -f "$$m" ] && echo "$$m")
|
||||
ifeq (${KEY_FIND},)
|
||||
$(error Error: No ${ROT_KEY} located)
|
||||
else
|
||||
$(info Using ROT_KEY: ${ROT_KEY})
|
||||
endif
|
||||
else
|
||||
$(error "Unsupported ARM_ROTPK_LOCATION value")
|
||||
endif
|
||||
|
||||
$(eval $(call add_define,ARM_ROTPK_LOCATION_ID))
|
||||
PLAT_BL_COMMON_SOURCES+=plat/brcm/board/common/board_arm_trusted_boot.c
|
||||
endif
|
||||
|
||||
#M0 runtime firmware
|
||||
ifdef SCP_BL2
|
||||
$(eval $(call add_define,NEED_SCP_BL2))
|
||||
SCP_CFG_DIR=$(dir ${SCP_BL2})
|
||||
PLAT_INCLUDES += -I${SCP_CFG_DIR}
|
||||
endif
|
||||
|
||||
ifneq (${NEED_BL33},yes)
|
||||
# If there is no BL33, BL31 will jump to this address.
|
||||
ifeq (${USE_DDR},yes)
|
||||
PRELOADED_BL33_BASE := 0x80000000
|
||||
else
|
||||
PRELOADED_BL33_BASE := 0x74000000
|
||||
endif
|
||||
endif
|
||||
|
||||
# Use translation tables library v1 by default
|
||||
ARM_XLAT_TABLES_LIB_V1 := 1
|
||||
ifeq (${ARM_XLAT_TABLES_LIB_V1}, 1)
|
||||
$(eval $(call assert_boolean,ARM_XLAT_TABLES_LIB_V1))
|
||||
$(eval $(call add_define,ARM_XLAT_TABLES_LIB_V1))
|
||||
PLAT_BL_COMMON_SOURCES += lib/xlat_tables/aarch64/xlat_tables.c \
|
||||
lib/xlat_tables/xlat_tables_common.c
|
||||
endif
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright 2015 - 2020 Broadcom
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <common/debug.h>
|
||||
|
||||
void tls_exit(int code)
|
||||
{
|
||||
INFO("%s: 0x%x\n", __func__, code);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2017 - 2020, Broadcom
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef CHIP_ID_H
|
||||
#define CHIP_ID_H
|
||||
|
||||
#include <lib/mmio.h>
|
||||
|
||||
#include <platform_def.h>
|
||||
|
||||
#define CHIP_REV_MAJOR_MASK 0xF0
|
||||
#define CHIP_REV_MAJOR_AX 0x00
|
||||
#define CHIP_REV_MAJOR_BX 0x10
|
||||
#define CHIP_REV_MAJOR_CX 0x20
|
||||
#define CHIP_REV_MAJOR_DX 0x30
|
||||
|
||||
/* Get Chip ID (product number) of the chip */
|
||||
static inline unsigned int chip_get_product_id(void)
|
||||
{
|
||||
return PLAT_CHIP_ID_GET;
|
||||
}
|
||||
|
||||
/* Get Revision ID (major and minor) number of the chip */
|
||||
static inline unsigned int chip_get_rev_id(void)
|
||||
{
|
||||
return PLAT_CHIP_REV_GET;
|
||||
}
|
||||
|
||||
static inline unsigned int chip_get_rev_id_major(void)
|
||||
{
|
||||
return (chip_get_rev_id() & CHIP_REV_MAJOR_MASK);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* Copyright (c) 2015 - 2020, Broadcom
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef CMN_PLAT_DEF_H
|
||||
#define CMN_PLAT_DEF_H
|
||||
|
||||
#include <bcm_elog.h>
|
||||
#include <platform_def.h>
|
||||
|
||||
#ifndef GET_LOG_LEVEL
|
||||
#define GET_LOG_LEVEL() LOG_LEVEL
|
||||
#endif
|
||||
|
||||
#ifndef SET_LOG_LEVEL
|
||||
#define SET_LOG_LEVEL(x) ((void)(x))
|
||||
#endif
|
||||
|
||||
#define PLAT_LOG_NOTICE(...) \
|
||||
do { \
|
||||
if (GET_LOG_LEVEL() >= LOG_LEVEL_NOTICE) { \
|
||||
bcm_elog(LOG_MARKER_NOTICE __VA_ARGS__); \
|
||||
tf_log(LOG_MARKER_NOTICE __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define PLAT_LOG_ERROR(...) \
|
||||
do { \
|
||||
if (GET_LOG_LEVEL() >= LOG_LEVEL_ERROR) { \
|
||||
bcm_elog(LOG_MARKER_ERROR, __VA_ARGS__); \
|
||||
tf_log(LOG_MARKER_ERROR __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define PLAT_LOG_WARN(...) \
|
||||
do { \
|
||||
if (GET_LOG_LEVEL() >= LOG_LEVEL_WARNING) { \
|
||||
bcm_elog(LOG_MARKER_WARNING, __VA_ARGS__);\
|
||||
tf_log(LOG_MARKER_WARNING __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define PLAT_LOG_INFO(...) \
|
||||
do { \
|
||||
if (GET_LOG_LEVEL() >= LOG_LEVEL_INFO) { \
|
||||
bcm_elog(LOG_MARKER_INFO __VA_ARGS__); \
|
||||
tf_log(LOG_MARKER_INFO __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define PLAT_LOG_VERBOSE(...) \
|
||||
do { \
|
||||
if (GET_LOG_LEVEL() >= LOG_LEVEL_VERBOSE) { \
|
||||
bcm_elog(LOG_MARKER_VERBOSE __VA_ARGS__);\
|
||||
tf_log(LOG_MARKER_VERBOSE __VA_ARGS__); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* The number of regions like RO(code), coherent and data required by
|
||||
* different BL stages which need to be mapped in the MMU.
|
||||
*/
|
||||
#if USE_COHERENT_MEM
|
||||
#define CMN_BL_REGIONS 3
|
||||
#else
|
||||
#define CMN_BL_REGIONS 2
|
||||
#endif
|
||||
|
||||
/*
|
||||
* FIP definitions
|
||||
*/
|
||||
#define PLAT_FIP_ATTEMPT_OFFSET 0x20000
|
||||
#define PLAT_FIP_NUM_ATTEMPTS 128
|
||||
|
||||
#define PLAT_BRCM_FIP_QSPI_BASE QSPI_BASE_ADDR
|
||||
#define PLAT_BRCM_FIP_NAND_BASE NAND_BASE_ADDR
|
||||
#define PLAT_BRCM_FIP_MAX_SIZE 0x01000000
|
||||
|
||||
#define PLAT_BRCM_FIP_BASE PLAT_BRCM_FIP_QSPI_BASE
|
||||
#endif
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (c) 2015 - 2020, Broadcom
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef CMN_PLAT_UTIL_H
|
||||
#define CMN_PLAT_UTIL_H
|
||||
|
||||
#include <lib/mmio.h>
|
||||
|
||||
/* BOOT source */
|
||||
#define BOOT_SOURCE_MASK 7
|
||||
#define BOOT_SOURCE_QSPI 0
|
||||
#define BOOT_SOURCE_NAND 1
|
||||
#define BOOT_SOURCE_SPI_NAND 2
|
||||
#define BOOT_SOURCE_UART 3
|
||||
#define BOOT_SOURCE_RES4 4
|
||||
#define BOOT_SOURCE_EMMC 5
|
||||
#define BOOT_SOURCE_ATE 6
|
||||
#define BOOT_SOURCE_USB 7
|
||||
#define BOOT_SOURCE_MAX 8
|
||||
#define BOOT_SOURCE_UNKNOWN (-1)
|
||||
|
||||
#define KHMAC_SHA256_KEY_SIZE 32
|
||||
|
||||
#define SOFT_PWR_UP_RESET_L0 0
|
||||
#define SOFT_SYS_RESET_L1 1
|
||||
#define SOFT_RESET_L3 0x3
|
||||
|
||||
#define BOOT_SOURCE_SOFT_DATA_OFFSET 8
|
||||
#define BOOT_SOURCE_SOFT_ENABLE_OFFSET 14
|
||||
#define BOOT_SOURCE_SOFT_ENABLE_MASK BIT(BOOT_SOURCE_SOFT_ENABLE_OFFSET)
|
||||
|
||||
typedef struct _key {
|
||||
uint8_t hmac_sha256[KHMAC_SHA256_KEY_SIZE];
|
||||
} cmn_key_t;
|
||||
|
||||
uint32_t boot_source_get(void);
|
||||
void bl1_platform_wait_events(void);
|
||||
void plat_soft_reset(uint32_t reset);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2020, Broadcom
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <common/debug.h>
|
||||
#include <lib/mmio.h>
|
||||
|
||||
#include <cmn_sec.h>
|
||||
|
||||
#pragma weak plat_tz_master_default_cfg
|
||||
#pragma weak plat_tz_sdio_ns_master_set
|
||||
#pragma weak plat_tz_usb_ns_master_set
|
||||
|
||||
void plat_tz_master_default_cfg(void)
|
||||
{
|
||||
/* This function should be implemented in the platform side. */
|
||||
ERROR("%s: TZ CONFIGURATION NOT SET!!!\n", __func__);
|
||||
}
|
||||
|
||||
void plat_tz_sdio_ns_master_set(uint32_t ns)
|
||||
{
|
||||
/* This function should be implemented in the platform side. */
|
||||
ERROR("%s: TZ CONFIGURATION NOT SET!!!\n", __func__);
|
||||
}
|
||||
|
||||
void plat_tz_usb_ns_master_set(uint32_t ns)
|
||||
{
|
||||
/* This function should be implemented in the platform side. */
|
||||
ERROR("%s: TZ CONFIGURATION NOT SET!!!\n", __func__);
|
||||
}
|
||||
|
||||
void tz_master_default_cfg(void)
|
||||
{
|
||||
plat_tz_master_default_cfg();
|
||||
}
|
||||
|
||||
void tz_sdio_ns_master_set(uint32_t ns)
|
||||
{
|
||||
plat_tz_sdio_ns_master_set(ns);
|
||||
}
|
||||
|
||||
void tz_usb_ns_master_set(uint32_t ns)
|
||||
{
|
||||
plat_tz_usb_ns_master_set(ns);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2020, Broadcom
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef CMN_SEC_H
|
||||
#define CMN_SEC_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define SECURE_MASTER 0
|
||||
#define NS_MASTER 1
|
||||
|
||||
void tz_master_default_cfg(void);
|
||||
void tz_usb_ns_master_set(uint32_t ns);
|
||||
void tz_sdio_ns_master_set(uint32_t ns);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2016 - 2020, Broadcom
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <arch_helpers.h>
|
||||
#include <common/debug.h>
|
||||
#include <drivers/console.h>
|
||||
#include <lib/mmio.h>
|
||||
|
||||
#include <platform_def.h>
|
||||
|
||||
#define L0_RESET 0x2
|
||||
|
||||
/*
|
||||
* Brcm error handler
|
||||
*/
|
||||
void plat_error_handler(int err)
|
||||
{
|
||||
INFO("L0 reset...\n");
|
||||
|
||||
/* Ensure the characters are flushed out */
|
||||
console_flush();
|
||||
|
||||
mmio_write_32(CRMU_SOFT_RESET_CTRL, L0_RESET);
|
||||
|
||||
/*
|
||||
* In case we get here:
|
||||
* Loop until the watchdog resets the system
|
||||
*/
|
||||
while (1) {
|
||||
wfi();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (c) 2015 - 2020, Broadcom
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <plat/common/platform.h>
|
||||
|
||||
#include <platform_def.h>
|
||||
|
||||
/*
|
||||
* This function returns the fixed clock frequency at which private
|
||||
* timers run. This value will be programmed into CNTFRQ_EL0.
|
||||
*/
|
||||
unsigned int plat_get_syscnt_freq2(void)
|
||||
{
|
||||
return SYSCNT_FREQ;
|
||||
}
|
||||
|
||||
static const char * const plat_prefix_str[] = {
|
||||
"E: ", "N: ", "W: ", "I: ", "V: "
|
||||
};
|
||||
|
||||
const char *plat_log_get_prefix(unsigned int log_level)
|
||||
{
|
||||
return plat_prefix_str[log_level - 1U];
|
||||
}
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2020, Broadcom
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <arch_helpers.h>
|
||||
#include <common/debug.h>
|
||||
#include <drivers/brcm/sotp.h>
|
||||
|
||||
#include <cmn_plat_util.h>
|
||||
#include <platform_def.h>
|
||||
|
||||
uint32_t boot_source_get(void)
|
||||
{
|
||||
uint32_t data;
|
||||
|
||||
#ifdef FORCE_BOOTSOURCE
|
||||
data = FORCE_BOOTSOURCE;
|
||||
#else
|
||||
/* Read primary boot strap from CRMU persistent registers */
|
||||
data = mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG1);
|
||||
if (data & BOOT_SOURCE_SOFT_ENABLE_MASK) {
|
||||
data >>= BOOT_SOURCE_SOFT_DATA_OFFSET;
|
||||
} else {
|
||||
uint64_t sotp_atf_row;
|
||||
|
||||
sotp_atf_row =
|
||||
sotp_mem_read(SOTP_ATF_CFG_ROW_ID, SOTP_ROW_NO_ECC);
|
||||
|
||||
if (sotp_atf_row & SOTP_BOOT_SOURCE_ENABLE_MASK) {
|
||||
/* Construct the boot source based on SOTP bits */
|
||||
data = 0;
|
||||
if (sotp_atf_row & SOTP_BOOT_SOURCE_BITS0)
|
||||
data |= 0x1;
|
||||
if (sotp_atf_row & SOTP_BOOT_SOURCE_BITS1)
|
||||
data |= 0x2;
|
||||
if (sotp_atf_row & SOTP_BOOT_SOURCE_BITS2)
|
||||
data |= 0x4;
|
||||
} else {
|
||||
|
||||
/*
|
||||
* This path is for L0 reset with
|
||||
* Primary Boot source disabled in SOTP.
|
||||
* BOOT_SOURCE_FROM_PR_ON_L1 compile flag will allow
|
||||
* to never come back here so that the
|
||||
* external straps will not be read on L1 reset.
|
||||
*/
|
||||
|
||||
/* Use the external straps */
|
||||
data = mmio_read_32(ROM_S0_IDM_IO_STATUS);
|
||||
|
||||
#ifdef BOOT_SOURCE_FROM_PR_ON_L1
|
||||
/* Enable boot source read from PR#1 */
|
||||
mmio_setbits_32(CRMU_IHOST_SW_PERSISTENT_REG1,
|
||||
BOOT_SOURCE_SOFT_ENABLE_MASK);
|
||||
|
||||
/* set boot source */
|
||||
data &= BOOT_SOURCE_MASK;
|
||||
mmio_clrsetbits_32(CRMU_IHOST_SW_PERSISTENT_REG1,
|
||||
BOOT_SOURCE_MASK << BOOT_SOURCE_SOFT_DATA_OFFSET,
|
||||
data << BOOT_SOURCE_SOFT_DATA_OFFSET);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return (data & BOOT_SOURCE_MASK);
|
||||
}
|
||||
|
||||
void __dead2 plat_soft_reset(uint32_t reset)
|
||||
{
|
||||
if (reset == SOFT_RESET_L3) {
|
||||
mmio_setbits_32(CRMU_IHOST_SW_PERSISTENT_REG1, reset);
|
||||
mmio_write_32(CRMU_MAIL_BOX0, 0x0);
|
||||
mmio_write_32(CRMU_MAIL_BOX1, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
if (reset != SOFT_SYS_RESET_L1)
|
||||
reset = SOFT_PWR_UP_RESET_L0;
|
||||
|
||||
if (reset == SOFT_PWR_UP_RESET_L0)
|
||||
INFO("L0 RESET...\n");
|
||||
|
||||
if (reset == SOFT_SYS_RESET_L1)
|
||||
INFO("L1 RESET...\n");
|
||||
|
||||
console_flush();
|
||||
|
||||
mmio_clrbits_32(CRMU_SOFT_RESET_CTRL, 1 << reset);
|
||||
|
||||
while (1) {
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2015 - 2020, Broadcom
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <common/debug.h>
|
||||
|
||||
#include <platform_def.h>
|
||||
#include <sbl_util.h>
|
||||
#include <sotp.h>
|
||||
|
||||
#pragma weak plat_sbl_status
|
||||
|
||||
int plat_sbl_status(uint64_t sbl_status)
|
||||
{
|
||||
return sbl_status ? 1:0;
|
||||
}
|
||||
|
||||
int sbl_status(void)
|
||||
{
|
||||
uint64_t sbl_sotp = 0;
|
||||
int ret = SBL_DISABLED;
|
||||
|
||||
sbl_sotp = sotp_mem_read(SOTP_ATF_CFG_ROW_ID, SOTP_ROW_NO_ECC);
|
||||
|
||||
if (sbl_sotp != SOTP_ECC_ERR_DETECT) {
|
||||
|
||||
sbl_sotp &= SOTP_SBL_MASK;
|
||||
|
||||
if (plat_sbl_status(sbl_sotp))
|
||||
ret = SBL_ENABLED;
|
||||
}
|
||||
|
||||
VERBOSE("SBL status: %d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright (c) 2015 - 2020, Broadcom
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef SBL_UTIL_H
|
||||
#define SBL_UTIL_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <sotp.h>
|
||||
|
||||
#define SBL_DISABLED 0
|
||||
#define SBL_ENABLED 1
|
||||
|
||||
int sbl_status(void);
|
||||
|
||||
#endif /* #ifdef SBL_UTIL_H */
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) 2015 - 2020, Broadcom
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <arch_helpers.h>
|
||||
#include <common/debug.h>
|
||||
#include <lib/mmio.h>
|
||||
|
||||
#include <platform_def.h>
|
||||
#include <timer_sync.h>
|
||||
|
||||
/*******************************************************************************
|
||||
* Defines related to time sync and satelite timers
|
||||
******************************************************************************/
|
||||
#define TIME_SYNC_WR_ENA ((uint32_t)0xACCE55 << 8)
|
||||
#define IHOST_STA_TMR_CTRL 0x1800
|
||||
#define IHOST_SAT_TMR_INC_L 0x1814
|
||||
#define IHOST_SAT_TMR_INC_H 0x1818
|
||||
|
||||
#define SAT_TMR_CYCLE_DELAY 2
|
||||
#define SAT_TMR_32BIT_WRAP_VAL (BIT_64(32) - SAT_TMR_CYCLE_DELAY)
|
||||
|
||||
void ihost_enable_satellite_timer(unsigned int cluster_id)
|
||||
{
|
||||
uintptr_t ihost_base;
|
||||
uint32_t time_lx, time_h;
|
||||
uintptr_t ihost_enable;
|
||||
|
||||
VERBOSE("Program iHost%u satellite timer\n", cluster_id);
|
||||
ihost_base = IHOST0_BASE + cluster_id * IHOST_ADDR_SPACE;
|
||||
|
||||
/* this read starts the satellite timer counting from 0 */
|
||||
ihost_enable = CENTRAL_TIMER_GET_IHOST_ENA_BASE + cluster_id * 4;
|
||||
time_lx = mmio_read_32(ihost_enable);
|
||||
|
||||
/*
|
||||
* Increment the satellite timer by the central timer plus 2
|
||||
* to accommodate for a 1 cycle delay through NOC
|
||||
* plus counter starting from 0.
|
||||
*/
|
||||
mmio_write_32(ihost_base + IHOST_SAT_TMR_INC_L,
|
||||
time_lx + SAT_TMR_CYCLE_DELAY);
|
||||
|
||||
/*
|
||||
* Read the latched upper data, if lx will wrap by adding 2 to it
|
||||
* we need to handle the wrap
|
||||
*/
|
||||
time_h = mmio_read_32(CENTRAL_TIMER_GET_H);
|
||||
if (time_lx >= SAT_TMR_32BIT_WRAP_VAL)
|
||||
mmio_write_32(ihost_base + IHOST_SAT_TMR_INC_H, time_h + 1);
|
||||
else
|
||||
mmio_write_32(ihost_base + IHOST_SAT_TMR_INC_H, time_h);
|
||||
}
|
||||
|
||||
void brcm_timer_sync_init(void)
|
||||
{
|
||||
unsigned int cluster_id;
|
||||
|
||||
/* Get the Time Sync module out of reset */
|
||||
mmio_setbits_32(CDRU_MISC_RESET_CONTROL,
|
||||
BIT(CDRU_MISC_RESET_CONTROL_TS_RESET_N));
|
||||
|
||||
/* Deassert the Central Timer TIMER_EN signal for all module */
|
||||
mmio_write_32(CENTRAL_TIMER_SAT_TMR_ENA, TIME_SYNC_WR_ENA);
|
||||
|
||||
/* enables/programs iHost0 satellite timer*/
|
||||
cluster_id = MPIDR_AFFLVL1_VAL(read_mpidr());
|
||||
ihost_enable_satellite_timer(cluster_id);
|
||||
}
|
||||
Reference in New Issue
Block a user