mirror of
https://github.com/CTCaer/switch-l4t-atf.git
synced 2024-11-24 02:09:46 +00:00
Add BL2 support for Broadcom stingray platform
Change-Id: I5daa3f2b4b9d85cb857547a588571a9aa8ad05c2 Signed-off-by: Sheetal Tigadoli <sheetal.tigadoli@broadcom.com>
This commit is contained in:
parent
9a40c0fba6
commit
f29d1e0c72
232
drivers/brcm/iproc_gpio.c
Normal file
232
drivers/brcm/iproc_gpio.c
Normal file
@ -0,0 +1,232 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
204
drivers/brcm/ocotp.c
Normal file
204
drivers/brcm/ocotp.c
Normal file
@ -0,0 +1,204 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
100
drivers/brcm/scp.c
Normal file
100
drivers/brcm/scp.c
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
323
drivers/brcm/sotp.c
Normal file
323
drivers/brcm/sotp.c
Normal file
@ -0,0 +1,323 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
94
include/drivers/brcm/chimp.h
Normal file
94
include/drivers/brcm/chimp.h
Normal file
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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
|
144
include/drivers/brcm/fru.h
Normal file
144
include/drivers/brcm/fru.h
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* 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 */
|
20
include/drivers/brcm/iproc_gpio.h
Normal file
20
include/drivers/brcm/iproc_gpio.h
Normal file
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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 */
|
27
include/drivers/brcm/ocotp.h
Normal file
27
include/drivers/brcm/ocotp.h
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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 */
|
14
include/drivers/brcm/scp.h
Normal file
14
include/drivers/brcm/scp.h
Normal file
@ -0,0 +1,14 @@
|
||||
/*
|
||||
* 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 */
|
71
include/drivers/brcm/sotp.h
Normal file
71
include/drivers/brcm/sotp.h
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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
|
38
include/plat/brcm/common/bcm_elog.h
Normal file
38
include/plat/brcm/common/bcm_elog.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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 */
|
268
plat/brcm/board/common/bcm_elog.c
Normal file
268
plat/brcm/board/common/bcm_elog.c
Normal file
@ -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);
|
||||
}
|
133
plat/brcm/board/common/bcm_elog_ddr.c
Normal file
133
plat/brcm/board/common/bcm_elog_ddr.c
Normal file
@ -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");
|
||||
}
|
107
plat/brcm/board/common/bcm_elog_ddr.h
Normal file
107
plat/brcm/board/common/bcm_elog_ddr.h
Normal file
@ -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 */
|
624
plat/brcm/board/common/board_arm_trusted_boot.c
Normal file
624
plat/brcm/board/common/board_arm_trusted_boot.c
Normal file
@ -0,0 +1,624 @@
|
||||
/*
|
||||
* 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))
|
||||
|
12
plat/brcm/board/common/brcm_mbedtls.c
Normal file
12
plat/brcm/board/common/brcm_mbedtls.c
Normal file
@ -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);
|
||||
}
|
37
plat/brcm/board/common/chip_id.h
Normal file
37
plat/brcm/board/common/chip_id.h
Normal file
@ -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
|
@ -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)
|
||||
|
40
plat/brcm/board/common/sbl_util.c
Normal file
40
plat/brcm/board/common/sbl_util.c
Normal file
@ -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;
|
||||
}
|
19
plat/brcm/board/common/sbl_util.h
Normal file
19
plat/brcm/board/common/sbl_util.h
Normal file
@ -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 */
|
@ -14,3 +14,9 @@ include plat/brcm/board/stingray/bcm958742t.mk
|
||||
ifneq (${BL33_OVERRIDE_LOAD_ADDR},)
|
||||
$(eval $(call add_define_val,BL33_OVERRIDE_LOAD_ADDR,0xFF000000))
|
||||
endif
|
||||
|
||||
# Nitro DDR secure memory
|
||||
# Nitro FW and config 0x8AE00000 - 0x8B000000
|
||||
# Nitro Crash dump 0x8B000000 - 0x8D000000
|
||||
DDR_NITRO_SECURE_REGION_START := 0x8AE00000
|
||||
DDR_NITRO_SECURE_REGION_END := 0x8D000000
|
||||
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020, Broadcom
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef BOARD_FAMILY_H
|
||||
#define BOARD_FAMILY_H
|
||||
|
||||
#if defined(DRIVER_SPD_ENABLE) && !defined(DRIVER_SPD_SPOOF)
|
||||
#include <spd.h>
|
||||
#endif
|
||||
|
||||
#ifdef USE_GPIO
|
||||
/* max number of supported GPIOs to construct the bitmap for board detection */
|
||||
#define MAX_NR_GPIOS 4
|
||||
|
||||
/* max GPIO bitmap value */
|
||||
#define MAX_GPIO_BITMAP_VAL (BIT(MAX_NR_GPIOS) - 1)
|
||||
#endif
|
||||
|
||||
struct mcb_ref_group {
|
||||
uint32_t mcb_ref;
|
||||
unsigned int *mcb_cfg;
|
||||
};
|
||||
|
||||
#define MCB_REF_GROUP(ref) \
|
||||
{ \
|
||||
.mcb_ref = 0x ## ref, \
|
||||
.mcb_cfg = mcb_ ## ref, \
|
||||
}
|
||||
|
||||
#endif
|
302
plat/brcm/board/stingray/driver/ext_sram_init/ext_sram_init.c
Normal file
302
plat/brcm/board/stingray/driver/ext_sram_init/ext_sram_init.c
Normal file
@ -0,0 +1,302 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2020, Broadcom
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <arch_helpers.h>
|
||||
#include <common/bl_common.h>
|
||||
#include <common/debug.h>
|
||||
#include <drivers/delay_timer.h>
|
||||
#include <lib/mmio.h>
|
||||
|
||||
#include <platform_def.h>
|
||||
|
||||
static void brcm_stingray_pnor_pinmux_init(void)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
INFO(" - pnor pinmux init start.\n");
|
||||
|
||||
/* Set PNOR_ADV_N_MODE_SEL_CONTROL.fsel = 0x2 */
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2dc),
|
||||
MODE_SEL_CONTROL_FSEL_MASK,
|
||||
MODE_SEL_CONTROL_FSEL_MODE2);
|
||||
|
||||
/* Set PNOR_BAA_N_MODE_SEL_CONTROL.fsel = 0x2 */
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2e0),
|
||||
MODE_SEL_CONTROL_FSEL_MASK,
|
||||
MODE_SEL_CONTROL_FSEL_MODE2);
|
||||
|
||||
/* Set PNOR_BLS_0_N_MODE_SEL_CONTROL.fsel = 0x2 */
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2e4),
|
||||
MODE_SEL_CONTROL_FSEL_MASK,
|
||||
MODE_SEL_CONTROL_FSEL_MODE2);
|
||||
|
||||
/* Set PNOR_BLS_1_N_MODE_SEL_CONTROL.fsel = 0x2 */
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2e8),
|
||||
MODE_SEL_CONTROL_FSEL_MASK,
|
||||
MODE_SEL_CONTROL_FSEL_MODE2);
|
||||
|
||||
/* Set PNOR_CRE_MODE_SEL_CONTROL.fsel = 0x2 */
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2ec),
|
||||
MODE_SEL_CONTROL_FSEL_MASK,
|
||||
MODE_SEL_CONTROL_FSEL_MODE2);
|
||||
|
||||
/* Set PNOR_CS_2_N_MODE_SEL_CONTROL.fsel = 0x2 */
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2f0),
|
||||
MODE_SEL_CONTROL_FSEL_MASK,
|
||||
MODE_SEL_CONTROL_FSEL_MODE2);
|
||||
|
||||
/* Set PNOR_CS_1_N_MODE_SEL_CONTROL.fsel = 0x2 */
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2f4),
|
||||
MODE_SEL_CONTROL_FSEL_MASK,
|
||||
MODE_SEL_CONTROL_FSEL_MODE2);
|
||||
|
||||
/* Set PNOR_CS_0_N_MODE_SEL_CONTROL.fsel = 0x2 */
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2f8),
|
||||
MODE_SEL_CONTROL_FSEL_MASK,
|
||||
MODE_SEL_CONTROL_FSEL_MODE2);
|
||||
|
||||
/* Set PNOR_WE_N_MODE_SEL_CONTROL.fsel = 0x2 */
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2fc),
|
||||
MODE_SEL_CONTROL_FSEL_MASK,
|
||||
MODE_SEL_CONTROL_FSEL_MODE2);
|
||||
|
||||
/* Set PNOR_OE_N_MODE_SEL_CONTROL.fsel = 0x2 */
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x300),
|
||||
MODE_SEL_CONTROL_FSEL_MASK,
|
||||
MODE_SEL_CONTROL_FSEL_MODE2);
|
||||
|
||||
/* Set PNOR_INTR_MODE_SEL_CONTROL.fsel = 0x2 */
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x304),
|
||||
MODE_SEL_CONTROL_FSEL_MASK,
|
||||
MODE_SEL_CONTROL_FSEL_MODE2);
|
||||
|
||||
/* Set PNOR_DAT_x_MODE_SEL_CONTROL.fsel = 0x2 */
|
||||
for (i = 0; i < 0x40; i += 0x4) {
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x308 + i),
|
||||
MODE_SEL_CONTROL_FSEL_MASK,
|
||||
MODE_SEL_CONTROL_FSEL_MODE2);
|
||||
}
|
||||
|
||||
/* Set NAND_CE1_N_MODE_SEL_CONTROL.fsel = 0x2 */
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x348),
|
||||
MODE_SEL_CONTROL_FSEL_MASK,
|
||||
MODE_SEL_CONTROL_FSEL_MODE2);
|
||||
|
||||
/* Set NAND_CE0_N_MODE_SEL_CONTROL.fsel = 0x2 */
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x34c),
|
||||
MODE_SEL_CONTROL_FSEL_MASK,
|
||||
MODE_SEL_CONTROL_FSEL_MODE2);
|
||||
|
||||
/* Set NAND_WE_N_MODE_SEL_CONTROL.fsel = 0x2 */
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x350),
|
||||
MODE_SEL_CONTROL_FSEL_MASK,
|
||||
MODE_SEL_CONTROL_FSEL_MODE2);
|
||||
|
||||
/* Set NAND_WP_N_MODE_SEL_CONTROL.fsel = 0x2 */
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x354),
|
||||
MODE_SEL_CONTROL_FSEL_MASK,
|
||||
MODE_SEL_CONTROL_FSEL_MODE2);
|
||||
|
||||
/* Set NAND_RE_N_MODE_SEL_CONTROL.fsel = 0x2 */
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x358),
|
||||
MODE_SEL_CONTROL_FSEL_MASK,
|
||||
MODE_SEL_CONTROL_FSEL_MODE2);
|
||||
|
||||
/* Set NAND_RDY_BSY_N_MODE_SEL_CONTROL.fsel = 0x2 */
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x35c),
|
||||
MODE_SEL_CONTROL_FSEL_MASK,
|
||||
MODE_SEL_CONTROL_FSEL_MODE2);
|
||||
|
||||
/* Set NAND_IOx_0_MODE_SEL_CONTROL.fsel = 0x2 */
|
||||
for (i = 0; i < 0x40; i += 0x4) {
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x360 + i),
|
||||
MODE_SEL_CONTROL_FSEL_MASK,
|
||||
MODE_SEL_CONTROL_FSEL_MODE2);
|
||||
}
|
||||
|
||||
/* Set NAND_ALE_MODE_SEL_CONTROL.fsel = 0x2 */
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x3a0),
|
||||
MODE_SEL_CONTROL_FSEL_MASK,
|
||||
MODE_SEL_CONTROL_FSEL_MODE2);
|
||||
|
||||
/* Set NAND_CLE_MODE_SEL_CONTROL.fsel = 0x2 */
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x3a4),
|
||||
MODE_SEL_CONTROL_FSEL_MASK,
|
||||
MODE_SEL_CONTROL_FSEL_MODE2);
|
||||
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x40), (7 << 1), 0x8);
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x44), (7 << 1), 0x8);
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x48), (7 << 1), 0x8);
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x4c), (7 << 1), 0x8);
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x50), (7 << 1), 0x8);
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x54), (7 << 1), 0x8);
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x58), (7 << 1), 0x8);
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x5c), (7 << 1), 0x8);
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x60), (7 << 1), 0x8);
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x64), (7 << 1), 0x8);
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x68), (7 << 1), 0x8);
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x6c), (7 << 1), 0x8);
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x70), (7 << 1), 0x8);
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x74), (7 << 1), 0x8);
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x78), (7 << 1), 0x8);
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x7c), (7 << 1), 0x8);
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x80), (7 << 1), 0x8);
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x84), (7 << 1), 0x8);
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x88), (7 << 1), 0x8);
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x8c), (7 << 1), 0x8);
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x90), (7 << 1), 0x8);
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x94), (7 << 1), 0x8);
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x98), (7 << 1), 0x8);
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x9c), (7 << 1), 0x8);
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0xa0), (7 << 1), 0x8);
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0xa4), (7 << 1), 0x8);
|
||||
mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0xa8), (7 << 1), 0x8);
|
||||
|
||||
INFO(" - pnor pinmux init done.\n");
|
||||
}
|
||||
|
||||
#if BL2_TEST_EXT_SRAM
|
||||
#define SRAM_CHECKS_GRANUL 0x100000
|
||||
#define SRAM_CHECKS_CNT 8
|
||||
static unsigned int sram_checks[SRAM_CHECKS_CNT] = {
|
||||
/* offset, magic */
|
||||
0xd00dfeed,
|
||||
0xfadebabe,
|
||||
0xc001d00d,
|
||||
0xa5a5b5b5,
|
||||
0x5a5a5b5b,
|
||||
0xc5c5d5d5,
|
||||
0x5c5c5d5d,
|
||||
0xe5e5f5f5,
|
||||
};
|
||||
#endif
|
||||
|
||||
static void brcm_stingray_pnor_sram_init(void)
|
||||
{
|
||||
unsigned int val, tmp;
|
||||
#if BL2_TEST_EXT_SRAM
|
||||
unsigned int off, i;
|
||||
#endif
|
||||
INFO(" - pnor sram init start.\n");
|
||||
|
||||
/* Enable PNOR Clock */
|
||||
INFO(" -- enable pnor clock\n");
|
||||
mmio_write_32((uintptr_t)(PNOR_IDM_IO_CONTROL_DIRECT), 0x1);
|
||||
udelay(500);
|
||||
|
||||
/* Reset PNOR */
|
||||
INFO(" -- reset pnor\n");
|
||||
mmio_setbits_32((uintptr_t)(PNOR_IDM_IO_RESET_CONTROL), 0x1);
|
||||
udelay(500);
|
||||
mmio_clrbits_32((uintptr_t)(PNOR_IDM_IO_RESET_CONTROL), 0x1);
|
||||
udelay(500);
|
||||
|
||||
/* Configure slave address to chip-select mapping */
|
||||
INFO(" -- configure pnor slave address to chip-select mapping\n");
|
||||
/* 0x74000000-0x75ffffff => CS0 (32MB) */
|
||||
val = (0xfe << PNOR_ICFG_CS_x_MASK0_SHIFT);
|
||||
val |= (0x74);
|
||||
mmio_write_32((uintptr_t)(PNOR_ICFG_CS_0), val);
|
||||
/* 0x76000000-0x77ffffff => CS1 (32MB) */
|
||||
val = (0xfe << PNOR_ICFG_CS_x_MASK0_SHIFT);
|
||||
val |= (0x76);
|
||||
mmio_write_32((uintptr_t)(PNOR_ICFG_CS_1), val);
|
||||
/* 0xffffffff-0xffffffff => CS2 (0MB) */
|
||||
val = (0x00 << PNOR_ICFG_CS_x_MASK0_SHIFT);
|
||||
val |= (0xff);
|
||||
mmio_write_32((uintptr_t)(PNOR_ICFG_CS_2), val);
|
||||
|
||||
/* Print PNOR ID */
|
||||
tmp = 0x0;
|
||||
val = mmio_read_32((uintptr_t)(PNOR_REG_PERIPH_ID0));
|
||||
tmp |= (val & PNOR_REG_PERIPH_IDx_MASK);
|
||||
val = mmio_read_32((uintptr_t)(PNOR_REG_PERIPH_ID1));
|
||||
tmp |= ((val & PNOR_REG_PERIPH_IDx_MASK) << 8);
|
||||
val = mmio_read_32((uintptr_t)(PNOR_REG_PERIPH_ID2));
|
||||
tmp |= ((val & PNOR_REG_PERIPH_IDx_MASK) << 16);
|
||||
val = mmio_read_32((uintptr_t)(PNOR_REG_PERIPH_ID3));
|
||||
tmp |= ((val & PNOR_REG_PERIPH_IDx_MASK) << 24);
|
||||
INFO(" -- pnor primecell_id = 0x%x\n", tmp);
|
||||
|
||||
/* PNOR set_cycles */
|
||||
#ifdef EMULATION_SETUP
|
||||
val = 0x00129A44;
|
||||
#else
|
||||
val = 0x00125954; /* 0x00002DEF; */
|
||||
#endif
|
||||
mmio_write_32((uintptr_t)(PNOR_REG_SET_CYCLES), val);
|
||||
INFO(" -- pnor set_cycles = 0x%x\n", val);
|
||||
|
||||
/* PNOR set_opmode */
|
||||
val = 0x0;
|
||||
#ifdef EMULATION_SETUP
|
||||
/* TODO: Final values to be provided by DV folks */
|
||||
val &= ~(0x7 << 7); /* set_wr_bl */
|
||||
val &= ~(0x7 << 3); /* set_rd_bl */
|
||||
val &= ~(0x3);
|
||||
val |= (0x1); /* set_mw */
|
||||
#else
|
||||
/* TODO: Final values to be provided by DV folks */
|
||||
val &= ~(0x7 << 7); /* set_wr_bl */
|
||||
val &= ~(0x7 << 3); /* set_rd_bl */
|
||||
val &= ~(0x3);
|
||||
val |= (0x1); /* set_mw */
|
||||
#endif
|
||||
mmio_write_32((uintptr_t)(PNOR_REG_SET_OPMODE), val);
|
||||
INFO(" -- pnor set_opmode = 0x%x\n", val);
|
||||
|
||||
#ifndef EMULATION_SETUP
|
||||
/* Actual SRAM chip will require self-refresh */
|
||||
val = 0x1;
|
||||
mmio_write_32((uintptr_t)(PNOR_REG_REFRESH_0), val);
|
||||
INFO(" -- pnor refresh_0 = 0x%x\n", val);
|
||||
#endif
|
||||
|
||||
#if BL2_TEST_EXT_SRAM
|
||||
/* Check PNOR SRAM access */
|
||||
for (off = 0; off < NOR_SIZE; off += SRAM_CHECKS_GRANUL) {
|
||||
i = (off / SRAM_CHECKS_GRANUL) % SRAM_CHECKS_CNT;
|
||||
val = sram_checks[i];
|
||||
INFO(" -- pnor sram write addr=0x%lx value=0x%lx\n",
|
||||
(unsigned long)(NOR_BASE_ADDR + off),
|
||||
(unsigned long)val);
|
||||
mmio_write_32((uintptr_t)(NOR_BASE_ADDR + off), val);
|
||||
}
|
||||
tmp = 0;
|
||||
for (off = 0; off < NOR_SIZE; off += SRAM_CHECKS_GRANUL) {
|
||||
i = (off / SRAM_CHECKS_GRANUL) % SRAM_CHECKS_CNT;
|
||||
val = mmio_read_32((uintptr_t)(NOR_BASE_ADDR + off));
|
||||
INFO(" -- pnor sram read addr=0x%lx value=0x%lx\n",
|
||||
(unsigned long)(NOR_BASE_ADDR + off),
|
||||
(unsigned long)val);
|
||||
if (val == sram_checks[i])
|
||||
tmp++;
|
||||
}
|
||||
INFO(" -- pnor sram checks pass=%d total=%d\n",
|
||||
tmp, (NOR_SIZE / SRAM_CHECKS_GRANUL));
|
||||
|
||||
if (tmp != (NOR_SIZE / SRAM_CHECKS_GRANUL)) {
|
||||
INFO(" - pnor sram init failed.\n");
|
||||
while (1)
|
||||
;
|
||||
} else {
|
||||
INFO(" - pnor sram init done.\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void ext_sram_init(void)
|
||||
{
|
||||
INFO("%s start.\n", __func__);
|
||||
|
||||
brcm_stingray_pnor_pinmux_init();
|
||||
|
||||
brcm_stingray_pnor_sram_init();
|
||||
|
||||
INFO("%s done.\n", __func__);
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2020, Broadcom
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef EXT_SRAM_INIT_H
|
||||
#define EXT_SRAM_INIT_H
|
||||
|
||||
void ext_sram_init(void);
|
||||
#endif
|
375
plat/brcm/board/stingray/driver/swreg.c
Normal file
375
plat/brcm/board/stingray/driver/swreg.c
Normal file
@ -0,0 +1,375 @@
|
||||
/*
|
||||
* Copyright (c) 2017 - 2020, Broadcom
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <common/debug.h>
|
||||
#include <drivers/delay_timer.h>
|
||||
#include <lib/mmio.h>
|
||||
|
||||
#include <sr_utils.h>
|
||||
#include <swreg.h>
|
||||
|
||||
#define MIN_VOLT 760000
|
||||
#define MAX_VOLT 1060000
|
||||
|
||||
#define BSTI_WRITE 0x1
|
||||
#define BSTI_READ 0x2
|
||||
#define BSTI_COMMAND_TA 0x2
|
||||
#define BSTI_COMMAND_DATA 0xFF
|
||||
#define BSTI_CONTROL_VAL 0x81
|
||||
#define BSTI_CONTROL_BUSY 0x100
|
||||
#define BSTI_TOGGLE_BIT 0x2
|
||||
#define BSTI_CONFI_DONE_MASK 0xFFFFFFFD
|
||||
#define BSTI_REG_DATA_MASK 0xFFFF
|
||||
#define BSTI_CMD(sb, op, pa, ra, ta, data) \
|
||||
((((sb) & 0x3) << 30) | (((op) & 0x3) << 28) | \
|
||||
(((pa) & 0x1F) << 23) | (((ra) & 0x1F) << 18) | \
|
||||
(((ta) & 0x3) << 16) | (data))
|
||||
|
||||
#define PHY_REG0 0x0
|
||||
#define PHY_REG1 0x1
|
||||
#define PHY_REG4 0x4
|
||||
#define PHY_REG5 0x5
|
||||
#define PHY_REG6 0x6
|
||||
#define PHY_REG7 0x7
|
||||
#define PHY_REGC 0xc
|
||||
|
||||
#define IHOST_VDDC_DATA 0x560
|
||||
#define DDR_CORE_DATA 0x2560
|
||||
#define UPDATE_POS_EDGE(data, set) ((data) | ((set) << 1))
|
||||
|
||||
/*
|
||||
* Formula for SR A2 reworked board:
|
||||
* step = ((vol/(1.4117 * 0.98)) - 500000)/3125
|
||||
* where,
|
||||
* vol - input voltage
|
||||
* 500000 - Reference voltage
|
||||
* 3125 - one step value
|
||||
*/
|
||||
#define A2_VOL_REF 500000
|
||||
#define ONE_STEP_VALUE 3125
|
||||
#define VOL_DIV(vol) (((vol*10000ull)/(14117*98ull)) * 100ull)
|
||||
#define STEP_VALUE(vol) \
|
||||
((((((VOL_DIV(vol)) - A2_VOL_REF) / ONE_STEP_VALUE) & 0xFF) << 8) | 4)
|
||||
|
||||
#define B0_VOL_REF ((500000/100)*98)
|
||||
#define B0_ONE_STEP_VALUE 3125
|
||||
/*
|
||||
* Formula for SR B0 chip for IHOST12/03 and VDDC_CORE
|
||||
* step = ((vol/1.56) - (500000 * 0.98))/3125
|
||||
* where,
|
||||
* vol - input voltage
|
||||
* 500000 - Reference voltage
|
||||
* 3125 - one step value
|
||||
*/
|
||||
#define B0_VOL_DIV(vol) (((vol)*100ull)/156)
|
||||
#define B0_STEP_VALUE(vol) \
|
||||
((((((B0_VOL_DIV(vol)) - B0_VOL_REF) / B0_ONE_STEP_VALUE) \
|
||||
& 0xFF) << 8) | 4)
|
||||
|
||||
/*
|
||||
* Formula for SR B0 chip for DDR-CORE
|
||||
* step = ((vol/1) - (500000 * 0.98))/3125
|
||||
* where,
|
||||
* vol - input voltage
|
||||
* 500000 - Reference voltage
|
||||
* 3125 - one step value
|
||||
*/
|
||||
#define B0_DDR_VDDC_VOL_DIV(vol) ((vol)/1)
|
||||
#define B0_DDR_VDDC_STEP_VALUE(vol) \
|
||||
((((((B0_DDR_VDDC_VOL_DIV(vol)) - B0_VOL_REF) / B0_ONE_STEP_VALUE) \
|
||||
& 0xFF) << 8) | 4)
|
||||
|
||||
#define MAX_SWREG_CNT 8
|
||||
#define MAX_ADDR_PER_SWREG 16
|
||||
#define MAX_REG_ADDR 0xF
|
||||
#define MIN_REG_ADDR 0x0
|
||||
|
||||
static const char *sw_reg_name[MAX_SWREG_CNT] = {
|
||||
"DDR_VDDC",
|
||||
"IHOST03",
|
||||
"IHOST12",
|
||||
"IHOST_ARRAY",
|
||||
"DDRIO_SLAVE",
|
||||
"VDDC_CORE",
|
||||
"VDDC1",
|
||||
"DDRIO_MASTER"
|
||||
};
|
||||
|
||||
/* firmware values for all SWREG for 3.3V input operation */
|
||||
static const uint16_t swreg_fm_data_bx[MAX_SWREG_CNT][MAX_ADDR_PER_SWREG] = {
|
||||
/* DDR logic: Power Domains independent of 12v or 3p3v */
|
||||
{0x25E0, 0x2D54, 0x0EC6, 0x01EC, 0x28BB, 0x1144, 0x0200, 0x69C0,
|
||||
0x0010, 0x0EDF, 0x90D7, 0x8000, 0x820C, 0x0003, 0x0001, 0x0000},
|
||||
|
||||
/* ihost03, 3p3V */
|
||||
{0x05E0, 0x39E5, 0x03C1, 0x007C, 0x8BA9, 0x4444, 0x3300, 0x6B80,
|
||||
0x003F, 0x0FFF, 0x90D7, 0x8000, 0x240C, 0x0003, 0x0001, 0x0000},
|
||||
|
||||
/* ihost12 3p3v */
|
||||
{0x05E0, 0x39E5, 0x03C1, 0x007C, 0x8BA9, 0x4444, 0x3300, 0x6B80,
|
||||
0x003F, 0x0FFF, 0x90D7, 0x8000, 0x240C, 0x0003, 0x0001, 0x0000},
|
||||
|
||||
/* ihost array */
|
||||
{0x25E0, 0x2D94, 0x0EC6, 0x01EC, 0x2ABB, 0x1144, 0x0340, 0x69C0,
|
||||
0x0010, 0x0EDF, 0x90D7, 0x8000, 0x860C, 0x0003, 0x0001, 0x0000},
|
||||
|
||||
/* ddr io slave : 3p3v */
|
||||
{0x0560, 0x4438, 0x0000, 0x001F, 0x8028, 0x4444, 0x0300, 0x4380,
|
||||
0x003F, 0x0FFF, 0x10D7, 0x8000, 0xA70C, 0x0003, 0x0001, 0x0000},
|
||||
|
||||
/* core master 3p3v */
|
||||
{0x05E0, 0x39E5, 0x03C1, 0x007C, 0x8BA9, 0x4444, 0x3300, 0x6B80,
|
||||
0x003F, 0x0FFF, 0x90D7, 0x8000, 0x240C, 0x0003, 0x0001, 0x0000},
|
||||
|
||||
/* core slave 3p3v */
|
||||
{0x0560, 0x4438, 0x0000, 0x001F, 0x8028, 0x4444, 0x0300, 0x4380,
|
||||
0x003F, 0x0FFF, 0x10D7, 0x8000, 0x240C, 0x0003, 0x0001, 0x0000},
|
||||
|
||||
/* ddr io master : 3p3v */
|
||||
{0x05E0, 0x39E5, 0x03C1, 0x007C, 0x8BA9, 0x4444, 0x3300, 0x6B80,
|
||||
0x003F, 0x0FFF, 0x90D7, 0x8000, 0xA70C, 0x0003, 0x0001, 0x0000},
|
||||
};
|
||||
|
||||
#define FM_DATA swreg_fm_data_bx
|
||||
|
||||
static int swreg_poll(void)
|
||||
{
|
||||
uint32_t data;
|
||||
int retry = 100;
|
||||
|
||||
do {
|
||||
data = mmio_read_32(BSTI_CONTROL_OFFSET);
|
||||
if ((data & BSTI_CONTROL_BUSY) != BSTI_CONTROL_BUSY)
|
||||
return 0;
|
||||
retry--;
|
||||
udelay(1);
|
||||
} while (retry > 0);
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int write_swreg_config(enum sw_reg reg_id, uint32_t addr, uint32_t data)
|
||||
{
|
||||
uint32_t cmd;
|
||||
int ret;
|
||||
|
||||
cmd = BSTI_CMD(0x1, BSTI_WRITE, reg_id, addr, BSTI_COMMAND_TA, data);
|
||||
mmio_write_32(BSTI_CONTROL_OFFSET, BSTI_CONTROL_VAL);
|
||||
mmio_write_32(BSTI_COMMAND_OFFSET, cmd);
|
||||
ret = swreg_poll();
|
||||
if (ret) {
|
||||
ERROR("Failed to write swreg %s addr 0x%x\n",
|
||||
sw_reg_name[reg_id-1], addr);
|
||||
return ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int read_swreg_config(enum sw_reg reg_id, uint32_t addr, uint32_t *data)
|
||||
{
|
||||
uint32_t cmd;
|
||||
int ret;
|
||||
|
||||
cmd = BSTI_CMD(0x1, BSTI_READ, reg_id, addr, BSTI_COMMAND_TA, PHY_REG0);
|
||||
mmio_write_32(BSTI_CONTROL_OFFSET, BSTI_CONTROL_VAL);
|
||||
mmio_write_32(BSTI_COMMAND_OFFSET, cmd);
|
||||
ret = swreg_poll();
|
||||
if (ret) {
|
||||
ERROR("Failed to read swreg %s addr 0x%x\n",
|
||||
sw_reg_name[reg_id-1], addr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
*data = mmio_read_32(BSTI_COMMAND_OFFSET);
|
||||
*data &= BSTI_REG_DATA_MASK;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int swreg_config_done(enum sw_reg reg_id)
|
||||
{
|
||||
uint32_t read_data;
|
||||
int ret;
|
||||
|
||||
ret = read_swreg_config(reg_id, PHY_REG0, &read_data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
read_data &= BSTI_CONFI_DONE_MASK;
|
||||
read_data |= BSTI_TOGGLE_BIT;
|
||||
ret = write_swreg_config(reg_id, PHY_REG0, read_data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = read_swreg_config(reg_id, PHY_REG0, &read_data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
read_data &= BSTI_CONFI_DONE_MASK;
|
||||
ret = write_swreg_config(reg_id, PHY_REG0, read_data);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef DUMP_SWREG
|
||||
static void dump_swreg_firmware(void)
|
||||
{
|
||||
enum sw_reg reg_id;
|
||||
uint32_t data;
|
||||
int addr;
|
||||
int ret;
|
||||
|
||||
for (reg_id = DDR_VDDC; reg_id <= DDRIO_MASTER; reg_id++) {
|
||||
INFO("SWREG: %s\n", sw_reg_name[reg_id - 1]);
|
||||
for (addr = MIN_REG_ADDR; addr <= MAX_REG_ADDR; addr++) {
|
||||
ret = read_swreg_config(reg_id, addr, &data);
|
||||
if (ret)
|
||||
ERROR("Failed to read offset %d\n", addr);
|
||||
INFO("\t0x%x: 0x%04x\n", addr, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int set_swreg(enum sw_reg reg_id, uint32_t micro_volts)
|
||||
{
|
||||
uint32_t step, programmed_step;
|
||||
uint32_t data = IHOST_VDDC_DATA;
|
||||
int ret;
|
||||
|
||||
if ((micro_volts > MAX_VOLT) || (micro_volts < MIN_VOLT)) {
|
||||
ERROR("input voltage out-of-range\n");
|
||||
ret = -EINVAL;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
ret = read_swreg_config(reg_id, PHY_REGC, &programmed_step);
|
||||
if (ret)
|
||||
goto failed;
|
||||
|
||||
if (reg_id == DDR_VDDC)
|
||||
step = B0_DDR_VDDC_STEP_VALUE(micro_volts);
|
||||
else
|
||||
step = B0_STEP_VALUE(micro_volts);
|
||||
|
||||
if ((step >> 8) != (programmed_step >> 8)) {
|
||||
ret = write_swreg_config(reg_id, PHY_REGC, step);
|
||||
if (ret)
|
||||
goto failed;
|
||||
|
||||
if (reg_id == DDR_VDDC)
|
||||
data = DDR_CORE_DATA;
|
||||
|
||||
ret = write_swreg_config(reg_id, PHY_REG0,
|
||||
UPDATE_POS_EDGE(data, 1));
|
||||
if (ret)
|
||||
goto failed;
|
||||
|
||||
ret = write_swreg_config(reg_id, PHY_REG0,
|
||||
UPDATE_POS_EDGE(data, 0));
|
||||
if (ret)
|
||||
goto failed;
|
||||
}
|
||||
|
||||
INFO("%s voltage updated to %duV\n", sw_reg_name[reg_id-1],
|
||||
micro_volts);
|
||||
return ret;
|
||||
|
||||
failed:
|
||||
/*
|
||||
* Stop booting if voltages are not set
|
||||
* correctly. Booting will fail at random point
|
||||
* if we continue with wrong voltage settings.
|
||||
*/
|
||||
ERROR("Failed to set %s voltage to %duV\n", sw_reg_name[reg_id-1],
|
||||
micro_volts);
|
||||
assert(0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Update SWREG firmware for all power doman for A2 chip */
|
||||
int swreg_firmware_update(void)
|
||||
{
|
||||
enum sw_reg reg_id;
|
||||
uint32_t data;
|
||||
int addr;
|
||||
int ret;
|
||||
|
||||
/* write firmware values */
|
||||
for (reg_id = DDR_VDDC; reg_id <= DDRIO_MASTER; reg_id++) {
|
||||
/* write higher location first */
|
||||
for (addr = MAX_REG_ADDR; addr >= MIN_REG_ADDR; addr--) {
|
||||
ret = write_swreg_config(reg_id, addr,
|
||||
FM_DATA[reg_id - 1][addr]);
|
||||
if (ret)
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* trigger SWREG firmware update */
|
||||
for (reg_id = DDR_VDDC; reg_id <= DDRIO_MASTER; reg_id++) {
|
||||
/*
|
||||
* Slave regulator doesn't have to be updated,
|
||||
* Updating Master is enough
|
||||
*/
|
||||
if ((reg_id == DDRIO_SLAVE) || (reg_id == VDDC1))
|
||||
continue;
|
||||
|
||||
ret = swreg_config_done(reg_id);
|
||||
if (ret) {
|
||||
ERROR("Failed to trigger SWREG firmware update for %s\n"
|
||||
, sw_reg_name[reg_id-1]);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
for (reg_id = DDR_VDDC; reg_id <= DDRIO_MASTER; reg_id++) {
|
||||
/*
|
||||
* IHOST_ARRAY will be used on some boards like STRATUS and
|
||||
* there will not be any issue even if it is updated on other
|
||||
* boards where it is not used.
|
||||
*/
|
||||
if (reg_id == IHOST_ARRAY)
|
||||
continue;
|
||||
|
||||
for (addr = MIN_REG_ADDR; addr <= MAX_REG_ADDR; addr++) {
|
||||
ret = read_swreg_config(reg_id, addr, &data);
|
||||
if (ret || (!ret &&
|
||||
(data != FM_DATA[reg_id - 1][addr]))) {
|
||||
ERROR("swreg fm update failed: %s at off %d\n",
|
||||
sw_reg_name[reg_id - 1], addr);
|
||||
ERROR("Read val: 0x%x, expected val: 0x%x\n",
|
||||
data, FM_DATA[reg_id - 1][addr]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
INFO("Updated SWREG firmware\n");
|
||||
|
||||
#ifdef DUMP_SWREG
|
||||
dump_swreg_firmware();
|
||||
#endif
|
||||
return ret;
|
||||
|
||||
exit:
|
||||
/*
|
||||
* Stop booting if swreg firmware update fails.
|
||||
* Booting will fail at random point if we
|
||||
* continue with wrong voltage settings.
|
||||
*/
|
||||
ERROR("Failed to update firmware for %s SWREG\n",
|
||||
sw_reg_name[reg_id-1]);
|
||||
assert(0);
|
||||
|
||||
return ret;
|
||||
}
|
38
plat/brcm/board/stingray/include/board_info.h
Normal file
38
plat/brcm/board/stingray/include/board_info.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2017 - 2020, Broadcom
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef BOARD_INFO_H
|
||||
#define BOARD_INFO_H
|
||||
|
||||
#define IHOST_REG_INTEGRATED 0
|
||||
#define IHOST_REG_EXT_PROGRAMMABLE 1
|
||||
#define IHOST_REG_EXT_FIXED 2
|
||||
|
||||
#if defined(IHOST_REG_TYPE)
|
||||
#if ((IHOST_REG_TYPE != IHOST_REG_INTEGRATED) && \
|
||||
(IHOST_REG_TYPE != IHOST_REG_EXT_PROGRAMMABLE) && \
|
||||
(IHOST_REG_TYPE != IHOST_REG_EXT_FIXED))
|
||||
#error "IHOST_REG_TYPE not valid"
|
||||
#endif
|
||||
#else
|
||||
#define IHOST_REG_TYPE IHOST_REG_INTEGRATED
|
||||
#endif
|
||||
|
||||
#define VDDC_REG_INTEGRATED 0
|
||||
#define VDDC_REG_EXT_PROGRAMMABLE 1
|
||||
#define VDDC_REG_EXT_FIXED 2
|
||||
|
||||
#if defined(VDDC_REG_TYPE)
|
||||
#if ((VDDC_REG_TYPE != VDDC_REG_INTEGRATED) && \
|
||||
(VDDC_REG_TYPE != VDDC_REG_EXT_PROGRAMMABLE) && \
|
||||
(VDDC_REG_TYPE != VDDC_REG_EXT_FIXED))
|
||||
#error "VDDC_REG_TYPE not valid"
|
||||
#endif
|
||||
#else
|
||||
#define VDDC_REG_TYPE VDDC_REG_INTEGRATED
|
||||
#endif
|
||||
|
||||
#endif
|
39
plat/brcm/board/stingray/include/ddr_init.h
Normal file
39
plat/brcm/board/stingray/include/ddr_init.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2016 - 2020, Broadcom
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef DDR_INIT_H
|
||||
#define DDR_INIT_H
|
||||
|
||||
#include <fru.h>
|
||||
|
||||
#pragma weak ddr_initialize
|
||||
#pragma weak ddr_secure_region_config
|
||||
#pragma weak ddr_info_save
|
||||
#pragma weak get_active_ddr_channel
|
||||
#pragma weak is_warmboot
|
||||
|
||||
void ddr_initialize(struct ddr_info *ddr)
|
||||
{
|
||||
}
|
||||
|
||||
void ddr_secure_region_config(uint64_t start, uint64_t end)
|
||||
{
|
||||
}
|
||||
|
||||
void ddr_info_save(void)
|
||||
{
|
||||
}
|
||||
|
||||
unsigned char get_active_ddr_channel(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline unsigned int is_warmboot(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
@ -12,10 +12,8 @@
|
||||
#include <plat/common/common_def.h>
|
||||
|
||||
#include <brcm_def.h>
|
||||
|
||||
#include <cmn_plat_def.h>
|
||||
|
||||
#include "sr_def.h"
|
||||
#include <cmn_plat_def.h>
|
||||
|
||||
/*
|
||||
* Most platform porting definitions provided by included headers
|
||||
|
36
plat/brcm/board/stingray/include/platform_sotp.h
Normal file
36
plat/brcm/board/stingray/include/platform_sotp.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2020, Broadcom
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef PLATFORM_SOTP_H
|
||||
#define PLATFORM_SOTP_H
|
||||
|
||||
#define SOTP_DEVICE_SECURE_CFG0_ROW 17
|
||||
#define SOTP_DEVICE_SECURE_CFG1_ROW 18
|
||||
#define SOTP_DEVICE_SECURE_CFG2_ROW 19
|
||||
#define SOTP_DEVICE_SECURE_CFG3_ROW 20
|
||||
#define SOTP_BRCM_SOFTWARE_CFG0_ROW 21
|
||||
#define SOTP_BRCM_SOFTWARE_CFG1_ROW 22
|
||||
#define SOTP_BRCM_SOFTWARE_CFG2_ROW 23
|
||||
#define SOTP_BRCM_SOFTWARE_CFG3_ROW 24
|
||||
#define SOTP_CUSTOMER_ID_CFG0_ROW 25
|
||||
#define SOTP_CUSTOMER_ID_CFG1_ROW 26
|
||||
#define SOTP_CUSTOMER_ID_CFG2_ROW 27
|
||||
#define SOTP_CUSTOMER_ID_CFG3_ROW 28
|
||||
#define SOTP_CUSTOMER_DEV_CFG0_ROW 29
|
||||
#define SOTP_CUSTOMER_DEV_CFG1_ROW 30
|
||||
#define SOTP_CUSTOMER_DEV_CFG2_ROW 31
|
||||
#define SOTP_CUSTOMER_DEV_CFG3_ROW 32
|
||||
#define SOTP_DAUTH_ROW 33
|
||||
#define SOTP_K_HMAC_ROW 45
|
||||
#define SOTP_K_AES_ROW 57
|
||||
#define SOTP_NVCOUNTER_ROW 69
|
||||
|
||||
#define SOTP_BRCM_CFG_ECC_ERROR_MASK 0x100000
|
||||
#define SOTP_DAUTH_ECC_ERROR_MASK 0x800000
|
||||
#define SOTP_K_HMAC_ECC_ERROR_MASK 0x1000000
|
||||
#define SOTP_K_AES_ECC_ERROR_MASK 0x2000000
|
||||
|
||||
#endif
|
25
plat/brcm/board/stingray/include/scp_cmd.h
Normal file
25
plat/brcm/board/stingray/include/scp_cmd.h
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2020, Broadcom
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef SCP_CMD_H
|
||||
#define SCP_SMD_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
int cmd;
|
||||
int completed;
|
||||
int ret;
|
||||
} crmu_response_t;
|
||||
|
||||
|
||||
#define SCP_CMD_MASK 0xffff
|
||||
#define SCP_CMD_DEFAULT_TIMEOUT_US 1000
|
||||
#define SCP_CMD_SCP_BOOT_TIMEOUT_US 5000
|
||||
|
||||
int scp_send_cmd(uint32_t cmd, uint32_t param, uint32_t timeout);
|
||||
|
||||
#endif
|
34
plat/brcm/board/stingray/include/scp_utils.h
Normal file
34
plat/brcm/board/stingray/include/scp_utils.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) 2019-2020, Broadcom
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef SCP_UTILS_H
|
||||
#define SCP_UTILS_H
|
||||
|
||||
#include <common/bl_common.h>
|
||||
#include <lib/mmio.h>
|
||||
|
||||
#include <m0_cfg.h>
|
||||
|
||||
int plat_bcm_bl2_plat_handle_scp_bl2(image_info_t *scp_bl2_image_info);
|
||||
|
||||
bool is_crmu_alive(void);
|
||||
bool bcm_scp_issue_sys_reset(void);
|
||||
|
||||
#define SCP_READ_CFG(cfg) mmio_read_32(CRMU_CFG_BASE + \
|
||||
offsetof(M0CFG, cfg))
|
||||
#define SCP_WRITE_CFG(cfg, value) mmio_write_32(CRMU_CFG_BASE + \
|
||||
offsetof(M0CFG, cfg), value)
|
||||
|
||||
#define SCP_READ_CFG16(cfg) mmio_read_16(CRMU_CFG_BASE + \
|
||||
offsetof(M0CFG, cfg))
|
||||
#define SCP_WRITE_CFG16(cfg, value) mmio_write_16(CRMU_CFG_BASE + \
|
||||
offsetof(M0CFG, cfg), value)
|
||||
|
||||
#define SCP_READ_CFG8(cfg) mmio_read_8(CRMU_CFG_BASE + \
|
||||
offsetof(M0CFG, cfg))
|
||||
#define SCP_WRITE_CFG8(cfg, value) mmio_write_8(CRMU_CFG_BASE + \
|
||||
offsetof(M0CFG, cfg), value)
|
||||
#endif
|
42
plat/brcm/board/stingray/include/sr_utils.h
Normal file
42
plat/brcm/board/stingray/include/sr_utils.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (c) 2017 - 2020, Broadcom
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef SR_UTILS_H
|
||||
#define SR_UTILS_H
|
||||
|
||||
#include <lib/mmio.h>
|
||||
|
||||
#include <chip_id.h>
|
||||
#include <cmn_plat_util.h>
|
||||
#include <sr_def.h>
|
||||
|
||||
static inline void brcm_stingray_set_qspi_mux(int enable_ap)
|
||||
{
|
||||
mmio_write_32(QSPI_HOLD_N_MODE_SEL_CONTROL, enable_ap);
|
||||
mmio_write_32(QSPI_WP_N_MODE_SEL_CONTROL, enable_ap);
|
||||
mmio_write_32(QSPI_SCK_MODE_SEL_CONTROL, enable_ap);
|
||||
mmio_write_32(QSPI_CS_N_MODE_SEL_CONTROL, enable_ap);
|
||||
mmio_write_32(QSPI_MOSI_MODE_SEL_CONTROL, enable_ap);
|
||||
mmio_write_32(QSPI_MISO_MODE_SEL_CONTROL, enable_ap);
|
||||
}
|
||||
|
||||
static inline void brcm_stingray_set_straps(uint32_t boot_source)
|
||||
{
|
||||
/* Enable software strap override */
|
||||
mmio_setbits_32(CDRU_CHIP_STRAP_CTRL,
|
||||
BIT(CDRU_CHIP_STRAP_CTRL__SOFTWARE_OVERRIDE));
|
||||
|
||||
/* set straps to the next boot source */
|
||||
mmio_clrsetbits_32(CDRU_CHIP_STRAP_DATA,
|
||||
BOOT_SOURCE_MASK,
|
||||
boot_source);
|
||||
|
||||
/* Disable software strap override */
|
||||
mmio_clrbits_32(CDRU_CHIP_STRAP_CTRL,
|
||||
BIT(CDRU_CHIP_STRAP_CTRL__SOFTWARE_OVERRIDE));
|
||||
}
|
||||
|
||||
#endif
|
36
plat/brcm/board/stingray/include/swreg.h
Normal file
36
plat/brcm/board/stingray/include/swreg.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) 2017 - 2020, Broadcom
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef SWREG_H
|
||||
#define SWREG_H
|
||||
|
||||
/* default voltage if no valid OTP */
|
||||
#define VDDC_CORE_DEF_VOLT 910000 /* 0.91v */
|
||||
#define IHOST_DEF_VOLT 940000 /* 0.94v */
|
||||
|
||||
#define B0_VDDC_CORE_DEF_VOLT 950000 /* 0.95v */
|
||||
#define B0_IHOST_DEF_VOLT 950000 /* 0.95v */
|
||||
#define B0_DDR_VDDC_DEF_VOLT 1000000 /* 1v */
|
||||
|
||||
#define SWREG_IHOST1_DIS 4
|
||||
#define SWREG_IHOST1_REG_RESETB 5
|
||||
#define SWREG_IHOST1_PMU_STABLE 2
|
||||
|
||||
enum sw_reg {
|
||||
DDR_VDDC = 1,
|
||||
IHOST03,
|
||||
IHOST12,
|
||||
IHOST_ARRAY,
|
||||
DDRIO_SLAVE,
|
||||
VDDC_CORE,
|
||||
VDDC1,
|
||||
DDRIO_MASTER
|
||||
};
|
||||
|
||||
int set_swreg(enum sw_reg reg_id, uint32_t micro_volts);
|
||||
int swreg_firmware_update(void);
|
||||
|
||||
#endif
|
@ -4,6 +4,19 @@
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
#
|
||||
|
||||
# Set the toc_flags to 1 for 100% speed operation
|
||||
# Set the toc_flags to 2 for 50% speed operation
|
||||
# Set the toc_flags to 3 for 25% speed operation
|
||||
# Set the toc_flags bit 3 to indicate ignore the fip in UEFI copy mode
|
||||
PLAT_TOC_FLAGS := 0x0
|
||||
|
||||
# Set the IHOST_PLL_FREQ to,
|
||||
# 1 for full speed
|
||||
# 2 for 50% speed
|
||||
# 3 for 25% speed
|
||||
# 0 for bypass
|
||||
$(eval $(call add_define_val,IHOST_PLL_FREQ,1))
|
||||
|
||||
# Enable workaround for ERRATA_A72_859971
|
||||
ERRATA_A72_859971 := 1
|
||||
|
||||
@ -16,16 +29,42 @@ ARM_BL31_IN_DRAM := 1
|
||||
|
||||
USE_CRMU_SRAM := yes
|
||||
|
||||
# Enable error logging by default for Stingray
|
||||
BCM_ELOG := yes
|
||||
|
||||
# Enable FRU support by default for Stingray
|
||||
ifeq (${USE_FRU},)
|
||||
USE_FRU := no
|
||||
endif
|
||||
|
||||
# Use single cluster
|
||||
ifeq (${USE_SINGLE_CLUSTER},yes)
|
||||
$(info Using Single Cluster)
|
||||
$(eval $(call add_define,USE_SINGLE_CLUSTER))
|
||||
endif
|
||||
|
||||
# Use DDR
|
||||
ifeq (${USE_DDR},yes)
|
||||
$(info Using DDR)
|
||||
$(eval $(call add_define,USE_DDR))
|
||||
endif
|
||||
|
||||
ifeq (${BOARD_CFG},)
|
||||
BOARD_CFG := bcm958742k
|
||||
endif
|
||||
|
||||
# Use NAND
|
||||
ifeq (${USE_NAND},$(filter yes, ${USE_NAND}))
|
||||
$(info Using NAND)
|
||||
$(eval $(call add_define,USE_NAND))
|
||||
endif
|
||||
|
||||
# Enable Broadcom error logging support
|
||||
ifeq (${BCM_ELOG},yes)
|
||||
$(info Using BCM_ELOG)
|
||||
$(eval $(call add_define,BCM_ELOG))
|
||||
endif
|
||||
|
||||
# BL31 build for standalone mode
|
||||
ifeq (${STANDALONE_BL31},yes)
|
||||
RESET_TO_BL31 := 1
|
||||
@ -43,6 +82,9 @@ endif
|
||||
# Default soft reset is L3
|
||||
$(eval $(call add_define,CONFIG_SOFT_RESET_L3))
|
||||
|
||||
# Enable Chip OTP driver
|
||||
DRIVER_OCOTP_ENABLE := 1
|
||||
|
||||
include plat/brcm/board/common/board_common.mk
|
||||
|
||||
SOC_DIR := brcm/board/stingray
|
||||
@ -58,6 +100,17 @@ PLAT_BL_COMMON_SOURCES += lib/cpus/aarch64/cortex_a72.S \
|
||||
drivers/arm/tzc/tzc400.c \
|
||||
plat/${SOC_DIR}/src/topology.c
|
||||
|
||||
BL2_SOURCES += plat/${SOC_DIR}/driver/ihost_pll_config.c \
|
||||
plat/${SOC_DIR}/src/bl2_setup.c \
|
||||
plat/${SOC_DIR}/driver/swreg.c
|
||||
|
||||
|
||||
ifeq (${USE_DDR},yes)
|
||||
PLAT_INCLUDES += -Iplat/${SOC_DIR}/driver/ddr/soc/include
|
||||
else
|
||||
PLAT_INCLUDES += -Iplat/${SOC_DIR}/driver/ext_sram_init
|
||||
BL2_SOURCES += plat/${SOC_DIR}/driver/ext_sram_init/ext_sram_init.c
|
||||
endif
|
||||
|
||||
# Include GICv3 driver files
|
||||
include drivers/arm/gic/v3/gicv3.mk
|
||||
@ -77,6 +130,12 @@ BL31_SOURCES += \
|
||||
ifdef SCP_BL2
|
||||
PLAT_INCLUDES += -Iplat/brcm/common/
|
||||
|
||||
BL2_SOURCES += plat/brcm/common/brcm_mhu.c \
|
||||
plat/brcm/common/brcm_scpi.c \
|
||||
plat/${SOC_DIR}/src/scp_utils.c \
|
||||
plat/${SOC_DIR}/src/scp_cmd.c \
|
||||
drivers/brcm/scp.c
|
||||
|
||||
BL31_SOURCES += plat/brcm/common/brcm_mhu.c \
|
||||
plat/brcm/common/brcm_scpi.c \
|
||||
plat/${SOC_DIR}/src/brcm_pm_ops.c
|
||||
@ -85,5 +144,19 @@ BL31_SOURCES += plat/${SOC_DIR}/src/ihost_pm.c \
|
||||
plat/${SOC_DIR}/src/pm.c
|
||||
endif
|
||||
|
||||
ifeq (${ELOG_SUPPORT},1)
|
||||
ifeq (${ELOG_STORE_MEDIA},DDR)
|
||||
BL2_SOURCES += plat/brcm/board/common/bcm_elog_ddr.c
|
||||
endif
|
||||
endif
|
||||
|
||||
# Do not execute the startup code on warm reset.
|
||||
PROGRAMMABLE_RESET_ADDRESS := 1
|
||||
|
||||
# Nitro FW, config and Crash log uses secure DDR memory
|
||||
# Inaddition to above, Nitro master and slave is also secure
|
||||
ifneq ($(NITRO_SECURE_ACCESS),)
|
||||
$(eval $(call add_define,NITRO_SECURE_ACCESS))
|
||||
$(eval $(call add_define,DDR_NITRO_SECURE_REGION_START))
|
||||
$(eval $(call add_define,DDR_NITRO_SECURE_REGION_END))
|
||||
endif
|
||||
|
742
plat/brcm/board/stingray/src/bl2_setup.c
Normal file
742
plat/brcm/board/stingray/src/bl2_setup.c
Normal file
@ -0,0 +1,742 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2020, Broadcom
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <arch_helpers.h>
|
||||
#include <common/bl_common.h>
|
||||
#include <common/debug.h>
|
||||
#include <drivers/arm/sp805.h>
|
||||
#include <drivers/delay_timer.h>
|
||||
#include <lib/mmio.h>
|
||||
|
||||
#include <chimp.h>
|
||||
#include <chip_id.h>
|
||||
#include <cmn_plat_util.h>
|
||||
#include <dmu.h>
|
||||
#include <fru.h>
|
||||
#ifdef USE_GPIO
|
||||
#include <drivers/gpio.h>
|
||||
#include <iproc_gpio.h>
|
||||
#endif
|
||||
#include <platform_def.h>
|
||||
#include <sotp.h>
|
||||
#include <swreg.h>
|
||||
#include <sr_utils.h>
|
||||
#ifdef USE_DDR
|
||||
#include <ddr_init.h>
|
||||
#else
|
||||
#include <ext_sram_init.h>
|
||||
#endif
|
||||
#if DRIVER_OCOTP_ENABLE
|
||||
#include <ocotp.h>
|
||||
#endif
|
||||
#include "board_info.h"
|
||||
|
||||
#define WORD_SIZE 8
|
||||
#define SWREG_AVS_OTP_OFFSET (13 * WORD_SIZE) /* 13th row byte offset */
|
||||
#define AON_GPIO_OTP_OFFSET (28 * WORD_SIZE) /* 28th row byte offset */
|
||||
#define BYTES_TO_READ 8
|
||||
|
||||
/* OTP voltage step definitions */
|
||||
#define MVOLT_STEP_MAX 0x18 /* 1v */
|
||||
#define MVOLT_PER_STEP 10 /* 0.01mv per step */
|
||||
#define MVOLT_BASE 760 /* 0.76v */
|
||||
|
||||
#define STEP_TO_UVOLTS(step) \
|
||||
((MVOLT_BASE + (MVOLT_PER_STEP * (step))) * 1000)
|
||||
|
||||
#define GET_BITS(first, last, data) \
|
||||
((data >> first) & ((1 << (last - first + 1)) - 1))
|
||||
|
||||
/*
|
||||
* SW-REG OTP encoding:
|
||||
*
|
||||
* SWREG_bits[11:0] = OTP 13th row 12 bits[55:44]
|
||||
* SWREG_bits[11:10] - Valid Bits (0x2 - valid, if not 0x2 - Invalid)
|
||||
* SWREG_bits[9:5] - iHost03, iHost12
|
||||
* SWREG_bits[4:0] - Core VDDC
|
||||
*/
|
||||
#define SWREG_OTP_BITS_START 12 /* 44th bit in MSB 32-bits */
|
||||
#define SWREG_OTP_BITS_END 23 /* 55th bit in MSB 32-bits */
|
||||
#define SWREG_VDDC_FIELD_START 0
|
||||
#define SWREG_VDDC_FIELD_END 4
|
||||
#define SWREG_IHOST_FIELD_START 5
|
||||
#define SWREG_IHOST_FIELD_END 9
|
||||
#define SWREG_VALID_BIT_START 10
|
||||
#define SWREG_VALID_BIT_END 11
|
||||
#define SWREG_VALID_BITS 0x2
|
||||
|
||||
/*
|
||||
* Row 13 bit 56 is programmed as '1' today. It is not being used, so plan
|
||||
* is to flip this bit to '0' for B1 rev. Hence SW can leverage this bit
|
||||
* to identify Bx chip to program different sw-regulators.
|
||||
*/
|
||||
#define SPARE_BIT 24
|
||||
|
||||
#define IS_SR_B0(data) (((data) >> SPARE_BIT) & 0x1)
|
||||
|
||||
#if DRIVER_OCOTP_ENABLE
|
||||
static struct otpc_map otp_stingray_map = {
|
||||
.otpc_row_size = 2,
|
||||
.data_r_offset = {0x10, 0x5c},
|
||||
.data_w_offset = {0x2c, 0x64},
|
||||
.word_size = 8,
|
||||
.stride = 8,
|
||||
};
|
||||
#endif
|
||||
|
||||
void plat_bcm_bl2_early_platform_setup(void)
|
||||
{
|
||||
/* Select UART0 for AP via mux setting*/
|
||||
if (PLAT_BRCM_BOOT_UART_BASE == UART0_BASE_ADDR) {
|
||||
mmio_write_32(UART0_SIN_MODE_SEL_CONTROL, 1);
|
||||
mmio_write_32(UART0_SOUT_MODE_SEL_CONTROL, 1);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_NAND
|
||||
static void brcm_stingray_nand_init(void)
|
||||
{
|
||||
unsigned int val;
|
||||
unsigned int nand_idm_reset_control = 0x68e0a800;
|
||||
|
||||
VERBOSE(" stingray nand init start.\n");
|
||||
|
||||
/* Reset NAND */
|
||||
VERBOSE(" - reset nand\n");
|
||||
val = mmio_read_32((uintptr_t)(nand_idm_reset_control + 0x0));
|
||||
mmio_write_32((uintptr_t)(nand_idm_reset_control + 0x0), val | 0x1);
|
||||
udelay(500);
|
||||
val = mmio_read_32((uintptr_t)(nand_idm_reset_control + 0x0));
|
||||
mmio_write_32((uintptr_t)(nand_idm_reset_control + 0x0), val & ~0x1);
|
||||
udelay(500);
|
||||
|
||||
VERBOSE(" stingray nand init done.\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(USE_PAXB) || defined(USE_PAXC) || defined(USE_SATA)
|
||||
#define PCIE_RESCAL_CFG_0 0x40000130
|
||||
#define PCIE_CFG_RESCAL_RSTB_R (1 << 16)
|
||||
#define PCIE_CFG_RESCAL_PWRDNB_R (1 << 8)
|
||||
#define PCIE_RESCAL_STATUS_0 0x4000014c
|
||||
#define PCIE_STAT_PON_VALID_R (1 << 0)
|
||||
#define PCIE_RESCAL_OUTPUT_STATUS 0x40000154
|
||||
#define CDRU_PCIE_RESET_N_R (1 << CDRU_MISC_RESET_CONTROL__CDRU_PCIE_RESET_N_R)
|
||||
|
||||
#ifdef EMULATION_SETUP
|
||||
static void brcm_stingray_pcie_reset(void)
|
||||
{
|
||||
}
|
||||
#else
|
||||
static void brcm_stingray_pcie_reset(void)
|
||||
{
|
||||
unsigned int data;
|
||||
int try;
|
||||
|
||||
if (bcm_chimp_is_nic_mode()) {
|
||||
INFO("NIC mode detected; PCIe reset/rescal not executed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
mmio_clrbits_32(CDRU_MISC_RESET_CONTROL, CDRU_PCIE_RESET_N_R);
|
||||
mmio_setbits_32(CDRU_MISC_RESET_CONTROL, CDRU_PCIE_RESET_N_R);
|
||||
/* Release reset */
|
||||
mmio_setbits_32(PCIE_RESCAL_CFG_0, PCIE_CFG_RESCAL_RSTB_R);
|
||||
mdelay(1);
|
||||
/* Power UP */
|
||||
mmio_setbits_32(PCIE_RESCAL_CFG_0,
|
||||
(PCIE_CFG_RESCAL_RSTB_R | PCIE_CFG_RESCAL_PWRDNB_R));
|
||||
|
||||
try = 1000;
|
||||
do {
|
||||
udelay(1);
|
||||
data = mmio_read_32(PCIE_RESCAL_STATUS_0);
|
||||
try--;
|
||||
} while ((data & PCIE_STAT_PON_VALID_R) == 0x0 && (try > 0));
|
||||
|
||||
if (try <= 0)
|
||||
ERROR("PCIE_RESCAL_STATUS_0: 0x%x\n", data);
|
||||
|
||||
VERBOSE("PCIE_SATA_RESCAL_STATUS_0 0x%x.\n",
|
||||
mmio_read_32(PCIE_RESCAL_STATUS_0));
|
||||
VERBOSE("PCIE_SATA_RESCAL_OUTPUT_STATUS 0x%x.\n",
|
||||
mmio_read_32(PCIE_RESCAL_OUTPUT_STATUS));
|
||||
INFO("PCIE SATA Rescal Init done\n");
|
||||
}
|
||||
#endif /* EMULATION_SETUP */
|
||||
#endif /* USE_PAXB || USE_PAXC || USE_SATA */
|
||||
|
||||
#ifdef USE_PAXC
|
||||
void brcm_stingray_chimp_check_and_fastboot(void)
|
||||
{
|
||||
int fastboot_init_result;
|
||||
|
||||
if (bcm_chimp_is_nic_mode())
|
||||
/* Do not wait here */
|
||||
return;
|
||||
|
||||
#if WARMBOOT_DDR_S3_SUPPORT
|
||||
/*
|
||||
* Currently DDR shmoo parameters and QSPI boot source are
|
||||
* tied. DDR shmoo parameters are stored in QSPI, which is
|
||||
* used for warmboot.
|
||||
* Do not reset nitro for warmboot
|
||||
*/
|
||||
if (is_warmboot() && (boot_source_get() == BOOT_SOURCE_QSPI))
|
||||
return;
|
||||
#endif /* WARMBOOT_DDR_S3_SUPPORT */
|
||||
|
||||
/*
|
||||
* Not in NIC mode,
|
||||
* initiate fastboot (if enabled)
|
||||
*/
|
||||
if (FASTBOOT_TYPE == CHIMP_FASTBOOT_NITRO_RESET) {
|
||||
|
||||
VERBOSE("Bring up Nitro/ChiMP\n");
|
||||
|
||||
if (boot_source_get() == BOOT_SOURCE_QSPI)
|
||||
WARN("Nitro boots from QSPI when AP has booted from QSPI.\n");
|
||||
brcm_stingray_set_qspi_mux(0);
|
||||
VERBOSE("Nitro controls the QSPI\n");
|
||||
}
|
||||
|
||||
fastboot_init_result = bcm_chimp_initiate_fastboot(FASTBOOT_TYPE);
|
||||
if (fastboot_init_result && boot_source_get() != BOOT_SOURCE_QSPI)
|
||||
ERROR("Nitro init error %d. Status: 0x%x; bpe_mod reg: 0x%x\n"
|
||||
"fastboot register: 0x%x; handshake register 0x%x\n",
|
||||
fastboot_init_result,
|
||||
bcm_chimp_read_ctrl(CHIMP_REG_CTRL_BPE_STAT_REG),
|
||||
bcm_chimp_read_ctrl(CHIMP_REG_CTRL_BPE_MODE_REG),
|
||||
bcm_chimp_read_ctrl(CHIMP_REG_CTRL_FSTBOOT_PTR_REG),
|
||||
bcm_chimp_read(CHIMP_REG_ECO_RESERVED));
|
||||
|
||||
/*
|
||||
* CRMU watchdog kicks is an example, which is L1 reset,
|
||||
* does not clear Nitro scratch pad ram.
|
||||
* For Nitro resets: Clear the Nitro health status memory.
|
||||
*/
|
||||
bcm_chimp_write((CHIMP_REG_CHIMP_SCPAD + CHIMP_HEALTH_STATUS_OFFSET),
|
||||
0);
|
||||
}
|
||||
#endif
|
||||
|
||||
void set_ihost_vddc_swreg(uint32_t ihost_uvolts, uint32_t vddc_uvolts)
|
||||
{
|
||||
NOTICE("ihost_uvolts: %duv, vddc_uvolts: %duv\n",
|
||||
ihost_uvolts, vddc_uvolts);
|
||||
|
||||
set_swreg(VDDC_CORE, vddc_uvolts);
|
||||
set_swreg(IHOST03, ihost_uvolts);
|
||||
set_swreg(IHOST12, ihost_uvolts);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads SWREG AVS OTP bits (13th row) with ECC enabled and get voltage
|
||||
* defined in OTP if valid OTP is found
|
||||
*/
|
||||
void read_avs_otp_bits(uint32_t *ihost_uvolts, uint32_t *vddc_uvolts)
|
||||
{
|
||||
uint32_t offset = SWREG_AVS_OTP_OFFSET;
|
||||
uint32_t ihost_step, vddc_step;
|
||||
uint32_t avs_bits;
|
||||
uint32_t buf[2];
|
||||
|
||||
if (bcm_otpc_read(offset, &buf[0], BYTES_TO_READ, 1) == -1)
|
||||
return;
|
||||
|
||||
VERBOSE("AVS OTP %d ROW: 0x%x.0x%x\n",
|
||||
offset/WORD_SIZE, buf[1], buf[0]);
|
||||
|
||||
/* get voltage readings from AVS OTP bits */
|
||||
avs_bits = GET_BITS(SWREG_OTP_BITS_START,
|
||||
SWREG_OTP_BITS_END,
|
||||
buf[1]);
|
||||
|
||||
/* check for valid otp bits */
|
||||
if (GET_BITS(SWREG_VALID_BIT_START, SWREG_VALID_BIT_END, avs_bits) !=
|
||||
SWREG_VALID_BITS) {
|
||||
WARN("Invalid AVS OTP bits at %d row\n", offset/WORD_SIZE);
|
||||
return;
|
||||
}
|
||||
|
||||
/* get ihost and vddc step value */
|
||||
vddc_step = GET_BITS(SWREG_VDDC_FIELD_START,
|
||||
SWREG_VDDC_FIELD_END,
|
||||
avs_bits);
|
||||
|
||||
ihost_step = GET_BITS(SWREG_IHOST_FIELD_START,
|
||||
SWREG_IHOST_FIELD_END,
|
||||
avs_bits);
|
||||
|
||||
if ((ihost_step > MVOLT_STEP_MAX) || (vddc_step > MVOLT_STEP_MAX)) {
|
||||
WARN("OTP entry invalid\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* get voltage in micro-volts */
|
||||
*ihost_uvolts = STEP_TO_UVOLTS(ihost_step);
|
||||
*vddc_uvolts = STEP_TO_UVOLTS(vddc_step);
|
||||
}
|
||||
|
||||
/*
|
||||
* This api reads otp bits and program internal swreg's - ihos12, ihost03,
|
||||
* vddc_core and ddr_core based on different chip. External swreg's
|
||||
* programming will be done from crmu.
|
||||
*
|
||||
* For A2 chip:
|
||||
* Read OTP row 20, bit 50. This bit will be set for A2 chip. Once A2 chip is
|
||||
* found, read AVS OTP row 13, 12bits[55:44], if valid otp bits are found
|
||||
* then set ihost and vddc according to avs otp bits else set them to 0.94v
|
||||
* and 0.91v respectively. Also update the firmware after setting voltage.
|
||||
*
|
||||
* For B0 chip:
|
||||
* Read OTP row 13, bit 56. This bit will be set for B0 chip. Once B0 chip is
|
||||
* found then set ihost and vddc to 0.95v and ddr_core to 1v. No AVS OTP bits
|
||||
* are used get ihost/vddc voltages.
|
||||
*
|
||||
* For B1 chip:
|
||||
* Read AVS OTP row 13, 12bits[55:44], if valid otp bits are found then set
|
||||
* ihost and vddc according to avs otp bits else set them to 0.94v and 0.91v
|
||||
* respectively.
|
||||
*/
|
||||
void set_swreg_based_on_otp(void)
|
||||
{
|
||||
/* default voltage if no valid OTP */
|
||||
uint32_t vddc_uvolts = VDDC_CORE_DEF_VOLT;
|
||||
uint32_t ihost_uvolts = IHOST_DEF_VOLT;
|
||||
uint32_t ddrc_uvolts;
|
||||
uint32_t offset;
|
||||
uint32_t buf[2];
|
||||
|
||||
offset = SWREG_AVS_OTP_OFFSET;
|
||||
if (bcm_otpc_read(offset, &buf[0], BYTES_TO_READ, 1) == -1)
|
||||
return;
|
||||
|
||||
VERBOSE("OTP %d ROW: 0x%x.0x%x\n",
|
||||
offset/WORD_SIZE, buf[1], buf[0]);
|
||||
|
||||
if (IS_SR_B0(buf[1])) {
|
||||
/* don't read AVS OTP for B0 */
|
||||
ihost_uvolts = B0_IHOST_DEF_VOLT;
|
||||
vddc_uvolts = B0_VDDC_CORE_DEF_VOLT;
|
||||
ddrc_uvolts = B0_DDR_VDDC_DEF_VOLT;
|
||||
} else {
|
||||
read_avs_otp_bits(&ihost_uvolts, &vddc_uvolts);
|
||||
}
|
||||
|
||||
#if (IHOST_REG_TYPE == IHOST_REG_INTEGRATED) && \
|
||||
(VDDC_REG_TYPE == VDDC_REG_INTEGRATED)
|
||||
/* enable IHOST12 cluster before changing voltage */
|
||||
NOTICE("Switching on the Regulator idx: %u\n",
|
||||
SWREG_IHOST1_DIS);
|
||||
mmio_clrsetbits_32(CRMU_SWREG_CTRL_ADDR,
|
||||
BIT(SWREG_IHOST1_DIS),
|
||||
BIT(SWREG_IHOST1_REG_RESETB));
|
||||
|
||||
/* wait for regulator supply gets stable */
|
||||
while (!(mmio_read_32(CRMU_SWREG_STATUS_ADDR) &
|
||||
(1 << SWREG_IHOST1_PMU_STABLE)))
|
||||
;
|
||||
|
||||
INFO("Regulator supply got stable\n");
|
||||
|
||||
#ifndef DEFAULT_SWREG_CONFIG
|
||||
swreg_firmware_update();
|
||||
#endif
|
||||
|
||||
set_ihost_vddc_swreg(ihost_uvolts, vddc_uvolts);
|
||||
#endif
|
||||
if (IS_SR_B0(buf[1])) {
|
||||
NOTICE("ddrc_uvolts: %duv\n", ddrc_uvolts);
|
||||
set_swreg(DDR_VDDC, ddrc_uvolts);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_DDR
|
||||
static struct ddr_info ddr_info;
|
||||
#endif
|
||||
#ifdef USE_FRU
|
||||
static struct fru_area_info fru_area[FRU_MAX_NR_AREAS];
|
||||
static struct fru_board_info board_info;
|
||||
static struct fru_time fru_tm;
|
||||
static uint8_t fru_tbl[BCM_MAX_FRU_LEN];
|
||||
|
||||
static void board_detect_fru(void)
|
||||
{
|
||||
uint32_t i, result;
|
||||
int ret = -1;
|
||||
|
||||
result = bcm_emmc_init(false);
|
||||
if (!result) {
|
||||
ERROR("eMMC init failed\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* go through eMMC boot partitions looking for FRU table */
|
||||
for (i = EMMC_BOOT_PARTITION1; i <= EMMC_BOOT_PARTITION2; i++) {
|
||||
result = emmc_partition_select(i);
|
||||
if (!result) {
|
||||
ERROR("Switching to eMMC part %u failed\n", i);
|
||||
return;
|
||||
}
|
||||
|
||||
result = emmc_read(BCM_FRU_TBL_OFFSET, (uintptr_t)fru_tbl,
|
||||
BCM_MAX_FRU_LEN, BCM_MAX_FRU_LEN);
|
||||
if (!result) {
|
||||
ERROR("Failed to read from eMMC part %u\n", i);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Run sanity check and checksum to make sure valid FRU table
|
||||
* is detected
|
||||
*/
|
||||
ret = fru_validate(fru_tbl, fru_area);
|
||||
if (ret < 0) {
|
||||
WARN("FRU table not found in eMMC part %u\n", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* parse DDR information from FRU table */
|
||||
ret = fru_parse_ddr(fru_tbl, &fru_area[FRU_AREA_INTERNAL],
|
||||
&ddr_info);
|
||||
if (ret < 0) {
|
||||
WARN("No FRU DDR info found in eMMC part %u\n", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* parse board information from FRU table */
|
||||
ret = fru_parse_board(fru_tbl, &fru_area[FRU_AREA_BOARD_INFO],
|
||||
&board_info);
|
||||
if (ret < 0) {
|
||||
WARN("No FRU board info found in eMMC part %u\n", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* if we reach here, valid FRU table is parsed */
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
WARN("FRU table missing for this board\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < BCM_MAX_NR_DDR; i++) {
|
||||
INFO("DDR channel index: %d\n", ddr_info.mcb[i].idx);
|
||||
INFO("DDR size %u GB\n", ddr_info.mcb[i].size_mb / 1024);
|
||||
INFO("DDR ref ID by SW (Not MCB Ref ID) 0x%x\n",
|
||||
ddr_info.mcb[i].ref_id);
|
||||
}
|
||||
|
||||
fru_format_time(board_info.mfg_date, &fru_tm);
|
||||
|
||||
INFO("**** FRU board information ****\n");
|
||||
INFO("Language 0x%x\n", board_info.lang);
|
||||
INFO("Manufacturing Date %u.%02u.%02u, %02u:%02u\n",
|
||||
fru_tm.year, fru_tm.month, fru_tm.day,
|
||||
fru_tm.hour, fru_tm.min);
|
||||
INFO("Manufacturing Date(Raw) 0x%x\n", board_info.mfg_date);
|
||||
INFO("Manufacturer %s\n", board_info.manufacturer);
|
||||
INFO("Product Name %s\n", board_info.product_name);
|
||||
INFO("Serial number %s\n", board_info.serial_number);
|
||||
INFO("Part number %s\n", board_info.part_number);
|
||||
INFO("File ID %s\n", board_info.file_id);
|
||||
}
|
||||
#endif /* USE_FRU */
|
||||
|
||||
#ifdef USE_GPIO
|
||||
|
||||
#define INVALID_GPIO 0xffff
|
||||
|
||||
static const int gpio_cfg_bitmap[MAX_NR_GPIOS] = {
|
||||
#ifdef BRD_DETECT_GPIO_BIT0
|
||||
BRD_DETECT_GPIO_BIT0,
|
||||
#else
|
||||
INVALID_GPIO,
|
||||
#endif
|
||||
#ifdef BRD_DETECT_GPIO_BIT1
|
||||
BRD_DETECT_GPIO_BIT1,
|
||||
#else
|
||||
INVALID_GPIO,
|
||||
#endif
|
||||
#ifdef BRD_DETECT_GPIO_BIT2
|
||||
BRD_DETECT_GPIO_BIT2,
|
||||
#else
|
||||
INVALID_GPIO,
|
||||
#endif
|
||||
#ifdef BRD_DETECT_GPIO_BIT3
|
||||
BRD_DETECT_GPIO_BIT3,
|
||||
#else
|
||||
INVALID_GPIO,
|
||||
#endif
|
||||
};
|
||||
|
||||
static uint8_t gpio_bitmap;
|
||||
|
||||
/*
|
||||
* Use an odd number to avoid potential conflict with public GPIO level
|
||||
* defines
|
||||
*/
|
||||
#define GPIO_STATE_FLOAT 15
|
||||
|
||||
/*
|
||||
* If GPIO_SUPPORT_FLOAT_DETECTION is disabled, simply return GPIO level
|
||||
*
|
||||
* If GPIO_SUPPORT_FLOAT_DETECTION is enabled, add additional test for possible
|
||||
* pin floating (unconnected) scenario. This support is assuming externally
|
||||
* applied pull up / pull down will have a stronger pull than the internal pull
|
||||
* up / pull down.
|
||||
*/
|
||||
static uint8_t gpio_get_state(int gpio)
|
||||
{
|
||||
uint8_t val;
|
||||
|
||||
/* set direction to GPIO input */
|
||||
gpio_set_direction(gpio, GPIO_DIR_IN);
|
||||
|
||||
#ifndef GPIO_SUPPORT_FLOAT_DETECTION
|
||||
if (gpio_get_value(gpio) == GPIO_LEVEL_HIGH)
|
||||
val = GPIO_LEVEL_HIGH;
|
||||
else
|
||||
val = GPIO_LEVEL_LOW;
|
||||
|
||||
return val;
|
||||
#else
|
||||
/*
|
||||
* Enable internal pull down. If GPIO level is still high, there must
|
||||
* be an external pull up
|
||||
*/
|
||||
gpio_set_pull(gpio, GPIO_PULL_DOWN);
|
||||
if (gpio_get_value(gpio) == GPIO_LEVEL_HIGH) {
|
||||
val = GPIO_LEVEL_HIGH;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable internal pull up. If GPIO level is still low, there must
|
||||
* be an external pull down
|
||||
*/
|
||||
gpio_set_pull(gpio, GPIO_PULL_UP);
|
||||
if (gpio_get_value(gpio) == GPIO_LEVEL_LOW) {
|
||||
val = GPIO_LEVEL_LOW;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* if reached here, the pin must be not connected */
|
||||
val = GPIO_STATE_FLOAT;
|
||||
|
||||
exit:
|
||||
/* make sure internall pull is disabled */
|
||||
if (gpio_get_pull(gpio) != GPIO_PULL_NONE)
|
||||
gpio_set_pull(gpio, GPIO_PULL_NONE);
|
||||
|
||||
return val;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void board_detect_gpio(void)
|
||||
{
|
||||
unsigned int i, val;
|
||||
int gpio;
|
||||
|
||||
iproc_gpio_init(IPROC_GPIO_S_BASE, IPROC_GPIO_NR,
|
||||
IPROC_IOPAD_MODE_BASE, HSLS_IOPAD_BASE);
|
||||
|
||||
gpio_bitmap = 0;
|
||||
for (i = 0; i < MAX_NR_GPIOS; i++) {
|
||||
if (gpio_cfg_bitmap[i] == INVALID_GPIO)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Construct the bitmap based on GPIO value. Floating pin
|
||||
* detection is a special case. As soon as a floating pin is
|
||||
* detected, a special value of MAX_GPIO_BITMAP_VAL is
|
||||
* assigned and we break out of the loop immediately
|
||||
*/
|
||||
gpio = gpio_cfg_bitmap[i];
|
||||
val = gpio_get_state(gpio);
|
||||
if (val == GPIO_STATE_FLOAT) {
|
||||
gpio_bitmap = MAX_GPIO_BITMAP_VAL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (val == GPIO_LEVEL_HIGH)
|
||||
gpio_bitmap |= BIT(i);
|
||||
}
|
||||
|
||||
memcpy(&ddr_info, &gpio_ddr_info[gpio_bitmap], sizeof(ddr_info));
|
||||
INFO("Board detection GPIO bitmap = 0x%x\n", gpio_bitmap);
|
||||
}
|
||||
#endif /* USE_GPIO */
|
||||
|
||||
static void bcm_board_detect(void)
|
||||
{
|
||||
#ifdef DDR_LEGACY_MCB_SUPPORTED
|
||||
/* Loading default DDR info */
|
||||
memcpy(&ddr_info, &default_ddr_info, sizeof(ddr_info));
|
||||
#endif
|
||||
#ifdef USE_FRU
|
||||
board_detect_fru();
|
||||
#endif
|
||||
#ifdef USE_GPIO
|
||||
board_detect_gpio();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void dump_persistent_regs(void)
|
||||
{
|
||||
NOTICE("pr0: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG0));
|
||||
NOTICE("pr1: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG1));
|
||||
NOTICE("pr2: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG2));
|
||||
NOTICE("pr3: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG3));
|
||||
NOTICE("pr4: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG4));
|
||||
NOTICE("pr5: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG5));
|
||||
NOTICE("pr6: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG6));
|
||||
NOTICE("pr7: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG7));
|
||||
NOTICE("pr8: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG8));
|
||||
NOTICE("pr9: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG9));
|
||||
NOTICE("pr10: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG10));
|
||||
NOTICE("pr11: %x\n", mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG11));
|
||||
}
|
||||
|
||||
void plat_bcm_bl2_plat_arch_setup(void)
|
||||
{
|
||||
if (chip_get_rev_id_major() == CHIP_REV_MAJOR_AX) {
|
||||
if (!(sotp_mem_read(SOTP_ATF_CFG_ROW_ID, SOTP_ROW_NO_ECC) &
|
||||
SOTP_ATF_WATCHDOG_ENABLE_MASK)) {
|
||||
/*
|
||||
* Stop sp805 watchdog timer immediately.
|
||||
* It might has been set up by MCU patch earlier for
|
||||
* eMMC workaround.
|
||||
*
|
||||
* Note the watchdog timer started in CRMU has a very
|
||||
* short timeout and needs to be stopped immediately.
|
||||
* Down below we restart it with a much longer timeout
|
||||
* for BL2 and BL31
|
||||
*/
|
||||
sp805_stop(ARM_SP805_TWDG_BASE);
|
||||
}
|
||||
}
|
||||
|
||||
#if !BRCM_DISABLE_TRUSTED_WDOG
|
||||
/*
|
||||
* start secure watchdog for BL2 and BL31.
|
||||
* Note that UART download can take a longer time,
|
||||
* so do not allow watchdog for UART download,
|
||||
* as this boot source is not a standard modus operandi.
|
||||
*/
|
||||
if (boot_source_get() != BOOT_SOURCE_UART)
|
||||
sp805_start(ARM_SP805_TWDG_BASE, ARM_TWDG_LOAD_VAL);
|
||||
#endif
|
||||
|
||||
#ifdef BCM_ELOG
|
||||
/* Ensure logging is started out fresh in BL2. */
|
||||
mmio_write_32(BCM_ELOG_BL2_BASE, 0);
|
||||
#endif
|
||||
/*
|
||||
* In BL2, since we have very limited space to store logs, we only
|
||||
* save logs that are >= the WARNING level.
|
||||
*/
|
||||
bcm_elog_init((void *)BCM_ELOG_BL2_BASE, BCM_ELOG_BL2_SIZE,
|
||||
LOG_LEVEL_WARNING);
|
||||
|
||||
dump_persistent_regs();
|
||||
|
||||
/* Read CRMU mailbox 0 */
|
||||
NOTICE("RESET (reported by CRMU): 0x%x\n",
|
||||
mmio_read_32(CRMU_READ_MAIL_BOX0));
|
||||
|
||||
/*
|
||||
* All non-boot-source PADs are in forced input-mode at
|
||||
* reset so clear the force on non-boot-source PADs using
|
||||
* CDRU register.
|
||||
*/
|
||||
mmio_clrbits_32((uintptr_t)CDRU_CHIP_IO_PAD_CONTROL,
|
||||
(1 << CDRU_CHIP_IO_PAD_CONTROL__CDRU_IOMUX_FORCE_PAD_IN_R));
|
||||
|
||||
#if DRIVER_OCOTP_ENABLE
|
||||
bcm_otpc_init(&otp_stingray_map);
|
||||
#endif
|
||||
|
||||
set_swreg_based_on_otp();
|
||||
|
||||
#if IHOST_PLL_FREQ != 0
|
||||
bcm_set_ihost_pll_freq(0x0, IHOST_PLL_FREQ);
|
||||
#endif
|
||||
|
||||
#ifdef INCLUDE_EMMC_DRIVER_ERASE_CODE
|
||||
/* The erasable unit of the eMMC is the "Erase Group";
|
||||
* Erase group is measured in write blocks which are the
|
||||
* basic writable units of the Device.
|
||||
* The size of the Erase Group is a Device specific parameter
|
||||
*/
|
||||
emmc_erase(EMMC_ERASE_START_BLOCK, EMMC_ERASE_BLOCK_COUNT,
|
||||
EMMC_ERASE_PARTITION);
|
||||
#endif
|
||||
|
||||
bcm_board_detect();
|
||||
#ifdef DRIVER_EMMC_ENABLE
|
||||
/* Initialize the card, if it is not */
|
||||
if (bcm_emmc_init(true) < 0)
|
||||
WARN("eMMC Card Initialization Failed!!!\n");
|
||||
#endif
|
||||
|
||||
#if BL2_TEST_I2C
|
||||
i2c_test();
|
||||
#endif
|
||||
|
||||
#ifdef USE_DDR
|
||||
ddr_initialize(&ddr_info);
|
||||
|
||||
ddr_secure_region_config(SECURE_DDR_BASE_ADDRESS,
|
||||
SECURE_DDR_END_ADDRESS);
|
||||
#ifdef NITRO_SECURE_ACCESS
|
||||
ddr_secure_region_config(DDR_NITRO_SECURE_REGION_START,
|
||||
DDR_NITRO_SECURE_REGION_END);
|
||||
#endif
|
||||
#else
|
||||
ext_sram_init();
|
||||
#endif
|
||||
|
||||
#if BL2_TEST_MEM
|
||||
ddr_test();
|
||||
#endif
|
||||
|
||||
#ifdef USE_NAND
|
||||
brcm_stingray_nand_init();
|
||||
#endif
|
||||
|
||||
#if defined(USE_PAXB) || defined(USE_PAXC) || defined(USE_SATA)
|
||||
brcm_stingray_pcie_reset();
|
||||
#endif
|
||||
|
||||
#ifdef USE_PAXC
|
||||
if (boot_source_get() != BOOT_SOURCE_QSPI)
|
||||
brcm_stingray_chimp_check_and_fastboot();
|
||||
#endif
|
||||
|
||||
#if ((!CLEAN_DDR || MMU_DISABLED))
|
||||
/*
|
||||
* Now DDR has been initialized. We want to copy all the logs in SRAM
|
||||
* into DDR so we will have much more space to store the logs in the
|
||||
* next boot stage
|
||||
*/
|
||||
bcm_elog_copy_log((void *)BCM_ELOG_BL31_BASE,
|
||||
MIN(BCM_ELOG_BL2_SIZE, BCM_ELOG_BL31_SIZE)
|
||||
);
|
||||
|
||||
/*
|
||||
* We are not yet at the end of BL2, but we can stop log here so we do
|
||||
* not need to add 'bcm_elog_exit' to the standard BL2 code. The
|
||||
* benefit of capturing BL2 logs after this is very minimal in a
|
||||
* production system
|
||||
* NOTE: BL2 logging must be exited before going forward to setup
|
||||
* page tables
|
||||
*/
|
||||
bcm_elog_exit();
|
||||
#endif
|
||||
}
|
60
plat/brcm/board/stingray/src/scp_cmd.c
Normal file
60
plat/brcm/board/stingray/src/scp_cmd.c
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2020, Broadcom
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <arch_helpers.h>
|
||||
#include <common/bl_common.h>
|
||||
#include <drivers/delay_timer.h>
|
||||
|
||||
#include <platform_def.h>
|
||||
#include <scp.h>
|
||||
#include <scp_cmd.h>
|
||||
|
||||
#include "m0_ipc.h"
|
||||
|
||||
/*
|
||||
* Reads a response from CRMU MAILBOX
|
||||
* Assumes that access has been granted and locked.
|
||||
* Note that this is just a temporary implementation until
|
||||
* channels are introduced
|
||||
*/
|
||||
static void scp_read_response(crmu_response_t *resp)
|
||||
{
|
||||
uint32_t code;
|
||||
|
||||
code = mmio_read_32(CRMU_MAIL_BOX0);
|
||||
resp->completed = code & MCU_IPC_CMD_DONE_MASK;
|
||||
resp->cmd = code & SCP_CMD_MASK;
|
||||
resp->ret = (code & MCU_IPC_CMD_REPLY_MASK) >> MCU_IPC_CMD_REPLY_SHIFT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Send a command to SCP and wait for timeout us.
|
||||
* Return: 0 on success
|
||||
* -1 if there was no proper reply from SCP
|
||||
* >0 if there was a response from MCU, but
|
||||
* command completed with an error.
|
||||
*/
|
||||
int scp_send_cmd(uint32_t cmd, uint32_t param, uint32_t timeout)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
mmio_write_32(CRMU_MAIL_BOX0, cmd);
|
||||
mmio_write_32(CRMU_MAIL_BOX1, param);
|
||||
do {
|
||||
crmu_response_t scp_resp;
|
||||
|
||||
udelay(1);
|
||||
scp_read_response(&scp_resp);
|
||||
if (scp_resp.completed &&
|
||||
(scp_resp.cmd == cmd)) {
|
||||
/* This command has completed */
|
||||
ret = scp_resp.ret;
|
||||
break;
|
||||
}
|
||||
} while (--timeout);
|
||||
|
||||
return ret;
|
||||
}
|
227
plat/brcm/board/stingray/src/scp_utils.c
Normal file
227
plat/brcm/board/stingray/src/scp_utils.c
Normal file
@ -0,0 +1,227 @@
|
||||
/*
|
||||
* Copyright (c) 2017-2020, Broadcom
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <arch_helpers.h>
|
||||
#include <common/bl_common.h>
|
||||
#include <common/debug.h>
|
||||
#include <drivers/delay_timer.h>
|
||||
|
||||
#include <bcm_elog_ddr.h>
|
||||
#include <brcm_mhu.h>
|
||||
#include <brcm_scpi.h>
|
||||
#include <chimp.h>
|
||||
#include <cmn_plat_util.h>
|
||||
#include <ddr_init.h>
|
||||
#include <scp.h>
|
||||
#include <scp_cmd.h>
|
||||
#include <scp_utils.h>
|
||||
|
||||
#include "m0_cfg.h"
|
||||
#include "m0_ipc.h"
|
||||
|
||||
#ifdef BCM_ELOG
|
||||
static void prepare_elog(void)
|
||||
{
|
||||
#if (CLEAN_DDR && !defined(MMU_DISABLED))
|
||||
/*
|
||||
* Now DDR has been initialized. We want to copy all the logs in SRAM
|
||||
* into DDR so we will have much more space to store the logs in the
|
||||
* next boot stage
|
||||
*/
|
||||
bcm_elog_copy_log((void *)BCM_ELOG_BL31_BASE,
|
||||
MIN(BCM_ELOG_BL2_SIZE, BCM_ELOG_BL31_SIZE)
|
||||
);
|
||||
|
||||
/*
|
||||
* We are almost at the end of BL2, and we can stop log here so we do
|
||||
* not need to add 'bcm_elog_exit' to the standard BL2 code. The
|
||||
* benefit of capturing BL2 logs after this is very minimal in a
|
||||
* production system.
|
||||
*/
|
||||
bcm_elog_exit();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Notify CRMU that now it should pull logs from DDR instead of from
|
||||
* FS4 SRAM.
|
||||
*/
|
||||
SCP_WRITE_CFG(flash_log.can_use_ddr, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool is_crmu_alive(void)
|
||||
{
|
||||
return (scp_send_cmd(MCU_IPC_MCU_CMD_NOP, 0, SCP_CMD_DEFAULT_TIMEOUT_US)
|
||||
== 0);
|
||||
}
|
||||
|
||||
bool bcm_scp_issue_sys_reset(void)
|
||||
{
|
||||
return (scp_send_cmd(MCU_IPC_MCU_CMD_L1_RESET, 0,
|
||||
SCP_CMD_DEFAULT_TIMEOUT_US));
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that this is just a temporary implementation until
|
||||
* channels are introduced
|
||||
*/
|
||||
|
||||
int plat_bcm_bl2_plat_handle_scp_bl2(image_info_t *scp_bl2_image_info)
|
||||
{
|
||||
int scp_patch_activated, scp_patch_version;
|
||||
#ifndef EMULATION_SETUP
|
||||
uint8_t active_ch_bitmap, i;
|
||||
#endif
|
||||
uint32_t reset_state = 0;
|
||||
uint32_t mcu_ap_init_param = 0;
|
||||
|
||||
/*
|
||||
* First check if SCP patch has already been loaded
|
||||
* Send NOP command and see if there is a valid response
|
||||
*/
|
||||
scp_patch_activated =
|
||||
(scp_send_cmd(MCU_IPC_MCU_CMD_NOP, 0,
|
||||
SCP_CMD_DEFAULT_TIMEOUT_US) == 0);
|
||||
if (scp_patch_activated) {
|
||||
INFO("SCP Patch is already active.\n");
|
||||
|
||||
reset_state = SCP_READ_CFG(board_cfg.reset_state);
|
||||
mcu_ap_init_param = SCP_READ_CFG(board_cfg.mcu_init_param);
|
||||
|
||||
/* Clear reset state, it's been already read */
|
||||
SCP_WRITE_CFG(board_cfg.reset_state, 0);
|
||||
|
||||
if (mcu_ap_init_param & MCU_PATCH_LOADED_BY_NITRO) {
|
||||
/*
|
||||
* Reset "MCU_PATCH_LOADED_BY_NITRO" flag, but
|
||||
* Preserve any other flags we don't deal with here
|
||||
*/
|
||||
INFO("AP booted by Nitro\n");
|
||||
SCP_WRITE_CFG(
|
||||
board_cfg.mcu_init_param,
|
||||
mcu_ap_init_param &
|
||||
~MCU_PATCH_LOADED_BY_NITRO
|
||||
);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* MCU Patch not loaded, so load it.
|
||||
* MCU patch stamps critical points in REG9 (debug test-point)
|
||||
* Display its last content here. This helps to locate
|
||||
* where crash occurred if a CRMU watchdog kicked in.
|
||||
*/
|
||||
int ret;
|
||||
|
||||
INFO("MCU Patch Point: 0x%x\n",
|
||||
mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG9));
|
||||
|
||||
ret = download_scp_patch((void *)scp_bl2_image_info->image_base,
|
||||
scp_bl2_image_info->image_size);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
VERBOSE("SCP Patch loaded OK.\n");
|
||||
|
||||
ret = scp_send_cmd(MCU_IPC_MCU_CMD_INIT,
|
||||
MCU_PATCH_LOADED_BY_AP,
|
||||
SCP_CMD_SCP_BOOT_TIMEOUT_US);
|
||||
if (ret) {
|
||||
ERROR("SCP Patch could not initialize; error %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
INFO("SCP Patch successfully initialized.\n");
|
||||
}
|
||||
|
||||
scp_patch_version = scp_send_cmd(MCU_IPC_MCU_CMD_GET_FW_VERSION, 0,
|
||||
SCP_CMD_DEFAULT_TIMEOUT_US);
|
||||
INFO("SCP Patch version :0x%x\n", scp_patch_version);
|
||||
|
||||
/* Next block just reports current AVS voltages (if applicable) */
|
||||
{
|
||||
uint16_t vcore_mv, ihost03_mv, ihost12_mv;
|
||||
|
||||
vcore_mv = SCP_READ_CFG16(vcore.millivolts) +
|
||||
SCP_READ_CFG8(vcore.avs_cfg.additive_margin);
|
||||
ihost03_mv = SCP_READ_CFG16(ihost03.millivolts) +
|
||||
SCP_READ_CFG8(ihost03.avs_cfg.additive_margin);
|
||||
ihost12_mv = SCP_READ_CFG16(ihost12.millivolts) +
|
||||
SCP_READ_CFG8(ihost12.avs_cfg.additive_margin);
|
||||
|
||||
if (vcore_mv || ihost03_mv || ihost12_mv) {
|
||||
INFO("AVS voltages from cfg (including margin)\n");
|
||||
if (vcore_mv > 0)
|
||||
INFO("%s\tVCORE: %dmv\n",
|
||||
SCP_READ_CFG8(vcore.avs_cfg.avs_set) ?
|
||||
"*" : "n/a", vcore_mv);
|
||||
if (ihost03_mv > 0)
|
||||
INFO("%s\tIHOST03: %dmv\n",
|
||||
SCP_READ_CFG8(ihost03.avs_cfg.avs_set) ?
|
||||
"*" : "n/a", ihost03_mv);
|
||||
if (ihost12_mv > 0)
|
||||
INFO("%s\tIHOST12: %dmv\n",
|
||||
SCP_READ_CFG8(ihost12.avs_cfg.avs_set) ?
|
||||
"*" : "n/a", ihost12_mv);
|
||||
} else {
|
||||
INFO("AVS settings not applicable\n");
|
||||
}
|
||||
}
|
||||
|
||||
#if (CLEAN_DDR && !defined(MMU_DISABLED) && !defined(EMULATION_SETUP))
|
||||
/* This will clean the DDR and enable ECC if set */
|
||||
check_ddr_clean();
|
||||
#endif
|
||||
|
||||
#if (WARMBOOT_DDR_S3_SUPPORT && ELOG_STORE_MEDIA_DDR)
|
||||
elog_init_ddr_log();
|
||||
#endif
|
||||
|
||||
#ifdef BCM_ELOG
|
||||
/* Prepare ELOG to use DDR */
|
||||
prepare_elog();
|
||||
#endif
|
||||
|
||||
#ifndef EMULATION_SETUP
|
||||
/* Ask ddr_init to save obtained DDR information into DDR */
|
||||
ddr_info_save();
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Configure TMON DDR address.
|
||||
* This cfg is common for all cases
|
||||
*/
|
||||
SCP_WRITE_CFG(tmon_cfg.ddr_desc, TMON_SHARED_DDR_ADDRESS);
|
||||
|
||||
if (reset_state == SOFT_RESET_L3 && !mcu_ap_init_param) {
|
||||
INFO("SCP configuration after L3 RESET done.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (bcm_chimp_is_nic_mode())
|
||||
/* Configure AP WDT to not reset the NIC interface */
|
||||
SCP_WRITE_CFG(board_cfg.apwdt_reset_type, SOFT_RESET_L3);
|
||||
|
||||
#if (WARMBOOT_DDR_S3_SUPPORT && ELOG_STORE_MEDIA_DDR)
|
||||
/* When AP WDog triggers perform L3 reset if DDR err logging enabled */
|
||||
SCP_WRITE_CFG(board_cfg.apwdt_reset_type, SOFT_RESET_L3);
|
||||
#endif
|
||||
|
||||
#ifndef EMULATION_SETUP
|
||||
|
||||
#ifdef DDR_SCRUB_ENA
|
||||
ddr_scrub_enable();
|
||||
#endif
|
||||
/* Fill the Active channel information */
|
||||
active_ch_bitmap = get_active_ddr_channel();
|
||||
for (i = 0; i < MAX_NR_DDR_CH; i++)
|
||||
SCP_WRITE_CFG(ddr_cfg.ddr_cfg[i],
|
||||
(active_ch_bitmap & BIT(i)) ? 1 : 0);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user