Add BL2 support for Broadcom stingray platform

Change-Id: I5daa3f2b4b9d85cb857547a588571a9aa8ad05c2
Signed-off-by: Sheetal Tigadoli <sheetal.tigadoli@broadcom.com>
diff --git a/plat/brcm/board/common/bcm_elog.c b/plat/brcm/board/common/bcm_elog.c
new file mode 100644
index 0000000..093157e
--- /dev/null
+++ b/plat/brcm/board/common/bcm_elog.c
@@ -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);
+}
diff --git a/plat/brcm/board/common/bcm_elog_ddr.c b/plat/brcm/board/common/bcm_elog_ddr.c
new file mode 100644
index 0000000..89e7bff
--- /dev/null
+++ b/plat/brcm/board/common/bcm_elog_ddr.c
@@ -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");
+}
diff --git a/plat/brcm/board/common/bcm_elog_ddr.h b/plat/brcm/board/common/bcm_elog_ddr.h
new file mode 100644
index 0000000..6f21a68
--- /dev/null
+++ b/plat/brcm/board/common/bcm_elog_ddr.h
@@ -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 */
diff --git a/plat/brcm/board/common/board_arm_trusted_boot.c b/plat/brcm/board/common/board_arm_trusted_boot.c
new file mode 100644
index 0000000..7a4dad0
--- /dev/null
+++ b/plat/brcm/board/common/board_arm_trusted_boot.c
@@ -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);
+}
diff --git a/plat/brcm/board/common/board_common.mk b/plat/brcm/board/common/board_common.mk
index 7c9cf77..3a879de 100644
--- a/plat/brcm/board/common/board_common.mk
+++ b/plat/brcm/board/common/board_common.mk
@@ -28,6 +28,17 @@
 $(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 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 @@
 $(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_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 @@
 
 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))
diff --git a/plat/brcm/board/common/brcm_mbedtls.c b/plat/brcm/board/common/brcm_mbedtls.c
new file mode 100644
index 0000000..af42b86
--- /dev/null
+++ b/plat/brcm/board/common/brcm_mbedtls.c
@@ -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);
+}
diff --git a/plat/brcm/board/common/chip_id.h b/plat/brcm/board/common/chip_id.h
new file mode 100644
index 0000000..842ac1f
--- /dev/null
+++ b/plat/brcm/board/common/chip_id.h
@@ -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
diff --git a/plat/brcm/board/common/cmn_plat_def.h b/plat/brcm/board/common/cmn_plat_def.h
index 41d9222..8aa7fd4 100644
--- a/plat/brcm/board/common/cmn_plat_def.h
+++ b/plat/brcm/board/common/cmn_plat_def.h
@@ -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
 
diff --git a/plat/brcm/board/common/platform_common.c b/plat/brcm/board/common/platform_common.c
index 9bae83a..f4c9a73 100644
--- a/plat/brcm/board/common/platform_common.c
+++ b/plat/brcm/board/common/platform_common.c
@@ -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)
diff --git a/plat/brcm/board/common/sbl_util.c b/plat/brcm/board/common/sbl_util.c
new file mode 100644
index 0000000..06e5b33
--- /dev/null
+++ b/plat/brcm/board/common/sbl_util.c
@@ -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;
+}
diff --git a/plat/brcm/board/common/sbl_util.h b/plat/brcm/board/common/sbl_util.h
new file mode 100644
index 0000000..0747389
--- /dev/null
+++ b/plat/brcm/board/common/sbl_util.h
@@ -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 */