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

Add BL2 support for Broadcom stingray platform



Change-Id: I5daa3f2b4b9d85cb857547a588571a9aa8ad05c2
Signed-off-by: default avatarSheetal Tigadoli <sheetal.tigadoli@broadcom.com>
parent 9a40c0fb
/*
* 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;
}
/*
* 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 ...@@ -14,3 +14,9 @@ include plat/brcm/board/stingray/bcm958742t.mk
ifneq (${BL33_OVERRIDE_LOAD_ADDR},) ifneq (${BL33_OVERRIDE_LOAD_ADDR},)
$(eval $(call add_define_val,BL33_OVERRIDE_LOAD_ADDR,0xFF000000)) $(eval $(call add_define_val,BL33_OVERRIDE_LOAD_ADDR,0xFF000000))
endif 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
/*
* 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
/*
* 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__);
}
/*
* 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
/*
* 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;
}
/*
* 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
/*
* 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 @@ ...@@ -12,10 +12,8 @@
#include <plat/common/common_def.h> #include <plat/common/common_def.h>
#include <brcm_def.h> #include <brcm_def.h>
#include <cmn_plat_def.h>
#include "sr_def.h" #include "sr_def.h"
#include <cmn_plat_def.h>
/* /*
* Most platform porting definitions provided by included headers * Most platform porting definitions provided by included headers
......
/*
* 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
/*
* 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
/*
* 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
/*
* 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
/*
* 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 @@ ...@@ -4,6 +4,19 @@
# SPDX-License-Identifier: BSD-3-Clause # 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 # Enable workaround for ERRATA_A72_859971
ERRATA_A72_859971 := 1 ERRATA_A72_859971 := 1
...@@ -16,16 +29,42 @@ ARM_BL31_IN_DRAM := 1 ...@@ -16,16 +29,42 @@ ARM_BL31_IN_DRAM := 1
USE_CRMU_SRAM := yes 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 # Use single cluster
ifeq (${USE_SINGLE_CLUSTER},yes) ifeq (${USE_SINGLE_CLUSTER},yes)
$(info Using Single Cluster) $(info Using Single Cluster)
$(eval $(call add_define,USE_SINGLE_CLUSTER)) $(eval $(call add_define,USE_SINGLE_CLUSTER))
endif endif
# Use DDR
ifeq (${USE_DDR},yes)
$(info Using DDR)
$(eval $(call add_define,USE_DDR))
endif
ifeq (${BOARD_CFG},) ifeq (${BOARD_CFG},)
BOARD_CFG := bcm958742k BOARD_CFG := bcm958742k
endif 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 # BL31 build for standalone mode
ifeq (${STANDALONE_BL31},yes) ifeq (${STANDALONE_BL31},yes)
RESET_TO_BL31 := 1 RESET_TO_BL31 := 1
...@@ -43,6 +82,9 @@ endif ...@@ -43,6 +82,9 @@ endif
# Default soft reset is L3 # Default soft reset is L3
$(eval $(call add_define,CONFIG_SOFT_RESET_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 include plat/brcm/board/common/board_common.mk
SOC_DIR := brcm/board/stingray SOC_DIR := brcm/board/stingray
...@@ -58,6 +100,17 @@ PLAT_BL_COMMON_SOURCES += lib/cpus/aarch64/cortex_a72.S \ ...@@ -58,6 +100,17 @@ PLAT_BL_COMMON_SOURCES += lib/cpus/aarch64/cortex_a72.S \
drivers/arm/tzc/tzc400.c \ drivers/arm/tzc/tzc400.c \
plat/${SOC_DIR}/src/topology.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 GICv3 driver files
include drivers/arm/gic/v3/gicv3.mk include drivers/arm/gic/v3/gicv3.mk
...@@ -77,6 +130,12 @@ BL31_SOURCES += \ ...@@ -77,6 +130,12 @@ BL31_SOURCES += \
ifdef SCP_BL2 ifdef SCP_BL2
PLAT_INCLUDES += -Iplat/brcm/common/ 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 \ BL31_SOURCES += plat/brcm/common/brcm_mhu.c \
plat/brcm/common/brcm_scpi.c \ plat/brcm/common/brcm_scpi.c \
plat/${SOC_DIR}/src/brcm_pm_ops.c plat/${SOC_DIR}/src/brcm_pm_ops.c
...@@ -85,5 +144,19 @@ BL31_SOURCES += plat/${SOC_DIR}/src/ihost_pm.c \ ...@@ -85,5 +144,19 @@ BL31_SOURCES += plat/${SOC_DIR}/src/ihost_pm.c \
plat/${SOC_DIR}/src/pm.c plat/${SOC_DIR}/src/pm.c
endif 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. # Do not execute the startup code on warm reset.
PROGRAMMABLE_RESET_ADDRESS := 1 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
/*
* 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
}
/*
* 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;
}
/*
* 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;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment