Commit f29d1e0c authored by Sheetal Tigadoli's avatar Sheetal Tigadoli
Browse files

Add BL2 support for Broadcom stingray platform


Change-Id: I5daa3f2b4b9d85cb857547a588571a9aa8ad05c2
Signed-off-by: default avatarSheetal Tigadoli <sheetal.tigadoli@broadcom.com>
Showing with 2671 additions and 2 deletions
+2671 -2
/*
* Copyright (c) 2019-2020, Broadcom
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <drivers/gpio.h>
#include <lib/mmio.h>
#include <plat/common/platform.h>
#include <iproc_gpio.h>
#include <platform_def.h>
#define IPROC_GPIO_DATA_IN_OFFSET 0x00
#define IPROC_GPIO_DATA_OUT_OFFSET 0x04
#define IPROC_GPIO_OUT_EN_OFFSET 0x08
#define IPROC_GPIO_PAD_RES_OFFSET 0x34
#define IPROC_GPIO_RES_EN_OFFSET 0x38
#define PINMUX_OFFSET(gpio) ((gpio) * 4)
#define PINCONF_OFFSET(gpio) ((gpio) * 4)
#define PINCONF_PULL_UP BIT(4)
#define PINCONF_PULL_DOWN BIT(5)
/*
* iProc GPIO bank is always 0x200 per bank,
* with each bank supporting 32 GPIOs.
*/
#define GPIO_BANK_SIZE 0x200
#define NGPIOS_PER_BANK 32
#define GPIO_BANK(pin) ((pin) / NGPIOS_PER_BANK)
#define IPROC_GPIO_REG(pin, reg) (GPIO_BANK(pin) * GPIO_BANK_SIZE + (reg))
#define IPROC_GPIO_SHIFT(pin) ((pin) % NGPIOS_PER_BANK)
#define MUX_GPIO_MODE 0x3
/*
* @base: base address of the gpio controller
* @pinconf_base: base address of the pinconf
* @pinmux_base: base address of the mux controller
* @nr_gpios: maxinum number of GPIOs
*/
struct iproc_gpio {
uintptr_t base;
uintptr_t pinconf_base;
uintptr_t pinmux_base;
int nr_gpios;
};
static struct iproc_gpio iproc_gpio;
static void gpio_set_bit(uintptr_t base, unsigned int reg, int gpio, bool set)
{
unsigned int offset = IPROC_GPIO_REG(gpio, reg);
unsigned int shift = IPROC_GPIO_SHIFT(gpio);
uint32_t val;
val = mmio_read_32(base + offset);
if (set)
val |= BIT(shift);
else
val &= ~BIT(shift);
mmio_write_32(base + offset, val);
}
static bool gpio_get_bit(uintptr_t base, unsigned int reg, int gpio)
{
unsigned int offset = IPROC_GPIO_REG(gpio, reg);
unsigned int shift = IPROC_GPIO_SHIFT(gpio);
return !!(mmio_read_32(base + offset) & BIT(shift));
}
static void mux_to_gpio(struct iproc_gpio *g, int gpio)
{
/* mux pad to GPIO if IOPAD configuration is mandatory */
if (g->pinmux_base)
mmio_write_32(g->pinmux_base + PINMUX_OFFSET(gpio),
MUX_GPIO_MODE);
}
static void set_direction(int gpio, int direction)
{
struct iproc_gpio *g = &iproc_gpio;
bool dir = (direction == GPIO_DIR_OUT) ? true : false;
assert(gpio < g->nr_gpios);
mux_to_gpio(g, gpio);
gpio_set_bit(g->base, IPROC_GPIO_OUT_EN_OFFSET, gpio, dir);
}
static int get_direction(int gpio)
{
struct iproc_gpio *g = &iproc_gpio;
int dir;
assert(gpio < g->nr_gpios);
mux_to_gpio(g, gpio);
dir = gpio_get_bit(g->base, IPROC_GPIO_OUT_EN_OFFSET, gpio) ?
GPIO_DIR_OUT : GPIO_DIR_IN;
return dir;
}
static int get_value(int gpio)
{
struct iproc_gpio *g = &iproc_gpio;
unsigned int offset;
assert(gpio < g->nr_gpios);
mux_to_gpio(g, gpio);
/*
* If GPIO is configured as output, read from the GPIO_OUT register;
* otherwise, read from the GPIO_IN register
*/
offset = gpio_get_bit(g->base, IPROC_GPIO_OUT_EN_OFFSET, gpio) ?
IPROC_GPIO_DATA_OUT_OFFSET : IPROC_GPIO_DATA_IN_OFFSET;
return gpio_get_bit(g->base, offset, gpio);
}
static void set_value(int gpio, int val)
{
struct iproc_gpio *g = &iproc_gpio;
assert(gpio < g->nr_gpios);
mux_to_gpio(g, gpio);
/* make sure GPIO is configured to output, and then set the value */
gpio_set_bit(g->base, IPROC_GPIO_OUT_EN_OFFSET, gpio, true);
gpio_set_bit(g->base, IPROC_GPIO_DATA_OUT_OFFSET, gpio, !!(val));
}
static int get_pull(int gpio)
{
struct iproc_gpio *g = &iproc_gpio;
uint32_t val;
assert(gpio < g->nr_gpios);
mux_to_gpio(g, gpio);
/* when there's a valid pinconf_base, use it */
if (g->pinconf_base) {
val = mmio_read_32(g->pinconf_base + PINCONF_OFFSET(gpio));
if (val & PINCONF_PULL_UP)
return GPIO_PULL_UP;
else if (val & PINCONF_PULL_DOWN)
return GPIO_PULL_DOWN;
else
return GPIO_PULL_NONE;
}
/* no pinconf_base. fall back to GPIO internal pull control */
if (!gpio_get_bit(g->base, IPROC_GPIO_RES_EN_OFFSET, gpio))
return GPIO_PULL_NONE;
return gpio_get_bit(g->base, IPROC_GPIO_PAD_RES_OFFSET, gpio) ?
GPIO_PULL_UP : GPIO_PULL_DOWN;
}
static void set_pull(int gpio, int pull)
{
struct iproc_gpio *g = &iproc_gpio;
uint32_t val;
assert(gpio < g->nr_gpios);
mux_to_gpio(g, gpio);
/* when there's a valid pinconf_base, use it */
if (g->pinconf_base) {
val = mmio_read_32(g->pinconf_base + PINCONF_OFFSET(gpio));
if (pull == GPIO_PULL_NONE) {
val &= ~(PINCONF_PULL_UP | PINCONF_PULL_DOWN);
} else if (pull == GPIO_PULL_UP) {
val |= PINCONF_PULL_UP;
val &= ~PINCONF_PULL_DOWN;
} else if (pull == GPIO_PULL_DOWN) {
val |= PINCONF_PULL_DOWN;
val &= ~PINCONF_PULL_UP;
} else {
return;
}
mmio_write_32(g->pinconf_base + PINCONF_OFFSET(gpio), val);
}
/* no pinconf_base. fall back to GPIO internal pull control */
if (pull == GPIO_PULL_NONE) {
gpio_set_bit(g->base, IPROC_GPIO_RES_EN_OFFSET, gpio, false);
return;
}
/* enable pad register and pull up or down */
gpio_set_bit(g->base, IPROC_GPIO_RES_EN_OFFSET, gpio, true);
gpio_set_bit(g->base, IPROC_GPIO_PAD_RES_OFFSET, gpio,
!!(pull == GPIO_PULL_UP));
}
const gpio_ops_t iproc_gpio_ops = {
.get_direction = get_direction,
.set_direction = set_direction,
.get_value = get_value,
.set_value = set_value,
.get_pull = get_pull,
.set_pull = set_pull,
};
void iproc_gpio_init(uintptr_t base, int nr_gpios, uintptr_t pinmux_base,
uintptr_t pinconf_base)
{
iproc_gpio.base = base;
iproc_gpio.nr_gpios = nr_gpios;
/* pinmux/pinconf base is optional for some SoCs */
if (pinmux_base)
iproc_gpio.pinmux_base = pinmux_base;
if (pinconf_base)
iproc_gpio.pinconf_base = pinconf_base;
gpio_init(&iproc_gpio_ops);
}
/*
* Copyright (c) 2017 - 2020, Broadcom
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdint.h>
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <lib/mmio.h>
#include <ocotp.h>
#include <platform_def.h>
#define OTP_MAP 2
#define OTP_NUM_WORDS 2048
/*
* # of tries for OTP Status. The time to execute a command varies. The slowest
* commands are writes which also vary based on the # of bits turned on. Writing
* 0xffffffff takes ~3800 us.
*/
#define OTPC_RETRIES_US 5000
/* Sequence to enable OTP program */
#define OTPC_PROG_EN_SEQ { 0xf, 0x4, 0x8, 0xd }
/* OTPC Commands */
#define OTPC_CMD_READ 0x0
#define OTPC_CMD_OTP_PROG_ENABLE 0x2
#define OTPC_CMD_OTP_PROG_DISABLE 0x3
#define OTPC_CMD_PROGRAM 0x8
#define OTPC_CMD_ECC 0x10
#define OTPC_ECC_ADDR 0x1A
#define OTPC_ECC_VAL 0x00EC0000
/* OTPC Status Bits */
#define OTPC_STAT_CMD_DONE BIT(1)
#define OTPC_STAT_PROG_OK BIT(2)
/* OTPC register definition */
#define OTPC_MODE_REG_OFFSET 0x0
#define OTPC_MODE_REG_OTPC_MODE 0
#define OTPC_COMMAND_OFFSET 0x4
#define OTPC_COMMAND_COMMAND_WIDTH 6
#define OTPC_CMD_START_OFFSET 0x8
#define OTPC_CMD_START_START 0
#define OTPC_CPU_STATUS_OFFSET 0xc
#define OTPC_CPUADDR_REG_OFFSET 0x28
#define OTPC_CPUADDR_REG_OTPC_CPU_ADDRESS_WIDTH 16
#define OTPC_CPU_WRITE_REG_OFFSET 0x2c
#define OTPC_CMD_MASK (BIT(OTPC_COMMAND_COMMAND_WIDTH) - 1)
#define OTPC_ADDR_MASK (BIT(OTPC_CPUADDR_REG_OTPC_CPU_ADDRESS_WIDTH) - 1)
#define OTPC_MODE_REG OCOTP_REGS_BASE
struct chip_otp_cfg {
uint32_t base;
uint32_t num_words;
};
struct chip_otp_cfg ocotp_cfg = {
.base = OTPC_MODE_REG,
.num_words = 2048,
};
struct otpc_priv {
uint32_t base;
struct otpc_map *map;
int size;
int state;
};
struct otpc_priv otpc_info;
static inline void set_command(uint32_t base, uint32_t command)
{
mmio_write_32(base + OTPC_COMMAND_OFFSET, command & OTPC_CMD_MASK);
}
static inline void set_cpu_address(uint32_t base, uint32_t addr)
{
mmio_write_32(base + OTPC_CPUADDR_REG_OFFSET, addr & OTPC_ADDR_MASK);
}
static inline void set_start_bit(uint32_t base)
{
mmio_write_32(base + OTPC_CMD_START_OFFSET, 1 << OTPC_CMD_START_START);
}
static inline void reset_start_bit(uint32_t base)
{
mmio_write_32(base + OTPC_CMD_START_OFFSET, 0);
}
static inline void write_cpu_data(uint32_t base, uint32_t value)
{
mmio_write_32(base + OTPC_CPU_WRITE_REG_OFFSET, value);
}
static int poll_cpu_status(uint32_t base, uint32_t value)
{
uint32_t status;
uint32_t retries;
for (retries = 0; retries < OTPC_RETRIES_US; retries++) {
status = mmio_read_32(base + OTPC_CPU_STATUS_OFFSET);
if (status & value)
break;
udelay(1);
}
if (retries == OTPC_RETRIES_US)
return -1;
return 0;
}
static int bcm_otpc_ecc(uint32_t enable)
{
struct otpc_priv *priv = &otpc_info;
int ret;
set_command(priv->base, OTPC_CMD_ECC);
set_cpu_address(priv->base, OTPC_ECC_ADDR);
if (!enable)
write_cpu_data(priv->base, OTPC_ECC_VAL);
else
write_cpu_data(priv->base, ~OTPC_ECC_VAL);
set_start_bit(priv->base);
ret = poll_cpu_status(priv->base, OTPC_STAT_CMD_DONE);
if (ret) {
ERROR("otp ecc op error: 0x%x", ret);
return -1;
}
reset_start_bit(priv->base);
return 0;
}
/*
* bcm_otpc_read read otp data in the size of 8 byte rows.
* bytes has to be the multiple of 8.
* return -1 in error case, return read bytes in success.
*/
int bcm_otpc_read(unsigned int offset, void *val, uint32_t bytes,
uint32_t ecc_flag)
{
struct otpc_priv *priv = &otpc_info;
uint32_t *buf = val;
uint32_t bytes_read;
uint32_t address = offset / priv->map->word_size;
int i, ret;
if (!priv->state) {
ERROR("OCOTP read failed\n");
return -1;
}
bcm_otpc_ecc(ecc_flag);
for (bytes_read = 0; (bytes_read + priv->map->word_size) <= bytes;) {
set_command(priv->base, OTPC_CMD_READ);
set_cpu_address(priv->base, address++);
set_start_bit(priv->base);
ret = poll_cpu_status(priv->base, OTPC_STAT_CMD_DONE);
if (ret) {
ERROR("otp read error: 0x%x", ret);
return -1;
}
for (i = 0; i < priv->map->otpc_row_size; i++) {
*buf++ = mmio_read_32(priv->base +
priv->map->data_r_offset[i]);
bytes_read += sizeof(*buf);
}
reset_start_bit(priv->base);
}
return bytes_read;
}
int bcm_otpc_init(struct otpc_map *map)
{
struct otpc_priv *priv;
priv = &otpc_info;
priv->base = ocotp_cfg.base;
priv->map = map;
priv->size = 4 * ocotp_cfg.num_words;
/* Enable CPU access to OTPC. */
mmio_setbits_32(priv->base + OTPC_MODE_REG_OFFSET,
BIT(OTPC_MODE_REG_OTPC_MODE));
reset_start_bit(priv->base);
priv->state = 1;
VERBOSE("OTPC Initialization done\n");
return 0;
}
/*
* Copyright (c) 2017 - 2020, Broadcom
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <string.h>
#include <arch_helpers.h>
#include <common/debug.h>
/* MCU binary image structure: <header> <data>
*
* Header structure:
* <magic-start>
* <num-sections>
* {<src-offset> <src-size> <dst-addr>}*
* <magic-end>
*
* MCU data (<data>) consists of several sections of code/data, to be
* installed (copied) into MCU memories.
* Header (<header>) gives information about sections contained in <data>.
*
* The installer code iterates over sections in MCU binary.
* For each section, it copies the section into MCU memory.
*
* The header contains:
* - <magic-start> - 32-bit magic number to mark header start
* - <num-sections> - number of sections in <data>
* - <num-sections> tuples. Each tuple describes a section.
* A tuple contains three 32-bit words.
* - <magic-end> - 32-bit magic number to mark header end
*
* Each section is describes by a tuple, consisting of three 32-bit words:
* - offset of section within MCU binary (relative to beginning of <data>)
* - section size (in bytes) in MCU binary
* - target address (in MCU memory). Section is copied to this location.
*
* All fields are 32-bit unsigned integers in little endian format.
* All sizes are assumed to be 32-bit aligned.
*/
#define SCP_BIN_HEADER_MAGIC_START 0xfa587D01
#define SCP_BIN_HEADER_MAGIC_END 0xf3e06a85
int download_scp_patch(void *image, unsigned int image_size)
{
unsigned int *pheader = (unsigned int *)(image);
unsigned int header_size;
unsigned char *pdata;
void *dest;
unsigned int num_sections;
unsigned int section_src_offset;
unsigned int section_size;
if (pheader && (pheader[0] != SCP_BIN_HEADER_MAGIC_START)) {
ERROR("SCP: Could not find SCP header.\n");
return -1;
}
num_sections = pheader[1];
INFO("...Number of sections: %d\n", num_sections);
header_size = 4 * (1 + 1 + 3 * num_sections + 1);
if (image_size < header_size) {
ERROR("SCP: Wrong size.\n");
return -1;
}
if (*(pheader + header_size/4 - 1) != SCP_BIN_HEADER_MAGIC_END) {
ERROR("SCP: Could not find SCP footer.\n");
return -1;
}
VERBOSE("SCP image header validated successfully\n");
pdata = (unsigned char *)pheader + header_size;
for (pheader += 2; num_sections > 0; num_sections--) {
section_src_offset = pheader[0];
section_size = pheader[1];
dest = (void *)(unsigned long)pheader[2];
INFO("section: src:0x%x, size:%d, dst:0x%x\n",
section_src_offset, section_size, pheader[2]);
if ((section_src_offset + section_size) > image_size) {
ERROR("SCP: Section points to outside of patch.\n");
return -1;
}
/* copy from source to target section */
memcpy(dest, pdata + section_src_offset, section_size);
flush_dcache_range((uintptr_t)dest, section_size);
/* next section */
pheader += 3;
}
return 0;
}
/*
* Copyright (c) 2016-2020, Broadcom
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <string.h>
#include <common/debug.h>
#include <lib/mmio.h>
#include <sotp.h>
#include <platform_def.h>
#include <platform_sotp.h>
#ifdef USE_SOFT_SOTP
extern uint64_t soft_sotp[];
#endif
#define SOTP_PROG_CONTROL (SOTP_REGS_OTP_BASE + 0x0000)
#define SOTP_PROG_CONTROL__OTP_CPU_MODE_EN 15
#define SOTP_PROG_CONTROL__OTP_DISABLE_ECC 9
#define SOTP_PROG_CONTROL__OTP_ECC_WREN 8
#define SOTP_WRDATA_0 (SOTP_REGS_OTP_BASE + 0x0004)
#define SOTP_WRDATA_1 (SOTP_REGS_OTP_BASE + 0x0008)
#define SOTP_ADDR (SOTP_REGS_OTP_BASE + 0x000c)
#define SOTP_ADDR__OTP_ROW_ADDR_R 6
#define SOTP_ADDR_MASK 0x3FF
#define SOTP_CTRL_0 (SOTP_REGS_OTP_BASE + 0x0010)
#define SOTP_CTRL_0__START 0
#define SOTP_CTRL_0__OTP_CMD 1
#define SOTP_STATUS_0 (SOTP_REGS_OTP_BASE + 0x0018)
#define SOTP_STATUS__FDONE 3
#define SOTP_STATUS_1 (SOTP_REGS_OTP_BASE + 0x001c)
#define SOTP_STATUS_1__CMD_DONE 1
#define SOTP_STATUS_1__ECC_DET 17
#define SOTP_RDDATA_0 (SOTP_REGS_OTP_BASE + 0x0020)
#define SOTP_RDDATA_1 (SOTP_REGS_OTP_BASE + 0x0024)
#define SOTP_READ 0
#define SOTP_PROG_WORD 10
#define SOTP_STATUS__PROGOK 2
#define SOTP_PROG_ENABLE 2
#define SOTP_ROW_DATA_MASK 0xffffffff
#define SOTP_ECC_ERR_BITS_MASK 0x1ff00000000
#define SOTP_CHIP_CTRL_SW_OVERRIDE_CHIP_STATES 4
#define SOTP_CHIP_CTRL_SW_MANU_PROG 5
#define SOTP_CHIP_CTRL_SW_CID_PROG 6
#define SOTP_CHIP_CTRL_SW_AB_DEVICE 8
#define SOTP_CHIP_CTRL_SW_AB_DEV_MODE 9
#define CHIP_STATE_UNPROGRAMMED 0x1
#define CHIP_STATE_UNASSIGNED 0x2
uint64_t sotp_mem_read(uint32_t offset, uint32_t sotp_add_ecc)
{
#ifdef USE_SOFT_SOTP
(void)sotp_add_ecc;
return soft_sotp[offset];
#else
uint64_t read_data = 0;
uint64_t read_data1 = 0;
uint64_t read_data2 = 0;
/* Check for FDONE status */
while ((mmio_read_32(SOTP_STATUS_0) & BIT(SOTP_STATUS__FDONE)) !=
BIT(SOTP_STATUS__FDONE))
;
/* Enable OTP access by CPU */
mmio_setbits_32(SOTP_PROG_CONTROL,
BIT(SOTP_PROG_CONTROL__OTP_CPU_MODE_EN));
if (sotp_add_ecc == 1) {
mmio_clrbits_32(SOTP_PROG_CONTROL,
BIT(SOTP_PROG_CONTROL__OTP_DISABLE_ECC));
}
if (sotp_add_ecc == 0) {
mmio_setbits_32(SOTP_PROG_CONTROL,
BIT(SOTP_PROG_CONTROL__OTP_DISABLE_ECC));
}
mmio_write_32(SOTP_ADDR,
((offset & SOTP_ADDR_MASK) << SOTP_ADDR__OTP_ROW_ADDR_R));
mmio_write_32(SOTP_CTRL_0, (SOTP_READ << SOTP_CTRL_0__OTP_CMD));
/* Start bit to tell SOTP to send command to the OTP controller */
mmio_setbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START));
/* Wait for SOTP command done to be set */
while ((mmio_read_32(SOTP_STATUS_1) & BIT(SOTP_STATUS_1__CMD_DONE)) !=
BIT(SOTP_STATUS_1__CMD_DONE))
;
/* Clr Start bit after command done */
mmio_clrbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START));
if ((offset > SOTP_DEVICE_SECURE_CFG3_ROW) &&
(mmio_read_32(SOTP_STATUS_1) & BIT(SOTP_STATUS_1__ECC_DET))) {
ERROR("SOTP ECC ERROR Detected row offset %d\n", offset);
read_data = SOTP_ECC_ERR_DETECT;
} else {
read_data1 = (uint64_t)mmio_read_32(SOTP_RDDATA_0);
read_data1 = read_data1 & 0xFFFFFFFF;
read_data2 = (uint64_t)mmio_read_32(SOTP_RDDATA_1);
read_data2 = (read_data2 & 0x1ff) << 32;
read_data = read_data1 | read_data2;
}
/* Command done is cleared */
mmio_setbits_32(SOTP_STATUS_1, BIT(SOTP_STATUS_1__CMD_DONE));
/* disable OTP access by CPU */
mmio_clrbits_32(SOTP_PROG_CONTROL,
BIT(SOTP_PROG_CONTROL__OTP_CPU_MODE_EN));
return read_data;
#endif
}
void sotp_mem_write(uint32_t addr, uint32_t sotp_add_ecc, uint64_t wdata)
{
#ifdef USE_SOFT_SOTP
(void)sotp_add_ecc;
soft_sotp[addr] = wdata;
#else
uint32_t loop;
uint8_t prog_array[4] = { 0x0F, 0x04, 0x08, 0x0D };
uint32_t chip_state_default =
(CHIP_STATE_UNASSIGNED|CHIP_STATE_UNPROGRAMMED);
uint32_t chip_state = mmio_read_32(SOTP_REGS_SOTP_CHIP_STATES);
uint32_t chip_ctrl_default = 0;
/*
* The override settings is required to allow the customer to program
* the application specific keys into SOTP, before the conversion to
* one of the AB modes.
* At the end of write operation, the chip ctrl settings will restored
* to the state prior to write call
*/
if (chip_state & chip_state_default) {
uint32_t chip_ctrl;
chip_ctrl_default = mmio_read_32(SOTP_CHIP_CTRL);
INFO("SOTP: enable special prog mode\n");
chip_ctrl = BIT(SOTP_CHIP_CTRL_SW_OVERRIDE_CHIP_STATES) |
BIT(SOTP_CHIP_CTRL_SW_MANU_PROG) |
BIT(SOTP_CHIP_CTRL_SW_CID_PROG) |
BIT(SOTP_CHIP_CTRL_SW_AB_DEVICE);
mmio_write_32(SOTP_CHIP_CTRL, chip_ctrl);
}
/* Check for FDONE status */
while ((mmio_read_32(SOTP_STATUS_0) & BIT(SOTP_STATUS__FDONE)) !=
BIT(SOTP_STATUS__FDONE))
;
/* Enable OTP acces by CPU */
mmio_setbits_32(SOTP_PROG_CONTROL,
BIT(SOTP_PROG_CONTROL__OTP_CPU_MODE_EN));
if (addr > SOTP_DEVICE_SECURE_CFG3_ROW) {
if (sotp_add_ecc == 0) {
mmio_clrbits_32(SOTP_PROG_CONTROL,
BIT(SOTP_PROG_CONTROL__OTP_ECC_WREN));
}
if (sotp_add_ecc == 1) {
mmio_setbits_32(SOTP_PROG_CONTROL,
BIT(SOTP_PROG_CONTROL__OTP_ECC_WREN));
}
} else {
mmio_clrbits_32(SOTP_PROG_CONTROL,
BIT(SOTP_PROG_CONTROL__OTP_ECC_WREN));
}
mmio_write_32(SOTP_CTRL_0, (SOTP_PROG_ENABLE << 1));
/*
* In order to avoid unintentional writes / programming of the OTP
* array, the OTP Controller must be put into programming mode before
* it will accept program commands. This is done by writing 0xF, 0x4,
* 0x8, 0xD with program commands prior to starting the actual
* programming sequence
*/
for (loop = 0; loop < 4; loop++) {
mmio_write_32(SOTP_WRDATA_0, prog_array[loop]);
/*
* Start bit to tell SOTP to send command to the OTP controller
*/
mmio_setbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START));
/* Wait for SOTP command done to <-- be set */
while ((mmio_read_32(SOTP_STATUS_1) &
BIT(SOTP_STATUS_1__CMD_DONE)) !=
BIT(SOTP_STATUS_1__CMD_DONE))
;
/* Command done is cleared w1c */
mmio_setbits_32(SOTP_STATUS_1, BIT(SOTP_STATUS_1__CMD_DONE));
/* Clr Start bit after command done */
mmio_clrbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START));
}
/* Check for PROGOK */
while ((mmio_read_32(SOTP_STATUS_0) & 0x4) != BIT(SOTP_STATUS__PROGOK))
;
/* Set 10 bit row address */
mmio_write_32(SOTP_ADDR,
((addr & SOTP_ADDR_MASK) << SOTP_ADDR__OTP_ROW_ADDR_R));
/* Set SOTP Row data */
mmio_write_32(SOTP_WRDATA_0, (wdata & SOTP_ROW_DATA_MASK));
/* Set SOTP ECC and error bits */
mmio_write_32(SOTP_WRDATA_1, ((wdata & SOTP_ECC_ERR_BITS_MASK) >> 32));
/* Set prog_word command */
mmio_write_32(SOTP_CTRL_0, (SOTP_PROG_WORD << 1));
/* Start bit to tell SOTP to send command to the OTP controller */
mmio_setbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START));
/* Wait for SOTP command done to be set */
while ((mmio_read_32(SOTP_STATUS_1) & BIT(SOTP_STATUS_1__CMD_DONE)) !=
BIT(SOTP_STATUS_1__CMD_DONE))
;
/* Command done is cleared w1c */
mmio_setbits_32(SOTP_STATUS_1, BIT(SOTP_STATUS_1__CMD_DONE));
/* disable OTP acces by CPU */
mmio_clrbits_32(SOTP_PROG_CONTROL,
BIT(SOTP_PROG_CONTROL__OTP_CPU_MODE_EN));
/* Clr Start bit after command done */
mmio_clrbits_32(SOTP_CTRL_0, BIT(SOTP_CTRL_0__START));
if (chip_state & chip_state_default)
mmio_write_32(SOTP_CHIP_CTRL, chip_ctrl_default);
#endif
}
int sotp_read_key(uint8_t *key, size_t keysize, int start_row, int end_row)
{
int row;
uint32_t status = 0;
uint32_t status2 = 0xFFFFFFFF;
uint64_t row_data;
uint32_t data;
uint32_t *temp_key = (uint32_t *)key;
row = start_row;
while ((keysize > 0) && (row <= end_row)) {
row_data = sotp_mem_read(row, SOTP_ROW_ECC);
if (!(row_data & (SOTP_ECC_ERR_DETECT | SOTP_FAIL_BITS))) {
memcpy(temp_key++, &row_data, sizeof(uint32_t));
keysize -= sizeof(uint32_t);
data = (uint32_t)(row_data & SOTP_ROW_DATA_MASK);
status |= data;
status2 &= data;
}
row++;
}
if ((status2 == 0xFFFFFFFF) || (status == 0) || (row > end_row))
return -1;
return 0;
}
int sotp_key_erased(void)
{
uint64_t row_data;
int status = 0;
row_data = sotp_mem_read(SOTP_DEVICE_SECURE_CFG0_ROW, 0);
if (row_data & SOTP_DEVICE_SECURE_CFG0_OTP_ERASED_MASK)
status = 1;
else if (mmio_read_32(SOTP_REGS_SOTP_CHIP_STATES) &
SOTP_REGS_SOTP_CHIP_STATES_OTP_ERASED_MASK)
status = 1;
return status;
}
/*
* This function optimise the SOTP redundancy
* by considering the 00- zero and 01,10,11 - one
*/
uint32_t sotp_redundancy_reduction(uint32_t sotp_row_data)
{
uint32_t opt_data;
uint32_t opt_loop;
uint32_t temp_data;
opt_data = 0;
for (opt_loop = 0; opt_loop < 16; opt_loop = opt_loop + 1) {
temp_data = ((sotp_row_data >> (opt_loop * 2)) & 0x3);
if (temp_data != 0x0)
opt_data = (opt_data | (1 << opt_loop));
}
return opt_data;
}
/*
* Copyright (c) 2016 - 2020, Broadcom
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef SR_CHIMP_H
#define SR_CHIMP_H
#include <common/bl_common.h>
#include <common/debug.h>
#include <lib/mmio.h>
#include <platform_def.h>
#define CHIMP_WINDOW_SIZE 0x400000
#define CHIMP_ERROR_OFFSET 28
#define CHIMP_ERROR_MASK 0xf0000000
#ifndef EMULATION_SETUP
#define CHIMP_HANDSHAKE_TIMEOUT_MS 10000
#else
/*
* 1hr timeout for test in emulator
* By doing this ChiMP is given a chance to boot
* fully from the QSPI
* (on Palladium this takes upto 50 min depending on QSPI clk)
*/
#define CHIMP_HANDSHAKE_TIMEOUT_MS 3600000
#endif
#define CHIMP_BPE_MODE_ID_PATTERN (0x25000000)
#define CHIMP_BPE_MODE_ID_MASK (0x7f000000)
#define NIC_RESET_RELEASE_TIMEOUT_US (10)
/* written by M0, used by ChiMP ROM */
#define SR_IN_SMARTNIC_MODE_BIT 0
/* written by M0, used by ChiMP ROM */
#define SR_CHIMP_SECURE_BOOT_BIT 1
/* cleared by AP, set by ChiMP BC2 code */
#define SR_FLASH_ACCESS_DONE_BIT 2
#ifdef USE_CHIMP
void bcm_chimp_write(uintptr_t addr, uint32_t value);
uint32_t bcm_chimp_read(uintptr_t addr);
uint32_t bcm_chimp_read_ctrl(uint32_t offset);
void bcm_chimp_clrbits(uintptr_t addr, uint32_t bits);
void bcm_chimp_setbits(uintptr_t addr, uint32_t bits);
int bcm_chimp_is_nic_mode(void);
void bcm_chimp_fru_prog_done(bool status);
int bcm_chimp_handshake_done(void);
int bcm_chimp_wait_handshake(void);
/* Fastboot-related*/
int bcm_chimp_initiate_fastboot(int fastboot_type);
#else
static inline void bcm_chimp_write(uintptr_t addr, uint32_t value)
{
}
static inline uint32_t bcm_chimp_read(uintptr_t addr)
{
return 0;
}
static inline uint32_t bcm_chimp_read_ctrl(uint32_t offset)
{
return 0;
}
static inline void bcm_chimp_clrbits(uintptr_t addr, uint32_t bits)
{
}
static inline void bcm_chimp_setbits(uintptr_t addr, uint32_t bits)
{
}
static inline int bcm_chimp_is_nic_mode(void)
{
return 0;
}
static inline void bcm_chimp_fru_prog_done(bool status)
{
}
static inline int bcm_chimp_handshake_done(void)
{
return 0;
}
static inline int bcm_chimp_wait_handshake(void)
{
return 0;
}
static inline int bcm_chimp_initiate_fastboot(int fastboot_type)
{
return 0;
}
#endif /* USE_CHIMP */
#endif
/*
* Copyright (c) 2019-2020, Broadcom
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef FRU_H
#define FRU_H
#include <stdbool.h>
#include <stdint.h>
/* max string length */
#define FRU_MAX_STR_LEN 32
/* max number of DDR channels */
#define BCM_MAX_NR_DDR 3
/* max supported FRU table size */
#define BCM_MAX_FRU_LEN 512
/* FRU table starting offset */
#define BCM_FRU_TBL_OFFSET 0x300000
/* FRU time constants */
#define MINS_PER_DAY 1440
#define MINS_PER_HOUR 60
#define FRU_YEAR_START 1996
#define FRU_MONTH_START 1
#define FRU_DAY_START 1
#define MONTHS_PER_YEAR 12
/*
* FRU areas based on the spec
*/
enum fru_area_name {
FRU_AREA_INTERNAL = 0,
FRU_AREA_CHASSIS_INFO,
FRU_AREA_BOARD_INFO,
FRU_AREA_PRODUCT_INFO,
FRU_AREA_MRECORD_INFO,
FRU_MAX_NR_AREAS
};
/*
* FRU area information
*
* @use: indicate this area is being used
* @version: format version
* @offset: offset of this area from the beginning of the FRU table
* @len: total length of the area
*/
struct fru_area_info {
bool use;
uint8_t version;
unsigned int offset;
unsigned int len;
};
/*
* DDR MCB information
*
* @idx: DDR channel index
* @size_mb: DDR size of this channel in MB
* @ref_id: DDR MCB reference ID
*/
struct ddr_mcb {
unsigned int idx;
unsigned int size_mb;
uint32_t ref_id;
};
/*
* DDR information
*
* @ddr_info: array that contains MCB related info for each channel
*/
struct ddr_info {
struct ddr_mcb mcb[BCM_MAX_NR_DDR];
};
/*
* FRU board area information
*
* @lang: Language code
* @mfg_date: Manufacturing date
* @manufacturer: Manufacturer
* @product_name: Product name
* @serial_number: Serial number
* @part_number: Part number
* @file_id: FRU file ID
*/
struct fru_board_info {
unsigned char lang;
unsigned int mfg_date;
unsigned char manufacturer[FRU_MAX_STR_LEN];
unsigned char product_name[FRU_MAX_STR_LEN];
unsigned char serial_number[FRU_MAX_STR_LEN];
unsigned char part_number[FRU_MAX_STR_LEN];
unsigned char file_id[FRU_MAX_STR_LEN];
};
/*
* FRU manufacture date in human readable format
*/
struct fru_time {
unsigned int min;
unsigned int hour;
unsigned int day;
unsigned int month;
unsigned int year;
};
#ifdef USE_FRU
int fru_validate(uint8_t *data, struct fru_area_info *fru_area);
int fru_parse_ddr(uint8_t *data, struct fru_area_info *area,
struct ddr_info *ddr);
int fru_parse_board(uint8_t *data, struct fru_area_info *area,
struct fru_board_info *board);
void fru_format_time(unsigned int min, struct fru_time *tm);
#else
static inline int fru_validate(uint8_t *data, struct fru_area_info *fru_area)
{
return -1;
}
static inline int fru_parse_ddr(uint8_t *data, struct fru_area_info *area,
struct ddr_info *ddr)
{
return -1;
}
static inline int fru_parse_board(uint8_t *data, struct fru_area_info *area,
struct fru_board_info *board)
{
return -1;
}
static inline void fru_format_time(unsigned int min, struct fru_time *tm)
{
}
#endif /* USE_FRU */
#endif /* FRU_H */
/*
* Copyright (c) 2019-2020, Broadcom
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef IPROC_GPIO_H
#define IPROC_GPIO_H
#ifdef USE_GPIO
void iproc_gpio_init(uintptr_t base, int nr_gpios, uintptr_t pinmux_base,
uintptr_t pinconf_base);
#else
static void iproc_gpio_init(uintptr_t base, int nr_gpios, uintptr_t pinmux_base,
uintptr_t pinconf_base)
{
}
#endif /* IPROC_GPIO */
#endif /* IPROC_GPIO_H */
/*
* Copyright (c) 2016 - 2020, Broadcom
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef OCOTP_H
#define OCOTP_H
#include <stdint.h>
struct otpc_map {
/* in words. */
uint32_t otpc_row_size;
/* 128 bit row / 4 words support. */
uint16_t data_r_offset[4];
/* 128 bit row / 4 words support. */
uint16_t data_w_offset[4];
int word_size;
int stride;
};
int bcm_otpc_init(struct otpc_map *map);
int bcm_otpc_read(unsigned int offset, void *val, uint32_t bytes,
uint32_t ecc_flag);
#endif /* OCOTP_H */
/*
* Copyright (c) 2017 - 2020, Broadcom
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef SCP_H_
#define SCP_H
#include <stdint.h>
int download_scp_patch(void *image, unsigned int image_size);
#endif /* SCP_H */
/*
* Copyright (c) 2016-2020, Broadcom
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef SOTP_H
#define SOTP_H
#include <stddef.h>
#include <stdint.h>
#include <platform_sotp.h>
#define SOTP_ROW_NO_ECC 0
#define SOTP_ROW_ECC 1
#define SOTP_STATUS_1 (SOTP_REGS_OTP_BASE + 0x001c)
#define SOTP_FAIL_BITS 0x18000000000
#define SOTP_ECC_ERR_DETECT 0x8000000000000000
#define SOTP_REGS_SOTP_CHIP_STATES (SOTP_REGS_OTP_BASE + 0x0028)
#define SOTP_REGS_OTP_WR_LOCK (SOTP_REGS_OTP_BASE + 0x0038)
#define SOTP_CHIP_STATES_MANU_DEBUG_MASK (1 << 8)
#define SOTP_DEVICE_SECURE_CFG0_OTP_ERASED_MASK (3 << 16)
#define SOTP_REGS_SOTP_CHIP_STATES_OTP_ERASED_MASK (1 << 16)
#define SOTP_DEVICE_SECURE_CFG0_CID_MASK (3 << 2)
#define SOTP_DEVICE_SECURE_CFG0_AB_MASK (3 << 6)
#define SOTP_DEVICE_SECURE_CFG0_DEV_MASK (3 << 8)
#define SOTP_BOOT_SOURCE_SHIFT 8
/* bits 14 and 15 */
#define SOTP_BOOT_SOURCE_ENABLE_MASK (0xC0 << SOTP_BOOT_SOURCE_SHIFT)
/* bits 8 to 13 */
#define SOTP_BOOT_SOURCE_BITS0 (0x03 << SOTP_BOOT_SOURCE_SHIFT)
#define SOTP_BOOT_SOURCE_BITS1 (0x0C << SOTP_BOOT_SOURCE_SHIFT)
#define SOTP_BOOT_SOURCE_BITS2 (0x30 << SOTP_BOOT_SOURCE_SHIFT)
#define SOTP_BOOT_SOURCE_MASK (0x3F << SOTP_BOOT_SOURCE_SHIFT)
#define SOTP_ATF_CFG_ROW_ID SOTP_DEVICE_SECURE_CFG2_ROW
/* bits 28 and 29 */
#define SOTP_SBL_MASK (3 << 28)
/* bits 30 and 31 */
#define SOTP_ATF_NVCOUNTER_ENABLE_MASK ((uint64_t)3 << 30)
/* bits 32 and 33 */
#define SOTP_ATF_WATCHDOG_ENABLE_MASK ((uint64_t)3 << 32)
/* bits 34 and 35 */
#define SOTP_ATF_PLL_ON ((uint64_t)3 << 34)
/* bits 36 and 37 */
#define SOTP_ATF_RESET_RETRY ((uint64_t)3 << 36)
/* bits 38 to 40 */
#define SOTP_ATF_LOG_LEVEL_SHIFT 38
#define SOTP_ATF_LOG_LEVEL ((uint64_t)7 << SOTP_ATF_LOG_LEVEL_SHIFT)
#define SOTP_ATF2_CFG_ROW_ID SOTP_DEVICE_SECURE_CFG3_ROW
/* bits 16 and 17 */
#define SOTP_ROMKEY_MASK (3 << 16)
/* bits 18 and 19 */
#define SOTP_EC_EN_MASK (3 << 18)
#define SOTP_ENC_DEV_TYPE_AB_DEV ((uint64_t)0x19999800000)
#define SOTP_ENC_DEV_TYPE_MASK ((uint64_t)0x1ffff800000)
uint64_t sotp_mem_read(uint32_t offset, uint32_t sotp_add_ecc);
void sotp_mem_write(uint32_t addr, uint32_t sotp_add_ecc, uint64_t wdata);
int sotp_read_key(uint8_t *key, size_t keysize, int start_row, int end_row);
int sotp_key_erased(void);
uint32_t sotp_redundancy_reduction(uint32_t sotp_row_data);
#endif
/*
* Copyright (c) 2018 - 2020, Broadcom
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef BCM_ELOG_H
#define BCM_ELOG_H
#ifndef __ASSEMBLER__
#include <stdint.h>
#if defined(BCM_ELOG) && (defined(IMAGE_BL2) || defined(IMAGE_BL31))
int bcm_elog_init(void *base, uint32_t size, unsigned int level);
void bcm_elog_exit(void);
int bcm_elog_copy_log(void *dst, uint32_t max_size);
void bcm_elog(const char *fmt, ...);
#else
static inline int bcm_elog_init(void *base, uint32_t size,
unsigned int level)
{
return 0;
}
static inline void bcm_elog_exit(void)
{
}
static inline int bcm_elog_copy_log(void *dst, uint32_t max_size)
{
return 0;
}
static inline void bcm_elog(const char *fmt, ...)
{
}
#endif /* BCM_ELOG */
#endif /* __ASSEMBLER__ */
#endif /* BCM_ELOG_H */
/*
* 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);
}
/*
* 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");
}
/*
* 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 */
/*
* Copyright 2015 - 2020 Broadcom
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.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%llx\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);
}
......@@ -28,6 +28,17 @@ SYSCNT_FREQ := $(GENTIMER_ACTUAL_CLOCK)
$(eval $(call add_define,SYSCNT_FREQ))
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
......@@ -36,6 +47,7 @@ $(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
......@@ -45,6 +57,29 @@ 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
# Use CRMU SRAM from iHOST
ifneq (${USE_CRMU_SRAM},)
$(eval $(call add_define,USE_CRMU_SRAM))
......@@ -63,15 +98,18 @@ PLAT_INCLUDES += -Iplat/brcm/board/common \
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
BL2_SOURCES += plat/brcm/common/brcm_bl2_mem_params_desc.c \
......@@ -82,6 +120,88 @@ 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}
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 '${MBEDTLS_DIR}')
ifneq (${MBEDTLS_CHECK},)
$(info Found mbedTLS at ${MBEDTLS_DIR})
PLAT_INCLUDES += -I${MBEDTLS_DIR}/include/mbedtls
# Specify mbedTLS configuration file
MBEDTLS_CONFIG_FILE := "<brcm_mbedtls_config.h>"
# 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.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))
......
/*
* 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);
}
/*
* 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
......@@ -7,6 +7,56 @@
#ifndef CMN_PLAT_DEF_H
#define CMN_PLAT_DEF_H
#include <bcm_elog.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)
/* Print file and line number on assert */
#define PLAT_LOG_LEVEL_ASSERT LOG_LEVEL_INFO
......
......@@ -6,14 +6,65 @@
#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)
{
/* For now return BOOT_SOURCE_QSPI */
return BOOT_SOURCE_QSPI;
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)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment