diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:13:47 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 09:13:47 +0000 |
commit | 102b0d2daa97dae68d3eed54d8fe37a9cc38a892 (patch) | |
tree | bcf648efac40ca6139842707f0eba5a4496a6dd2 /plat/brcm | |
parent | Initial commit. (diff) | |
download | arm-trusted-firmware-102b0d2daa97dae68d3eed54d8fe37a9cc38a892.tar.xz arm-trusted-firmware-102b0d2daa97dae68d3eed54d8fe37a9cc38a892.zip |
Adding upstream version 2.8.0+dfsg.upstream/2.8.0+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
82 files changed, 15176 insertions, 0 deletions
diff --git a/plat/brcm/board/common/bcm_console.c b/plat/brcm/board/common/bcm_console.c new file mode 100644 index 0000000..5f20094 --- /dev/null +++ b/plat/brcm/board/common/bcm_console.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2018-2020, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> + +#include <common/debug.h> +#include <drivers/console.h> +#include <drivers/ti/uart/uart_16550.h> + +#include <platform_def.h> + +/******************************************************************************* + * Functions that set up the console + ******************************************************************************/ +static console_t bcm_boot_console; +static console_t bcm_runtime_console; + +/* Initialize the console to provide early debug support */ +void bcm_console_boot_init(void) +{ + int rc = console_16550_register(PLAT_BRCM_BOOT_UART_BASE, + PLAT_BRCM_BOOT_UART_CLK_IN_HZ, + BRCM_CONSOLE_BAUDRATE, + &bcm_boot_console); + if (rc == 0) { + /* + * The crash console doesn't use the multi console API, it uses + * the core console functions directly. It is safe to call panic + * and let it print debug information. + */ + panic(); + } + + console_set_scope(&bcm_boot_console, CONSOLE_FLAG_BOOT); +} + +void bcm_console_boot_end(void) +{ + console_flush(); + + (void)console_unregister(&bcm_boot_console); +} + +/* Initialize the runtime console */ +void bcm_console_runtime_init(void) +{ + int rc = console_16550_register(PLAT_BRCM_BL31_RUN_UART_BASE, + PLAT_BRCM_BL31_RUN_UART_CLK_IN_HZ, + BRCM_CONSOLE_BAUDRATE, + &bcm_runtime_console); + if (rc == 0) + panic(); + + console_set_scope(&bcm_runtime_console, CONSOLE_FLAG_RUNTIME); +} + +void bcm_console_runtime_end(void) +{ + console_flush(); + + (void)console_unregister(&bcm_runtime_console); +} 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..da18c31 --- /dev/null +++ b/plat/brcm/board/common/board_arm_trusted_boot.c @@ -0,0 +1,625 @@ +/* + * Copyright 2015 - 2020 Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <inttypes.h> +#include <stdint.h> +#include <string.h> + +#include <common/debug.h> +#include <lib/mmio.h> +#include <plat/common/platform.h> +#include <tools_share/tbbr_oid.h> + +#include <sbl_util.h> +#include <sotp.h> + +/* Weak definition may be overridden in specific platform */ +#pragma weak plat_match_rotpk +#pragma weak plat_get_nv_ctr +#pragma weak plat_set_nv_ctr + +/* SHA256 algorithm */ +#define SHA256_BYTES 32 + +/* ROTPK locations */ +#define ARM_ROTPK_REGS_ID 1 +#define ARM_ROTPK_DEVEL_RSA_ID 2 +#define BRCM_ROTPK_SOTP_RSA_ID 3 + +#if !ARM_ROTPK_LOCATION_ID + #error "ARM_ROTPK_LOCATION_ID not defined" +#endif + +static const unsigned char rotpk_hash_hdr[] = + "\x30\x31\x30\x0D\x06\x09\x60\x86\x48" + "\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20"; +static const unsigned int rotpk_hash_hdr_len = sizeof(rotpk_hash_hdr) - 1; +static unsigned char rotpk_hash_der[sizeof(rotpk_hash_hdr) - 1 + SHA256_BYTES]; + +#if (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_DEVEL_RSA_ID) +static const unsigned char arm_devel_rotpk_hash[] = + "\xB0\xF3\x82\x09\x12\x97\xD8\x3A" + "\x37\x7A\x72\x47\x1B\xEC\x32\x73" + "\xE9\x92\x32\xE2\x49\x59\xF6\x5E" + "\x8B\x4A\x4A\x46\xD8\x22\x9A\xDA"; +#endif + +#pragma weak plat_rotpk_hash +const unsigned char plat_rotpk_hash[] = + "\xdb\x06\x67\x95\x4f\x88\x2b\x88" + "\x49\xbf\x70\x3f\xde\x50\x4a\x96" + "\xd8\x17\x69\xd4\xa0\x6c\xba\xee" + "\x66\x3e\x71\x82\x2d\x95\x69\xe4"; + +#pragma weak rom_slice +const unsigned char rom_slice[] = + "\x77\x06\xbc\x98\x40\xbe\xfd\xab" + "\x60\x4b\x74\x3c\x9a\xb3\x80\x75" + "\x39\xb6\xda\x27\x07\x2e\x5b\xbf" + "\x5c\x47\x91\xc9\x95\x26\x26\x0c"; + +#if (ARM_ROTPK_LOCATION_ID == BRCM_ROTPK_SOTP_RSA_ID) +static int plat_is_trusted_boot(void) +{ + uint64_t section3_row0_data; + + section3_row0_data = sotp_mem_read(SOTP_DEVICE_SECURE_CFG0_ROW, 0); + + if ((section3_row0_data & SOTP_DEVICE_SECURE_CFG0_AB_MASK) == 0) { + INFO("NOT AB\n"); + return 0; + } + + INFO("AB\n"); + return TRUSTED_BOARD_BOOT; +} + +/* + * FAST AUTH is enabled if all following conditions are met: + * - AB part + * - SOTP.DEV != 0 + * - SOTP.CID != 0 + * - SOTP.ENC_DEV_TYPE = ENC_AB_DEV + * - Manuf_debug strap set high + */ +static int plat_fast_auth_enabled(void) +{ + uint32_t chip_state; + uint64_t section3_row0_data; + uint64_t section3_row1_data; + + section3_row0_data = + sotp_mem_read(SOTP_DEVICE_SECURE_CFG0_ROW, 0); + section3_row1_data = + sotp_mem_read(SOTP_DEVICE_SECURE_CFG1_ROW, 0); + + chip_state = mmio_read_32(SOTP_REGS_SOTP_CHIP_STATES); + + if (plat_is_trusted_boot() && + (section3_row0_data & SOTP_DEVICE_SECURE_CFG0_DEV_MASK) && + (section3_row0_data & SOTP_DEVICE_SECURE_CFG0_CID_MASK) && + ((section3_row1_data & SOTP_ENC_DEV_TYPE_MASK) == + SOTP_ENC_DEV_TYPE_AB_DEV) && + (chip_state & SOTP_CHIP_STATES_MANU_DEBUG_MASK)) + return 1; + + return 0; +} +#endif + +/* + * Return the ROTPK hash in the following ASN.1 structure in DER format: + * + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL + * } + * + * DigestInfo ::= SEQUENCE { + * digestAlgorithm AlgorithmIdentifier, + * digest OCTET STRING + * } + */ +int plat_get_rotpk_info(void *cookie, void **key_ptr, unsigned int *key_len, + unsigned int *flags) +{ + uint8_t *dst; + + assert(key_ptr != NULL); + assert(key_len != NULL); + assert(flags != NULL); + + *flags = 0; + + /* Copy the DER header */ + memcpy(rotpk_hash_der, rotpk_hash_hdr, rotpk_hash_hdr_len); + dst = (uint8_t *)&rotpk_hash_der[rotpk_hash_hdr_len]; + +#if (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_DEVEL_RSA_ID) + memcpy(dst, arm_devel_rotpk_hash, SHA256_BYTES); +#elif (ARM_ROTPK_LOCATION_ID == ARM_ROTPK_REGS_ID) + uint32_t *src, tmp; + unsigned int words, i; + + /* + * Append the hash from Trusted Root-Key Storage registers. The hash has + * not been written linearly into the registers, so we have to do a bit + * of byte swapping: + * + * 0x00 0x04 0x08 0x0C 0x10 0x14 0x18 0x1C + * +---------------------------------------------------------------+ + * | Reg0 | Reg1 | Reg2 | Reg3 | Reg4 | Reg5 | Reg6 | Reg7 | + * +---------------------------------------------------------------+ + * | ... ... | | ... ... | + * | +--------------------+ | +-------+ + * | | | | + * +----------------------------+ +----------------------------+ + * | | | | + * +-------+ | +--------------------+ | + * | | | | + * v v v v + * +---------------------------------------------------------------+ + * | | | + * +---------------------------------------------------------------+ + * 0 15 16 31 + * + * Additionally, we have to access the registers in 32-bit words + */ + words = SHA256_BYTES >> 3; + + /* Swap bytes 0-15 (first four registers) */ + src = (uint32_t *)TZ_PUB_KEY_HASH_BASE; + for (i = 0 ; i < words ; i++) { + tmp = src[words - 1 - i]; + /* Words are read in little endian */ + *dst++ = (uint8_t)((tmp >> 24) & 0xFF); + *dst++ = (uint8_t)((tmp >> 16) & 0xFF); + *dst++ = (uint8_t)((tmp >> 8) & 0xFF); + *dst++ = (uint8_t)(tmp & 0xFF); + } + + /* Swap bytes 16-31 (last four registers) */ + src = (uint32_t *)(TZ_PUB_KEY_HASH_BASE + SHA256_BYTES / 2); + for (i = 0 ; i < words ; i++) { + tmp = src[words - 1 - i]; + *dst++ = (uint8_t)((tmp >> 24) & 0xFF); + *dst++ = (uint8_t)((tmp >> 16) & 0xFF); + *dst++ = (uint8_t)((tmp >> 8) & 0xFF); + *dst++ = (uint8_t)(tmp & 0xFF); + } +#elif (ARM_ROTPK_LOCATION_ID == BRCM_ROTPK_SOTP_RSA_ID) +{ + int i; + int ret = -1; + + /* + * In non-AB mode, we do not read the key. + * In AB mode: + * - The Dauth is in BL11 if SBL is enabled + * - The Dauth is in SOTP if SBL is disabled. + */ + if (plat_is_trusted_boot() == 0) { + + INFO("NON-AB: Do not read DAUTH!\n"); + *flags = ROTPK_NOT_DEPLOYED; + ret = 0; + + } else if ((sbl_status() == SBL_ENABLED) && + (mmio_read_32(BL11_DAUTH_BASE) == BL11_DAUTH_ID)) { + + /* Read hash from BL11 */ + INFO("readKeys (DAUTH) from BL11\n"); + + memcpy(dst, + (void *)(BL11_DAUTH_BASE + sizeof(uint32_t)), + SHA256_BYTES); + + for (i = 0; i < SHA256_BYTES; i++) + if (dst[i] != 0) + break; + + if (i >= SHA256_BYTES) + ERROR("Hash not valid from BL11\n"); + else + ret = 0; + + } else if (sotp_key_erased()) { + + memcpy(dst, plat_rotpk_hash, SHA256_BYTES); + + INFO("SOTP erased, Use internal key hash.\n"); + ret = 0; + + } else if (plat_fast_auth_enabled()) { + + INFO("AB DEV: FAST AUTH!\n"); + *flags = ROTPK_NOT_DEPLOYED; + ret = 0; + + } else if (!(mmio_read_32(SOTP_STATUS_1) & SOTP_DAUTH_ECC_ERROR_MASK)) { + + /* Read hash from SOTP */ + ret = sotp_read_key(dst, + SHA256_BYTES, + SOTP_DAUTH_ROW, + SOTP_K_HMAC_ROW-1); + + INFO("sotp_read_key (DAUTH): %i\n", ret); + + } else { + + uint64_t row_data; + uint32_t k; + + for (k = 0; k < (SOTP_K_HMAC_ROW - SOTP_DAUTH_ROW); k++) { + row_data = sotp_mem_read(SOTP_DAUTH_ROW + k, + SOTP_ROW_NO_ECC); + + if (row_data != 0) + break; + } + + if (k == (SOTP_K_HMAC_ROW - SOTP_DAUTH_ROW)) { + INFO("SOTP NOT PROGRAMMED: Do not use DAUTH!\n"); + + if (sotp_mem_read(SOTP_ATF2_CFG_ROW_ID, + SOTP_ROW_NO_ECC) & SOTP_ROMKEY_MASK) { + memcpy(dst, plat_rotpk_hash, SHA256_BYTES); + + INFO("Use internal key hash.\n"); + ret = 0; + } else { + *flags = ROTPK_NOT_DEPLOYED; + ret = 0; + } + } else { + INFO("No hash found in SOTP\n"); + } + } + if (ret) + return ret; +} +#endif + + *key_ptr = (void *)rotpk_hash_der; + *key_len = (unsigned int)sizeof(rotpk_hash_der); + *flags |= ROTPK_IS_HASH; + + return 0; +} + +#define SOTP_NUM_BITS_PER_ROW 41 +#define SOTP_NVCTR_ROW_ALL_ONES 0x1ffffffffff +#define SOTP_NVCTR_TRUSTED_IN_USE \ + ((uint64_t)0x3 << (SOTP_NUM_BITS_PER_ROW-2)) +#define SOTP_NVCTR_NON_TRUSTED_IN_USE ((uint64_t)0x3) +#define SOTP_NVCTR_TRUSTED_NEAR_END SOTP_NVCTR_NON_TRUSTED_IN_USE +#define SOTP_NVCTR_NON_TRUSTED_NEAR_END SOTP_NVCTR_TRUSTED_IN_USE + +#define SOTP_NVCTR_ROW_START 64 +#define SOTP_NVCTR_ROW_END 75 + +/* + * SOTP NVCTR are stored in section 10 of SOTP (rows 64-75). + * Each row of SOTP is 41 bits. + * NVCTR's are stored in a bitstream format. + * We are tolerant to consecutive bit errors. + * Trusted NVCTR starts at the top of row 64 in bitstream format. + * Non Trusted NVCTR starts at the bottom of row 75 in reverse bitstream. + * Each row can only be used by 1 of the 2 counters. This is determined + * by 2 zeros remaining at the beginning or end of the last available row. + * If one counter has already starting using a row, the other will be + * prevent from writing to that row. + * + * Example counter values for SOTP programmed below: + * Trusted Counter (rows64-69) = 5 * 41 + 40 = 245 + * NonTrusted Counter (row75-71) = 3 * 41 + 4 = 127 + * 40 39 38 37 36 ..... 5 4 3 2 1 0 + * row 64 1 1 1 1 1 1 1 1 1 1 1 + * row 65 1 1 1 1 1 1 1 1 1 1 1 + * row 66 1 1 1 1 1 1 1 1 1 1 1 + * row 67 1 1 1 1 1 1 1 1 1 1 1 + * row 68 1 1 1 1 1 1 1 1 1 1 1 + * row 69 1 1 1 1 1 1 1 1 1 1 0 + * row 71 0 0 0 0 0 0 0 0 0 0 0 + * row 71 0 0 0 0 0 0 0 0 0 0 0 + * row 71 0 0 0 0 0 0 0 1 1 1 1 + * row 73 1 1 1 1 1 1 1 1 1 1 1 + * row 74 1 1 1 1 1 1 1 1 1 1 1 + * row 75 1 1 1 1 1 1 1 1 1 1 1 + * + */ + +#if (DEBUG == 1) +/* + * Dump sotp rows + */ +void sotp_dump_rows(uint32_t start_row, uint32_t end_row) +{ + int32_t rownum; + uint64_t rowdata; + + for (rownum = start_row; rownum <= end_row; rownum++) { + rowdata = sotp_mem_read(rownum, SOTP_ROW_NO_ECC); + INFO("%d 0x%" PRIx64 "\n", rownum, rowdata); + } +} +#endif + +/* + * Get SOTP Trusted nvctr + */ +unsigned int sotp_get_trusted_nvctr(void) +{ + uint64_t rowdata; + uint64_t nextrowdata; + uint32_t rownum; + unsigned int nvctr; + + rownum = SOTP_NVCTR_ROW_START; + nvctr = SOTP_NUM_BITS_PER_ROW; + + /* + * Determine what row has last valid data for trusted ctr + */ + rowdata = sotp_mem_read(rownum, SOTP_ROW_NO_ECC); + while ((rowdata & SOTP_NVCTR_TRUSTED_IN_USE) && + (rowdata & SOTP_NVCTR_TRUSTED_NEAR_END) && + (rownum < SOTP_NVCTR_ROW_END)) { + /* + * Current row in use and has data in last 2 bits as well. + * Check if next row also has data for this counter + */ + nextrowdata = sotp_mem_read(rownum+1, SOTP_ROW_NO_ECC); + if (nextrowdata & SOTP_NVCTR_TRUSTED_IN_USE) { + /* Next row also has data so increment rownum */ + rownum++; + nvctr += SOTP_NUM_BITS_PER_ROW; + rowdata = nextrowdata; + } else { + /* Next row does not have data */ + break; + } + } + + if (rowdata & SOTP_NVCTR_TRUSTED_IN_USE) { + while ((rowdata & 0x1) == 0) { + nvctr--; + rowdata >>= 1; + } + } else + nvctr -= SOTP_NUM_BITS_PER_ROW; + + INFO("CTR %i\n", nvctr); + return nvctr; +} + +/* + * Get SOTP NonTrusted nvctr + */ +unsigned int sotp_get_nontrusted_nvctr(void) +{ + uint64_t rowdata; + uint64_t nextrowdata; + uint32_t rownum; + unsigned int nvctr; + + nvctr = SOTP_NUM_BITS_PER_ROW; + rownum = SOTP_NVCTR_ROW_END; + + /* + * Determine what row has last valid data for nontrusted ctr + */ + rowdata = sotp_mem_read(rownum, SOTP_ROW_NO_ECC); + while ((rowdata & SOTP_NVCTR_NON_TRUSTED_NEAR_END) && + (rowdata & SOTP_NVCTR_NON_TRUSTED_IN_USE) && + (rownum > SOTP_NVCTR_ROW_START)) { + /* + * Current row in use and has data in last 2 bits as well. + * Check if next row also has data for this counter + */ + nextrowdata = sotp_mem_read(rownum-1, SOTP_ROW_NO_ECC); + if (nextrowdata & SOTP_NVCTR_NON_TRUSTED_IN_USE) { + /* Next row also has data so decrement rownum */ + rownum--; + nvctr += SOTP_NUM_BITS_PER_ROW; + rowdata = nextrowdata; + } else { + /* Next row does not have data */ + break; + } + } + + if (rowdata & SOTP_NVCTR_NON_TRUSTED_IN_USE) { + while ((rowdata & ((uint64_t)0x1 << (SOTP_NUM_BITS_PER_ROW-1))) + == + 0) { + nvctr--; + rowdata <<= 1; + } + } else + nvctr -= SOTP_NUM_BITS_PER_ROW; + + INFO("NCTR %i\n", nvctr); + return nvctr; +} + +/* + * Set SOTP Trusted nvctr + */ +int sotp_set_trusted_nvctr(unsigned int nvctr) +{ + int numrows_available; + uint32_t nontrusted_rownum; + uint32_t trusted_rownum; + uint64_t rowdata; + unsigned int maxnvctr; + + /* + * Read SOTP to find out how many rows are used by the + * NON Trusted nvctr + */ + nontrusted_rownum = SOTP_NVCTR_ROW_END; + do { + rowdata = sotp_mem_read(nontrusted_rownum, SOTP_ROW_NO_ECC); + if (rowdata & SOTP_NVCTR_NON_TRUSTED_IN_USE) + nontrusted_rownum--; + else + break; + } while (nontrusted_rownum >= SOTP_NVCTR_ROW_START); + + /* + * Calculate maximum value we can have for nvctr based on + * number of available rows. + */ + numrows_available = nontrusted_rownum - SOTP_NVCTR_ROW_START + 1; + maxnvctr = numrows_available * SOTP_NUM_BITS_PER_ROW; + if (maxnvctr) { + /* + * Last 2 bits of counter can't be written or it will + * overflow with nontrusted counter + */ + maxnvctr -= 2; + } + + if (nvctr > maxnvctr) { + /* Error - not enough room */ + WARN("tctr not set\n"); + return 1; + } + + /* + * It is safe to write the nvctr, fill all 1's up to the + * last row and then fill the last row with partial bitstream + */ + trusted_rownum = SOTP_NVCTR_ROW_START; + rowdata = SOTP_NVCTR_ROW_ALL_ONES; + + while (nvctr >= SOTP_NUM_BITS_PER_ROW) { + sotp_mem_write(trusted_rownum, SOTP_ROW_NO_ECC, rowdata); + nvctr -= SOTP_NUM_BITS_PER_ROW; + trusted_rownum++; + } + rowdata <<= (SOTP_NUM_BITS_PER_ROW - nvctr); + sotp_mem_write(trusted_rownum, SOTP_ROW_NO_ECC, rowdata); + return 0; +} + +/* + * Set SOTP NonTrusted nvctr + */ +int sotp_set_nontrusted_nvctr(unsigned int nvctr) +{ + int numrows_available; + uint32_t nontrusted_rownum; + uint32_t trusted_rownum; + uint64_t rowdata; + unsigned int maxnvctr; + + /* + * Read SOTP to find out how many rows are used by the + * Trusted nvctr + */ + trusted_rownum = SOTP_NVCTR_ROW_START; + do { + rowdata = sotp_mem_read(trusted_rownum, SOTP_ROW_NO_ECC); + if (rowdata & SOTP_NVCTR_TRUSTED_IN_USE) + trusted_rownum++; + else + break; + } while (trusted_rownum <= SOTP_NVCTR_ROW_END); + + /* + * Calculate maximum value we can have for nvctr based on + * number of available rows. + */ + numrows_available = SOTP_NVCTR_ROW_END - trusted_rownum + 1; + maxnvctr = numrows_available * SOTP_NUM_BITS_PER_ROW; + if (maxnvctr) { + /* + * Last 2 bits of counter can't be written or it will + * overflow with nontrusted counter + */ + maxnvctr -= 2; + } + + if (nvctr > maxnvctr) { + /* Error - not enough room */ + WARN("nctr not set\n"); + return 1; + } + + /* + * It is safe to write the nvctr, fill all 1's up to the + * last row and then fill the last row with partial bitstream + */ + nontrusted_rownum = SOTP_NVCTR_ROW_END; + rowdata = SOTP_NVCTR_ROW_ALL_ONES; + + while (nvctr >= SOTP_NUM_BITS_PER_ROW) { + sotp_mem_write(nontrusted_rownum, SOTP_ROW_NO_ECC, rowdata); + nvctr -= SOTP_NUM_BITS_PER_ROW; + nontrusted_rownum--; + } + rowdata >>= (SOTP_NUM_BITS_PER_ROW - nvctr); + sotp_mem_write(nontrusted_rownum, SOTP_ROW_NO_ECC, rowdata); + return 0; +} + +/* + * Return the non-volatile counter value stored in the platform. The cookie + * will contain the OID of the counter in the certificate. + * + * Return: 0 = success, Otherwise = error + */ +int plat_get_nv_ctr(void *cookie, unsigned int *nv_ctr) +{ + const char *oid; + + assert(cookie != NULL); + assert(nv_ctr != NULL); + + *nv_ctr = 0; + if ((sotp_mem_read(SOTP_ATF_CFG_ROW_ID, SOTP_ROW_NO_ECC) & + SOTP_ATF_NVCOUNTER_ENABLE_MASK)) { + oid = (const char *)cookie; + if (strcmp(oid, TRUSTED_FW_NVCOUNTER_OID) == 0) + *nv_ctr = sotp_get_trusted_nvctr(); + else if (strcmp(oid, NON_TRUSTED_FW_NVCOUNTER_OID) == 0) + *nv_ctr = sotp_get_nontrusted_nvctr(); + else + return 1; + } + return 0; +} + +/* + * Store a new non-volatile counter value. + * + * Return: 0 = success, Otherwise = error + */ +int plat_set_nv_ctr(void *cookie, unsigned int nv_ctr) +{ + const char *oid; + + if (sotp_mem_read(SOTP_ATF_CFG_ROW_ID, SOTP_ROW_NO_ECC) & + SOTP_ATF_NVCOUNTER_ENABLE_MASK) { + INFO("set CTR %i\n", nv_ctr); + oid = (const char *)cookie; + if (strcmp(oid, TRUSTED_FW_NVCOUNTER_OID) == 0) + return sotp_set_trusted_nvctr(nv_ctr); + else if (strcmp(oid, NON_TRUSTED_FW_NVCOUNTER_OID) == 0) + return sotp_set_nontrusted_nvctr(nv_ctr); + return 1; + } + return 0; +} + +int plat_get_mbedtls_heap(void **heap_addr, size_t *heap_size) +{ + return get_mbedtls_heap_helper(heap_addr, heap_size); +} diff --git a/plat/brcm/board/common/board_common.c b/plat/brcm/board/common/board_common.c new file mode 100644 index 0000000..2f764ab --- /dev/null +++ b/plat/brcm/board/common/board_common.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2016 - 2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <brcm_def.h> +#include <plat_brcm.h> + +#if IMAGE_BL2 +const mmap_region_t plat_brcm_mmap[] = { + HSLS_REGION, + BRCM_MAP_SHARED_RAM, + BRCM_MAP_NAND_RO, + BRCM_MAP_QSPI_RO, +#ifdef PERIPH0_REGION + PERIPH0_REGION, +#endif +#ifdef PERIPH1_REGION + PERIPH1_REGION, +#endif +#ifdef USE_DDR + BRCM_MAP_NS_DRAM1, +#if BRCM_BL31_IN_DRAM + BRCM_MAP_BL31_SEC_DRAM, +#endif +#else +#ifdef BRCM_MAP_EXT_SRAM + BRCM_MAP_EXT_SRAM, +#endif +#endif +#if defined(USE_CRMU_SRAM) && defined(CRMU_SRAM_BASE) + CRMU_SRAM_REGION, +#endif + {0} +}; +#endif + +#if IMAGE_BL31 +const mmap_region_t plat_brcm_mmap[] = { + HSLS_REGION, +#ifdef PERIPH0_REGION + PERIPH0_REGION, +#endif +#ifdef PERIPH1_REGION + PERIPH1_REGION, +#endif +#ifdef PERIPH2_REGION + PERIPH2_REGION, +#endif +#ifdef USB_REGION + USB_REGION, +#endif +#ifdef USE_DDR + BRCM_MAP_NS_DRAM1, +#ifdef BRCM_MAP_NS_SHARED_DRAM + BRCM_MAP_NS_SHARED_DRAM, +#endif +#else +#ifdef BRCM_MAP_EXT_SRAM + BRCM_MAP_EXT_SRAM, +#endif +#endif +#if defined(USE_CRMU_SRAM) && defined(CRMU_SRAM_BASE) + CRMU_SRAM_REGION, +#endif + {0} +}; +#endif + +CASSERT((ARRAY_SIZE(plat_brcm_mmap) - 1) <= PLAT_BRCM_MMAP_ENTRIES, + assert_plat_brcm_mmap_mismatch); +CASSERT((PLAT_BRCM_MMAP_ENTRIES + BRCM_BL_REGIONS) <= MAX_MMAP_REGIONS, + assert_max_mmap_regions); diff --git a/plat/brcm/board/common/board_common.mk b/plat/brcm/board/common/board_common.mk new file mode 100644 index 0000000..24a27ed --- /dev/null +++ b/plat/brcm/board/common/board_common.mk @@ -0,0 +1,294 @@ +# +# Copyright (c) 2015 - 2021, Broadcom +# +# SPDX-License-Identifier: BSD-3-Clause +# + +PLAT_BL_COMMON_SOURCES += plat/brcm/board/common/board_common.c + +# If no board config makefile, do not include it +ifneq (${BOARD_CFG},) +BOARD_CFG_MAKE := $(shell find plat/brcm/board/${PLAT} -name '${BOARD_CFG}.mk') +$(eval $(call add_define,BOARD_CFG)) +ifneq (${BOARD_CFG_MAKE},) +$(info Including ${BOARD_CFG_MAKE}) +include ${BOARD_CFG_MAKE} +else +$(error Error: File ${BOARD_CFG}.mk not found in plat/brcm/board/${PLAT}) +endif +endif + +# To compile with highest log level (VERBOSE) set value to 50 +LOG_LEVEL := 40 + +# Use custom generic timer clock +ifneq (${GENTIMER_ACTUAL_CLOCK},) +$(info Using GENTIMER_ACTUAL_CLOCK=$(GENTIMER_ACTUAL_CLOCK)) +SYSCNT_FREQ := $(GENTIMER_ACTUAL_CLOCK) +$(eval $(call add_define,SYSCNT_FREQ)) +endif + +ifeq (${DRIVER_EMMC_ENABLE},) +DRIVER_EMMC_ENABLE :=1 +endif + +ifeq (${DRIVER_SPI_ENABLE},) +DRIVER_SPI_ENABLE := 0 +endif + +ifeq (${DRIVER_I2C_ENABLE},) +DRIVER_I2C_ENABLE := 0 +endif + +# By default, Trusted Watchdog is always enabled unless SPIN_ON_BL1_EXIT is set +ifeq (${BRCM_DISABLE_TRUSTED_WDOG},) +BRCM_DISABLE_TRUSTED_WDOG := 0 +endif +ifeq (${SPIN_ON_BL1_EXIT}, 1) +BRCM_DISABLE_TRUSTED_WDOG := 1 +endif + +$(eval $(call assert_boolean,BRCM_DISABLE_TRUSTED_WDOG)) +$(eval $(call add_define,BRCM_DISABLE_TRUSTED_WDOG)) + +# Process ARM_BL31_IN_DRAM flag +ifeq (${ARM_BL31_IN_DRAM},) +ARM_BL31_IN_DRAM := 0 +endif +$(eval $(call assert_boolean,ARM_BL31_IN_DRAM)) +$(eval $(call add_define,ARM_BL31_IN_DRAM)) + +ifeq (${STANDALONE_BL2},yes) +BL2_LOG_LEVEL := 40 +$(eval $(call add_define,MMU_DISABLED)) +endif + +# BL2 XIP from QSPI +RUN_BL2_FROM_QSPI := 0 +ifeq (${RUN_BL2_FROM_QSPI},1) +$(eval $(call add_define,RUN_BL2_FROM_QSPI)) +endif + +# BL2 XIP from NAND +RUN_BL2_FROM_NAND := 0 +ifeq (${RUN_BL2_FROM_NAND},1) +$(eval $(call add_define,RUN_BL2_FROM_NAND)) +endif + +ifneq (${ELOG_AP_UART_LOG_BASE},) +$(eval $(call add_define,ELOG_AP_UART_LOG_BASE)) +endif + +ifeq (${ELOG_SUPPORT},1) +ifeq (${ELOG_STORE_MEDIA},DDR) +$(eval $(call add_define,ELOG_STORE_MEDIA_DDR)) +ifneq (${ELOG_STORE_OFFSET},) +$(eval $(call add_define,ELOG_STORE_OFFSET)) +endif +endif +endif + +ifneq (${BL2_LOG_LEVEL},) +$(eval $(call add_define,BL2_LOG_LEVEL)) +endif + +ifneq (${BL31_LOG_LEVEL},) +$(eval $(call add_define,BL31_LOG_LEVEL)) +endif + +# Use CRMU SRAM from iHOST +ifneq (${USE_CRMU_SRAM},) +$(eval $(call add_define,USE_CRMU_SRAM)) +endif + +# Use PIO mode if DDR is not used +ifeq (${USE_DDR},yes) +EMMC_USE_DMA := 1 +else +EMMC_USE_DMA := 0 +endif +$(eval $(call add_define,EMMC_USE_DMA)) + +# On BRCM platforms, separate the code and read-only data sections to allow +# mapping the former as executable and the latter as execute-never. +SEPARATE_CODE_AND_RODATA := 1 + +# Use generic OID definition (tbbr_oid.h) +USE_TBBR_DEFS := 1 + +PLAT_INCLUDES += -Iplat/brcm/board/common \ + -Iinclude/drivers/brcm \ + -Iinclude/drivers/brcm/emmc \ + -Iinclude/drivers/brcm/mdio + +PLAT_BL_COMMON_SOURCES += plat/brcm/common/brcm_common.c \ + plat/brcm/board/common/cmn_sec.c \ + plat/brcm/board/common/bcm_console.c \ + plat/brcm/board/common/brcm_mbedtls.c \ + plat/brcm/board/common/plat_setup.c \ + plat/brcm/board/common/platform_common.c \ + drivers/arm/sp804/sp804_delay_timer.c \ + drivers/brcm/sotp.c \ + drivers/delay_timer/delay_timer.c \ + drivers/io/io_fip.c \ + drivers/io/io_memmap.c \ + drivers/io/io_storage.c \ + plat/brcm/common/brcm_io_storage.c \ + plat/brcm/board/common/err.c \ + plat/brcm/board/common/sbl_util.c \ + drivers/arm/sp805/sp805.c + +# Add RNG driver +DRIVER_RNG_ENABLE := 1 +ifeq (${DRIVER_RNG_ENABLE},1) +PLAT_BL_COMMON_SOURCES += drivers/brcm/rng.c +endif + +# Add eMMC driver +ifeq (${DRIVER_EMMC_ENABLE},1) +$(eval $(call add_define,DRIVER_EMMC_ENABLE)) + +EMMC_SOURCES += drivers/brcm/emmc/emmc_chal_sd.c \ + drivers/brcm/emmc/emmc_csl_sdcard.c \ + drivers/brcm/emmc/emmc_csl_sdcmd.c \ + drivers/brcm/emmc/emmc_pboot_hal_memory_drv.c + +PLAT_BL_COMMON_SOURCES += ${EMMC_SOURCES} + +ifeq (${DRIVER_EMMC_ENABLE_DATA_WIDTH_8BIT},) +$(eval $(call add_define,DRIVER_EMMC_ENABLE_DATA_WIDTH_8BIT)) +endif +endif + +BL2_SOURCES += plat/brcm/common/brcm_bl2_mem_params_desc.c \ + plat/brcm/common/brcm_image_load.c \ + common/desc_image_load.c + +BL2_SOURCES += plat/brcm/common/brcm_bl2_setup.c + +BL31_SOURCES += plat/brcm/common/brcm_bl31_setup.c + +ifeq (${BCM_ELOG},yes) +ELOG_SOURCES += plat/brcm/board/common/bcm_elog.c +BL2_SOURCES += ${ELOG_SOURCES} +BL31_SOURCES += ${ELOG_SOURCES} +endif + +# Add spi driver +ifeq (${DRIVER_SPI_ENABLE},1) +PLAT_BL_COMMON_SOURCES += drivers/brcm/spi/iproc_spi.c \ + drivers/brcm/spi/iproc_qspi.c +endif + +# Add spi nor/flash driver +ifeq (${DRIVER_SPI_NOR_ENABLE},1) +PLAT_BL_COMMON_SOURCES += drivers/brcm/spi_sf.c \ + drivers/brcm/spi_flash.c +endif + +ifeq (${DRIVER_I2C_ENABLE},1) +$(eval $(call add_define,DRIVER_I2C_ENABLE)) +BL2_SOURCES += drivers/brcm/i2c/i2c.c +PLAT_INCLUDES += -Iinclude/drivers/brcm/i2c +endif + +ifeq (${DRIVER_OCOTP_ENABLE},1) +$(eval $(call add_define,DRIVER_OCOTP_ENABLE)) +BL2_SOURCES += drivers/brcm/ocotp.c +endif + +# Enable FRU table support +ifeq (${USE_FRU},yes) +$(eval $(call add_define,USE_FRU)) +BL2_SOURCES += drivers/brcm/fru.c +endif + +# Enable GPIO support +ifeq (${USE_GPIO},yes) +$(eval $(call add_define,USE_GPIO)) +BL2_SOURCES += drivers/gpio/gpio.c +BL2_SOURCES += drivers/brcm/iproc_gpio.c +ifeq (${GPIO_SUPPORT_FLOAT_DETECTION},yes) +$(eval $(call add_define,GPIO_SUPPORT_FLOAT_DETECTION)) +endif +endif + +# Include mbedtls if it can be located +MBEDTLS_DIR ?= mbedtls +MBEDTLS_CHECK := $(shell find ${MBEDTLS_DIR}/include -name '$(notdir ${MBEDTLS_DIR})') + +ifneq (${MBEDTLS_CHECK},) +$(info Found mbedTLS at ${MBEDTLS_DIR}) +PLAT_INCLUDES += -I${MBEDTLS_DIR}/include/mbedtls + +# By default, use RSA keys +KEY_ALG := rsa_1_5 + +# Include common TBB sources +AUTH_SOURCES += drivers/auth/auth_mod.c \ + drivers/auth/crypto_mod.c \ + drivers/auth/img_parser_mod.c \ + drivers/auth/tbbr/tbbr_cot_common.c \ + drivers/auth/tbbr/tbbr_cot_bl2.c + +BL2_SOURCES += ${AUTH_SOURCES} + +# Use ATF framework for MBEDTLS +TRUSTED_BOARD_BOOT := 1 +CRYPTO_LIB_MK := drivers/auth/mbedtls/mbedtls_crypto.mk +IMG_PARSER_LIB_MK := drivers/auth/mbedtls/mbedtls_x509.mk +$(info Including ${CRYPTO_LIB_MK}) +include ${CRYPTO_LIB_MK} +$(info Including ${IMG_PARSER_LIB_MK}) +include ${IMG_PARSER_LIB_MK} + +# Use ATF secure boot functions +# Use Hardcoded hash for devel + +ARM_ROTPK_LOCATION=arm_rsa +ifeq (${ARM_ROTPK_LOCATION}, arm_rsa) +ARM_ROTPK_LOCATION_ID=ARM_ROTPK_DEVEL_RSA_ID +ROT_KEY=plat/arm/board/common/rotpk/arm_rotprivk_rsa.pem +else ifeq (${ARM_ROTPK_LOCATION}, brcm_rsa) +ARM_ROTPK_LOCATION_ID=BRCM_ROTPK_SOTP_RSA_ID +ifeq (${ROT_KEY},) +ROT_KEY=plat/brcm/board/common/rotpk/rsa_dauth2048_key.pem +endif +KEY_FIND := $(shell m="${ROT_KEY}"; [ -f "$$m" ] && echo "$$m") +ifeq (${KEY_FIND},) +$(error Error: No ${ROT_KEY} located) +else +$(info Using ROT_KEY: ${ROT_KEY}) +endif +else +$(error "Unsupported ARM_ROTPK_LOCATION value") +endif + +$(eval $(call add_define,ARM_ROTPK_LOCATION_ID)) +PLAT_BL_COMMON_SOURCES+=plat/brcm/board/common/board_arm_trusted_boot.c +endif + +#M0 runtime firmware +ifdef SCP_BL2 +$(eval $(call add_define,NEED_SCP_BL2)) +SCP_CFG_DIR=$(dir ${SCP_BL2}) +PLAT_INCLUDES += -I${SCP_CFG_DIR} +endif + +ifneq (${NEED_BL33},yes) +# If there is no BL33, BL31 will jump to this address. +ifeq (${USE_DDR},yes) +PRELOADED_BL33_BASE := 0x80000000 +else +PRELOADED_BL33_BASE := 0x74000000 +endif +endif + +# Use translation tables library v1 by default +ARM_XLAT_TABLES_LIB_V1 := 1 +ifeq (${ARM_XLAT_TABLES_LIB_V1}, 1) +$(eval $(call assert_boolean,ARM_XLAT_TABLES_LIB_V1)) +$(eval $(call add_define,ARM_XLAT_TABLES_LIB_V1)) +PLAT_BL_COMMON_SOURCES += lib/xlat_tables/aarch64/xlat_tables.c \ + lib/xlat_tables/xlat_tables_common.c +endif 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 new file mode 100644 index 0000000..79d9a29 --- /dev/null +++ b/plat/brcm/board/common/cmn_plat_def.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2015 - 2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef CMN_PLAT_DEF_H +#define CMN_PLAT_DEF_H + +#include <bcm_elog.h> +#include <platform_def.h> + +#ifndef GET_LOG_LEVEL +#define GET_LOG_LEVEL() LOG_LEVEL +#endif + +#ifndef SET_LOG_LEVEL +#define SET_LOG_LEVEL(x) ((void)(x)) +#endif + +#define PLAT_LOG_NOTICE(...) \ + do { \ + if (GET_LOG_LEVEL() >= LOG_LEVEL_NOTICE) { \ + bcm_elog(LOG_MARKER_NOTICE __VA_ARGS__); \ + tf_log(LOG_MARKER_NOTICE __VA_ARGS__); \ + } \ + } while (0) + +#define PLAT_LOG_ERROR(...) \ + do { \ + if (GET_LOG_LEVEL() >= LOG_LEVEL_ERROR) { \ + bcm_elog(LOG_MARKER_ERROR, __VA_ARGS__); \ + tf_log(LOG_MARKER_ERROR __VA_ARGS__); \ + } \ + } while (0) + +#define PLAT_LOG_WARN(...) \ + do { \ + if (GET_LOG_LEVEL() >= LOG_LEVEL_WARNING) { \ + bcm_elog(LOG_MARKER_WARNING, __VA_ARGS__);\ + tf_log(LOG_MARKER_WARNING __VA_ARGS__); \ + } \ + } while (0) + +#define PLAT_LOG_INFO(...) \ + do { \ + if (GET_LOG_LEVEL() >= LOG_LEVEL_INFO) { \ + bcm_elog(LOG_MARKER_INFO __VA_ARGS__); \ + tf_log(LOG_MARKER_INFO __VA_ARGS__); \ + } \ + } while (0) + +#define PLAT_LOG_VERBOSE(...) \ + do { \ + if (GET_LOG_LEVEL() >= LOG_LEVEL_VERBOSE) { \ + bcm_elog(LOG_MARKER_VERBOSE __VA_ARGS__);\ + tf_log(LOG_MARKER_VERBOSE __VA_ARGS__); \ + } \ + } while (0) + +/* + * The number of regions like RO(code), coherent and data required by + * different BL stages which need to be mapped in the MMU. + */ +#if USE_COHERENT_MEM +#define CMN_BL_REGIONS 3 +#else +#define CMN_BL_REGIONS 2 +#endif + +/* + * FIP definitions + */ +#define PLAT_FIP_ATTEMPT_OFFSET 0x20000 +#define PLAT_FIP_NUM_ATTEMPTS 128 + +#define PLAT_BRCM_FIP_QSPI_BASE QSPI_BASE_ADDR +#define PLAT_BRCM_FIP_NAND_BASE NAND_BASE_ADDR +#define PLAT_BRCM_FIP_MAX_SIZE 0x01000000 + +#define PLAT_BRCM_FIP_BASE PLAT_BRCM_FIP_QSPI_BASE +#endif diff --git a/plat/brcm/board/common/cmn_plat_util.h b/plat/brcm/board/common/cmn_plat_util.h new file mode 100644 index 0000000..178c843 --- /dev/null +++ b/plat/brcm/board/common/cmn_plat_util.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2015 - 2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef CMN_PLAT_UTIL_H +#define CMN_PLAT_UTIL_H + +#include <lib/mmio.h> + +/* BOOT source */ +#define BOOT_SOURCE_MASK 7 +#define BOOT_SOURCE_QSPI 0 +#define BOOT_SOURCE_NAND 1 +#define BOOT_SOURCE_SPI_NAND 2 +#define BOOT_SOURCE_UART 3 +#define BOOT_SOURCE_RES4 4 +#define BOOT_SOURCE_EMMC 5 +#define BOOT_SOURCE_ATE 6 +#define BOOT_SOURCE_USB 7 +#define BOOT_SOURCE_MAX 8 +#define BOOT_SOURCE_UNKNOWN (-1) + +#define KHMAC_SHA256_KEY_SIZE 32 + +#define SOFT_PWR_UP_RESET_L0 0 +#define SOFT_SYS_RESET_L1 1 +#define SOFT_RESET_L3 0x3 + +#define BOOT_SOURCE_SOFT_DATA_OFFSET 8 +#define BOOT_SOURCE_SOFT_ENABLE_OFFSET 14 +#define BOOT_SOURCE_SOFT_ENABLE_MASK BIT(BOOT_SOURCE_SOFT_ENABLE_OFFSET) + +typedef struct _key { + uint8_t hmac_sha256[KHMAC_SHA256_KEY_SIZE]; +} cmn_key_t; + +uint32_t boot_source_get(void); +void bl1_platform_wait_events(void); +void plat_soft_reset(uint32_t reset); + +#endif diff --git a/plat/brcm/board/common/cmn_sec.c b/plat/brcm/board/common/cmn_sec.c new file mode 100644 index 0000000..c80d5dd --- /dev/null +++ b/plat/brcm/board/common/cmn_sec.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2015-2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <stdint.h> + +#include <common/debug.h> +#include <lib/mmio.h> + +#include <cmn_sec.h> + +#pragma weak plat_tz_master_default_cfg +#pragma weak plat_tz_sdio_ns_master_set +#pragma weak plat_tz_usb_ns_master_set + +void plat_tz_master_default_cfg(void) +{ + /* This function should be implemented in the platform side. */ + ERROR("%s: TZ CONFIGURATION NOT SET!!!\n", __func__); +} + +void plat_tz_sdio_ns_master_set(uint32_t ns) +{ + /* This function should be implemented in the platform side. */ + ERROR("%s: TZ CONFIGURATION NOT SET!!!\n", __func__); +} + +void plat_tz_usb_ns_master_set(uint32_t ns) +{ + /* This function should be implemented in the platform side. */ + ERROR("%s: TZ CONFIGURATION NOT SET!!!\n", __func__); +} + +void tz_master_default_cfg(void) +{ + plat_tz_master_default_cfg(); +} + +void tz_sdio_ns_master_set(uint32_t ns) +{ + plat_tz_sdio_ns_master_set(ns); +} + +void tz_usb_ns_master_set(uint32_t ns) +{ + plat_tz_usb_ns_master_set(ns); +} diff --git a/plat/brcm/board/common/cmn_sec.h b/plat/brcm/board/common/cmn_sec.h new file mode 100644 index 0000000..f74863d --- /dev/null +++ b/plat/brcm/board/common/cmn_sec.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2015-2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef CMN_SEC_H +#define CMN_SEC_H + +#include <stdint.h> + +#define SECURE_MASTER 0 +#define NS_MASTER 1 + +void tz_master_default_cfg(void); +void tz_usb_ns_master_set(uint32_t ns); +void tz_sdio_ns_master_set(uint32_t ns); + +#endif diff --git a/plat/brcm/board/common/err.c b/plat/brcm/board/common/err.c new file mode 100644 index 0000000..1fc73c4 --- /dev/null +++ b/plat/brcm/board/common/err.c @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2016 - 2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <stdint.h> + +#include <arch_helpers.h> +#include <common/debug.h> +#include <drivers/console.h> +#include <lib/mmio.h> + +#include <platform_def.h> + +#define L0_RESET 0x2 + +/* + * Brcm error handler + */ +void plat_error_handler(int err) +{ + INFO("L0 reset...\n"); + + /* Ensure the characters are flushed out */ + console_flush(); + + mmio_write_32(CRMU_SOFT_RESET_CTRL, L0_RESET); + + /* + * In case we get here: + * Loop until the watchdog resets the system + */ + while (1) { + wfi(); + } +} diff --git a/plat/brcm/board/common/plat_setup.c b/plat/brcm/board/common/plat_setup.c new file mode 100644 index 0000000..95e12ed --- /dev/null +++ b/plat/brcm/board/common/plat_setup.c @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2015 - 2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <plat/common/platform.h> + +#include <platform_def.h> + +/* + * This function returns the fixed clock frequency at which private + * timers run. This value will be programmed into CNTFRQ_EL0. + */ +unsigned int plat_get_syscnt_freq2(void) +{ + return SYSCNT_FREQ; +} + +static const char * const plat_prefix_str[] = { + "E: ", "N: ", "W: ", "I: ", "V: " +}; + +const char *plat_log_get_prefix(unsigned int log_level) +{ + return plat_prefix_str[log_level - 1U]; +} diff --git a/plat/brcm/board/common/platform_common.c b/plat/brcm/board/common/platform_common.c new file mode 100644 index 0000000..f4c9a73 --- /dev/null +++ b/plat/brcm/board/common/platform_common.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2015-2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch_helpers.h> +#include <common/debug.h> +#include <drivers/brcm/sotp.h> + +#include <cmn_plat_util.h> +#include <platform_def.h> + +uint32_t boot_source_get(void) +{ + uint32_t data; + +#ifdef FORCE_BOOTSOURCE + data = FORCE_BOOTSOURCE; +#else + /* Read primary boot strap from CRMU persistent registers */ + data = mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG1); + if (data & BOOT_SOURCE_SOFT_ENABLE_MASK) { + data >>= BOOT_SOURCE_SOFT_DATA_OFFSET; + } else { + uint64_t sotp_atf_row; + + sotp_atf_row = + sotp_mem_read(SOTP_ATF_CFG_ROW_ID, SOTP_ROW_NO_ECC); + + if (sotp_atf_row & SOTP_BOOT_SOURCE_ENABLE_MASK) { + /* Construct the boot source based on SOTP bits */ + data = 0; + if (sotp_atf_row & SOTP_BOOT_SOURCE_BITS0) + data |= 0x1; + if (sotp_atf_row & SOTP_BOOT_SOURCE_BITS1) + data |= 0x2; + if (sotp_atf_row & SOTP_BOOT_SOURCE_BITS2) + data |= 0x4; + } else { + + /* + * This path is for L0 reset with + * Primary Boot source disabled in SOTP. + * BOOT_SOURCE_FROM_PR_ON_L1 compile flag will allow + * to never come back here so that the + * external straps will not be read on L1 reset. + */ + + /* Use the external straps */ + data = mmio_read_32(ROM_S0_IDM_IO_STATUS); + +#ifdef BOOT_SOURCE_FROM_PR_ON_L1 + /* Enable boot source read from PR#1 */ + mmio_setbits_32(CRMU_IHOST_SW_PERSISTENT_REG1, + BOOT_SOURCE_SOFT_ENABLE_MASK); + + /* set boot source */ + data &= BOOT_SOURCE_MASK; + mmio_clrsetbits_32(CRMU_IHOST_SW_PERSISTENT_REG1, + BOOT_SOURCE_MASK << BOOT_SOURCE_SOFT_DATA_OFFSET, + data << BOOT_SOURCE_SOFT_DATA_OFFSET); +#endif + } + } +#endif + return (data & BOOT_SOURCE_MASK); +} + +void __dead2 plat_soft_reset(uint32_t reset) +{ + if (reset == SOFT_RESET_L3) { + mmio_setbits_32(CRMU_IHOST_SW_PERSISTENT_REG1, reset); + mmio_write_32(CRMU_MAIL_BOX0, 0x0); + mmio_write_32(CRMU_MAIL_BOX1, 0xFFFFFFFF); + } + + if (reset != SOFT_SYS_RESET_L1) + reset = SOFT_PWR_UP_RESET_L0; + + if (reset == SOFT_PWR_UP_RESET_L0) + INFO("L0 RESET...\n"); + + if (reset == SOFT_SYS_RESET_L1) + INFO("L1 RESET...\n"); + + console_flush(); + + mmio_clrbits_32(CRMU_SOFT_RESET_CTRL, 1 << reset); + + while (1) { + ; + } +} 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 */ diff --git a/plat/brcm/board/common/timer_sync.c b/plat/brcm/board/common/timer_sync.c new file mode 100644 index 0000000..7e33a94 --- /dev/null +++ b/plat/brcm/board/common/timer_sync.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2015 - 2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch_helpers.h> +#include <common/debug.h> +#include <lib/mmio.h> + +#include <platform_def.h> +#include <timer_sync.h> + +/******************************************************************************* + * Defines related to time sync and satelite timers + ******************************************************************************/ +#define TIME_SYNC_WR_ENA ((uint32_t)0xACCE55 << 8) +#define IHOST_STA_TMR_CTRL 0x1800 +#define IHOST_SAT_TMR_INC_L 0x1814 +#define IHOST_SAT_TMR_INC_H 0x1818 + +#define SAT_TMR_CYCLE_DELAY 2 +#define SAT_TMR_32BIT_WRAP_VAL (BIT_64(32) - SAT_TMR_CYCLE_DELAY) + +void ihost_enable_satellite_timer(unsigned int cluster_id) +{ + uintptr_t ihost_base; + uint32_t time_lx, time_h; + uintptr_t ihost_enable; + + VERBOSE("Program iHost%u satellite timer\n", cluster_id); + ihost_base = IHOST0_BASE + cluster_id * IHOST_ADDR_SPACE; + + /* this read starts the satellite timer counting from 0 */ + ihost_enable = CENTRAL_TIMER_GET_IHOST_ENA_BASE + cluster_id * 4; + time_lx = mmio_read_32(ihost_enable); + + /* + * Increment the satellite timer by the central timer plus 2 + * to accommodate for a 1 cycle delay through NOC + * plus counter starting from 0. + */ + mmio_write_32(ihost_base + IHOST_SAT_TMR_INC_L, + time_lx + SAT_TMR_CYCLE_DELAY); + + /* + * Read the latched upper data, if lx will wrap by adding 2 to it + * we need to handle the wrap + */ + time_h = mmio_read_32(CENTRAL_TIMER_GET_H); + if (time_lx >= SAT_TMR_32BIT_WRAP_VAL) + mmio_write_32(ihost_base + IHOST_SAT_TMR_INC_H, time_h + 1); + else + mmio_write_32(ihost_base + IHOST_SAT_TMR_INC_H, time_h); +} + +void brcm_timer_sync_init(void) +{ + unsigned int cluster_id; + + /* Get the Time Sync module out of reset */ + mmio_setbits_32(CDRU_MISC_RESET_CONTROL, + BIT(CDRU_MISC_RESET_CONTROL_TS_RESET_N)); + + /* Deassert the Central Timer TIMER_EN signal for all module */ + mmio_write_32(CENTRAL_TIMER_SAT_TMR_ENA, TIME_SYNC_WR_ENA); + + /* enables/programs iHost0 satellite timer*/ + cluster_id = MPIDR_AFFLVL1_VAL(read_mpidr()); + ihost_enable_satellite_timer(cluster_id); +} diff --git a/plat/brcm/board/stingray/aarch64/plat_helpers.S b/plat/brcm/board/stingray/aarch64/plat_helpers.S new file mode 100644 index 0000000..9a2039d --- /dev/null +++ b/plat/brcm/board/stingray/aarch64/plat_helpers.S @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2015-2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <asm_macros.S> +#include <assert_macros.S> +#include <cpu_macros.S> +#include <cortex_a72.h> +#include <drivers/ti/uart/uart_16550.h> + +#include <platform_def.h> + + .globl plat_reset_handler + .globl platform_get_entrypoint + .globl plat_secondary_cold_boot_setup + .globl platform_mem_init + .globl platform_check_mpidr + .globl plat_crash_console_init + .globl plat_crash_console_putc + .globl plat_crash_console_flush + .globl plat_disable_acp + .globl plat_is_my_cpu_primary + .globl plat_my_core_pos + .globl platform_is_primary_cpu + .globl plat_brcm_calc_core_pos + .globl plat_get_my_entrypoint + + + /* ------------------------------------------------------------ + * void plat_l2_init(void); + * + * BL1 and BL2 run with one core, one cluster + * This is safe to disable cluster coherency + * to make use of the data cache MMU WB attribute + * for the SRAM. + * + * Set L2 Auxiliary Control Register + * -------------------------------------------------------------------- + */ +func plat_l2_init + mrs x0, CORTEX_A72_L2ACTLR_EL1 +#if (IMAGE_BL1 || IMAGE_BL2) || defined(USE_SINGLE_CLUSTER) + orr x0, x0, #CORTEX_A72_L2ACTLR_DISABLE_ACE_SH_OR_CHI +#else + bic x0, x0, #CORTEX_A72_L2ACTLR_DISABLE_ACE_SH_OR_CHI +#endif + msr CORTEX_A72_L2ACTLR_EL1, x0 + + /* Set L2 Control Register */ + mrs x0, CORTEX_A72_L2CTLR_EL1 + mov x1, #((CORTEX_A72_L2_DATA_RAM_LATENCY_MASK << \ + CORTEX_A72_L2CTLR_DATA_RAM_LATENCY_SHIFT) | \ + (CORTEX_A72_L2_TAG_RAM_LATENCY_MASK << \ + CORTEX_A72_L2CTLR_TAG_RAM_LATENCY_SHIFT) | \ + (U(0x1) << CORTEX_A72_L2CTLR_TAG_RAM_SETUP_SHIFT) | \ + (U(0x1) << CORTEX_A72_L2CTLR_DATA_RAM_SETUP_SHIFT)) + bic x0, x0, x1 + mov x1, #((CORTEX_A72_L2_DATA_RAM_LATENCY_3_CYCLES << \ + CORTEX_A72_L2CTLR_DATA_RAM_LATENCY_SHIFT) | \ + (U(0x1) << CORTEX_A72_L2CTLR_TAG_RAM_SETUP_SHIFT) | \ + (U(0x1) << CORTEX_A72_L2CTLR_DATA_RAM_SETUP_SHIFT)) + orr x0, x0, x1 + msr CORTEX_A72_L2CTLR_EL1, x0 + + isb + ret +endfunc plat_l2_init + + /* -------------------------------------------------------------------- + * void plat_reset_handler(void); + * + * Before adding code in this function, refer to the guidelines in + * docs/firmware-design.md. + * + * -------------------------------------------------------------------- + */ +func plat_reset_handler + mov x9, x30 + bl plat_l2_init + mov x30, x9 + ret +endfunc plat_reset_handler + + /* ----------------------------------------------------- + * void platform_get_entrypoint (unsigned int mpid); + * + * Main job of this routine is to distinguish between + * a cold and warm boot. + * On a cold boot the secondaries first wait for the + * platform to be initialized after which they are + * hotplugged in. The primary proceeds to perform the + * platform initialization. + * ----------------------------------------------------- + */ +func platform_get_entrypoint + /*TBD-STINGRAY*/ + mov x0, #0 + ret +endfunc platform_get_entrypoint + + /* ----------------------------------------------------- + * void plat_secondary_cold_boot_setup (void); + * + * This function performs any platform specific actions + * needed for a secondary cpu after a cold reset e.g + * mark the cpu's presence, mechanism to place it in a + * holding pen etc. + * ----------------------------------------------------- + */ +func plat_secondary_cold_boot_setup + bl plat_my_core_pos + mov_imm x1, SECONDARY_CPU_SPIN_BASE_ADDR + add x0, x1, x0, LSL #3 + mov x1, #0 + str x1, [x0] + + /* Wait until the entrypoint gets populated */ +poll_mailbox: + ldr x1, [x0] + cbz x1, 1f + br x1 +1: + wfe + b poll_mailbox +endfunc plat_secondary_cold_boot_setup + + + /* ----------------------------------------------------- + * void platform_mem_init(void); + * + * We don't need to carry out any memory initialization + * on CSS platforms. The Secure RAM is accessible straight away. + * ----------------------------------------------------- + */ +func platform_mem_init + /*TBD-STINGRAY*/ + ret +endfunc platform_mem_init + + /* ----------------------------------------------------- + * Placeholder function which should be redefined by + * each platform. + * ----------------------------------------------------- + */ +func platform_check_mpidr + /*TBD-STINGRAY*/ + mov x0, xzr + ret +endfunc platform_check_mpidr + + /* --------------------------------------------- + * int plat_crash_console_init(void) + * Function to initialize the crash console + * without a C Runtime to print crash report. + * Clobber list : x0, x1, x2 + * --------------------------------------------- + */ + +func plat_crash_console_init + mov_imm x0, BRCM_CRASH_CONSOLE_BASE + mov_imm x1, BRCM_CRASH_CONSOLE_REFCLK + mov_imm x2, BRCM_CRASH_CONSOLE_BAUDRATE + b console_16550_core_init + ret +endfunc plat_crash_console_init + + /* --------------------------------------------- + * int plat_crash_console_putc(void) + * Function to print a character on the crash + * console without a C Runtime. + * Clobber list : x1, x2, x3 + * --------------------------------------------- + */ + +func plat_crash_console_putc + mov_imm x1, BRCM_CRASH_CONSOLE_BASE + b console_16550_core_putc + ret +endfunc plat_crash_console_putc + + /* --------------------------------------------- + * void plat_crash_console_flush(void) + * Function to flush crash console + * Clobber list : x0, x1 + * --------------------------------------------- + */ +func plat_crash_console_flush + mov_imm x0, BRCM_CRASH_CONSOLE_BASE + b console_16550_core_flush + ret +endfunc plat_crash_console_flush + + /* ----------------------------------------------------- + * Placeholder function which should be redefined by + * each platform. This function is allowed to use + * registers x0 - x17. + * ----------------------------------------------------- + */ + +func plat_disable_acp + /*TBD-STINGRAY*/ + ret +endfunc plat_disable_acp + + /* ----------------------------------------------------- + * unsigned int plat_is_my_cpu_primary (void); + * + * Find out whether the current cpu is the primary + * cpu (applicable only after a cold boot) + * ----------------------------------------------------- + */ +func plat_is_my_cpu_primary + mrs x0, mpidr_el1 + b platform_is_primary_cpu +endfunc plat_is_my_cpu_primary + + /* ----------------------------------------------------- + * unsigned int plat_my_core_pos(void) + * This function uses the plat_brcm_calc_core_pos() + * definition to get the index of the calling CPU. + * ----------------------------------------------------- + */ +func plat_my_core_pos + mrs x0, mpidr_el1 + b plat_brcm_calc_core_pos +endfunc plat_my_core_pos + + /* ----------------------------------------------------- + * unsigned int platform_is_primary_cpu (void); + * + * Find out whether the current cpu is the primary + * cpu (applicable only after a cold boot) + * ----------------------------------------------------- + */ +func platform_is_primary_cpu + mov x9, x30 + bl plat_my_core_pos + cmp x0, #PRIMARY_CPU + cset x0, eq + ret x9 +endfunc platform_is_primary_cpu + + /* ----------------------------------------------------- + * unsigned int plat_brcm_calc_core_pos(uint64_t mpidr) + * Helper function to calculate the core position. + * With this function: CorePos = (ClusterId * 4) + + * CoreId + * ----------------------------------------------------- + */ +func plat_brcm_calc_core_pos + and x1, x0, #MPIDR_CPU_MASK + and x0, x0, #MPIDR_CLUSTER_MASK + add x0, x1, x0, LSR #7 + ret +endfunc plat_brcm_calc_core_pos + +func plat_get_my_entrypoint + mrs x0, mpidr_el1 + b platform_get_entrypoint +endfunc plat_get_my_entrypoint diff --git a/plat/brcm/board/stingray/bcm958742t-ns3.mk b/plat/brcm/board/stingray/bcm958742t-ns3.mk new file mode 100644 index 0000000..5164eeb --- /dev/null +++ b/plat/brcm/board/stingray/bcm958742t-ns3.mk @@ -0,0 +1,22 @@ +# +# Copyright (c) 2015 - 2020, Broadcom +# +# SPDX-License-Identifier: BSD-3-Clause +# + +####################################################### +# Board config file for bcm958742t-ns3 Stingray SST100-NS3 +####################################################### + +include plat/brcm/board/stingray/bcm958742t.mk + +# Load BL33 at 0xFF00_0000 address +ifneq (${BL33_OVERRIDE_LOAD_ADDR},) +$(eval $(call add_define_val,BL33_OVERRIDE_LOAD_ADDR,0xFF000000)) +endif + +# Nitro DDR secure memory +# Nitro FW and config 0x8AE00000 - 0x8B000000 +# Nitro Crash dump 0x8B000000 - 0x8D000000 +DDR_NITRO_SECURE_REGION_START := 0x8AE00000 +DDR_NITRO_SECURE_REGION_END := 0x8D000000 diff --git a/plat/brcm/board/stingray/bcm958742t.mk b/plat/brcm/board/stingray/bcm958742t.mk new file mode 100644 index 0000000..5e164b8 --- /dev/null +++ b/plat/brcm/board/stingray/bcm958742t.mk @@ -0,0 +1,19 @@ +# +# Copyright (c) 2015 - 2020, Broadcom +# +# SPDX-License-Identifier: BSD-3-Clause +# + +####################################################### +# Board config file for bcm958742t Stingray SST100 +####################################################### +BOARD_FAMILY := "<bcm958742t.h>" +$(eval $(call add_define,BOARD_FAMILY)) + +# Board has internal programmable regulator +IHOST_REG_TYPE := IHOST_REG_INTEGRATED +$(eval $(call add_define,IHOST_REG_TYPE)) + +# Board has internal programmable regulator +VDDC_REG_TYPE := VDDC_REG_INTEGRATED +$(eval $(call add_define,VDDC_REG_TYPE)) diff --git a/plat/brcm/board/stingray/driver/ddr/soc/include/board_family.h b/plat/brcm/board/stingray/driver/ddr/soc/include/board_family.h new file mode 100644 index 0000000..b2427cf --- /dev/null +++ b/plat/brcm/board/stingray/driver/ddr/soc/include/board_family.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2019-2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef BOARD_FAMILY_H +#define BOARD_FAMILY_H + +#if defined(DRIVER_SPD_ENABLE) && !defined(DRIVER_SPD_SPOOF) +#include <spd.h> +#endif + +#ifdef USE_GPIO +/* max number of supported GPIOs to construct the bitmap for board detection */ +#define MAX_NR_GPIOS 4 + +/* max GPIO bitmap value */ +#define MAX_GPIO_BITMAP_VAL (BIT(MAX_NR_GPIOS) - 1) +#endif + +struct mcb_ref_group { + uint32_t mcb_ref; + unsigned int *mcb_cfg; +}; + +#define MCB_REF_GROUP(ref) \ +{ \ + .mcb_ref = 0x ## ref, \ + .mcb_cfg = mcb_ ## ref, \ +} + +#endif diff --git a/plat/brcm/board/stingray/driver/ext_sram_init/ext_sram_init.c b/plat/brcm/board/stingray/driver/ext_sram_init/ext_sram_init.c new file mode 100644 index 0000000..74d2077 --- /dev/null +++ b/plat/brcm/board/stingray/driver/ext_sram_init/ext_sram_init.c @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2016-2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> + +#include <arch_helpers.h> +#include <common/bl_common.h> +#include <common/debug.h> +#include <drivers/delay_timer.h> +#include <lib/mmio.h> + +#include <platform_def.h> + +static void brcm_stingray_pnor_pinmux_init(void) +{ + unsigned int i; + + INFO(" - pnor pinmux init start.\n"); + + /* Set PNOR_ADV_N_MODE_SEL_CONTROL.fsel = 0x2 */ + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2dc), + MODE_SEL_CONTROL_FSEL_MASK, + MODE_SEL_CONTROL_FSEL_MODE2); + + /* Set PNOR_BAA_N_MODE_SEL_CONTROL.fsel = 0x2 */ + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2e0), + MODE_SEL_CONTROL_FSEL_MASK, + MODE_SEL_CONTROL_FSEL_MODE2); + + /* Set PNOR_BLS_0_N_MODE_SEL_CONTROL.fsel = 0x2 */ + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2e4), + MODE_SEL_CONTROL_FSEL_MASK, + MODE_SEL_CONTROL_FSEL_MODE2); + + /* Set PNOR_BLS_1_N_MODE_SEL_CONTROL.fsel = 0x2 */ + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2e8), + MODE_SEL_CONTROL_FSEL_MASK, + MODE_SEL_CONTROL_FSEL_MODE2); + + /* Set PNOR_CRE_MODE_SEL_CONTROL.fsel = 0x2 */ + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2ec), + MODE_SEL_CONTROL_FSEL_MASK, + MODE_SEL_CONTROL_FSEL_MODE2); + + /* Set PNOR_CS_2_N_MODE_SEL_CONTROL.fsel = 0x2 */ + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2f0), + MODE_SEL_CONTROL_FSEL_MASK, + MODE_SEL_CONTROL_FSEL_MODE2); + + /* Set PNOR_CS_1_N_MODE_SEL_CONTROL.fsel = 0x2 */ + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2f4), + MODE_SEL_CONTROL_FSEL_MASK, + MODE_SEL_CONTROL_FSEL_MODE2); + + /* Set PNOR_CS_0_N_MODE_SEL_CONTROL.fsel = 0x2 */ + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2f8), + MODE_SEL_CONTROL_FSEL_MASK, + MODE_SEL_CONTROL_FSEL_MODE2); + + /* Set PNOR_WE_N_MODE_SEL_CONTROL.fsel = 0x2 */ + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x2fc), + MODE_SEL_CONTROL_FSEL_MASK, + MODE_SEL_CONTROL_FSEL_MODE2); + + /* Set PNOR_OE_N_MODE_SEL_CONTROL.fsel = 0x2 */ + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x300), + MODE_SEL_CONTROL_FSEL_MASK, + MODE_SEL_CONTROL_FSEL_MODE2); + + /* Set PNOR_INTR_MODE_SEL_CONTROL.fsel = 0x2 */ + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x304), + MODE_SEL_CONTROL_FSEL_MASK, + MODE_SEL_CONTROL_FSEL_MODE2); + + /* Set PNOR_DAT_x_MODE_SEL_CONTROL.fsel = 0x2 */ + for (i = 0; i < 0x40; i += 0x4) { + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x308 + i), + MODE_SEL_CONTROL_FSEL_MASK, + MODE_SEL_CONTROL_FSEL_MODE2); + } + + /* Set NAND_CE1_N_MODE_SEL_CONTROL.fsel = 0x2 */ + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x348), + MODE_SEL_CONTROL_FSEL_MASK, + MODE_SEL_CONTROL_FSEL_MODE2); + + /* Set NAND_CE0_N_MODE_SEL_CONTROL.fsel = 0x2 */ + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x34c), + MODE_SEL_CONTROL_FSEL_MASK, + MODE_SEL_CONTROL_FSEL_MODE2); + + /* Set NAND_WE_N_MODE_SEL_CONTROL.fsel = 0x2 */ + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x350), + MODE_SEL_CONTROL_FSEL_MASK, + MODE_SEL_CONTROL_FSEL_MODE2); + + /* Set NAND_WP_N_MODE_SEL_CONTROL.fsel = 0x2 */ + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x354), + MODE_SEL_CONTROL_FSEL_MASK, + MODE_SEL_CONTROL_FSEL_MODE2); + + /* Set NAND_RE_N_MODE_SEL_CONTROL.fsel = 0x2 */ + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x358), + MODE_SEL_CONTROL_FSEL_MASK, + MODE_SEL_CONTROL_FSEL_MODE2); + + /* Set NAND_RDY_BSY_N_MODE_SEL_CONTROL.fsel = 0x2 */ + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x35c), + MODE_SEL_CONTROL_FSEL_MASK, + MODE_SEL_CONTROL_FSEL_MODE2); + + /* Set NAND_IOx_0_MODE_SEL_CONTROL.fsel = 0x2 */ + for (i = 0; i < 0x40; i += 0x4) { + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x360 + i), + MODE_SEL_CONTROL_FSEL_MASK, + MODE_SEL_CONTROL_FSEL_MODE2); + } + + /* Set NAND_ALE_MODE_SEL_CONTROL.fsel = 0x2 */ + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x3a0), + MODE_SEL_CONTROL_FSEL_MASK, + MODE_SEL_CONTROL_FSEL_MODE2); + + /* Set NAND_CLE_MODE_SEL_CONTROL.fsel = 0x2 */ + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x3a4), + MODE_SEL_CONTROL_FSEL_MASK, + MODE_SEL_CONTROL_FSEL_MODE2); + + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x40), (7 << 1), 0x8); + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x44), (7 << 1), 0x8); + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x48), (7 << 1), 0x8); + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x4c), (7 << 1), 0x8); + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x50), (7 << 1), 0x8); + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x54), (7 << 1), 0x8); + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x58), (7 << 1), 0x8); + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x5c), (7 << 1), 0x8); + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x60), (7 << 1), 0x8); + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x64), (7 << 1), 0x8); + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x68), (7 << 1), 0x8); + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x6c), (7 << 1), 0x8); + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x70), (7 << 1), 0x8); + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x74), (7 << 1), 0x8); + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x78), (7 << 1), 0x8); + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x7c), (7 << 1), 0x8); + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x80), (7 << 1), 0x8); + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x84), (7 << 1), 0x8); + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x88), (7 << 1), 0x8); + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x8c), (7 << 1), 0x8); + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x90), (7 << 1), 0x8); + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x94), (7 << 1), 0x8); + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x98), (7 << 1), 0x8); + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0x9c), (7 << 1), 0x8); + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0xa0), (7 << 1), 0x8); + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0xa4), (7 << 1), 0x8); + mmio_clrsetbits_32((uintptr_t)(HSLS_IOPAD_BASE + 0xa8), (7 << 1), 0x8); + + INFO(" - pnor pinmux init done.\n"); +} + +#if BL2_TEST_EXT_SRAM +#define SRAM_CHECKS_GRANUL 0x100000 +#define SRAM_CHECKS_CNT 8 +static unsigned int sram_checks[SRAM_CHECKS_CNT] = { + /* offset, magic */ + 0xd00dfeed, + 0xfadebabe, + 0xc001d00d, + 0xa5a5b5b5, + 0x5a5a5b5b, + 0xc5c5d5d5, + 0x5c5c5d5d, + 0xe5e5f5f5, +}; +#endif + +static void brcm_stingray_pnor_sram_init(void) +{ + unsigned int val, tmp; +#if BL2_TEST_EXT_SRAM + unsigned int off, i; +#endif + INFO(" - pnor sram init start.\n"); + + /* Enable PNOR Clock */ + INFO(" -- enable pnor clock\n"); + mmio_write_32((uintptr_t)(PNOR_IDM_IO_CONTROL_DIRECT), 0x1); + udelay(500); + + /* Reset PNOR */ + INFO(" -- reset pnor\n"); + mmio_setbits_32((uintptr_t)(PNOR_IDM_IO_RESET_CONTROL), 0x1); + udelay(500); + mmio_clrbits_32((uintptr_t)(PNOR_IDM_IO_RESET_CONTROL), 0x1); + udelay(500); + + /* Configure slave address to chip-select mapping */ + INFO(" -- configure pnor slave address to chip-select mapping\n"); + /* 0x74000000-0x75ffffff => CS0 (32MB) */ + val = (0xfe << PNOR_ICFG_CS_x_MASK0_SHIFT); + val |= (0x74); + mmio_write_32((uintptr_t)(PNOR_ICFG_CS_0), val); + /* 0x76000000-0x77ffffff => CS1 (32MB) */ + val = (0xfe << PNOR_ICFG_CS_x_MASK0_SHIFT); + val |= (0x76); + mmio_write_32((uintptr_t)(PNOR_ICFG_CS_1), val); + /* 0xffffffff-0xffffffff => CS2 (0MB) */ + val = (0x00 << PNOR_ICFG_CS_x_MASK0_SHIFT); + val |= (0xff); + mmio_write_32((uintptr_t)(PNOR_ICFG_CS_2), val); + + /* Print PNOR ID */ + tmp = 0x0; + val = mmio_read_32((uintptr_t)(PNOR_REG_PERIPH_ID0)); + tmp |= (val & PNOR_REG_PERIPH_IDx_MASK); + val = mmio_read_32((uintptr_t)(PNOR_REG_PERIPH_ID1)); + tmp |= ((val & PNOR_REG_PERIPH_IDx_MASK) << 8); + val = mmio_read_32((uintptr_t)(PNOR_REG_PERIPH_ID2)); + tmp |= ((val & PNOR_REG_PERIPH_IDx_MASK) << 16); + val = mmio_read_32((uintptr_t)(PNOR_REG_PERIPH_ID3)); + tmp |= ((val & PNOR_REG_PERIPH_IDx_MASK) << 24); + INFO(" -- pnor primecell_id = 0x%x\n", tmp); + + /* PNOR set_cycles */ +#ifdef EMULATION_SETUP + val = 0x00129A44; +#else + val = 0x00125954; /* 0x00002DEF; */ +#endif + mmio_write_32((uintptr_t)(PNOR_REG_SET_CYCLES), val); + INFO(" -- pnor set_cycles = 0x%x\n", val); + + /* PNOR set_opmode */ + val = 0x0; +#ifdef EMULATION_SETUP + /* TODO: Final values to be provided by DV folks */ + val &= ~(0x7 << 7); /* set_wr_bl */ + val &= ~(0x7 << 3); /* set_rd_bl */ + val &= ~(0x3); + val |= (0x1); /* set_mw */ +#else + /* TODO: Final values to be provided by DV folks */ + val &= ~(0x7 << 7); /* set_wr_bl */ + val &= ~(0x7 << 3); /* set_rd_bl */ + val &= ~(0x3); + val |= (0x1); /* set_mw */ +#endif + mmio_write_32((uintptr_t)(PNOR_REG_SET_OPMODE), val); + INFO(" -- pnor set_opmode = 0x%x\n", val); + +#ifndef EMULATION_SETUP + /* Actual SRAM chip will require self-refresh */ + val = 0x1; + mmio_write_32((uintptr_t)(PNOR_REG_REFRESH_0), val); + INFO(" -- pnor refresh_0 = 0x%x\n", val); +#endif + +#if BL2_TEST_EXT_SRAM + /* Check PNOR SRAM access */ + for (off = 0; off < NOR_SIZE; off += SRAM_CHECKS_GRANUL) { + i = (off / SRAM_CHECKS_GRANUL) % SRAM_CHECKS_CNT; + val = sram_checks[i]; + INFO(" -- pnor sram write addr=0x%lx value=0x%lx\n", + (unsigned long)(NOR_BASE_ADDR + off), + (unsigned long)val); + mmio_write_32((uintptr_t)(NOR_BASE_ADDR + off), val); + } + tmp = 0; + for (off = 0; off < NOR_SIZE; off += SRAM_CHECKS_GRANUL) { + i = (off / SRAM_CHECKS_GRANUL) % SRAM_CHECKS_CNT; + val = mmio_read_32((uintptr_t)(NOR_BASE_ADDR + off)); + INFO(" -- pnor sram read addr=0x%lx value=0x%lx\n", + (unsigned long)(NOR_BASE_ADDR + off), + (unsigned long)val); + if (val == sram_checks[i]) + tmp++; + } + INFO(" -- pnor sram checks pass=%d total=%d\n", + tmp, (NOR_SIZE / SRAM_CHECKS_GRANUL)); + + if (tmp != (NOR_SIZE / SRAM_CHECKS_GRANUL)) { + INFO(" - pnor sram init failed.\n"); + while (1) + ; + } else { + INFO(" - pnor sram init done.\n"); + } +#endif +} + +void ext_sram_init(void) +{ + INFO("%s start.\n", __func__); + + brcm_stingray_pnor_pinmux_init(); + + brcm_stingray_pnor_sram_init(); + + INFO("%s done.\n", __func__); +} diff --git a/plat/brcm/board/stingray/driver/ext_sram_init/ext_sram_init.h b/plat/brcm/board/stingray/driver/ext_sram_init/ext_sram_init.h new file mode 100644 index 0000000..8508653 --- /dev/null +++ b/plat/brcm/board/stingray/driver/ext_sram_init/ext_sram_init.h @@ -0,0 +1,11 @@ +/* + * Copyright (c) 2016-2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef EXT_SRAM_INIT_H +#define EXT_SRAM_INIT_H + +void ext_sram_init(void); +#endif diff --git a/plat/brcm/board/stingray/driver/ihost_pll_config.c b/plat/brcm/board/stingray/driver/ihost_pll_config.c new file mode 100644 index 0000000..1184928 --- /dev/null +++ b/plat/brcm/board/stingray/driver/ihost_pll_config.c @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2016-2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <stdint.h> + +#include <common/debug.h> +#include <lib/mmio.h> + +#include <dmu.h> + +#define IHOST0_CONFIG_ROOT 0x66000000 +#define IHOST1_CONFIG_ROOT 0x66002000 +#define IHOST2_CONFIG_ROOT 0x66004000 +#define IHOST3_CONFIG_ROOT 0x66006000 +#define A72_CRM_PLL_PWR_ON 0x00000070 +#define A72_CRM_PLL_PWR_ON__PLL0_RESETB_R 4 +#define A72_CRM_PLL_PWR_ON__PLL0_POST_RESETB_R 5 +#define A72_CRM_PLL_CHNL_BYPS_EN 0x000000ac +#define A72_CRM_PLL_CHNL_BYPS_EN__PLL_0_CHNL_0_BYPS_EN_R 0 +#define A72_CRM_PLL_CHNL_BYPS_EN_DATAMASK 0x0000ec1f +#define A72_CRM_PLL_CMD 0x00000080 +#define A72_CRM_PLL_CMD__UPDATE_PLL0_FREQUENCY_VCO_R 0 +#define A72_CRM_PLL_CMD__UPDATE_PLL0_FREQUENCY_POST_R 1 +#define A72_CRM_PLL_STATUS 0x00000084 +#define A72_CRM_PLL_STATUS__PLL0_LOCK_R 9 +#define A72_CRM_PLL0_CTRL1 0x00000100 +#define A72_CRM_PLL0_CTRL2 0x00000104 +#define A72_CRM_PLL0_CTRL3 0x00000108 +#define A72_CRM_PLL0_CTRL3__PLL0_PDIV_R 12 +#define A72_CRM_PLL0_CTRL4 0x0000010c +#define A72_CRM_PLL0_CTRL4__PLL0_KP_R 0 +#define A72_CRM_PLL0_CTRL4__PLL0_KI_R 4 +#define A72_CRM_PLL0_CTRL4__PLL0_KA_R 7 +#define A72_CRM_PLL0_CTRL4__PLL0_FREFEFF_INFO_R 10 + +#define PLL_MODE_VCO 0x0 +#define PLL_MODE_BYPASS 0x1 +#define PLL_RESET_TYPE_PLL 0x1 +#define PLL_RESET_TYPE_POST 0x2 +#define PLL_VCO 0x1 +#define PLL_POSTDIV 0x2 +#define ARM_FREQ_3G PLL_FREQ_FULL +#define ARM_FREQ_1P5G PLL_FREQ_HALF +#define ARM_FREQ_750M PLL_FREQ_QRTR + +static unsigned int ARMCOE_crm_getBaseAddress(unsigned int cluster_num) +{ + unsigned int ihostx_config_root; + + switch (cluster_num) { + case 0: + default: + ihostx_config_root = IHOST0_CONFIG_ROOT; + break; + case 1: + ihostx_config_root = IHOST1_CONFIG_ROOT; + break; + case 2: + ihostx_config_root = IHOST2_CONFIG_ROOT; + break; + case 3: + ihostx_config_root = IHOST3_CONFIG_ROOT; + break; + } + + return ihostx_config_root; +} + +static void ARMCOE_crm_pllAssertReset(unsigned int cluster_num, + unsigned int reset_type) +{ + unsigned long ihostx_config_root; + unsigned int pll_rst_ctrl; + + ihostx_config_root = ARMCOE_crm_getBaseAddress(cluster_num); + pll_rst_ctrl = mmio_read_32(ihostx_config_root + A72_CRM_PLL_PWR_ON); + + // PLL reset + if (reset_type & PLL_RESET_TYPE_PLL) { + pll_rst_ctrl &= ~(0x1<<A72_CRM_PLL_PWR_ON__PLL0_RESETB_R); + } + // post-div channel reset + if (reset_type & PLL_RESET_TYPE_POST) { + pll_rst_ctrl &= ~(0x1<<A72_CRM_PLL_PWR_ON__PLL0_POST_RESETB_R); + } + + mmio_write_32(ihostx_config_root + A72_CRM_PLL_PWR_ON, pll_rst_ctrl); +} + +static void ARMCOE_crm_pllSetMode(unsigned int cluster_num, unsigned int mode) +{ + unsigned long ihostx_config_root; + unsigned int pll_byp_ctrl; + + ihostx_config_root = ARMCOE_crm_getBaseAddress(cluster_num); + pll_byp_ctrl = mmio_read_32(ihostx_config_root + + A72_CRM_PLL_CHNL_BYPS_EN); + + if (mode == PLL_MODE_VCO) { + // use PLL DCO output + pll_byp_ctrl &= + ~BIT(A72_CRM_PLL_CHNL_BYPS_EN__PLL_0_CHNL_0_BYPS_EN_R); + } else { + // use PLL bypass sources + pll_byp_ctrl |= + BIT(A72_CRM_PLL_CHNL_BYPS_EN__PLL_0_CHNL_0_BYPS_EN_R); + } + + mmio_write_32(ihostx_config_root + A72_CRM_PLL_CHNL_BYPS_EN, + pll_byp_ctrl); +} + +static void ARMCOE_crm_pllFreqSet(unsigned int cluster_num, + unsigned int ihost_pll_freq_sel, + unsigned int pdiv) +{ + unsigned int ndiv_int; + unsigned int ndiv_frac_low, ndiv_frac_high; + unsigned long ihostx_config_root; + + ndiv_frac_low = 0x0; + ndiv_frac_high = 0x0; + + if (ihost_pll_freq_sel == ARM_FREQ_3G) { + ndiv_int = 0x78; + } else if (ihost_pll_freq_sel == ARM_FREQ_1P5G) { + ndiv_int = 0x3c; + } else if (ihost_pll_freq_sel == ARM_FREQ_750M) { + ndiv_int = 0x1e; + } else { + return; + } + + ndiv_int &= 0x3FF; // low 10 bits + ndiv_frac_low &= 0x3FF; + ndiv_frac_high &= 0x3FF; + + ihostx_config_root = ARMCOE_crm_getBaseAddress(cluster_num); + + mmio_write_32(ihostx_config_root+A72_CRM_PLL0_CTRL1, ndiv_frac_low); + mmio_write_32(ihostx_config_root+A72_CRM_PLL0_CTRL2, ndiv_frac_high); + mmio_write_32(ihostx_config_root+A72_CRM_PLL0_CTRL3, + ndiv_int | + ((pdiv << A72_CRM_PLL0_CTRL3__PLL0_PDIV_R & 0xF000))); + + mmio_write_32(ihostx_config_root + A72_CRM_PLL0_CTRL4, + /* From Section 10 of PLL spec */ + (3 << A72_CRM_PLL0_CTRL4__PLL0_KP_R) | + /* From Section 10 of PLL spec */ + (2 << A72_CRM_PLL0_CTRL4__PLL0_KI_R) | + /* Normal mode (i.e. not fast-locking) */ + (0 << A72_CRM_PLL0_CTRL4__PLL0_KA_R) | + /* 50 MHz */ + (50 << A72_CRM_PLL0_CTRL4__PLL0_FREFEFF_INFO_R)); +} + +static void ARMCOE_crm_pllDeassertReset(unsigned int cluster_num, + unsigned int reset_type) +{ + unsigned long ihostx_config_root; + unsigned int pll_rst_ctrl; + + ihostx_config_root = ARMCOE_crm_getBaseAddress(cluster_num); + pll_rst_ctrl = mmio_read_32(ihostx_config_root + A72_CRM_PLL_PWR_ON); + + // PLL reset + if (reset_type & PLL_RESET_TYPE_PLL) { + pll_rst_ctrl |= (0x1 << A72_CRM_PLL_PWR_ON__PLL0_RESETB_R); + } + + // post-div channel reset + if (reset_type & PLL_RESET_TYPE_POST) { + pll_rst_ctrl |= (0x1 << A72_CRM_PLL_PWR_ON__PLL0_POST_RESETB_R); + } + + mmio_write_32(ihostx_config_root + A72_CRM_PLL_PWR_ON, pll_rst_ctrl); +} + +static void ARMCOE_crm_pllUpdate(unsigned int cluster_num, unsigned int type) +{ + unsigned long ihostx_config_root; + unsigned int pll_cmd; + + ihostx_config_root = ARMCOE_crm_getBaseAddress(cluster_num); + pll_cmd = mmio_read_32(ihostx_config_root + A72_CRM_PLL_CMD); + + // VCO update + if (type & PLL_VCO) { + pll_cmd |= BIT(A72_CRM_PLL_CMD__UPDATE_PLL0_FREQUENCY_VCO_R); + } + // post-div channel update + if (type & PLL_POSTDIV) { + pll_cmd |= BIT(A72_CRM_PLL_CMD__UPDATE_PLL0_FREQUENCY_POST_R); + } + + mmio_write_32(ihostx_config_root+A72_CRM_PLL_CMD, pll_cmd); +} + +static void insert_delay(unsigned int delay) +{ + volatile unsigned int index; + + for (index = 0; index < delay; index++) + ; +} + + +/* + * Returns 1 if PLL locked within certain interval + */ +static unsigned int ARMCOE_crm_pllIsLocked(unsigned int cluster_num) +{ + unsigned long ihostx_config_root; + unsigned int lock_status; + unsigned int i; + + ihostx_config_root = ARMCOE_crm_getBaseAddress(cluster_num); + + /* wait a while for pll to lock before returning from this function */ + for (i = 0; i < 1500; i++) { + insert_delay(256); + lock_status = mmio_read_32(ihostx_config_root + + A72_CRM_PLL_STATUS); + if (lock_status & BIT(A72_CRM_PLL_STATUS__PLL0_LOCK_R)) + return 1; + } + + ERROR("PLL of Cluster #%u failed to lock\n", cluster_num); + return 0; +} + +/* + * ihost PLL Variable Frequency Configuration + * + * Frequency Limit {VCO,ARM} (GHz): + * 0 - no limit, + * 1 - {3.0,1.5}, + * 2 - {4.0,2.0}, + * 3 - {5.0,2.5} + */ +uint32_t bcm_set_ihost_pll_freq(uint32_t cluster_num, int ihost_pll_freq_sel) +{ + NOTICE("cluster: %u, freq_sel:0x%x\n", cluster_num, ihost_pll_freq_sel); + + //bypass PLL + ARMCOE_crm_pllSetMode(cluster_num, PLL_MODE_BYPASS); + //assert reset + ARMCOE_crm_pllAssertReset(cluster_num, + PLL_RESET_TYPE_PLL | PLL_RESET_TYPE_POST); + //set ndiv_int for different freq + ARMCOE_crm_pllFreqSet(cluster_num, ihost_pll_freq_sel, 0x1); + //de-assert reset + ARMCOE_crm_pllDeassertReset(cluster_num, PLL_RESET_TYPE_PLL); + ARMCOE_crm_pllUpdate(cluster_num, PLL_VCO); + //waiting for PLL lock + ARMCOE_crm_pllIsLocked(cluster_num); + ARMCOE_crm_pllDeassertReset(cluster_num, PLL_RESET_TYPE_POST); + //disable bypass PLL + ARMCOE_crm_pllSetMode(cluster_num, PLL_MODE_VCO); + + return 0; +} + +uint32_t bcm_get_ihost_pll_freq(uint32_t cluster_num) +{ + unsigned long ihostx_config_root; + uint32_t ndiv_int; + uint32_t ihost_pll_freq_sel; + + ihostx_config_root = ARMCOE_crm_getBaseAddress(cluster_num); + ndiv_int = mmio_read_32(ihostx_config_root+A72_CRM_PLL0_CTRL3) & 0x3FF; + + if (ndiv_int == 0x78) { + ihost_pll_freq_sel = ARM_FREQ_3G; + } else if (ndiv_int == 0x3c) { + ihost_pll_freq_sel = ARM_FREQ_1P5G; + } else if (ndiv_int == 0x1e) { + ihost_pll_freq_sel = ARM_FREQ_750M; + } else { + /* return unlimit otherwise*/ + ihost_pll_freq_sel = 0; + } + return ihost_pll_freq_sel; +} diff --git a/plat/brcm/board/stingray/driver/plat_emmc.c b/plat/brcm/board/stingray/driver/plat_emmc.c new file mode 100644 index 0000000..82085e1 --- /dev/null +++ b/plat/brcm/board/stingray/driver/plat_emmc.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2016 - 2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <stdint.h> + +#include <lib/mmio.h> + +#include <platform_def.h> + +#define ICFG_IPROC_IOPAD_CTRL_4 (IPROC_ROOT + 0x9c0) +#define ICFG_IPROC_IOPAD_CTRL_5 (IPROC_ROOT + 0x9c4) +#define ICFG_IPROC_IOPAD_CTRL_6 (IPROC_ROOT + 0x9c8) +#define ICFG_IPROC_IOPAD_CTRL_7 (IPROC_ROOT + 0x9cc) + +#define IOPAD_CTRL4_SDIO0_CD_IND_R 30 +#define IOPAD_CTRL4_SDIO0_CD_SRC_R 31 +#define IOPAD_CTRL4_SDIO0_CD_HYS_R 29 +#define IOPAD_CTRL4_SDIO0_CD_PULL_R 28 +#define IOPAD_CTRL4_SDIO0_CD_DRIVE_R 24 +#define IOPAD_CTRL4_SDIO0_CLK_SDCARD_SRC_R 23 +#define IOPAD_CTRL4_SDIO0_CLK_SDCARD_HYS_R 21 +#define IOPAD_CTRL4_SDIO0_CLK_SDCARD_DRIVE_R 17 + +#define IOPAD_CTRL4_SDIO0_DATA0_SRC_R 15 +#define IOPAD_CTRL4_SDIO0_DATA0_HYS_R 13 +#define IOPAD_CTRL4_SDIO0_DATA0_DRIVE_R 9 +#define IOPAD_CTRL4_SDIO0_DATA1_SRC_R 7 +#define IOPAD_CTRL4_SDIO0_DATA1_HYS_R 5 +#define IOPAD_CTRL4_SDIO0_DATA1_DRIVE_R 1 + +#define IOPAD_CTRL5_SDIO0_DATA2_SRC_R 31 +#define IOPAD_CTRL5_SDIO0_DATA2_HYS_R 29 +#define IOPAD_CTRL5_SDIO0_DATA2_DRIVE_R 25 +#define IOPAD_CTRL5_SDIO0_DATA3_SRC_R 23 +#define IOPAD_CTRL5_SDIO0_DATA3_IND_R 22 +#define IOPAD_CTRL5_SDIO0_DATA3_HYS_R 21 +#define IOPAD_CTRL5_SDIO0_DATA3_DRIVE_R 17 +#define IOPAD_CTRL5_SDIO0_DATA4_SRC_R 15 +#define IOPAD_CTRL5_SDIO0_DATA4_HYS_R 13 +#define IOPAD_CTRL5_SDIO0_DATA4_DRIVE_R 9 +#define IOPAD_CTRL5_SDIO0_DATA5_SRC_R 7 +#define IOPAD_CTRL5_SDIO0_DATA5_HYS_R 5 +#define IOPAD_CTRL5_SDIO0_DATA5_DRIVE_R 1 + +#define IOPAD_CTRL6_SDIO0_DATA6_SRC_R 31 +#define IOPAD_CTRL6_SDIO0_DATA6_HYS_R 29 +#define IOPAD_CTRL6_SDIO0_DATA6_DRIVE_R 25 +#define IOPAD_CTRL6_SDIO0_DATA7_SRC_R 23 +#define IOPAD_CTRL6_SDIO0_DATA7_HYS_R 21 +#define IOPAD_CTRL6_SDIO0_DATA7_DRIVE_R 17 + +void emmc_soft_reset(void) +{ + uint32_t val = 0; + + val = (BIT(IOPAD_CTRL6_SDIO0_DATA7_SRC_R) | + BIT(IOPAD_CTRL6_SDIO0_DATA7_HYS_R) | + BIT(IOPAD_CTRL6_SDIO0_DATA7_DRIVE_R) | + BIT(IOPAD_CTRL6_SDIO0_DATA6_SRC_R) | + BIT(IOPAD_CTRL6_SDIO0_DATA6_HYS_R) | + BIT(IOPAD_CTRL6_SDIO0_DATA6_DRIVE_R)); + + mmio_write_32(ICFG_IPROC_IOPAD_CTRL_6, val); + + val = (BIT(IOPAD_CTRL5_SDIO0_DATA3_SRC_R) | + BIT(IOPAD_CTRL5_SDIO0_DATA3_HYS_R) | + BIT(IOPAD_CTRL5_SDIO0_DATA3_DRIVE_R) | + BIT(IOPAD_CTRL5_SDIO0_DATA4_SRC_R) | + BIT(IOPAD_CTRL5_SDIO0_DATA4_HYS_R) | + BIT(IOPAD_CTRL5_SDIO0_DATA4_DRIVE_R) | + BIT(IOPAD_CTRL5_SDIO0_DATA5_SRC_R) | + BIT(IOPAD_CTRL5_SDIO0_DATA5_HYS_R) | + BIT(IOPAD_CTRL5_SDIO0_DATA5_DRIVE_R)); + + mmio_write_32(ICFG_IPROC_IOPAD_CTRL_5, val); + + val = (BIT(IOPAD_CTRL4_SDIO0_DATA0_SRC_R) | + BIT(IOPAD_CTRL4_SDIO0_DATA0_HYS_R) | + BIT(IOPAD_CTRL4_SDIO0_DATA0_DRIVE_R) | + BIT(IOPAD_CTRL4_SDIO0_DATA1_SRC_R) | + BIT(IOPAD_CTRL4_SDIO0_DATA1_HYS_R) | + BIT(IOPAD_CTRL4_SDIO0_DATA1_DRIVE_R) | + BIT(IOPAD_CTRL5_SDIO0_DATA2_SRC_R) | + BIT(IOPAD_CTRL5_SDIO0_DATA2_HYS_R) | + BIT(IOPAD_CTRL5_SDIO0_DATA2_DRIVE_R)); + + mmio_write_32(ICFG_IPROC_IOPAD_CTRL_6, val); + + val = (BIT(IOPAD_CTRL4_SDIO0_CLK_SDCARD_SRC_R) | + BIT(IOPAD_CTRL4_SDIO0_CLK_SDCARD_HYS_R) | + BIT(IOPAD_CTRL4_SDIO0_CLK_SDCARD_DRIVE_R) | + BIT(IOPAD_CTRL4_SDIO0_CD_SRC_R) | + BIT(IOPAD_CTRL4_SDIO0_CD_HYS_R)); + + /* + * set pull-down, clear pull-up=0 + * bit 12: pull-down bit 11: pull-up + * Note: In emulation, this pull-down setting was not + * sufficient. Board design likely requires pull down on + * this pin for eMMC. + */ + + val |= BIT(IOPAD_CTRL4_SDIO0_CD_PULL_R); + + mmio_write_32(ICFG_IPROC_IOPAD_CTRL_4, val); +} diff --git a/plat/brcm/board/stingray/driver/sr_usb.h b/plat/brcm/board/stingray/driver/sr_usb.h new file mode 100644 index 0000000..5033683 --- /dev/null +++ b/plat/brcm/board/stingray/driver/sr_usb.h @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2019 - 2021, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef SR_USB_H +#define SR_USB_H + +#define CDRU_PM_RESET_N_R BIT(CDRU_MISC_RESET_CONTROL__CDRU_PM_RESET_N_R) +#define CDRU_USBSS_RESET_N BIT(CDRU_MISC_RESET_CONTROL__CDRU_USBSS_RESET_N) +#define CDRU_MISC_CLK_USBSS \ + BIT(CDRU_MISC_CLK_ENABLE_CONTROL__CDRU_USBSS_CLK_EN_R) + +#define RESCAL_I_RSTB BIT(26) +#define RESCAL_I_PWRDNB BIT(27) + +#define DRDU3_U3PHY_CTRL 0x68500014 +#define PHY_RESET BIT(1) +#define POR_RESET BIT(28) +#define MDIO_RESET BIT(29) + +#define DRDU3_PWR_CTRL 0x6850002c +#define POWER_CTRL_OVRD BIT(2) + +#define USB3H_U3PHY_CTRL 0x68510014 +#define USB3H_U3SOFT_RST_N BIT(30) + +#define USB3H_PWR_CTRL 0x68510028 + +#define USB3_PHY_MDIO_BLOCK_BASE_REG 0x1f +#define BDC_AXI_SOFT_RST_N_OFFSET 0 +#define XHC_AXI_SOFT_RST_N_OFFSET 1 +#define MDIO_BUS_ID 3 +#define USB3H_PHY_ID 5 +#define USB3DRD_PHY_ID 2 + +#define USB3_PHY_RXPMD_BLOCK_BASE 0x8020 +#define USB3_PHY_RXPMD_REG1 0x1 +#define USB3_PHY_RXPMD_REG2 0x2 +#define USB3_PHY_RXPMD_REG5 0x5 +#define USB3_PHY_RXPMD_REG7 0x7 + +#define USB3_PHY_TXPMD_BLOCK_BASE 0x8040 +#define USB3_PHY_TXPMD_REG1 0x1 +#define USB3_PHY_TXPMD_REG2 0x2 + +#define USB3_PHY_ANA_BLOCK_BASE 0x8090 +#define USB3_PHY_ANA_REG0 0x0 +#define USB3_PHY_ANA_REG1 0x1 +#define USB3_PHY_ANA_REG2 0x2 +#define USB3_PHY_ANA_REG5 0x5 +#define USB3_PHY_ANA_REG8 0x8 +#define USB3_PHY_ANA_REG11 0xb + +#define USB3_PHY_AEQ_BLOCK_BASE 0x80e0 +#define USB3_PHY_AEQ_REG1 0x1 +#define USB3_PHY_AEQ_REG3 0x3 + +#ifdef USB_DMA_COHERENT +#define DRDU3_U3XHC_SOFT_RST_N BIT(31) +#define DRDU3_U3BDC_SOFT_RST_N BIT(30) + +#define DRDU3_SOFT_RESET_CTRL 0x68500030 +#define DRDU3_XHC_AXI_SOFT_RST_N BIT(1) +#define DRDU3_BDC_AXI_SOFT_RST_N BIT(0) + +#define DRDU2_PHY_CTRL 0x6852000c +#define DRDU2_U2SOFT_RST_N BIT(29) + +#define USB3H_SOFT_RESET_CTRL 0x6851002c +#define USB3H_XHC_AXI_SOFT_RST_N BIT(1) + +#define DRDU2_SOFT_RESET_CTRL 0x68520020 +#define DRDU2_BDC_AXI_SOFT_RST_N BIT(0) + +#define DRD2U3H_XHC_REGS_AXIWRA 0x68511c08 +#define DRD2U3H_XHC_REGS_AXIRDA 0x68511c0c +#define DRDU2D_BDC_REGS_AXIWRA 0x68521c08 +#define DRDU2D_BDC_REGS_AXIRDA 0x68521c0c +#define DRDU3H_XHC_REGS_AXIWRA 0x68501c08 +#define DRDU3H_XHC_REGS_AXIRDA 0x68501c0c +#define DRDU3D_BDC_REGS_AXIWRA 0x68502c08 +#define DRDU3D_BDC_REGS_AXIRDA 0x68502c0c +/* cacheable write-back, allocate on both reads and writes */ +#define USBAXI_AWCACHE 0xf +#define USBAXI_ARCACHE 0xf +/* non-secure */ +#define USBAXI_AWPROT 0x8 +#define USBAXI_ARPROT 0x8 +#define USBAXIWR_SA_VAL ((USBAXI_AWCACHE << 4 | USBAXI_AWPROT) << 0) +#define USBAXIWR_SA_MASK ((0xf << 4 | 0xf) << 0) +#define USBAXIWR_UA_VAL ((USBAXI_AWCACHE << 4 | USBAXI_AWPROT) << 16) +#define USBAXIWR_UA_MASK ((0xf << 4 | 0xf) << 0) +#define USBAXIRD_SA_VAL ((USBAXI_ARCACHE << 4 | USBAXI_ARPROT) << 0) +#define USBAXIRD_SA_MASK ((0xf << 4 | 0xf) << 0) +#define USBAXIRD_UA_VAL ((USBAXI_ARCACHE << 4 | USBAXI_ARPROT) << 16) +#define USBAXIRD_UA_MASK ((0xf << 4 | 0xf) << 0) +#endif /* USB_DMA_COHERENT */ + +#define ICFG_DRDU3_SID_CTRL 0x6850001c +#define ICFG_USB3H_SID_CTRL 0x6851001c +#define ICFG_DRDU2_SID_CTRL 0x68520010 +#define ICFG_USB_SID_SHIFT 5 +#define ICFG_USB_SID_AWADDR_OFFSET 0x0 +#define ICFG_USB_SID_ARADDR_OFFSET 0x4 + +#define USBIC_GPV_BASE 0x68600000 +#define USBIC_GPV_SECURITY0 (USBIC_GPV_BASE + 0x8) +#define USBIC_GPV_SECURITY0_FIELD BIT(0) +#define USBIC_GPV_SECURITY1 (USBIC_GPV_BASE + 0xc) +#define USBIC_GPV_SECURITY1_FIELD (BIT(0) | BIT(1)) +#define USBIC_GPV_SECURITY2 (USBIC_GPV_BASE + 0x10) +#define USBIC_GPV_SECURITY2_FIELD (BIT(0) | BIT(1)) +#define USBIC_GPV_SECURITY4 (USBIC_GPV_BASE + 0x18) +#define USBIC_GPV_SECURITY4_FIELD BIT(0) +#define USBIC_GPV_SECURITY10 (USBIC_GPV_BASE + 0x30) +#define USBIC_GPV_SECURITY10_FIELD (0x7 << 0) + +#define USBSS_TZPCDECPROT_BASE 0x68540800 +#define USBSS_TZPCDECPROT0set (USBSS_TZPCDECPROT_BASE + 0x4) +#define USBSS_TZPCDECPROT0clr (USBSS_TZPCDECPROT_BASE + 0x8) +#define DECPROT0_USBSS_DRD2U3H BIT(3) +#define DECPROT0_USBSS_DRDU2H BIT(2) +#define DECPROT0_USBSS_DRDU3D BIT(1) +#define DECPROT0_USBSS_DRDU2D BIT(0) +#define USBSS_TZPCDECPROT0 \ + (DECPROT0_USBSS_DRD2U3H | \ + DECPROT0_USBSS_DRDU2H | \ + DECPROT0_USBSS_DRDU3D | \ + DECPROT0_USBSS_DRDU2D) + +int32_t usb_device_init(unsigned int); + +#endif /* SR_USB_H */ diff --git a/plat/brcm/board/stingray/driver/swreg.c b/plat/brcm/board/stingray/driver/swreg.c new file mode 100644 index 0000000..2b7c53b --- /dev/null +++ b/plat/brcm/board/stingray/driver/swreg.c @@ -0,0 +1,375 @@ +/* + * Copyright (c) 2017 - 2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <errno.h> +#include <stdint.h> + +#include <common/debug.h> +#include <drivers/delay_timer.h> +#include <lib/mmio.h> + +#include <sr_utils.h> +#include <swreg.h> + +#define MIN_VOLT 760000 +#define MAX_VOLT 1060000 + +#define BSTI_WRITE 0x1 +#define BSTI_READ 0x2 +#define BSTI_COMMAND_TA 0x2 +#define BSTI_COMMAND_DATA 0xFF +#define BSTI_CONTROL_VAL 0x81 +#define BSTI_CONTROL_BUSY 0x100 +#define BSTI_TOGGLE_BIT 0x2 +#define BSTI_CONFI_DONE_MASK 0xFFFFFFFD +#define BSTI_REG_DATA_MASK 0xFFFF +#define BSTI_CMD(sb, op, pa, ra, ta, data) \ + ((((sb) & 0x3) << 30) | (((op) & 0x3) << 28) | \ + (((pa) & 0x1F) << 23) | (((ra) & 0x1F) << 18) | \ + (((ta) & 0x3) << 16) | (data)) + +#define PHY_REG0 0x0 +#define PHY_REG1 0x1 +#define PHY_REG4 0x4 +#define PHY_REG5 0x5 +#define PHY_REG6 0x6 +#define PHY_REG7 0x7 +#define PHY_REGC 0xc + +#define IHOST_VDDC_DATA 0x560 +#define DDR_CORE_DATA 0x2560 +#define UPDATE_POS_EDGE(data, set) ((data) | ((set) << 1)) + +/* + * Formula for SR A2 reworked board: + * step = ((vol/(1.4117 * 0.98)) - 500000)/3125 + * where, + * vol - input voltage + * 500000 - Reference voltage + * 3125 - one step value + */ +#define A2_VOL_REF 500000 +#define ONE_STEP_VALUE 3125 +#define VOL_DIV(vol) (((vol*10000ull)/(14117*98ull)) * 100ull) +#define STEP_VALUE(vol) \ + ((((((VOL_DIV(vol)) - A2_VOL_REF) / ONE_STEP_VALUE) & 0xFF) << 8) | 4) + +#define B0_VOL_REF ((500000/100)*98) +#define B0_ONE_STEP_VALUE 3125 +/* + * Formula for SR B0 chip for IHOST12/03 and VDDC_CORE + * step = ((vol/1.56) - (500000 * 0.98))/3125 + * where, + * vol - input voltage + * 500000 - Reference voltage + * 3125 - one step value + */ +#define B0_VOL_DIV(vol) (((vol)*100ull)/156) +#define B0_STEP_VALUE(vol) \ + ((((((B0_VOL_DIV(vol)) - B0_VOL_REF) / B0_ONE_STEP_VALUE) \ + & 0xFF) << 8) | 4) + +/* + * Formula for SR B0 chip for DDR-CORE + * step = ((vol/1) - (500000 * 0.98))/3125 + * where, + * vol - input voltage + * 500000 - Reference voltage + * 3125 - one step value + */ +#define B0_DDR_VDDC_VOL_DIV(vol) ((vol)/1) +#define B0_DDR_VDDC_STEP_VALUE(vol) \ + ((((((B0_DDR_VDDC_VOL_DIV(vol)) - B0_VOL_REF) / B0_ONE_STEP_VALUE) \ + & 0xFF) << 8) | 4) + +#define MAX_SWREG_CNT 8 +#define MAX_ADDR_PER_SWREG 16 +#define MAX_REG_ADDR 0xF +#define MIN_REG_ADDR 0x0 + +static const char *sw_reg_name[MAX_SWREG_CNT] = { + "DDR_VDDC", + "IHOST03", + "IHOST12", + "IHOST_ARRAY", + "DDRIO_SLAVE", + "VDDC_CORE", + "VDDC1", + "DDRIO_MASTER" +}; + +/* firmware values for all SWREG for 3.3V input operation */ +static const uint16_t swreg_fm_data_bx[MAX_SWREG_CNT][MAX_ADDR_PER_SWREG] = { + /* DDR logic: Power Domains independent of 12v or 3p3v */ + {0x25E0, 0x2D54, 0x0EC6, 0x01EC, 0x28BB, 0x1144, 0x0200, 0x69C0, + 0x0010, 0x0EDF, 0x90D7, 0x8000, 0x820C, 0x0003, 0x0001, 0x0000}, + + /* ihost03, 3p3V */ + {0x05E0, 0x39E5, 0x03C1, 0x007C, 0x8BA9, 0x4444, 0x3300, 0x6B80, + 0x003F, 0x0FFF, 0x90D7, 0x8000, 0x240C, 0x0003, 0x0001, 0x0000}, + + /* ihost12 3p3v */ + {0x05E0, 0x39E5, 0x03C1, 0x007C, 0x8BA9, 0x4444, 0x3300, 0x6B80, + 0x003F, 0x0FFF, 0x90D7, 0x8000, 0x240C, 0x0003, 0x0001, 0x0000}, + + /* ihost array */ + {0x25E0, 0x2D94, 0x0EC6, 0x01EC, 0x2ABB, 0x1144, 0x0340, 0x69C0, + 0x0010, 0x0EDF, 0x90D7, 0x8000, 0x860C, 0x0003, 0x0001, 0x0000}, + + /* ddr io slave : 3p3v */ + {0x0560, 0x4438, 0x0000, 0x001F, 0x8028, 0x4444, 0x0300, 0x4380, + 0x003F, 0x0FFF, 0x10D7, 0x8000, 0xA70C, 0x0003, 0x0001, 0x0000}, + + /* core master 3p3v */ + {0x05E0, 0x39E5, 0x03C1, 0x007C, 0x8BA9, 0x4444, 0x3300, 0x6B80, + 0x003F, 0x0FFF, 0x90D7, 0x8000, 0x240C, 0x0003, 0x0001, 0x0000}, + + /* core slave 3p3v */ + {0x0560, 0x4438, 0x0000, 0x001F, 0x8028, 0x4444, 0x0300, 0x4380, + 0x003F, 0x0FFF, 0x10D7, 0x8000, 0x240C, 0x0003, 0x0001, 0x0000}, + + /* ddr io master : 3p3v */ + {0x05E0, 0x39E5, 0x03C1, 0x007C, 0x8BA9, 0x4444, 0x3300, 0x6B80, + 0x003F, 0x0FFF, 0x90D7, 0x8000, 0xA70C, 0x0003, 0x0001, 0x0000}, +}; + +#define FM_DATA swreg_fm_data_bx + +static int swreg_poll(void) +{ + uint32_t data; + int retry = 100; + + do { + data = mmio_read_32(BSTI_CONTROL_OFFSET); + if ((data & BSTI_CONTROL_BUSY) != BSTI_CONTROL_BUSY) + return 0; + retry--; + udelay(1); + } while (retry > 0); + + return -ETIMEDOUT; +} + +static int write_swreg_config(enum sw_reg reg_id, uint32_t addr, uint32_t data) +{ + uint32_t cmd; + int ret; + + cmd = BSTI_CMD(0x1, BSTI_WRITE, reg_id, addr, BSTI_COMMAND_TA, data); + mmio_write_32(BSTI_CONTROL_OFFSET, BSTI_CONTROL_VAL); + mmio_write_32(BSTI_COMMAND_OFFSET, cmd); + ret = swreg_poll(); + if (ret) { + ERROR("Failed to write swreg %s addr 0x%x\n", + sw_reg_name[reg_id-1], addr); + return ret; + } + return ret; +} + +static int read_swreg_config(enum sw_reg reg_id, uint32_t addr, uint32_t *data) +{ + uint32_t cmd; + int ret; + + cmd = BSTI_CMD(0x1, BSTI_READ, reg_id, addr, BSTI_COMMAND_TA, PHY_REG0); + mmio_write_32(BSTI_CONTROL_OFFSET, BSTI_CONTROL_VAL); + mmio_write_32(BSTI_COMMAND_OFFSET, cmd); + ret = swreg_poll(); + if (ret) { + ERROR("Failed to read swreg %s addr 0x%x\n", + sw_reg_name[reg_id-1], addr); + return ret; + } + + *data = mmio_read_32(BSTI_COMMAND_OFFSET); + *data &= BSTI_REG_DATA_MASK; + return ret; +} + +static int swreg_config_done(enum sw_reg reg_id) +{ + uint32_t read_data; + int ret; + + ret = read_swreg_config(reg_id, PHY_REG0, &read_data); + if (ret) + return ret; + + read_data &= BSTI_CONFI_DONE_MASK; + read_data |= BSTI_TOGGLE_BIT; + ret = write_swreg_config(reg_id, PHY_REG0, read_data); + if (ret) + return ret; + + ret = read_swreg_config(reg_id, PHY_REG0, &read_data); + if (ret) + return ret; + + read_data &= BSTI_CONFI_DONE_MASK; + ret = write_swreg_config(reg_id, PHY_REG0, read_data); + if (ret) + return ret; + + return ret; +} + +#ifdef DUMP_SWREG +static void dump_swreg_firmware(void) +{ + enum sw_reg reg_id; + uint32_t data; + int addr; + int ret; + + for (reg_id = DDR_VDDC; reg_id <= DDRIO_MASTER; reg_id++) { + INFO("SWREG: %s\n", sw_reg_name[reg_id - 1]); + for (addr = MIN_REG_ADDR; addr <= MAX_REG_ADDR; addr++) { + ret = read_swreg_config(reg_id, addr, &data); + if (ret) + ERROR("Failed to read offset %d\n", addr); + INFO("\t0x%x: 0x%04x\n", addr, data); + } + } +} +#endif + +int set_swreg(enum sw_reg reg_id, uint32_t micro_volts) +{ + uint32_t step, programmed_step; + uint32_t data = IHOST_VDDC_DATA; + int ret; + + if ((micro_volts > MAX_VOLT) || (micro_volts < MIN_VOLT)) { + ERROR("input voltage out-of-range\n"); + ret = -EINVAL; + goto failed; + } + + ret = read_swreg_config(reg_id, PHY_REGC, &programmed_step); + if (ret) + goto failed; + + if (reg_id == DDR_VDDC) + step = B0_DDR_VDDC_STEP_VALUE(micro_volts); + else + step = B0_STEP_VALUE(micro_volts); + + if ((step >> 8) != (programmed_step >> 8)) { + ret = write_swreg_config(reg_id, PHY_REGC, step); + if (ret) + goto failed; + + if (reg_id == DDR_VDDC) + data = DDR_CORE_DATA; + + ret = write_swreg_config(reg_id, PHY_REG0, + UPDATE_POS_EDGE(data, 1)); + if (ret) + goto failed; + + ret = write_swreg_config(reg_id, PHY_REG0, + UPDATE_POS_EDGE(data, 0)); + if (ret) + goto failed; + } + + INFO("%s voltage updated to %duV\n", sw_reg_name[reg_id-1], + micro_volts); + return ret; + +failed: + /* + * Stop booting if voltages are not set + * correctly. Booting will fail at random point + * if we continue with wrong voltage settings. + */ + ERROR("Failed to set %s voltage to %duV\n", sw_reg_name[reg_id-1], + micro_volts); + assert(0); + + return ret; +} + +/* Update SWREG firmware for all power doman for A2 chip */ +int swreg_firmware_update(void) +{ + enum sw_reg reg_id; + uint32_t data; + int addr; + int ret; + + /* write firmware values */ + for (reg_id = DDR_VDDC; reg_id <= DDRIO_MASTER; reg_id++) { + /* write higher location first */ + for (addr = MAX_REG_ADDR; addr >= MIN_REG_ADDR; addr--) { + ret = write_swreg_config(reg_id, addr, + FM_DATA[reg_id - 1][addr]); + if (ret) + goto exit; + } + } + + /* trigger SWREG firmware update */ + for (reg_id = DDR_VDDC; reg_id <= DDRIO_MASTER; reg_id++) { + /* + * Slave regulator doesn't have to be updated, + * Updating Master is enough + */ + if ((reg_id == DDRIO_SLAVE) || (reg_id == VDDC1)) + continue; + + ret = swreg_config_done(reg_id); + if (ret) { + ERROR("Failed to trigger SWREG firmware update for %s\n" + , sw_reg_name[reg_id-1]); + return ret; + } + } + + for (reg_id = DDR_VDDC; reg_id <= DDRIO_MASTER; reg_id++) { + /* + * IHOST_ARRAY will be used on some boards like STRATUS and + * there will not be any issue even if it is updated on other + * boards where it is not used. + */ + if (reg_id == IHOST_ARRAY) + continue; + + for (addr = MIN_REG_ADDR; addr <= MAX_REG_ADDR; addr++) { + ret = read_swreg_config(reg_id, addr, &data); + if (ret || (!ret && + (data != FM_DATA[reg_id - 1][addr]))) { + ERROR("swreg fm update failed: %s at off %d\n", + sw_reg_name[reg_id - 1], addr); + ERROR("Read val: 0x%x, expected val: 0x%x\n", + data, FM_DATA[reg_id - 1][addr]); + return -1; + } + } + } + + INFO("Updated SWREG firmware\n"); + +#ifdef DUMP_SWREG + dump_swreg_firmware(); +#endif + return ret; + +exit: + /* + * Stop booting if swreg firmware update fails. + * Booting will fail at random point if we + * continue with wrong voltage settings. + */ + ERROR("Failed to update firmware for %s SWREG\n", + sw_reg_name[reg_id-1]); + assert(0); + + return ret; +} diff --git a/plat/brcm/board/stingray/driver/usb.c b/plat/brcm/board/stingray/driver/usb.c new file mode 100644 index 0000000..4a84141 --- /dev/null +++ b/plat/brcm/board/stingray/driver/usb.c @@ -0,0 +1,296 @@ +/* + * Copyright (c) 2019 - 2021, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <stdint.h> + +#include <common/debug.h> +#include <drivers/delay_timer.h> +#include <lib/mmio.h> + +#include <mdio.h> +#include <platform_usb.h> +#include <sr_utils.h> +#include "sr_usb.h" +#include <usbh_xhci_regs.h> + +static uint32_t usb_func = USB3_DRD | USB3H_USB2DRD; + +static void usb_pm_rescal_init(void) +{ + uint32_t data; + uint32_t try; + + mmio_setbits_32(CDRU_MISC_RESET_CONTROL, CDRU_PM_RESET_N_R); + /* release reset */ + mmio_setbits_32(CDRU_CHIP_TOP_SPARE_REG0, RESCAL_I_RSTB); + udelay(10U); + /* power up */ + mmio_setbits_32(CDRU_CHIP_TOP_SPARE_REG0, + RESCAL_I_RSTB | RESCAL_I_PWRDNB); + try = 1000U; + do { + udelay(1U); + data = mmio_read_32(CDRU_CHIP_TOP_SPARE_REG1); + try--; + } while ((data & RESCAL_I_PWRDNB) == 0x0U && (try != 0U)); + + if (try == 0U) { + ERROR("CDRU_CHIP_TOP_SPARE_REG1: 0x%x\n", data); + } + + INFO("USB and PM Rescal Init done..\n"); +} + +const unsigned int xhc_portsc_reg_offset[MAX_USB_PORTS] = { + XHC_PORTSC1_OFFSET, + XHC_PORTSC2_OFFSET, + XHC_PORTSC3_OFFSET, +}; + +static void usb3h_usb2drd_init(void) +{ + uint32_t val; + + INFO("USB3H + USB 2DRD init\n"); + mmio_clrbits_32(USB3H_U3PHY_CTRL, POR_RESET); + val = mmio_read_32(USB3H_PWR_CTRL); + val &= ~(0x3U << POWER_CTRL_OVRD); + val |= (1U << POWER_CTRL_OVRD); + mmio_write_32(USB3H_PWR_CTRL, val); + mmio_setbits_32(USB3H_U3PHY_CTRL, PHY_RESET); + /* Phy to come out of reset */ + udelay(2U); + mmio_clrbits_32(USB3H_U3PHY_CTRL, MDIO_RESET); + + /* MDIO in reset */ + udelay(2U); + mmio_setbits_32(USB3H_U3PHY_CTRL, MDIO_RESET); + + /* After MDIO reset release */ + udelay(2U); + + /* USB 3.0 phy Analog Block Initialization */ + mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_MDIO_BLOCK_BASE_REG, + USB3_PHY_ANA_BLOCK_BASE); + mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_ANA_REG0, 0x4646U); + mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_ANA_REG1, 0x80c9U); + mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_ANA_REG2, 0x88a6U); + mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_ANA_REG5, 0x7c12U); + mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_ANA_REG8, 0x1d07U); + mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_ANA_REG11, 0x25cU); + + /* USB 3.0 phy RXPMD Block initialization*/ + mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_MDIO_BLOCK_BASE_REG, + USB3_PHY_RXPMD_BLOCK_BASE); + mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_RXPMD_REG1, 0x4052U); + mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_RXPMD_REG2, 0x4cU); + mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_RXPMD_REG5, 0x7U); + mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_RXPMD_REG7, 0x173U); + + /* USB 3.0 phy AEQ Block initialization*/ + mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_MDIO_BLOCK_BASE_REG, + USB3_PHY_AEQ_BLOCK_BASE); + mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_AEQ_REG1, 0x3000U); + mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_AEQ_REG3, 0x2c70U); + + /* USB 3.0 phy TXPMD Block initialization*/ + mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_MDIO_BLOCK_BASE_REG, + USB3_PHY_TXPMD_BLOCK_BASE); + mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_TXPMD_REG1, 0x100fU); + mdio_write(MDIO_BUS_ID, USB3H_PHY_ID, USB3_PHY_TXPMD_REG2, 0x238cU); +} + +static void usb3drd_init(void) +{ + uint32_t val; + + INFO("USB3DRD init\n"); + mmio_clrbits_32(DRDU3_U3PHY_CTRL, POR_RESET); + val = mmio_read_32(DRDU3_PWR_CTRL); + val &= ~(0x3U << POWER_CTRL_OVRD); + val |= (1U << POWER_CTRL_OVRD); + mmio_write_32(DRDU3_PWR_CTRL, val); + mmio_setbits_32(DRDU3_U3PHY_CTRL, PHY_RESET); + /* Phy to come out of reset */ + udelay(2U); + mmio_clrbits_32(DRDU3_U3PHY_CTRL, MDIO_RESET); + + /* MDIO in reset */ + udelay(2U); + mmio_setbits_32(DRDU3_U3PHY_CTRL, MDIO_RESET); + + /* After MDIO reset release */ + udelay(2U); + + /* USB 3.0 DRD phy Analog Block Initialization */ + mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_MDIO_BLOCK_BASE_REG, + USB3_PHY_ANA_BLOCK_BASE); + mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_ANA_REG0, 0x4646U); + mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_ANA_REG1, 0x80c9U); + mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_ANA_REG2, 0x88a6U); + mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_ANA_REG5, 0x7c12U); + mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_ANA_REG8, 0x1d07U); + mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_ANA_REG11, 0x25cU); + + /* USB 3.0 DRD phy RXPMD Block initialization*/ + mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_MDIO_BLOCK_BASE_REG, + USB3_PHY_RXPMD_BLOCK_BASE); + mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_RXPMD_REG1, 0x4052U); + mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_RXPMD_REG2, 0x4cU); + mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_RXPMD_REG5, 0x7U); + mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_RXPMD_REG7, 0x173U); + + /* USB 3.0 DRD phy AEQ Block initialization*/ + mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_MDIO_BLOCK_BASE_REG, + USB3_PHY_AEQ_BLOCK_BASE); + mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_AEQ_REG1, 0x3000U); + mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_AEQ_REG3, 0x2c70U); + + /* USB 3.0 DRD phy TXPMD Block initialization*/ + mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_MDIO_BLOCK_BASE_REG, + USB3_PHY_TXPMD_BLOCK_BASE); + mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_TXPMD_REG1, 0x100fU); + mdio_write(MDIO_BUS_ID, USB3DRD_PHY_ID, USB3_PHY_TXPMD_REG2, 0x238cU); +} + +static void usb3_phy_init(void) +{ + usb_pm_rescal_init(); + + if ((usb_func & USB3H_USB2DRD) != 0U) { + usb3h_usb2drd_init(); + } + + if ((usb_func & USB3_DRD) != 0U) { + usb3drd_init(); + } +} + +#ifdef USB_DMA_COHERENT +void usb_enable_coherence(void) +{ + if (usb_func & USB3H_USB2DRD) { + mmio_setbits_32(USB3H_SOFT_RESET_CTRL, + USB3H_XHC_AXI_SOFT_RST_N); + mmio_setbits_32(DRDU2_SOFT_RESET_CTRL, + DRDU2_BDC_AXI_SOFT_RST_N); + mmio_setbits_32(USB3H_U3PHY_CTRL, USB3H_U3SOFT_RST_N); + mmio_setbits_32(DRDU2_PHY_CTRL, DRDU2_U2SOFT_RST_N); + + mmio_clrsetbits_32(DRD2U3H_XHC_REGS_AXIWRA, + (USBAXIWR_UA_MASK | USBAXIWR_SA_MASK), + (USBAXIWR_UA_VAL | USBAXIWR_SA_VAL)); + + mmio_clrsetbits_32(DRD2U3H_XHC_REGS_AXIRDA, + (USBAXIRD_UA_MASK | USBAXIRD_SA_MASK), + (USBAXIRD_UA_VAL | USBAXIRD_SA_VAL)); + + mmio_clrsetbits_32(DRDU2D_BDC_REGS_AXIWRA, + (USBAXIWR_UA_MASK | USBAXIWR_SA_MASK), + (USBAXIWR_UA_VAL | USBAXIWR_SA_VAL)); + + mmio_clrsetbits_32(DRDU2D_BDC_REGS_AXIRDA, + (USBAXIRD_UA_MASK | USBAXIRD_SA_MASK), + (USBAXIRD_UA_VAL | USBAXIRD_SA_VAL)); + + } + + if (usb_func & USB3_DRD) { + mmio_setbits_32(DRDU3_SOFT_RESET_CTRL, + (DRDU3_XHC_AXI_SOFT_RST_N | + DRDU3_BDC_AXI_SOFT_RST_N)); + mmio_setbits_32(DRDU3_U3PHY_CTRL, + (DRDU3_U3XHC_SOFT_RST_N | + DRDU3_U3BDC_SOFT_RST_N)); + + mmio_clrsetbits_32(DRDU3H_XHC_REGS_AXIWRA, + (USBAXIWR_UA_MASK | USBAXIWR_SA_MASK), + (USBAXIWR_UA_VAL | USBAXIWR_SA_VAL)); + + mmio_clrsetbits_32(DRDU3H_XHC_REGS_AXIRDA, + (USBAXIRD_UA_MASK | USBAXIRD_SA_MASK), + (USBAXIRD_UA_VAL | USBAXIRD_SA_VAL)); + + mmio_clrsetbits_32(DRDU3D_BDC_REGS_AXIWRA, + (USBAXIWR_UA_MASK | USBAXIWR_SA_MASK), + (USBAXIWR_UA_VAL | USBAXIWR_SA_VAL)); + + mmio_clrsetbits_32(DRDU3D_BDC_REGS_AXIRDA, + (USBAXIRD_UA_MASK | USBAXIRD_SA_MASK), + (USBAXIRD_UA_VAL | USBAXIRD_SA_VAL)); + } +} +#endif + +void xhci_phy_init(void) +{ + uint32_t val; + + INFO("usb init start\n"); + mmio_setbits_32(CDRU_MISC_CLK_ENABLE_CONTROL, + CDRU_MISC_CLK_USBSS); + + mmio_setbits_32(CDRU_MISC_RESET_CONTROL, CDRU_USBSS_RESET_N); + + if (usb_func & USB3_DRD) { + VERBOSE(" - configure stream_id = 0x6800 for DRDU3\n"); + val = SR_SID_VAL(0x3U, 0x1U, 0x0U) << ICFG_USB_SID_SHIFT; + mmio_write_32(ICFG_DRDU3_SID_CTRL + ICFG_USB_SID_AWADDR_OFFSET, + val); + mmio_write_32(ICFG_DRDU3_SID_CTRL + ICFG_USB_SID_ARADDR_OFFSET, + val); + + /* + * DRDU3 Device USB Space, DRDU3 Host USB Space, + * DRDU3 SS Config + */ + mmio_setbits_32(USBIC_GPV_SECURITY10, + USBIC_GPV_SECURITY10_FIELD); + } + + if (usb_func & USB3H_USB2DRD) { + VERBOSE(" - configure stream_id = 0x6801 for USB3H\n"); + val = SR_SID_VAL(0x3U, 0x1U, 0x1U) << ICFG_USB_SID_SHIFT; + mmio_write_32(ICFG_USB3H_SID_CTRL + ICFG_USB_SID_AWADDR_OFFSET, + val); + mmio_write_32(ICFG_USB3H_SID_CTRL + ICFG_USB_SID_ARADDR_OFFSET, + val); + + VERBOSE(" - configure stream_id = 0x6802 for DRDU2\n"); + val = SR_SID_VAL(0x3U, 0x1U, 0x2U) << ICFG_USB_SID_SHIFT; + mmio_write_32(ICFG_DRDU2_SID_CTRL + ICFG_USB_SID_AWADDR_OFFSET, + val); + mmio_write_32(ICFG_DRDU2_SID_CTRL + ICFG_USB_SID_ARADDR_OFFSET, + val); + + /* DRDU2 APB Bridge:DRDU2 USB Device, USB3H SS Config */ + mmio_setbits_32(USBIC_GPV_SECURITY1, USBIC_GPV_SECURITY1_FIELD); + + /* + * USB3H APB Bridge:DRDU2 Host + USB3 Host USB Space, + * USB3H SS Config + */ + mmio_setbits_32(USBIC_GPV_SECURITY2, USBIC_GPV_SECURITY2_FIELD); + } + + /* Configure Host masters as non-Secure */ + mmio_setbits_32(USBSS_TZPCDECPROT0set, USBSS_TZPCDECPROT0); + + /* CCN Slave on USBIC */ + mmio_setbits_32(USBIC_GPV_SECURITY0, USBIC_GPV_SECURITY0_FIELD); + + /* SLAVE_8:IDM Register Space */ + mmio_setbits_32(USBIC_GPV_SECURITY4, USBIC_GPV_SECURITY4_FIELD); + + usb3_phy_init(); +#ifdef USB_DMA_COHERENT + usb_enable_coherence(); +#endif + + usb_device_init(usb_func); + + INFO("PLAT USB: init done.\n"); +} diff --git a/plat/brcm/board/stingray/driver/usb_phy.c b/plat/brcm/board/stingray/driver/usb_phy.c new file mode 100644 index 0000000..54c98e1 --- /dev/null +++ b/plat/brcm/board/stingray/driver/usb_phy.c @@ -0,0 +1,601 @@ +/* + * Copyright (c) 2019 - 2021, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <platform_usb.h> +#include <usb_phy.h> + +#define USB_PHY_ALREADY_STARTED (-2) +#define USB_MAX_DEVICES 2 +#define USB3H_USB2DRD_PHY 0 +#define USB3_DRD_PHY 1 + +/* Common bit fields for all the USB2 phy */ +#define USB2_PHY_ISO DRDU2_U2PHY_ISO +#define USB2_AFE_PLL_PWRDWNB DRDU2_U2AFE_PLL_PWRDWNB +#define USB2_AFE_BG_PWRDWNB DRDU2_U2AFE_BG_PWRDWNB +#define USB2_AFE_LDO_PWRDWNB DRDU2_U2AFE_LDO_PWRDWNB +#define USB2_CTRL_CORERDY DRDU2_U2CTRL_CORERDY + +#define USB2_PHY_PCTL_MASK DRDU2_U2PHY_PCTL_MASK +#define USB2_PHY_PCTL_OFFSET DRDU2_U2PHY_PCTL_OFFSET +#define USB2_PHY_PCTL_VAL U2PHY_PCTL_VAL + +#define USB2_PLL_RESETB DRDU2_U2PLL_RESETB +#define USB2_PHY_RESETB DRDU2_U2PHY_RESETB + +static usb_phy_port_t usb_phy_port[2U][MAX_NR_PORTS]; + +static usb_phy_t usb_phy_info[2U] = { + {DRDU2_U2PLL_NDIV_FRAC, USB3H_PIPE_CTRL, 0U, USB3H_DRDU2_PHY}, + {0U, 0U, DRDU3_PIPE_CTRL, DRDU3_PHY} +}; + +typedef struct { + void *pcd_id; +} usb_platform_dev; + +/* index 0: USB3H + USB2 DRD, 1: USB3 DRD */ +static usb_platform_dev xhci_devices_configs[USB_MAX_DEVICES] = { + {&usb_phy_info[0U]}, + {&usb_phy_info[1U]} +}; + +static int32_t pll_lock_check(uint32_t address, uint32_t bit) +{ + uint32_t retry; + uint32_t data; + + retry = PLL_LOCK_RETRY_COUNT; + do { + data = mmio_read_32(address); + if ((data & bit) != 0U) { + return 0; + } + udelay(1); + } while (--retry != 0); + + ERROR("%s(): FAIL (0x%08x)\n", __func__, address); + return -1; +} + +/* + * USB2 PHY using external FSM bringup sequence + * Total #3 USB2 phys. All phys has the same + * bringup sequence. Register bit fields for + * some of the PHY's are different. + * Bit fields which are different are passed using + * struct u2_phy_ext_fsm with bit-fields and register addr. + */ + +static void u2_phy_ext_fsm_power_on(struct u2_phy_ext_fsm *u2_phy) +{ + mmio_setbits_32(u2_phy->phy_ctrl_reg, USB2_PHY_ISO); + /* Delay as per external FSM spec */ + udelay(10U); + + mmio_setbits_32(u2_phy->phy_ctrl_reg, u2_phy->phy_iddq); + /* Delay as per external FSM spec */ + udelay(10U); + + mmio_clrbits_32(u2_phy->phy_ctrl_reg, + (USB2_AFE_BG_PWRDWNB | + USB2_AFE_PLL_PWRDWNB | + USB2_AFE_LDO_PWRDWNB | + USB2_CTRL_CORERDY)); + + mmio_clrsetbits_32(u2_phy->phy_ctrl_reg, + (USB2_PHY_PCTL_MASK << USB2_PHY_PCTL_OFFSET), + (USB2_PHY_PCTL_VAL << USB2_PHY_PCTL_OFFSET)); + /* Delay as per external FSM spec */ + udelay(160U); + + mmio_setbits_32(u2_phy->phy_ctrl_reg, USB2_CTRL_CORERDY); + /* Delay as per external FSM spec */ + udelay(50U); + + mmio_setbits_32(u2_phy->phy_ctrl_reg, USB2_AFE_BG_PWRDWNB); + /* Delay as per external FSM spec */ + udelay(200U); + + mmio_setbits_32(u2_phy->pwr_ctrl_reg, u2_phy->pwr_onin); + mmio_setbits_32(u2_phy->phy_ctrl_reg, USB2_AFE_LDO_PWRDWNB); + /* Delay as per external FSM spec */ + udelay(10U); + + mmio_setbits_32(u2_phy->pwr_ctrl_reg, u2_phy->pwr_okin); + /* Delay as per external FSM spec */ + udelay(10U); + + mmio_setbits_32(u2_phy->phy_ctrl_reg, USB2_AFE_PLL_PWRDWNB); + /* Delay as per external FSM spec */ + udelay(10U); + + mmio_clrbits_32(u2_phy->phy_ctrl_reg, USB2_PHY_ISO); + /* Delay as per external FSM spec */ + udelay(10U); + mmio_clrbits_32(u2_phy->phy_ctrl_reg, u2_phy->phy_iddq); + /* Delay as per external FSM spec */ + udelay(1U); + + mmio_setbits_32(u2_phy->pll_ctrl_reg, USB2_PLL_RESETB); + mmio_setbits_32(u2_phy->phy_ctrl_reg, USB2_PHY_RESETB); + +} + +static int32_t usb3h_u2_phy_power_on(uint32_t base) +{ + int32_t status; + struct u2_phy_ext_fsm u2_phy; + + u2_phy.pll_ctrl_reg = base + USB3H_U2PLL_CTRL; + u2_phy.phy_ctrl_reg = base + USB3H_U2PHY_CTRL; + u2_phy.phy_iddq = USB3H_U2PHY_IDDQ; + u2_phy.pwr_ctrl_reg = base + USB3H_PWR_CTRL; + u2_phy.pwr_okin = USB3H_PWR_CTRL_U2PHY_DFE_SWITCH_PWROKIN; + u2_phy.pwr_onin = USB3H_PWR_CTRL_U2PHY_DFE_SWITCH_PWRONIN; + + u2_phy_ext_fsm_power_on(&u2_phy); + + status = pll_lock_check(base + USB3H_U2PLL_CTRL, USB3H_U2PLL_LOCK); + if (status != 0) { + /* re-try by toggling the PLL reset */ + mmio_clrbits_32(base + USB3H_U2PLL_CTRL, + (uint32_t)USB3H_U2PLL_RESETB); + mmio_setbits_32(base + USB3H_U2PLL_CTRL, USB3H_U2PLL_RESETB); + status = pll_lock_check(base + USB3H_U2PLL_CTRL, + USB3H_U2PLL_LOCK); + if (status != 0) + ERROR("%s() re-try PLL lock FAIL (0x%08x)\n", __func__, + base + USB3H_U2PLL_CTRL); + } + + mmio_clrsetbits_32(base + USB3H_U2PHY_CTRL, + (USB3H_U2PHY_PCTL_MASK << USB3H_U2PHY_PCTL_OFFSET), + (U2PHY_PCTL_NON_DRV_LOW << USB3H_U2PHY_PCTL_OFFSET)); + return status; +} + +static int32_t usb3h_u3_phy_power_on(uint32_t base) +{ + int32_t status; + + /* Set pctl with mode and soft reset */ + mmio_clrsetbits_32(base + USB3H_U3PHY_CTRL, + (USB3H_U3PHY_PCTL_MASK << USB3H_U3PHY_PCTL_OFFSET), + (U3PHY_PCTL_VAL << USB3H_U3PHY_PCTL_OFFSET)); + + mmio_clrbits_32(base + USB3H_U3PHY_PLL_CTRL, + (uint32_t) USB3H_U3SSPLL_SUSPEND_EN); + mmio_setbits_32(base + USB3H_U3PHY_PLL_CTRL, USB3H_U3PLL_SEQ_START); + mmio_setbits_32(base + USB3H_U3PHY_PLL_CTRL, USB3H_U3PLL_RESETB); + + /* Time to stabilize the PLL Control */ + mdelay(1U); + + status = pll_lock_check(base + USB3H_U3PHY_PLL_CTRL, + USB3H_U3PLL_SS_LOCK); + + return status; +} + +static int32_t drdu3_u2_phy_power_on(uint32_t base) +{ + int32_t status; + struct u2_phy_ext_fsm u2_phy; + + u2_phy.pll_ctrl_reg = base + DRDU3_U2PLL_CTRL; + u2_phy.phy_ctrl_reg = base + DRDU3_U2PHY_CTRL; + u2_phy.phy_iddq = DRDU3_U2PHY_IDDQ; + u2_phy.pwr_ctrl_reg = base + DRDU3_PWR_CTRL; + u2_phy.pwr_okin = DRDU3_U2PHY_DFE_SWITCH_PWROKIN; + u2_phy.pwr_onin = DRDU3_U2PHY_DFE_SWITCH_PWRONIN; + + u2_phy_ext_fsm_power_on(&u2_phy); + + status = pll_lock_check(base + DRDU3_U2PLL_CTRL, DRDU3_U2PLL_LOCK); + if (status != 0) { + /* re-try by toggling the PLL reset */ + mmio_clrbits_32(base + DRDU3_U2PLL_CTRL, + (uint32_t)DRDU2_U2PLL_RESETB); + mmio_setbits_32(base + DRDU3_U2PLL_CTRL, DRDU3_U2PLL_RESETB); + + status = pll_lock_check(base + DRDU3_U2PLL_CTRL, + DRDU3_U2PLL_LOCK); + if (status != 0) { + ERROR("%s() re-try PLL lock FAIL (0x%08x)\n", __func__, + base + DRDU3_U2PLL_CTRL); + } + } + mmio_clrsetbits_32(base + DRDU3_U2PHY_CTRL, + (DRDU3_U2PHY_PCTL_MASK << DRDU3_U2PHY_PCTL_OFFSET), + (U2PHY_PCTL_NON_DRV_LOW << DRDU3_U2PHY_PCTL_OFFSET)); + + return status; +} + +static int32_t drdu3_u3_phy_power_on(uint32_t base) +{ + int32_t status; + + /* Set pctl with mode and soft reset */ + mmio_clrsetbits_32(base + DRDU3_U3PHY_CTRL, + (DRDU3_U3PHY_PCTL_MASK << DRDU3_U3PHY_PCTL_OFFSET), + (U3PHY_PCTL_VAL << DRDU3_U3PHY_PCTL_OFFSET)); + + mmio_clrbits_32(base + DRDU3_U3PHY_PLL_CTRL, + (uint32_t) DRDU3_U3SSPLL_SUSPEND_EN); + mmio_setbits_32(base + DRDU3_U3PHY_PLL_CTRL, DRDU3_U3PLL_SEQ_START); + mmio_setbits_32(base + DRDU3_U3PHY_PLL_CTRL, DRDU3_U3PLL_RESETB); + + /* Time to stabilize the PLL Control */ + mdelay(1U); + + status = pll_lock_check(base + DRDU3_U3PHY_PLL_CTRL, + DRDU3_U3PLL_SS_LOCK); + + return status; +} + +static int32_t drdu2_u2_phy_power_on(uint32_t base) +{ + int32_t status; + struct u2_phy_ext_fsm u2_phy; + + u2_phy.pll_ctrl_reg = base + DRDU2_U2PLL_CTRL; + u2_phy.phy_ctrl_reg = base + DRDU2_PHY_CTRL; + u2_phy.phy_iddq = DRDU2_U2IDDQ; + u2_phy.pwr_ctrl_reg = base + DRDU2_PWR_CTRL; + u2_phy.pwr_okin = DRDU2_U2PHY_DFE_SWITCH_PWROKIN_I; + u2_phy.pwr_onin = DRDU2_U2PHY_DFE_SWITCH_PWRONIN_I; + + u2_phy_ext_fsm_power_on(&u2_phy); + + status = pll_lock_check(base + DRDU2_U2PLL_CTRL, DRDU2_U2PLL_LOCK); + if (status != 0) { + /* re-try by toggling the PLL reset */ + mmio_clrbits_32(base + DRDU2_U2PLL_CTRL, + (uint32_t)DRDU2_U2PLL_RESETB); + mmio_setbits_32(base + DRDU2_U2PLL_CTRL, DRDU2_U2PLL_RESETB); + + status = pll_lock_check(base + DRDU2_U2PLL_CTRL, + DRDU2_U2PLL_LOCK); + if (status != 0) + ERROR("%s() re-try PLL lock FAIL (0x%08x)\n", __func__, + base + DRDU2_U2PLL_CTRL); + } + mmio_clrsetbits_32(base + DRDU2_PHY_CTRL, + (DRDU2_U2PHY_PCTL_MASK << DRDU2_U2PHY_PCTL_OFFSET), + (U2PHY_PCTL_NON_DRV_LOW << DRDU2_U2PHY_PCTL_OFFSET)); + + return status; +} + +void u3h_u2drd_phy_reset(usb_phy_port_t *phy_port) +{ + usb_phy_t *phy = phy_port->p; + + switch (phy_port->port_id) { + case USB3HS_PORT: + mmio_clrbits_32(phy->usb3hreg + USB3H_U2PHY_CTRL, + (uint32_t) USB3H_U2CTRL_CORERDY); + mmio_setbits_32(phy->usb3hreg + USB3H_U2PHY_CTRL, + USB3H_U2CTRL_CORERDY); + break; + case DRDU2_PORT: + mmio_clrbits_32(phy->drdu2reg + DRDU2_PHY_CTRL, + (uint32_t) DRDU2_U2CTRL_CORERDY); + mmio_setbits_32(phy->drdu2reg + DRDU2_PHY_CTRL, + DRDU2_U2CTRL_CORERDY); + break; + } +} + +void u3drd_phy_reset(usb_phy_port_t *phy_port) +{ + usb_phy_t *phy = phy_port->p; + + if (phy_port->port_id == DRD3HS_PORT) { + mmio_clrbits_32(phy->drdu3reg + DRDU3_U2PHY_CTRL, + (uint32_t) DRDU3_U2CTRL_CORERDY); + mmio_setbits_32(phy->drdu3reg + DRDU3_U2PHY_CTRL, + DRDU3_U2CTRL_CORERDY); + } +} + +static int32_t u3h_u2drd_phy_power_on(usb_phy_port_t *phy_port) +{ + usb_phy_t *phy = phy_port->p; + int32_t status; + + switch (phy_port->port_id) { + case USB3SS_PORT: + mmio_clrbits_32(phy->usb3hreg + USB3H_PHY_PWR_CTRL, + (uint32_t) USB3H_DISABLE_USB30_P0); + status = usb3h_u3_phy_power_on(phy->usb3hreg); + if (status != 0) { + goto err_usb3h_phy_on; + } + break; + case USB3HS_PORT: + mmio_clrbits_32(phy->usb3hreg + USB3H_PHY_PWR_CTRL, + (uint32_t) USB3H_DISABLE_EUSB_P1); + mmio_setbits_32(AXI_DEBUG_CTRL, + AXI_DBG_CTRL_SSPHY_DRD_MODE_DISABLE); + mmio_setbits_32(USB3H_DEBUG_CTRL, + USB3H_DBG_CTRL_SSPHY_DRD_MODE_DISABLE); + + mmio_clrbits_32(phy->usb3hreg + USB3H_PWR_CTRL, + USB3H_PWR_CTRL_U2PHY_DFE_SWITCH_PWRONIN); + /* Delay as per external FSM spec */ + udelay(10U); + mmio_clrbits_32(phy->usb3hreg + USB3H_PWR_CTRL, + USB3H_PWR_CTRL_U2PHY_DFE_SWITCH_PWROKIN); + status = usb3h_u2_phy_power_on(phy->usb3hreg); + if (status != 0) { + goto err_usb3h_phy_on; + } + break; + case DRDU2_PORT: + mmio_clrbits_32(phy->usb3hreg + USB3H_PHY_PWR_CTRL, + (uint32_t) USB3H_DISABLE_EUSB_P0); + mmio_setbits_32(AXI_DEBUG_CTRL, + AXI_DBG_CTRL_SSPHY_DRD_MODE_DISABLE); + mmio_setbits_32(USB3H_DEBUG_CTRL, + USB3H_DBG_CTRL_SSPHY_DRD_MODE_DISABLE); + + mmio_clrbits_32(phy->usb3hreg + DRDU2_PWR_CTRL, + DRDU2_U2PHY_DFE_SWITCH_PWRONIN_I); + /* Delay as per external FSM spec */ + udelay(10U); + mmio_clrbits_32(phy->usb3hreg + DRDU2_PWR_CTRL, + DRDU2_U2PHY_DFE_SWITCH_PWROKIN_I); + + status = drdu2_u2_phy_power_on(phy->drdu2reg); + if (status != 0) { + mmio_setbits_32(phy->usb3hreg + USB3H_PHY_PWR_CTRL, + USB3H_DISABLE_EUSB_P0); + goto err_drdu2_phy_on; + } + break; + } + + /* Device Mode */ + if (phy_port->port_id == DRDU2_PORT) { + mmio_write_32(phy->drdu2reg + DRDU2_SOFT_RESET_CTRL, + DRDU2_BDC_AXI_SOFT_RST_N); + mmio_setbits_32(phy->drdu2reg + DRDU2_PHY_CTRL, + DRDU2_U2SOFT_RST_N); + } + /* Host Mode */ + mmio_write_32(phy->usb3hreg + USB3H_SOFT_RESET_CTRL, + USB3H_XHC_AXI_SOFT_RST_N); + mmio_setbits_32(phy->usb3hreg + USB3H_U3PHY_CTRL, USB3H_U3SOFT_RST_N); + + return 0U; + err_usb3h_phy_on:mmio_setbits_32(phy->usb3hreg + USB3H_PHY_PWR_CTRL, + (USB3H_DISABLE_EUSB_P1 | + USB3H_DISABLE_USB30_P0)); + err_drdu2_phy_on: + + return status; +} + +static int32_t u3drd_phy_power_on(usb_phy_port_t *phy_port) +{ + usb_phy_t *phy = phy_port->p; + int32_t status; + + switch (phy_port->port_id) { + case DRD3SS_PORT: + mmio_clrbits_32(phy->drdu3reg + DRDU3_PHY_PWR_CTRL, + (uint32_t) DRDU3_DISABLE_USB30_P0); + + status = drdu3_u3_phy_power_on(phy->drdu3reg); + if (status != 0) { + goto err_drdu3_phy_on; + } + break; + case DRD3HS_PORT: + mmio_clrbits_32(phy->drdu3reg + DRDU3_PHY_PWR_CTRL, + (uint32_t) DRDU3_DISABLE_EUSB_P0); + mmio_setbits_32(AXI_DEBUG_CTRL, + AXI_DBG_CTRL_SSPHY_DRD_MODE_DISABLE); + mmio_setbits_32(USB3H_DEBUG_CTRL, + USB3H_DBG_CTRL_SSPHY_DRD_MODE_DISABLE); + + mmio_clrbits_32(phy->drdu3reg + DRDU3_PWR_CTRL, + DRDU3_U2PHY_DFE_SWITCH_PWRONIN); + /* Delay as per external FSM spec */ + udelay(10U); + mmio_clrbits_32(phy->drdu3reg + DRDU3_PWR_CTRL, + DRDU3_U2PHY_DFE_SWITCH_PWROKIN); + + status = drdu3_u2_phy_power_on(phy->drdu3reg); + if (status != 0) { + goto err_drdu3_phy_on; + } + + /* Host Mode */ + mmio_setbits_32(phy->drdu3reg + DRDU3_SOFT_RESET_CTRL, + DRDU3_XHC_AXI_SOFT_RST_N); + mmio_setbits_32(phy->drdu3reg + DRDU3_U3PHY_CTRL, + DRDU3_U3XHC_SOFT_RST_N); + /* Device Mode */ + mmio_setbits_32(phy->drdu3reg + DRDU3_SOFT_RESET_CTRL, + DRDU3_BDC_AXI_SOFT_RST_N); + mmio_setbits_32(phy->drdu3reg + DRDU3_U3PHY_CTRL, + DRDU3_U3BDC_SOFT_RST_N); + break; + } + + return 0U; + err_drdu3_phy_on:mmio_setbits_32(phy->drdu3reg + DRDU3_PHY_PWR_CTRL, + (DRDU3_DISABLE_EUSB_P0 | + DRDU3_DISABLE_USB30_P0)); + + return status; +} + +static void u3h_u2drd_phy_power_off(usb_phy_port_t *phy_port) +{ + usb_phy_t *p = phy_port->p; + + switch (phy_port->port_id) { + case USB3SS_PORT: + mmio_setbits_32(p->usb3hreg + USB3H_PHY_PWR_CTRL, + USB3H_DISABLE_USB30_P0); + break; + case USB3HS_PORT: + mmio_setbits_32(p->usb3hreg + USB3H_PHY_PWR_CTRL, + USB3H_DISABLE_EUSB_P1); + break; + case DRDU2_PORT: + mmio_setbits_32(p->usb3hreg + USB3H_PHY_PWR_CTRL, + USB3H_DISABLE_EUSB_P0); + break; + } +} + +static void u3drd_phy_power_off(usb_phy_port_t *phy_port) +{ + usb_phy_t *p = phy_port->p; + + switch (phy_port->port_id) { + case DRD3SS_PORT: + mmio_setbits_32(p->drdu3reg + DRDU3_PHY_PWR_CTRL, + DRDU3_DISABLE_USB30_P0); + break; + case DRD3HS_PORT: + mmio_setbits_32(p->drdu3reg + DRDU3_PHY_PWR_CTRL, + DRDU3_DISABLE_EUSB_P0); + break; + } +} + +int32_t usb_info_fill(usb_phy_t *phy_info) +{ + int32_t index; + + if (phy_info->initialized != 0U) { + return USB_PHY_ALREADY_STARTED; + } + + if (phy_info->phy_id == USB3H_DRDU2_PHY) { + phy_info->phy_port = usb_phy_port[USB3H_DRDU2_PHY - 1U]; + phy_info->ports_enabled = 0x7U; + } else { + phy_info->phy_port = usb_phy_port[DRDU3_PHY - 1U]; + phy_info->ports_enabled = 0x3U; + } + + for (index = MAX_NR_PORTS - 1U; index > -1; index--) { + phy_info->phy_port[index].enabled = (phy_info->ports_enabled + >> index) & 0x1U; + phy_info->phy_port[index].p = phy_info; + phy_info->phy_port[index].port_id = index; + } + + return 0U; +} + +int32_t usb_phy_init(usb_platform_dev *device) +{ + int32_t status; + usb_phy_t *phy_info; + uint32_t index; + + phy_info = (usb_phy_t *)device->pcd_id; + + status = usb_info_fill(phy_info); + if (status != 0) { + return (status == USB_PHY_ALREADY_STARTED) ? 0 : status; + } + + for (index = 0U; index < MAX_NR_PORTS; index++) { + if (phy_info->phy_port[index].enabled != 0U) { + switch (phy_info->phy_id) { + case USB3H_DRDU2_PHY: + status = + u3h_u2drd_phy_power_on(&phy_info-> + phy_port[index]); + break; + default: + status = + u3drd_phy_power_on(&phy_info-> + phy_port[index]); + } + } + } + + phy_info->initialized = !status; + return status; +} + +void usb_phy_shutdown(usb_platform_dev *device) +{ + usb_phy_t *phy_info; + uint32_t index; + + phy_info = (usb_phy_t *)device->pcd_id; + + phy_info->initialized = 0U; + + for (index = 0U; index < MAX_NR_PORTS; index++) { + if (phy_info->phy_port[index].enabled != 0U) { + switch (phy_info->phy_id) { + case USB3H_DRDU2_PHY: + u3h_u2drd_phy_power_off(&phy_info-> + phy_port[index]); + break; + case DRDU3_PHY: + u3drd_phy_power_off(&phy_info->phy_port[index]); + break; + default: + INFO("%s: invalid phy id 0x%x\n", __func__, + phy_info->phy_id); + } + } + } +} + +int32_t usb_xhci_init(usb_platform_dev *device) +{ + int32_t status; + + status = usb_phy_init(device); + if (status == USB_PHY_ALREADY_STARTED) { + status = 0U; + } + + return status; +} + +int32_t usb_device_init(unsigned int usb_func) +{ + int32_t status; + int32_t devices_initialized = 0U; + + if ((usb_func & USB3H_USB2DRD) != 0U) { + status = usb_xhci_init( + &xhci_devices_configs[USB3H_USB2DRD_PHY]); + if (status == 0) { + devices_initialized++; + } else { + ERROR("%s(): USB3H_USB2DRD init failure\n", __func__); + } + } + + if ((usb_func & USB3_DRD) != 0U) { + status = usb_xhci_init(&xhci_devices_configs[USB3_DRD_PHY]); + if (status == 0) { + devices_initialized++; + } else { + ERROR("%s(): USB3_DRD init failure\n", __func__); + } + } + + return devices_initialized; +} diff --git a/plat/brcm/board/stingray/include/bl33_info.h b/plat/brcm/board/stingray/include/bl33_info.h new file mode 100644 index 0000000..1dac48c --- /dev/null +++ b/plat/brcm/board/stingray/include/bl33_info.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2019-2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef BL33_INFO_H +#define BL33_INFO_H + +/* Increase version number each time this file is modified */ +#define BL33_INFO_VERSION 4 + +struct chip_info { + unsigned int chip_id; + unsigned int rev_id; +}; + +struct boot_time_info { + unsigned int bl1_start; + unsigned int bl1_end; + unsigned int bl2_start; + unsigned int bl2_end; + unsigned int bl31_start; + unsigned int bl31_end; + unsigned int bl32_start; + unsigned int bl32_end; + unsigned int bl33_start; + unsigned int bl33_prompt; + unsigned int bl33_end; +}; + +struct bl33_info { + unsigned int version; + struct chip_info chip; + struct boot_time_info boot_time_info; +}; + +#endif diff --git a/plat/brcm/board/stingray/include/board_info.h b/plat/brcm/board/stingray/include/board_info.h new file mode 100644 index 0000000..8901259 --- /dev/null +++ b/plat/brcm/board/stingray/include/board_info.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2017 - 2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef BOARD_INFO_H +#define BOARD_INFO_H + +#define IHOST_REG_INTEGRATED 0 +#define IHOST_REG_EXT_PROGRAMMABLE 1 +#define IHOST_REG_EXT_FIXED 2 + +#if defined(IHOST_REG_TYPE) + #if ((IHOST_REG_TYPE != IHOST_REG_INTEGRATED) && \ + (IHOST_REG_TYPE != IHOST_REG_EXT_PROGRAMMABLE) && \ + (IHOST_REG_TYPE != IHOST_REG_EXT_FIXED)) + #error "IHOST_REG_TYPE not valid" + #endif +#else + #define IHOST_REG_TYPE IHOST_REG_INTEGRATED +#endif + +#define VDDC_REG_INTEGRATED 0 +#define VDDC_REG_EXT_PROGRAMMABLE 1 +#define VDDC_REG_EXT_FIXED 2 + +#if defined(VDDC_REG_TYPE) + #if ((VDDC_REG_TYPE != VDDC_REG_INTEGRATED) && \ + (VDDC_REG_TYPE != VDDC_REG_EXT_PROGRAMMABLE) && \ + (VDDC_REG_TYPE != VDDC_REG_EXT_FIXED)) + #error "VDDC_REG_TYPE not valid" + #endif +#else + #define VDDC_REG_TYPE VDDC_REG_INTEGRATED +#endif + +#endif diff --git a/plat/brcm/board/stingray/include/crmu_def.h b/plat/brcm/board/stingray/include/crmu_def.h new file mode 100644 index 0000000..ebc2bb6 --- /dev/null +++ b/plat/brcm/board/stingray/include/crmu_def.h @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2019-2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef CRMU_DEF_H +#define CRMU_DEF_H + +#define CRMU_REGS_BASE 0x66410000 +/* 32 kB IDRAM */ +#define CRMU_IDRAM_BASE_ADDR CRMU_REGS_BASE +#define CRMU_IDRAM_SIZE 0x8000 +/* 4 kB Scratch RAM */ +#define CRMU_SRAM_BASE (CRMU_IDRAM_BASE_ADDR + CRMU_IDRAM_SIZE) +#define CRMU_SRAM_SIZE 0x1000 + +#define CRMU_RESERVED_SPACE 0x3000 +#define CRMU_CORE_BASE (CRMU_SRAM_BASE + CRMU_SRAM_SIZE + \ + CRMU_RESERVED_SPACE) + +#define CRMU_SHARED_SRAM_BASE CRMU_SRAM_BASE +#define CRMU_SHARED_SRAM_SIZE 0x200 +#define CRMU_CFG_BASE (CRMU_SHARED_SRAM_BASE + \ + CRMU_SHARED_SRAM_SIZE) + +#define CRMU_PWR_GOOD_STATUS CRMU_CORE_BASE +#define CRMU_PWR_GOOD_STATUS__BBL_POWER_GOOD 0 +#define CRMU_ISO_CELL_CONTROL (CRMU_CORE_BASE + 0x4) +#define CRMU_ISO_CELL_CONTROL__CRMU_ISO_PDBBL 16 +#define CRMU_ISO_CELL_CONTROL__CRMU_ISO_PDBBL_TAMPER 24 +#define CRMU_SPRU_SOURCE_SEL_STAT (CRMU_CORE_BASE + 0xc) +#define CRMU_SPRU_SOURCE_SEL_STAT__SPRU_SOURCE_SELECT 0 +#define BSTI_BASE (CRMU_CORE_BASE + 0x28) +#define BSTI_CONTROL_OFFSET BSTI_BASE +#define BSTI_COMMAND_OFFSET (BSTI_BASE + 0x4) + +#define OCOTP_REGS_BASE (CRMU_CORE_BASE + 0x400) + +#define CRMU_TCI_BASE (CRMU_CORE_BASE + 0x800) +#define CRMU_SWREG_STATUS_ADDR (CRMU_TCI_BASE + 0x0c) +#define CRMU_CHIP_OTPC_STATUS (CRMU_TCI_BASE + 0x10) +#define CRMU_CHIP_OTPC_STATUS__OTP_BISR_LOAD_DONE 19 +#define CRMU_BISR_PDG_MASK (CRMU_TCI_BASE + 0x4c) +#define CRMU_BISR_PDG_MASK__CRMU_BISR_IHOST0 2 +#define CRMU_BISR_PDG_MASK__CRMU_BISR_IHOST1 3 +#define CRMU_BISR_PDG_MASK__CRMU_BISR_IHOST2 4 +#define CRMU_BISR_PDG_MASK__CRMU_BISR_IHOST3 0 +#define CRMU_POWER_POLL (CRMU_TCI_BASE + 0x60) +#define CRMU_OTP_STATUS CRMU_POWER_POLL +#define CRMU_OTP_STATUS_BIT 1 +#define CRMU_DDR_PHY_AON_CTRL (CRMU_TCI_BASE + 0x64) +#define CRMU_DDRPHY2_HW_RESETN_R BIT(21) +#define CRMU_DDRPHY2_PWROKIN_PHY_R BIT(20) +#define CRMU_DDRPHY2_PWRONIN_PHY_R BIT(19) +#define CRMU_DDRPHY2_ISO_PHY_DFI_R BIT(18) +#define CRMU_DDRPHY2_ISO_PHY_REGS_R BIT(17) +#define CRMU_DDRPHY2_ISO_PHY_PLL_R BIT(16) +#define CRMU_DDRPHY1_HW_RESETN_R BIT(13) +#define CRMU_DDRPHY1_PWROKIN_PHY_R BIT(12) +#define CRMU_DDRPHY1_PWRONIN_PHY_R BIT(11) +#define CRMU_DDRPHY1_ISO_PHY_DFI_R BIT(10) +#define CRMU_DDRPHY1_ISO_PHY_REGS_R BIT(9) +#define CRMU_DDRPHY1_ISO_PHY_PLL_R BIT(8) +#define CRMU_DDRPHY0_HW_RESETN_R BIT(5) +#define CRMU_DDRPHY0_PWROKIN_PHY_R BIT(4) +#define CRMU_DDRPHY0_PWRONIN_PHY_R BIT(3) +#define CRMU_DDRPHY0_ISO_PHY_DFI_R BIT(2) +#define CRMU_DDRPHY0_ISO_PHY_REGS_R BIT(1) +#define CRMU_DDRPHY0_ISO_PHY_PLL_R BIT(0) +#define CRMU_EMEM_RESET_N_R BIT(16) +#define CRMU_EMEM_PRESET_N_R BIT(0) +#define CRMU_SWREG_CTRL_ADDR (CRMU_TCI_BASE + 0x6c) +#define CRMU_AON_CTRL1 (CRMU_TCI_BASE + 0x70) +#define CRMU_AON_CTRL1__LCPLL1_ISO_IN 18 +#define CRMU_AON_CTRL1__LCPLL1_PWRON_LDO 19 +#define CRMU_AON_CTRL1__LCPLL1_PWR_ON 20 +#define CRMU_AON_CTRL1__LCPLL0_ISO_IN 21 +#define CRMU_AON_CTRL1__LCPLL0_PWRON_LDO 22 +#define CRMU_AON_CTRL1__LCPLL0_PWR_ON 23 +#define CRMU_PCIE_LCPLL_PWR_ON_SHIFT 29 +#define CRMU_PCIE_LCPLL_PWR_ON_MASK BIT(CRMU_PCIE_LCPLL_PWR_ON_SHIFT) +#define CRMU_PCIE_LCPLL_PWRON_LDO_SHIFT 28 +#define CRMU_PCIE_LCPLL_PWRON_LDO_MASK BIT(CRMU_PCIE_LCPLL_PWRON_LDO_SHIFT) +#define CRMU_PCIE_LCPLL_ISO_IN_SHIFT 27 +#define CRMU_PCIE_LCPLL_ISO_IN_MASK BIT(CRMU_PCIE_LCPLL_ISO_IN_SHIFT) +#define CRMU_MASTER_AXI_ARUSER_CONFIG (CRMU_TCI_BASE + 0x74) +#define CRMU_MASTER_AXI_AWUSER_CONFIG (CRMU_TCI_BASE + 0x78) +#define CRMU_DDR_PHY_AON_CTRL_1 (CRMU_TCI_BASE + 0x8c) + +#define CDRU_BASE_ADDR (CRMU_CORE_BASE + 0x1000) +#define CDRU_MISC_RESET_CONTROL CDRU_BASE_ADDR +#define CDRU_MISC_RESET_CONTROL_TS_RESET_N 16 +#define CDRU_MISC_RESET_CONTROL__CDRU_USBSS_RESET_N 14 +#define CDRU_MISC_RESET_CONTROL__CDRU_SATA_RESET_N_R 15 +#define CDRU_MISC_RESET_CONTROL__CDRU_MHB_RESET_N_R 13 +#define CDRU_MISC_RESET_CONTROL__CDRU_PCIE_RESET_N_R 3 +#define CDRU_MISC_RESET_CONTROL__CDRU_PM_RESET_N_R 2 +#define CDRU_MISC_RESET_CONTROL__CDRU_NITRO_RESET_N_R 1 + +#define CDRU_PROC_EVENT_CLEAR (CDRU_BASE_ADDR + 0x48) +#define CDRU_PROC_EVENT_CLEAR__IH0_CDRU_STANDBYWFIL2 0 +#define CDRU_PROC_EVENT_CLEAR__IH0_CDRU_STANDBYWFI 3 +#define CDRU_PROC_EVENT_CLEAR__IH1_CDRU_STANDBYWFIL2 5 +#define CDRU_PROC_EVENT_CLEAR__IH1_CDRU_STANDBYWFI 8 +#define CDRU_PROC_EVENT_CLEAR__IH2_CDRU_STANDBYWFIL2 10 +#define CDRU_PROC_EVENT_CLEAR__IH2_CDRU_STANDBYWFI 13 +#define CDRU_PROC_EVENT_CLEAR__IH3_CDRU_STANDBYWFIL2 15 +#define CDRU_PROC_EVENT_CLEAR__IH3_CDRU_STANDBYWFI 18 + +#define CDRU_CHIP_STRAP_CTRL (CDRU_BASE_ADDR + 0x50) +#define CDRU_CHIP_STRAP_CTRL__SOFTWARE_OVERRIDE 31 + +#define CDRU_CHIP_IO_PAD_CONTROL (CDRU_BASE_ADDR + 0x58) +#define CDRU_CHIP_IO_PAD_CONTROL__CDRU_IOMUX_FORCE_PDN_R 8 +#define CDRU_CHIP_IO_PAD_CONTROL__CDRU_IOMUX_FORCE_PAD_IN_R 0 + +#define CDRU_CHIP_STRAP_DATA_LSW (CDRU_BASE_ADDR + 0x5c) +#define CDRU_CHIP_STRAP_DATA_LSW__BISR_BYPASS_MODE 18 +#define CDRU_CHIP_STRAP_DATA_LSW__NIC_MODE_MASK BIT(8) +#define CDRU_CHIP_STRAP_DATA_LSW_PAD_USB_MODE BIT(26) + +#define CDRU_CHIP_STRAP_DATA (CDRU_BASE_ADDR + 0x5c) +#define CDRU_DDR0_CONTROL_OFFSET (CDRU_BASE_ADDR + 0xb8) +#define CDRU_DDR1_CONTROL_OFFSET (CDRU_BASE_ADDR + 0xbc) +#define CDRU_DDR2_CONTROL_OFFSET (CDRU_BASE_ADDR + 0xc0) +#define CRMU_SW_POR_RESET_CTRL (CDRU_BASE_ADDR + 0x100) + +#define CDRU_GENPLL2_CONTROL1 (CDRU_BASE_ADDR + 0x1b0) +#define CDRU_GENPLL2_CONTROL1__CHNL6_FS4_CLK BIT(11) +#define CDRU_GENPLL5_CONTROL1 (CDRU_BASE_ADDR + 0x24c) +#define CDRU_GENPLL5_CONTROL1__CHNL0_DME_CLK BIT(6) +#define CDRU_GENPLL5_CONTROL1__CHNL1_CRYPTO_AE_CLK BIT(7) +#define CDRU_GENPLL5_CONTROL1__CHNL2_RAID_AE_CLK BIT(8) + +#define CDRU_NITRO_CONTROL (CDRU_BASE_ADDR + 0x2c4) +#define CDRU_NITRO_CONTROL__CDRU_NITRO_SEC_MODE_R 20 +#define CDRU_NITRO_CONTROL__CDRU_NITRO_SEC_OVERRIDE_R 16 + +#define CDRU_MISC_CLK_ENABLE_CONTROL (CDRU_BASE_ADDR + 0x2c8) +#define CDRU_MISC_CLK_ENABLE_CONTROL__CDRU_EMEM2_CLK_EN_R 11 +#define CDRU_MISC_CLK_ENABLE_CONTROL__CDRU_EMEM1_CLK_EN_R 10 +#define CDRU_MISC_CLK_ENABLE_CONTROL__CDRU_EMEM0_CLK_EN_R 9 +#define CDRU_MISC_CLK_ENABLE_CONTROL__CDRU_SATA_CLK_EN_R 8 +#define CDRU_MISC_CLK_ENABLE_CONTROL__CDRU_USBSS_CLK_EN_R 7 +#define CDRU_MISC_CLK_ENABLE_CONTROL__CDRU_MHB_CLK_EN_R 6 +#define CDRU_MISC_CLK_ENABLE_CONTROL__CDRU_HSLS_CLK_EN_R 5 +#define CDRU_MISC_CLK_ENABLE_CONTROL__CDRU_SCR_CLK_EN_R 4 +#define CDRU_MISC_CLK_ENABLE_CONTROL__CDRU_FS4_CLK_EN_R 3 +#define CDRU_MISC_CLK_ENABLE_CONTROL__CDRU_PCIE_CLK_EN_R 2 +#define CDRU_MISC_CLK_ENABLE_CONTROL__CDRU_PM_CLK_EN_R 1 +#define CDRU_MISC_CLK_ENABLE_CONTROL__CDRU_NITRO_CLK_EN_R 0 + +#define CDRU_CCN_REGISTER_CONTROL_1 (CDRU_BASE_ADDR + 0x324) +#define CDRU_CCN_REGISTER_CONTROL_1__D2XS_PD_EMEM0_BIT 6 +#define CDRU_CCN_REGISTER_CONTROL_1__D2XS_PD_EMEM1_BIT 5 +#define CDRU_CCN_REGISTER_CONTROL_1__D2XS_PD_EMEM2_BIT 4 + +#define CDRU_CHIP_TOP_SPARE_REG0 (CDRU_BASE_ADDR + 0x378) +#define CDRU_CHIP_TOP_SPARE_REG1 (CDRU_BASE_ADDR + 0x37c) + +#define CENTRAL_TIMER_BASE (CRMU_CORE_BASE + 0x5000) +#define CENTRAL_TIMER_CTRL (CENTRAL_TIMER_BASE + 0x0) +#define CENTRAL_TIMER_GET_L (CENTRAL_TIMER_BASE + 0x4) +#define CENTRAL_TIMER_GET_L0 (CENTRAL_TIMER_BASE + 0x8) /* SCR STM */ +#define CENTRAL_TIMER_GET_L1 (CENTRAL_TIMER_BASE + 0xC) /* FS STM */ +#define CENTRAL_TIMER_GET_L2 (CENTRAL_TIMER_BASE + 0x10) /* iHost0 */ +#define CENTRAL_TIMER_GET_L3 (CENTRAL_TIMER_BASE + 0x14) /* iHost1 */ +#define CENTRAL_TIMER_GET_L4 (CENTRAL_TIMER_BASE + 0x18) /* iHost2 */ +#define CENTRAL_TIMER_GET_L5 (CENTRAL_TIMER_BASE + 0x1C) /* iHost3 */ +#define CENTRAL_TIMER_GET_H (CENTRAL_TIMER_BASE + 0x28) +#define CENTRAL_TIMER_SAT_TMR_ENA (CENTRAL_TIMER_BASE + 0x34) +#define CENTRAL_TIMER_GET_IHOST_ENA_BASE (CENTRAL_TIMER_GET_L2) + +#define CRMU_WDT_REGS_BASE (CRMU_CORE_BASE + 0x6000) + +#define CRMU_MAIL_BOX0 (CRMU_CORE_BASE + 0x8024) +#define CRMU_MAIL_BOX1 (CRMU_CORE_BASE + 0x8028) +#define CRMU_READ_MAIL_BOX0 (CRMU_CORE_BASE + 0x802c) +#define CRMU_READ_MAIL_BOX1 (CRMU_CORE_BASE + 0x8030) +#define AP_TO_SCP_MAILBOX1 CRMU_MAIL_BOX1 +#define SCP_TO_AP_MAILBOX1 CRMU_READ_MAIL_BOX1 +#define CRMU_IHOST_POWER_CONFIG (CRMU_CORE_BASE + 0x8038) +#define CRMU_RESET_EVENT_LOG (CRMU_CORE_BASE + 0x8064) +#define CRMU_SOFT_RESET_CTRL (CRMU_CORE_BASE + 0x8090) +#define CRMU_SOFT_RESET_CTRL__SOFT_PWR_UP_RST 0 +#define CRMU_SOFT_RESET_CTRL__SOFT_SYS_RST 1 +#define CRMU_SPARE_REG_0 (CRMU_CORE_BASE + 0x80b8) +#define CRMU_SPARE_REG_1 (CRMU_CORE_BASE + 0x80bc) +#define CRMU_SPARE_REG_2 (CRMU_CORE_BASE + 0x80c0) +#define CRMU_SPARE_REG_3 (CRMU_CORE_BASE + 0x80c4) +#define CRMU_SPARE_REG_4 (CRMU_CORE_BASE + 0x80c8) +#define CRMU_SPARE_REG_5 (CRMU_CORE_BASE + 0x80cc) +#define CRMU_CORE_ADDR_RANGE0_LOW (CRMU_CORE_BASE + 0x8c30) +#define CRMU_CORE_ADDR_RANGE1_LOW (CRMU_CORE_BASE + 0x8c38) +#define CRMU_CORE_ADDR_RANGE2_LOW (CRMU_CORE_BASE + 0x8c40) +#define CRMU_IHOST_SW_PERSISTENT_REG0 (CRMU_CORE_BASE + 0x8c54) +#define CRMU_IHOST_SW_PERSISTENT_REG1 (CRMU_CORE_BASE + 0x8c58) +#define CRMU_IHOST_SW_PERSISTENT_REG2 (CRMU_CORE_BASE + 0x8c5c) +#define CRMU_IHOST_SW_PERSISTENT_REG3 (CRMU_CORE_BASE + 0x8c60) +#define CRMU_IHOST_SW_PERSISTENT_REG4 (CRMU_CORE_BASE + 0x8c64) +#define CRMU_IHOST_SW_PERSISTENT_REG5 (CRMU_CORE_BASE + 0x8c68) +#define CRMU_IHOST_SW_PERSISTENT_REG6 (CRMU_CORE_BASE + 0x8c6c) +#define CRMU_IHOST_SW_PERSISTENT_REG7 (CRMU_CORE_BASE + 0x8c70) +#define CRMU_BBL_AUTH_CHECK (CRMU_CORE_BASE + 0x8c78) +#define CRMU_SOTP_NEUTRALIZE_ENABLE (CRMU_CORE_BASE + 0x8c84) +#define CRMU_IHOST_SW_PERSISTENT_REG8 (CRMU_CORE_BASE + 0x8c88) +#define CRMU_IHOST_SW_PERSISTENT_REG9 (CRMU_CORE_BASE + 0x8c8c) +#define CRMU_IHOST_SW_PERSISTENT_REG10 (CRMU_CORE_BASE + 0x8c90) +#define CRMU_IHOST_SW_PERSISTENT_REG11 (CRMU_CORE_BASE + 0x8c94) + +#define CNT_CONTROL_BASE (CRMU_CORE_BASE + 0x9000) +#define CNTCR (CNT_CONTROL_BASE) +#define CNTCR__EN BIT(0) + +#define SPRU_BBL_WDATA (CRMU_CORE_BASE + 0xa000) +#define SPRU_BBL_CMD (CRMU_CORE_BASE + 0xa004) +#define SPRU_BBL_CMD__IND_SOFT_RST_N 10 +#define SPRU_BBL_CMD__IND_WR 11 +#define SPRU_BBL_CMD__BBL_ADDR_R 0 +#define SPRU_BBL_CMD__IND_RD 12 +#define SPRU_BBL_CMD__BBL_ADDR_R 0 +#define SPRU_BBL_STATUS (CRMU_CORE_BASE + 0xa008) +#define SPRU_BBL_STATUS__ACC_DONE 0 +#define SPRU_BBL_RDATA (CRMU_CORE_BASE + 0xa00c) + +#endif /* CRMU_DEF_H */ diff --git a/plat/brcm/board/stingray/include/ddr_init.h b/plat/brcm/board/stingray/include/ddr_init.h new file mode 100644 index 0000000..0c135b1 --- /dev/null +++ b/plat/brcm/board/stingray/include/ddr_init.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2016 - 2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef DDR_INIT_H +#define DDR_INIT_H + +#include <fru.h> + +#pragma weak ddr_initialize +#pragma weak ddr_secure_region_config +#pragma weak ddr_info_save +#pragma weak get_active_ddr_channel +#pragma weak is_warmboot + +void ddr_initialize(struct ddr_info *ddr) +{ +} + +void ddr_secure_region_config(uint64_t start, uint64_t end) +{ +} + +void ddr_info_save(void) +{ +} + +unsigned char get_active_ddr_channel(void) +{ + return 0; +} + +static inline unsigned int is_warmboot(void) +{ + return 0; +} +#endif diff --git a/plat/brcm/board/stingray/include/fsx.h b/plat/brcm/board/stingray/include/fsx.h new file mode 100644 index 0000000..c52ff0a --- /dev/null +++ b/plat/brcm/board/stingray/include/fsx.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2017 - 2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef FSX_H +#define FSX_H + +#include <stdbool.h> + +typedef enum FSX_TYPE { + eFS4_RAID, + eFS4_CRYPTO, + eFS6_PKI, +} eFSX_TYPE; + +void fsx_init(eFSX_TYPE fsx_type, + unsigned int ring_count, + unsigned int dme_count, + unsigned int ae_count, + unsigned int start_stream_id, + unsigned int msi_dev_id, + uintptr_t idm_io_control_direct, + uintptr_t idm_reset_control, + uintptr_t base, + uintptr_t dme_base); + +void fsx_meminit(const char *name, + uintptr_t idm_io_control_direct, + uintptr_t idm_io_status); + +void fs4_disable_clocks(bool disable_sram, + bool disable_crypto, + bool disable_raid); + +#endif /* FSX_H */ diff --git a/plat/brcm/board/stingray/include/ihost_pm.h b/plat/brcm/board/stingray/include/ihost_pm.h new file mode 100644 index 0000000..83493ab --- /dev/null +++ b/plat/brcm/board/stingray/include/ihost_pm.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2016 - 2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef IHOST_PM +#define IHOST_PM + +#include <stdint.h> + +#define CLUSTER_POWER_ON 0x1 +#define CLUSTER_POWER_OFF 0x0 + +void ihost_power_on_cluster(u_register_t mpidr); +void ihost_power_on_secondary_core(u_register_t mpidr, uint64_t rvbar); +void ihost_enable_satellite_timer(unsigned int cluster_id); + +#endif diff --git a/plat/brcm/board/stingray/include/iommu.h b/plat/brcm/board/stingray/include/iommu.h new file mode 100644 index 0000000..e7b2985 --- /dev/null +++ b/plat/brcm/board/stingray/include/iommu.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2016 - 2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef IOMMU_H +#define IOMMU_H + +enum iommu_domain { + PCIE_PAXC, + DOMAIN_CRMU, +}; + +void arm_smmu_create_identity_map(enum iommu_domain dom); +void arm_smmu_reserve_secure_cntxt(void); +void arm_smmu_enable_secure_client_port(void); + +#endif /* IOMMU_H */ diff --git a/plat/brcm/board/stingray/include/ncsi.h b/plat/brcm/board/stingray/include/ncsi.h new file mode 100644 index 0000000..04dd640 --- /dev/null +++ b/plat/brcm/board/stingray/include/ncsi.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2019-2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef NCSI_H +#define NCSI_H + +/* + * There are 10 registers for NCSI IO drivers. + */ +#define NITRO_NCSI_IOPAD_CONTROL_NUM 10 +#define NITRO_NCSI_IOPAD_CONTROL_BASE 0x60e05080 + +/* + * NCSI IO Drive strength + * 000 - Drives 2mA + * 001 - Drives 4mA + * 010 - Drives 6mA + * 011 - Drives 8mA + * 100 - Drives 10mA + * 101 - Drives 12mA + * 110 - Drives 14mA + * 111 - Drives 16mA + */ +#define PAD_SELX_VALUE(selx) ((selx) << 1) +#define PAD_SELX_MASK (0x7 << 1) + +void brcm_stingray_ncsi_init(void); + +#endif diff --git a/plat/brcm/board/stingray/include/paxb.h b/plat/brcm/board/stingray/include/paxb.h new file mode 100644 index 0000000..c64c8a6 --- /dev/null +++ b/plat/brcm/board/stingray/include/paxb.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2016 - 2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PAXB_H +#define PAXB_H + +/* total number of PCIe cores */ +#define NUM_OF_SR_PCIE_CORES 8 +#define NUM_OF_NS3Z_PCIE_CORES 1 + +/* + * List of PCIe core and PAXB wrapper memory power registers + */ +#define PCIE_CORE_BASE 0x40000800 +#define PCIE_CORE_SOFT_RST_CFG_BASE (PCIE_CORE_BASE + 0x40) +#define PCIE_CORE_SOFT_RST 0x1 +#define PCIE_CORE_ISO_CFG_BASE (PCIE_CORE_BASE + 0x54) +#define PCIE_CORE_MEM_ISO 0x2 +#define PCIE_CORE_ISO 0x1 + +#define PCIE_CORE_MEM_PWR_BASE (PCIE_CORE_BASE + 0x58) +#define PCIE_PAXB_MEM_PWR_BASE (PCIE_CORE_BASE + 0x5c) +#define PCIE_CORE_PMI_CFG_BASE (PCIE_CORE_BASE + 0x64) +#define PCIE_CORE_RESERVED_CFG (PCIE_CORE_BASE + 0x6c) +#define PCIE_CORE_MEM_PWR_STATUS_BASE (PCIE_CORE_BASE + 0x74) +#define PCIE_PAXB_MEM_PWR_STATUS_BASE (PCIE_CORE_BASE + 0x78) +#define PCIE_CORE_PWR_OFFSET 0x100 + +#define SR_A0_DEVICE_ID 0xd713 +#define SR_B0_DEVICE_ID 0xd714 +/* TODO: Modify device ID once available */ +#define NS3Z_DEVICE_ID 0xd715 + +/* FIXME: change link speed to GEN3 when it's ready */ +#define GEN1_LINK_SPEED 1 +#define GEN2_LINK_SPEED 2 +#define GEN3_LINK_SPEED 3 + +typedef struct { + uint32_t type; + uint32_t device_id; + uint32_t pipemux_idx; + uint32_t num_cores; + int (*pipemux_init)(void); + int (*phy_init)(void); + int (*core_needs_enable)(unsigned int core_idx); + unsigned int (*get_link_width)(unsigned int core_idx); + unsigned int (*get_link_speed)(void); +} paxb_cfg; + +enum paxb_type { + PAXB_SR, + PAXB_NS3Z, +}; + +extern const paxb_cfg *paxb; + +#ifdef USE_PAXB +void paxb_init(void); +void paxb_rc_cfg_write(unsigned int core_idx, unsigned int where, + uint32_t val); +unsigned int paxb_rc_cfg_read(unsigned int core_idx, unsigned int where); +int pcie_core_needs_enable(unsigned int core_idx); +const paxb_cfg *paxb_get_sr_config(void); +#else +static inline void paxb_init(void) +{ +} +#endif + +#endif /* PAXB_H */ diff --git a/plat/brcm/board/stingray/include/paxc.h b/plat/brcm/board/stingray/include/paxc.h new file mode 100644 index 0000000..ae1af2e --- /dev/null +++ b/plat/brcm/board/stingray/include/paxc.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2017 - 2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PAXC_H +#define PAXC_H + +#ifdef USE_PAXC +void paxc_init(void); +void paxc_mhb_ns_init(void); +#else +static inline void paxc_init(void) +{ +} + +static inline void paxc_mhb_ns_init(void) +{ +} +#endif + +#endif /* PAXC_H */ diff --git a/plat/brcm/board/stingray/include/plat_macros.S b/plat/brcm/board/stingray/include/plat_macros.S new file mode 100644 index 0000000..dccd54a --- /dev/null +++ b/plat/brcm/board/stingray/include/plat_macros.S @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2015-2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PLAT_MACROS_S +#define PLAT_MACROS_S + +.section .rodata.gic_reg_name, "aS" +gicc_regs: + .asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", "" +gicd_pend_reg: + .asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n Offset:\t\t\tvalue\n" +newline: + .asciz "\n" +spacer: + .asciz ":\t\t0x" + +/* --------------------------------------------- + * The below required platform porting macro + * prints out relevant registers whenever an + * unhandled exception is taken in BL31. + * --------------------------------------------- + */ +.macro plat_crash_print_regs + nop +.endm + +/* --------------------------------------------- + * The below macro prints out relevant GIC + * registers whenever an unhandled exception is + * taken in BL31. + * --------------------------------------------- + */ +.macro plat_print_gic_regs + nop + /*TBD-STINGRAY*/ +.endm + +/* ------------------------------------------------ + * The below required platform porting macro prints + * out relevant interconnect registers whenever an + * unhandled exception is taken in BL3-1. + * ------------------------------------------------ + */ +.macro plat_print_interconnect_regs + nop + /*TBD-STINGRAY*/ +.endm + +#endif /* PLAT_MACROS_S */ diff --git a/plat/brcm/board/stingray/include/platform_def.h b/plat/brcm/board/stingray/include/platform_def.h new file mode 100644 index 0000000..4742124 --- /dev/null +++ b/plat/brcm/board/stingray/include/platform_def.h @@ -0,0 +1,268 @@ +/* + * Copyright (c) 2015-2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PLATFORM_DEF_H +#define PLATFORM_DEF_H + +#include <arch.h> +#include <common/tbbr/tbbr_img_def.h> +#include <plat/common/common_def.h> + +#include <brcm_def.h> +#include "sr_def.h" +#include <cmn_plat_def.h> + +/* + * Most platform porting definitions provided by included headers + */ +#define PLAT_BRCM_SCP_TZC_DRAM1_SIZE ULL(0x0) + +/* + * Required by standard platform porting definitions + */ +#define PLATFORM_CLUSTER0_CORE_COUNT 2 +#define PLATFORM_CLUSTER1_CORE_COUNT 2 +#define PLATFORM_CLUSTER2_CORE_COUNT 2 +#define PLATFORM_CLUSTER3_CORE_COUNT 2 + +#define BRCM_SYSTEM_COUNT 1 +#define BRCM_CLUSTER_COUNT 4 + +#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER0_CORE_COUNT + \ + PLATFORM_CLUSTER1_CORE_COUNT+ \ + PLATFORM_CLUSTER2_CORE_COUNT+ \ + PLATFORM_CLUSTER3_CORE_COUNT) + +#define PLAT_NUM_PWR_DOMAINS (BRCM_SYSTEM_COUNT + \ + BRCM_CLUSTER_COUNT + \ + PLATFORM_CORE_COUNT) + +#define PLAT_MAX_PWR_LVL MPIDR_AFFLVL2 + +/* TBD-STINGRAY */ +#define CACHE_WRITEBACK_SHIFT 6 +/* + * Some data must be aligned on the biggest cache line size in the platform. + * This is known only to the platform as it might have a combination of + * integrated and external caches. + */ +#define CACHE_WRITEBACK_GRANULE (1 << CACHE_WRITEBACK_SHIFT) + +/* TBD-STINGRAY */ +#define PLATFORM_MAX_AFFLVL MPIDR_AFFLVL1 + +#define BL1_PLATFORM_STACK_SIZE 0x3300 +#define BL2_PLATFORM_STACK_SIZE 0xc000 +#define BL11_PLATFORM_STACK_SIZE 0x2b00 +#define DEFAULT_PLATFORM_STACK_SIZE 0x400 +#if IMAGE_BL1 +# define PLATFORM_STACK_SIZE BL1_PLATFORM_STACK_SIZE +#else +#if IMAGE_BL2 +#ifdef USE_BL1_RW +# define PLATFORM_STACK_SIZE BL2_PLATFORM_STACK_SIZE +#else +# define PLATFORM_STACK_SIZE BL1_PLATFORM_STACK_SIZE +#endif +#else +#if IMAGE_BL11 +# define PLATFORM_STACK_SIZE BL11_PLATFORM_STACK_SIZE +#else +# define PLATFORM_STACK_SIZE DEFAULT_PLATFORM_STACK_SIZE +#endif +#endif +#endif + +#define PLAT_BRCM_TRUSTED_SRAM_BASE 0x66D00000 +#define PLAT_BRCM_TRUSTED_SRAM_SIZE 0x00040000 + +#ifdef RUN_BL1_FROM_QSPI /* BL1 XIP from QSPI */ +# define PLAT_BRCM_TRUSTED_ROM_BASE QSPI_BASE_ADDR +#elif RUN_BL1_FROM_NAND /* BL1 XIP from NAND */ +# define PLAT_BRCM_TRUSTED_ROM_BASE NAND_BASE_ADDR +#else /* BL1 executed in ROM */ +# define PLAT_BRCM_TRUSTED_ROM_BASE ROM_BASE_ADDR +#endif +#define PLAT_BRCM_TRUSTED_ROM_SIZE 0x00040000 + +/******************************************************************************* + * BL1 specific defines. + ******************************************************************************/ +#define BL1_RO_BASE PLAT_BRCM_TRUSTED_ROM_BASE +#define BL1_RO_LIMIT (PLAT_BRCM_TRUSTED_ROM_BASE \ + + PLAT_BRCM_TRUSTED_ROM_SIZE) + +/* + * Put BL1 RW at the beginning of the Trusted SRAM. + */ +#define BL1_RW_BASE (BRCM_BL_RAM_BASE) +#define BL1_RW_LIMIT (BL1_RW_BASE + 0x12000) + +#define BL11_RW_BASE BL1_RW_LIMIT +#define BL11_RW_LIMIT (PLAT_BRCM_TRUSTED_SRAM_BASE + \ + PLAT_BRCM_TRUSTED_SRAM_SIZE) + +/******************************************************************************* + * BL2 specific defines. + ******************************************************************************/ +#if RUN_BL2_FROM_QSPI /* BL2 XIP from QSPI */ +#define BL2_BASE QSPI_BASE_ADDR +#define BL2_LIMIT (BL2_BASE + 0x40000) +#define BL2_RW_BASE BL1_RW_LIMIT +#define BL2_RW_LIMIT (PLAT_BRCM_TRUSTED_SRAM_BASE + \ + PLAT_BRCM_TRUSTED_SRAM_SIZE) +#elif RUN_BL2_FROM_NAND /* BL2 XIP from NAND */ +#define BL2_BASE NAND_BASE_ADDR +#define BL2_LIMIT (BL2_BASE + 0x40000) +#define BL2_RW_BASE BL1_RW_LIMIT +#define BL2_RW_LIMIT (PLAT_BRCM_TRUSTED_SRAM_BASE + \ + PLAT_BRCM_TRUSTED_SRAM_SIZE) +#else +#define BL2_BASE (BL1_RW_LIMIT + PAGE_SIZE) +#define BL2_LIMIT (BRCM_BL_RAM_BASE + BRCM_BL_RAM_SIZE) +#endif + +/* + * BL1 persistent area in internal SRAM + * This area will increase as more features gets into BL1 + */ +#define BL1_PERSISTENT_DATA_SIZE 0x2000 + +/* To reduce BL2 runtime footprint, we can re-use some BL1_RW area */ +#define BL1_RW_RECLAIM_BASE (PLAT_BRCM_TRUSTED_SRAM_BASE + \ + BL1_PERSISTENT_DATA_SIZE) + +/******************************************************************************* + * BL3-1 specific defines. + ******************************************************************************/ +/* Max Size of BL31 (in DRAM) */ +#define PLAT_BRCM_MAX_BL31_SIZE 0x30000 + +#ifdef USE_DDR +#define BL31_BASE BRCM_AP_TZC_DRAM1_BASE + +#define BL31_LIMIT (BRCM_AP_TZC_DRAM1_BASE + \ + PLAT_BRCM_MAX_BL31_SIZE) +#else +/* Put BL3-1 at the end of external on-board SRAM connected as NOR flash */ +#define BL31_BASE (NOR_BASE_ADDR + NOR_SIZE - \ + PLAT_BRCM_MAX_BL31_SIZE) + +#define BL31_LIMIT (NOR_BASE_ADDR + NOR_SIZE) +#endif + +#define SECURE_DDR_END_ADDRESS BL31_LIMIT + +#ifdef NEED_SCP_BL2 +#define SCP_BL2_BASE BL31_BASE +#define PLAT_MAX_SCP_BL2_SIZE 0x9000 +#define PLAT_SCP_COM_SHARED_MEM_BASE (CRMU_SHARED_SRAM_BASE) +/* dummy defined */ +#define PLAT_BRCM_MHU_BASE 0x0 +#endif + +#define SECONDARY_CPU_SPIN_BASE_ADDR BRCM_SHARED_RAM_BASE + +/* Generic system timer counter frequency */ +#ifndef SYSCNT_FREQ +#define SYSCNT_FREQ (125 * 1000 * 1000) +#endif + +/* + * Enable the BL32 definitions, only when optee os is selected as secure + * payload (BL32). + */ +#ifdef SPD_opteed +/* + * Reserved Memory Map : SHMEM & TZDRAM. + * + * +--------+----------+ 0x8D000000 + * | SHMEM (NS) | 16MB + * +-------------------+ 0x8E000000 + * | | TEE_RAM(S)| 4MB + * + TZDRAM +----------+ 0x8E400000 + * | | TA_RAM(S) | 12MB + * +-------------------+ 0x8F000000 + * | BL31 Binary (S) | 192KB + * +-------------------+ 0x8F030000 + */ + +#define BL32_VA_SIZE (4 * 1024 * 1024) +#define BL32_BASE (0x8E000000) +#define BL32_LIMIT (BL32_BASE + BL32_VA_SIZE) +#define TSP_SEC_MEM_BASE BL32_BASE +#define TSP_SEC_MEM_SIZE BL32_VA_SIZE +#endif + +#ifdef SPD_opteed + #define SECURE_DDR_BASE_ADDRESS BL32_BASE +#else + #define SECURE_DDR_BASE_ADDRESS BL31_BASE +#endif +/******************************************************************************* + * Platform specific page table and MMU setup constants + ******************************************************************************/ + +#define MAX_XLAT_TABLES 7 + +#define PLAT_BRCM_MMAP_ENTRIES 10 + +#define MAX_MMAP_REGIONS (PLAT_BRCM_MMAP_ENTRIES + \ + BRCM_BL_REGIONS) + +#ifdef USE_DDR +#ifdef BL33_OVERRIDE_LOAD_ADDR +#define PLAT_BRCM_NS_IMAGE_OFFSET BL33_OVERRIDE_LOAD_ADDR +#else +/* + * BL3-3 image starting offset. + * Putting start of DRAM as of now. + */ +#define PLAT_BRCM_NS_IMAGE_OFFSET 0x80000000 +#endif /* BL33_OVERRIDE_LOAD_ADDR */ +#else +/* + * BL3-3 image starting offset. + * Putting start of external on-board SRAM as of now. + */ +#define PLAT_BRCM_NS_IMAGE_OFFSET NOR_BASE_ADDR +#endif /* USE_DDR */ +/****************************************************************************** + * Required platform porting definitions common to all BRCM platforms + *****************************************************************************/ + +#define MAX_IO_DEVICES 5 +#define MAX_IO_HANDLES 6 + +#define PRIMARY_CPU 0 + +/* GIC Parameter */ +#define PLAT_BRCM_GICD_BASE GIC500_BASE +#define PLAT_BRCM_GICR_BASE (GIC500_BASE + 0x200000) + +/* Define secure interrupt as per Group here */ +#define PLAT_BRCM_G1S_IRQ_PROPS(grp) \ + INTR_PROP_DESC(BRCM_IRQ_SEC_SGI_1, GIC_HIGHEST_SEC_PRIORITY, (grp), \ + GIC_INTR_CFG_EDGE), \ + INTR_PROP_DESC(BRCM_IRQ_SEC_SPI_0, GIC_HIGHEST_SEC_PRIORITY, (grp), \ + GIC_INTR_CFG_EDGE) + +#define PLAT_BRCM_G0_IRQ_PROPS(grp) \ + INTR_PROP_DESC(BRCM_IRQ_SEC_SGI_0, PLAT_SDEI_NORMAL_PRI, (grp), \ + GIC_INTR_CFG_EDGE), \ + +/* + *CCN 502 related constants. + */ +#define PLAT_BRCM_CLUSTER_COUNT 4 /* Number of RN-F Masters */ +#define PLAT_BRCM_CLUSTER_TO_CCN_ID_MAP CLUSTER0_NODE_ID, CLUSTER1_NODE_ID, CLUSTER2_NODE_ID, CLUSTER3_NODE_ID +#define CCN_SIZE 0x1000000 +#define CLUSTER0_NODE_ID 1 +#define CLUSTER1_NODE_ID 7 +#define CLUSTER2_NODE_ID 9 +#define CLUSTER3_NODE_ID 15 + +#endif diff --git a/plat/brcm/board/stingray/include/platform_sotp.h b/plat/brcm/board/stingray/include/platform_sotp.h new file mode 100644 index 0000000..0389f38 --- /dev/null +++ b/plat/brcm/board/stingray/include/platform_sotp.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2016-2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PLATFORM_SOTP_H +#define PLATFORM_SOTP_H + +#define SOTP_DEVICE_SECURE_CFG0_ROW 17 +#define SOTP_DEVICE_SECURE_CFG1_ROW 18 +#define SOTP_DEVICE_SECURE_CFG2_ROW 19 +#define SOTP_DEVICE_SECURE_CFG3_ROW 20 +#define SOTP_BRCM_SOFTWARE_CFG0_ROW 21 +#define SOTP_BRCM_SOFTWARE_CFG1_ROW 22 +#define SOTP_BRCM_SOFTWARE_CFG2_ROW 23 +#define SOTP_BRCM_SOFTWARE_CFG3_ROW 24 +#define SOTP_CUSTOMER_ID_CFG0_ROW 25 +#define SOTP_CUSTOMER_ID_CFG1_ROW 26 +#define SOTP_CUSTOMER_ID_CFG2_ROW 27 +#define SOTP_CUSTOMER_ID_CFG3_ROW 28 +#define SOTP_CUSTOMER_DEV_CFG0_ROW 29 +#define SOTP_CUSTOMER_DEV_CFG1_ROW 30 +#define SOTP_CUSTOMER_DEV_CFG2_ROW 31 +#define SOTP_CUSTOMER_DEV_CFG3_ROW 32 +#define SOTP_DAUTH_ROW 33 +#define SOTP_K_HMAC_ROW 45 +#define SOTP_K_AES_ROW 57 +#define SOTP_NVCOUNTER_ROW 69 + +#define SOTP_BRCM_CFG_ECC_ERROR_MASK 0x100000 +#define SOTP_DAUTH_ECC_ERROR_MASK 0x800000 +#define SOTP_K_HMAC_ECC_ERROR_MASK 0x1000000 +#define SOTP_K_AES_ECC_ERROR_MASK 0x2000000 + +#endif diff --git a/plat/brcm/board/stingray/include/platform_usb.h b/plat/brcm/board/stingray/include/platform_usb.h new file mode 100644 index 0000000..5b5309f --- /dev/null +++ b/plat/brcm/board/stingray/include/platform_usb.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2019 - 2021, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef PLATFORM_USB_H +#define PLATFORM_USB_H + +#include <platform_def.h> + +#define USB3_DRD BIT(0U) +#define USB3H_USB2DRD BIT(1U) + +extern const unsigned int xhc_portsc_reg_offset[MAX_USB_PORTS]; + +void xhci_phy_init(void); + +#endif /* PLATFORM_USB_H */ diff --git a/plat/brcm/board/stingray/include/scp_cmd.h b/plat/brcm/board/stingray/include/scp_cmd.h new file mode 100644 index 0000000..806ef56 --- /dev/null +++ b/plat/brcm/board/stingray/include/scp_cmd.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2017-2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef SCP_CMD_H +#define SCP_SMD_H + +#include <stdint.h> + +typedef struct { + int cmd; + int completed; + int ret; +} crmu_response_t; + + +#define SCP_CMD_MASK 0xffff +#define SCP_CMD_DEFAULT_TIMEOUT_US 1000 +#define SCP_CMD_SCP_BOOT_TIMEOUT_US 5000 + +int scp_send_cmd(uint32_t cmd, uint32_t param, uint32_t timeout); + +#endif diff --git a/plat/brcm/board/stingray/include/scp_utils.h b/plat/brcm/board/stingray/include/scp_utils.h new file mode 100644 index 0000000..c39b18c --- /dev/null +++ b/plat/brcm/board/stingray/include/scp_utils.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2019-2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef SCP_UTILS_H +#define SCP_UTILS_H + +#include <common/bl_common.h> +#include <lib/mmio.h> + +#include <m0_cfg.h> + +int plat_bcm_bl2_plat_handle_scp_bl2(image_info_t *scp_bl2_image_info); + +bool is_crmu_alive(void); +bool bcm_scp_issue_sys_reset(void); + +#define SCP_READ_CFG(cfg) mmio_read_32(CRMU_CFG_BASE + \ + offsetof(M0CFG, cfg)) +#define SCP_WRITE_CFG(cfg, value) mmio_write_32(CRMU_CFG_BASE + \ + offsetof(M0CFG, cfg), value) + +#define SCP_READ_CFG16(cfg) mmio_read_16(CRMU_CFG_BASE + \ + offsetof(M0CFG, cfg)) +#define SCP_WRITE_CFG16(cfg, value) mmio_write_16(CRMU_CFG_BASE + \ + offsetof(M0CFG, cfg), value) + +#define SCP_READ_CFG8(cfg) mmio_read_8(CRMU_CFG_BASE + \ + offsetof(M0CFG, cfg)) +#define SCP_WRITE_CFG8(cfg, value) mmio_write_8(CRMU_CFG_BASE + \ + offsetof(M0CFG, cfg), value) +#endif diff --git a/plat/brcm/board/stingray/include/sdio.h b/plat/brcm/board/stingray/include/sdio.h new file mode 100644 index 0000000..e08904e --- /dev/null +++ b/plat/brcm/board/stingray/include/sdio.h @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2019-2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef SDIO_H +#define SDIO_H + +#include <stdbool.h> + +#define SR_IPROC_SDIO0_CFG_BASE 0x689006e4 +#define SR_IPROC_SDIO0_SID_BASE 0x68900b00 +#define SR_IPROC_SDIO0_PAD_BASE 0x68a4017c +#define SR_IPROC_SDIO0_IOCTRL_BASE 0x68e02408 + +#define SR_IPROC_SDIO1_CFG_BASE 0x68900734 +#define SR_IPROC_SDIO1_SID_BASE 0x68900b08 +#define SR_IPROC_SDIO1_PAD_BASE 0x68a401b4 +#define SR_IPROC_SDIO1_IOCTRL_BASE 0x68e03408 + +#define NS3Z_IPROC_SDIO0_CFG_BASE 0x68a20540 +#define NS3Z_IPROC_SDIO0_SID_BASE 0x68900b00 +#define NS3Z_IPROC_SDIO0_TP_OUT_SEL 0x68a20308 +#define NS3Z_IPROC_SDIO0_PAD_BASE 0x68a20500 +#define NS3Z_IPROC_SDIO0_IOCTRL_BASE 0x68e02408 + +#define PHY_BYPASS BIT(14) +#define LEGACY_EN BIT(31) +#define PHY_DISABLE (LEGACY_EN | PHY_BYPASS) + +#define NS3Z_IPROC_SDIO1_CFG_BASE 0x68a30540 +#define NS3Z_IPROC_SDIO1_SID_BASE 0x68900b08 +#define NS3Z_IPROC_SDIO1_PAD_BASE 0x68a30500 +#define NS3Z_IPROC_SDIO1_IOCTRL_BASE 0x68e03408 + +#define ICFG_SDIO_CAP0 0x10 +#define ICFG_SDIO_CAP1 0x14 +#define ICFG_SDIO_STRAPSTATUS_0 0x0 +#define ICFG_SDIO_STRAPSTATUS_1 0x4 +#define ICFG_SDIO_STRAPSTATUS_2 0x8 +#define ICFG_SDIO_STRAPSTATUS_3 0xc +#define ICFG_SDIO_STRAPSTATUS_4 0x18 + +#define ICFG_SDIO_SID_ARADDR 0x0 +#define ICFG_SDIO_SID_AWADDR 0x4 + +#define ICFG_SDIOx_CAP0__SLOT_TYPE_MASK 0x3 +#define ICFG_SDIOx_CAP0__SLOT_TYPE_SHIFT 27 +#define ICFG_SDIOx_CAP0__INT_MODE_SHIFT 26 +#define ICFG_SDIOx_CAP0__SYS_BUS_64BIT_SHIFT 25 +#define ICFG_SDIOx_CAP0__VOLTAGE_1P8V_SHIFT 24 +#define ICFG_SDIOx_CAP0__VOLTAGE_3P0V_SHIFT 23 +#define ICFG_SDIOx_CAP0__VOLTAGE_3P3V_SHIFT 22 +#define ICFG_SDIOx_CAP0__SUSPEND_RESUME_SHIFT 21 +#define ICFG_SDIOx_CAP0__SDMA_SHIFT 20 +#define ICFG_SDIOx_CAP0__HIGH_SPEED_SHIFT 19 +#define ICFG_SDIOx_CAP0__ADMA2_SHIFT 18 +#define ICFG_SDIOx_CAP0__EXTENDED_MEDIA_SHIFT 17 +#define ICFG_SDIOx_CAP0__MAX_BLOCK_LEN_MASK 0x3 +#define ICFG_SDIOx_CAP0__MAX_BLOCK_LEN_SHIFT 15 +#define ICFG_SDIOx_CAP0__BASE_CLK_FREQ_MASK 0xff +#define ICFG_SDIOx_CAP0__BASE_CLK_FREQ_SHIFT 7 +#define ICFG_SDIOx_CAP0__TIMEOUT_UNIT_SHIFT 6 +#define ICFG_SDIOx_CAP0__TIMEOUT_CLK_FREQ_MASK 0x3f +#define ICFG_SDIOx_CAP0__TIMEOUT_CLK_FREQ_SHIFT 0 + +#define ICFG_SDIOx_CAP1__SPI_BLOCK_MODE_SHIFT 22 +#define ICFG_SDIOx_CAP1__SPI_MODE_SHIFT 21 +#define ICFG_SDIOx_CAP1__CLK_MULT_MASK 0xff +#define ICFG_SDIOx_CAP1__CLK_MULT_SHIFT 13 +#define ICFG_SDIOx_CAP1__RETUNING_MODE_MASK 0x3 +#define ICFG_SDIOx_CAP1__RETUNING_MODE_SHIFT 11 +#define ICFG_SDIOx_CAP1__TUNE_SDR50_SHIFT 10 +#define ICFG_SDIOx_CAP1__TIME_RETUNE_MASK 0xf +#define ICFG_SDIOx_CAP1__TIME_RETUNE_SHIFT 6 +#define ICFG_SDIOx_CAP1__DRIVER_D_SHIFT 5 +#define ICFG_SDIOx_CAP1__DRIVER_C_SHIFT 4 +#define ICFG_SDIOx_CAP1__DRIVER_A_SHIFT 3 +#define ICFG_SDIOx_CAP1__DDR50_SHIFT 2 +#define ICFG_SDIOx_CAP1__SDR104_SHIFT 1 +#define ICFG_SDIOx_CAP1__SDR50_SHIFT 0 + +#ifdef USE_DDR +#define SDIO_DMA 1 +#else +#define SDIO_DMA 0 +#endif + +#define SDIO0_CAP0_CFG \ + (0x1 << ICFG_SDIOx_CAP0__SLOT_TYPE_SHIFT) \ + | (0x0 << ICFG_SDIOx_CAP0__INT_MODE_SHIFT) \ + | (0x0 << ICFG_SDIOx_CAP0__SYS_BUS_64BIT_SHIFT) \ + | (0x1 << ICFG_SDIOx_CAP0__VOLTAGE_1P8V_SHIFT) \ + | (0x1 << ICFG_SDIOx_CAP0__VOLTAGE_3P0V_SHIFT) \ + | (0x1 << ICFG_SDIOx_CAP0__VOLTAGE_3P3V_SHIFT) \ + | (0x1 << ICFG_SDIOx_CAP0__SUSPEND_RESUME_SHIFT) \ + | (SDIO_DMA << ICFG_SDIOx_CAP0__SDMA_SHIFT) \ + | (SDIO_DMA << ICFG_SDIOx_CAP0__ADMA2_SHIFT) \ + | (0x1 << ICFG_SDIOx_CAP0__HIGH_SPEED_SHIFT) \ + | (0x1 << ICFG_SDIOx_CAP0__EXTENDED_MEDIA_SHIFT) \ + | (0x2 << ICFG_SDIOx_CAP0__MAX_BLOCK_LEN_SHIFT) \ + | (0xc8 << ICFG_SDIOx_CAP0__BASE_CLK_FREQ_SHIFT) \ + | (0x1 << ICFG_SDIOx_CAP0__TIMEOUT_UNIT_SHIFT) \ + | (0x30 << ICFG_SDIOx_CAP0__TIMEOUT_CLK_FREQ_SHIFT) + +#define SDIO0_CAP1_CFG \ + (0x1 << ICFG_SDIOx_CAP1__SPI_BLOCK_MODE_SHIFT)\ + | (0x1 << ICFG_SDIOx_CAP1__SPI_MODE_SHIFT)\ + | (0x0 << ICFG_SDIOx_CAP1__CLK_MULT_SHIFT)\ + | (0x2 << ICFG_SDIOx_CAP1__RETUNING_MODE_SHIFT)\ + | (0x1 << ICFG_SDIOx_CAP1__TUNE_SDR50_SHIFT)\ + | (0x0 << ICFG_SDIOx_CAP1__DRIVER_D_SHIFT)\ + | (0x0 << ICFG_SDIOx_CAP1__DRIVER_C_SHIFT)\ + | (0x1 << ICFG_SDIOx_CAP1__DRIVER_A_SHIFT)\ + | (0x1 << ICFG_SDIOx_CAP1__DDR50_SHIFT)\ + | (0x1 << ICFG_SDIOx_CAP1__SDR104_SHIFT)\ + | (0x1 << ICFG_SDIOx_CAP1__SDR50_SHIFT) + +#define SDIO1_CAP0_CFG \ + (0x0 << ICFG_SDIOx_CAP0__SLOT_TYPE_SHIFT) \ + | (0x0 << ICFG_SDIOx_CAP0__INT_MODE_SHIFT) \ + | (0x0 << ICFG_SDIOx_CAP0__SYS_BUS_64BIT_SHIFT) \ + | (0x1 << ICFG_SDIOx_CAP0__VOLTAGE_1P8V_SHIFT) \ + | (0x1 << ICFG_SDIOx_CAP0__VOLTAGE_3P0V_SHIFT) \ + | (0x1 << ICFG_SDIOx_CAP0__VOLTAGE_3P3V_SHIFT) \ + | (0x1 << ICFG_SDIOx_CAP0__SUSPEND_RESUME_SHIFT) \ + | (SDIO_DMA << ICFG_SDIOx_CAP0__SDMA_SHIFT) \ + | (SDIO_DMA << ICFG_SDIOx_CAP0__ADMA2_SHIFT) \ + | (0x1 << ICFG_SDIOx_CAP0__HIGH_SPEED_SHIFT) \ + | (0x1 << ICFG_SDIOx_CAP0__EXTENDED_MEDIA_SHIFT) \ + | (0x2 << ICFG_SDIOx_CAP0__MAX_BLOCK_LEN_SHIFT) \ + | (0xc8 << ICFG_SDIOx_CAP0__BASE_CLK_FREQ_SHIFT) \ + | (0x1 << ICFG_SDIOx_CAP0__TIMEOUT_UNIT_SHIFT) \ + | (0x30 << ICFG_SDIOx_CAP0__TIMEOUT_CLK_FREQ_SHIFT) + +#define SDIO1_CAP1_CFG \ + (0x1 << ICFG_SDIOx_CAP1__SPI_BLOCK_MODE_SHIFT)\ + | (0x1 << ICFG_SDIOx_CAP1__SPI_MODE_SHIFT)\ + | (0x0 << ICFG_SDIOx_CAP1__CLK_MULT_SHIFT)\ + | (0x2 << ICFG_SDIOx_CAP1__RETUNING_MODE_SHIFT)\ + | (0x1 << ICFG_SDIOx_CAP1__TUNE_SDR50_SHIFT)\ + | (0x0 << ICFG_SDIOx_CAP1__DRIVER_D_SHIFT)\ + | (0x0 << ICFG_SDIOx_CAP1__DRIVER_C_SHIFT)\ + | (0x1 << ICFG_SDIOx_CAP1__DRIVER_A_SHIFT)\ + | (0x1 << ICFG_SDIOx_CAP1__DDR50_SHIFT)\ + | (0x1 << ICFG_SDIOx_CAP1__SDR104_SHIFT)\ + | (0x1 << ICFG_SDIOx_CAP1__SDR50_SHIFT) + +#define PAD_SDIO_CLK 0x4 +#define PAD_SDIO_DATA0 0x8 +#define PAD_SDIO_DATA1 0xc +#define PAD_SDIO_DATA2 0x10 +#define PAD_SDIO_DATA3 0x14 +#define PAD_SDIO_DATA4 0x18 +#define PAD_SDIO_DATA5 0x1c +#define PAD_SDIO_DATA6 0x20 +#define PAD_SDIO_DATA7 0x24 +#define PAD_SDIO_CMD 0x28 + +/* 12mA Drive strength*/ +#define PAD_SDIO_SELX (0x5 << 1) +#define PAD_SDIO_SRC (1 << 0) +#define PAD_SDIO_MASK (0xF << 0) +#define PAD_SDIO_VALUE (PAD_SDIO_SELX | PAD_SDIO_SRC) + +/* + * SDIO_PRESETVAL0 + * + * Each 13 Bit filed consists: + * drivestrength - 12:11 + * clkgensel - b10 + * sdkclkfreqsel - 9:0 + * Field Bit(s) Description + * ============================================================ + * SDR25_PRESET 25:13 Preset Value for SDR25 + * SDR50_PRESET 12:0 Preset Value for SDR50 + */ +#define SDIO_PRESETVAL0 0x01005001 + +/* + * SDIO_PRESETVAL1 + * + * Each 13 Bit filed consists: + * drivestrength - 12:11 + * clkgensel - b10 + * sdkclkfreqsel - 9:0 + * Field Bit(s) Description + * ============================================================ + * SDR104_PRESET 25:13 Preset Value for SDR104 + * SDR12_PRESET 12:0 Preset Value for SDR12 + */ +#define SDIO_PRESETVAL1 0x03000004 + +/* + * SDIO_PRESETVAL2 + * + * Each 13 Bit filed consists: + * drivestrength - 12:11 + * clkgensel - b10 + * sdkclkfreqsel - 9:0 + * Field Bit(s) Description + * ============================================================ + * HIGH_SPEED_PRESET 25:13 Preset Value for High Speed + * INIT_PRESET 12:0 Preset Value for Initialization + */ +#define SDIO_PRESETVAL2 0x010040FA + +/* + * SDIO_PRESETVAL3 + * + * Each 13 Bit filed consists: + * drivestrength - 12:11 + * clkgensel - b10 + * sdkclkfreqsel - 9:0 + * Field Bit(s) Description + * ============================================================ + * DDR50_PRESET 25:13 Preset Value for DDR50 + * DEFAULT_PRESET 12:0 Preset Value for Default Speed + */ +#define SDIO_PRESETVAL3 0x01004004 + +/* + * SDIO_PRESETVAL4 + * + * Field Bit(s) Description + * ============================================================ + * FORCE_USE_IP_TUNE_CLK 30 Force use IP clock + * TUNING_COUNT 29:24 Tuning count + * OVERRIDE_1P8V 23:16 + * OVERRIDE_3P3V 15:8 + * OVERRIDE_3P0V 7:0 + */ +#define SDIO_PRESETVAL4 0x20010101 + +#define SDIO_SID_SHIFT 5 + +typedef struct { + uintptr_t cfg_base; + uintptr_t sid_base; + uintptr_t io_ctrl_base; + uintptr_t pad_base; +} SDIO_CFG; + +void brcm_stingray_sdio_init(void); + +#endif /* SDIO_H */ diff --git a/plat/brcm/board/stingray/include/sr_def.h b/plat/brcm/board/stingray/include/sr_def.h new file mode 100644 index 0000000..277836e --- /dev/null +++ b/plat/brcm/board/stingray/include/sr_def.h @@ -0,0 +1,624 @@ +/* + * Copyright (c) 2016-2021, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef SR_DEF_H +#define SR_DEF_H + +#ifndef __ASSEMBLER__ +#include <lib/mmio.h> +#endif + +#include <common/interrupt_props.h> +#include <drivers/arm/gic_common.h> + +#include <crmu_def.h> + +/* Special value used to verify platform parameters from BL2 to BL3-1 */ +#define BRCM_BL31_PLAT_PARAM_VAL ULL(0x0f1e2d3c4b5a6978) + +#define MHB_BASE_ADDR 0x60000000 +#define PLAT_BRCM_CCN_BASE 0x61000000 +#define CORESIGHT_BASE_ADDR 0x62000000 +#define SMMU_BASE 0x64000000 + +/* memory map entries*/ +/* Grouping block device for bigger MMU region */ +/* covers MHB, CNN, coresight, GIC, MMU, APB, CRMU */ +#define PERIPH0_BASE MHB_BASE_ADDR +#define PERIPH0_SIZE 0x06d00000 + +#define PERIPH1_BASE 0x66d80000 +#define PERIPH1_SIZE 0x00f80000 + +#define HSLS_BASE_ADDR 0x68900000 +#define HSLS_SIZE 0x04500000 + +#define GIC500_BASE 0x63c00000 +#define GIC500_SIZE 0x400000 + +/******************************************************************************* + * CCN related constants + ******************************************************************************/ +#define OLY_MN_REGISTERS_NODE0_SECURE_ACCESS (PLAT_BRCM_CCN_BASE + 0x0) + +#define OLY_RNI3PDVM_REGISTERS_NODE8_AUX_CTL (PLAT_BRCM_CCN_BASE + 0x880500) + +/* Used for acceleration of coherent ordered writes */ +#define OLY_RNI3PDVM_REGISTERS_NODE8_AUX_CTL_WUO BIT(4) +/* Wait for completion of requests at RN-I */ +#define OLY_RNI3PDVM_REGISTERS_NODE8_AUX_CTL_WFC BIT(3) + +/* + * Forces all reads from the RN-I to be sent with the request order bit set + * and this ensures ordered allocation of read data buffers in the RN-I + */ +#define OLY_RNI3PDVM_REGISTERS_NODE8_AUX_CTL_RQO BIT(5) + +#define OLY_RNI3PDVM_REGISTERS_NODE14_AUX_CTL (PLAT_BRCM_CCN_BASE + 0x8e0500) + +/* Wait for completion of requests at RN-I */ +#define OLY_RNI3PDVM_REGISTERS_NODE14_AUX_CTL_WFC BIT(3) + +#define OLY_HNI_REGISTERS_NODE0_POS_CONTROL (PLAT_BRCM_CCN_BASE + 0x80000) +#define POS_CONTROL_HNI_POS_EN BIT(0) + +#define OLY_HNI_REGISTERS_NODE0_PCIERC_RNI_NODEID_LIST \ + (PLAT_BRCM_CCN_BASE + 0x80008) +/* PAXB and PAXC connected to 8th Node */ +#define SR_RNI_PCIE_CONNECTED BIT(8) +/* PAXB connected to 6th Node */ +#define SRP_RNI_PCIE_CONNECTED BIT(6) + +#define OLY_HNI_REGISTERS_NODE0_SA_AUX_CTL (PLAT_BRCM_CCN_BASE + 0x80500) +#define SA_AUX_CTL_POS_EARLY_WR_COMP_EN BIT(5) +#define SA_AUX_CTL_SER_DEVNE_WR BIT(9) + +/******************************************************************************* + * Coresight related constants + ******************************************************************************/ +#define CORESIGHT_BASE_ADDR 0x62000000 + +#define IHOST0_BASE 0x66000000 +#define IHOST_ADDR_SPACE 0x2000 + +/******************************************************************************* + * SCR related constants + ******************************************************************************/ +#define SCR_BASE 0x6600a000 +#define SCR_ARCACHE_OFFSET 4 +#define SCR_ARCACHE_MASK (0x3 << SCR_ARCACHE_OFFSET) +#define SCR_AWCACHE_OFFSET 6 +#define SCR_AWCACHE_MASK (0x3 << SCR_AWCACHE_OFFSET) +#define SCR_AXCACHE_CONFIG_MASK (SCR_ARCACHE_MASK | SCR_AWCACHE_MASK) +#define SCR_TBUX_AXCACHE_CONFIG ((0x1 << SCR_AWCACHE_OFFSET) | \ + (0x1 << SCR_ARCACHE_OFFSET)) + +#define SCR_REGS_SCR_SOFT_RESET (SCR_BASE + 0x1c) +#define SCR_REGS_GIC_SOFT_RESET BIT(0) + +#define SCR_GPV_BASE 0x66100000 +#define SCR_NOC_SECURITY0 (SCR_GPV_BASE + 0x08) +#define SCR_NOC_DDR_REGISTER_ACCESS (SCR_GPV_BASE + 0x30) + +/******************************************************************************* + * MEMC and DDR related constants + ******************************************************************************/ +#define DDR0_CONTROL_ROOT 0x66200000 +#define EMEM_SS_CFG_0_ROOT 0x66202000 +#define EMEM_SYS_IF_0_ROOT 0x66204000 +#define DDR_PHY0_ROOT 0x66240000 + +#define DDR1_CONTROL_ROOT 0x66280000 +#define EMEM_SS_CFG_1_ROOT 0x66282000 +#define EMEM_SYS_IF_1_ROOT 0x66284000 +#define DDR_PHY1_ROOT 0x662c0000 + +#define DDR2_CONTROL_ROOT 0x66300000 +#define EMEM_SS_CFG_2_ROOT 0x66302000 +#define EMEM_SYS_IF_2_ROOT 0x66304000 +#define DDR_PHY2_ROOT 0x66340000 + +/******************************************************************************* + * TZC400 related constants + ******************************************************************************/ +#define TZC_400_BASE 0x66d84000 + +/******************************************************************************* + * FS4 related constants + ******************************************************************************/ +#define FS4_SRAM_IDM_IO_CONTROL_DIRECT 0x66d8a408 + +#define FS4_CRYPTO_IDM_IO_CONTROL_DIRECT 0x66d8e408 +#define FS4_CRYPTO_IDM_RESET_CONTROL 0x66d8e800 +#define FS4_CRYPTO_BASE 0x67000000 +#define FS4_CRYPTO_DME_BASE (FS4_CRYPTO_BASE + 0x280000) + +#define FS4_RAID_IDM_IO_CONTROL_DIRECT 0x66d8f408 +#define FS4_RAID_IDM_IO_STATUS 0x66d8f500 +#define FS4_RAID_IDM_RESET_CONTROL 0x66d8f800 +#define FS4_RAID_BASE 0x67400000 +#define FS4_RAID_DME_BASE (FS4_RAID_BASE + 0x280000) + +#define FS4_CRYPTO_GPV_BASE 0x67300000 +#define FS4_RAID_GPV_BASE 0x67700000 + +#define FS6_PKI_BASE 0x67400000 +#define FS6_PKI_DME_BASE 0x66D90000 + +#define TZC400_FS_SRAM_ROOT 0x66d84000 +#define GATE_KEEPER_OFFSET 0x8 +#define REGION_ATTRIBUTES_0_OFFSET 0x110 +#define REGION_ID_ACCESS_0_OFFSET 0x114 + +#define NIC400_FS_NOC_ROOT 0x66e00000 +#define NIC400_FS_NOC_SECURITY2_OFFSET 0x10 +#define NIC400_FS_NOC_SECURITY4_OFFSET 0x18 +#define NIC400_FS_NOC_SECURITY7_OFFSET 0x24 + +/******************************************************************************* + * SATA PHY related constants + ******************************************************************************/ +#define SATA_BASE 0x67d00000 + +/******************************************************************************* + * USB related constants + ******************************************************************************/ +#define USB_BASE 0x68500000 +#define USB_SIZE 0x00400000 +#define XHC_BASE (USB_BASE + 0x11000) +#define MAX_USB_PORTS 3 + +/******************************************************************************* + * HSLS related constants + ******************************************************************************/ +#define IPROC_ROOT 0x68900000 +#define HSLS_ICFG_REGS_BASE IPROC_ROOT +#define HSLS_IDM_REGS_BASE 0x68e00000 +#define HSLS_MODE_SEL_CONTROL 0x68a40000 +#define HSLS_TZPC_BASE 0x68b40000 +#define HSLS_GPV_BASE 0x6cd00000 + +/******************************************************************************* + * Chip ID related constants + ******************************************************************************/ +#define ICFG_CHIP_ID HSLS_ICFG_REGS_BASE +#define CHIP_ID_SR 0xd730 +#define CHIP_ID_NS3Z 0xe56d +#define CHIP_ID_MASK 0xf000 +#define ICFG_CHIP_REVISION_ID (HSLS_ICFG_REGS_BASE + 0x4) +#define PLAT_CHIP_ID_GET (mmio_read_32(ICFG_CHIP_ID)) +#define PLAT_CHIP_REV_GET (mmio_read_32(ICFG_CHIP_REVISION_ID)) + +/******************************************************************************* + * CMIC MII (MDIO) related constant + ******************************************************************************/ +#define PLAT_CMIC_MIIM_BASE 0x68920000U + +/******************************************************************************* + * Timers related constants + ******************************************************************************/ +/* ChipcommonG_tim0_TIM_TIMER1Load 0x68930000 */ +#define SP804_TIMER0_BASE 0x68930000 +#define SP804_TIMER1_BASE 0x68940000 +#define SP804_TIMER0_TIMER_VAL_REG_OFFSET 0x4 +#define SP804_TIMER0_CLKMULT 2 +#define SP804_TIMER0_CLKDIV 25 + +/******************************************************************************* + * GPIO related constants + ******************************************************************************/ +#define IPROC_GPIO_NS_BASE 0x689d0000 +#define IPROC_GPIO_S_BASE 0x68b00000 +#define IPROC_GPIO_NR 151 +#define GPIO_S_CNTRL_REG 0x68b60000 + +/******************************************************************************* + * I2C SMBUS related constants + ******************************************************************************/ +#define SMBUS0_REGS_BASE 0x689b0000 +#define SMBUS1_REGS_BASE 0x689e0000 + +/******************************************************************************* + * UART related constants + ******************************************************************************/ +#define ChipcommonG_UART0_UART_RBR_THR_DLL 0x68a00000 +#define ChipcommonG_UART1_UART_RBR_THR_DLL 0x68a10000 +#define ChipcommonG_UART2_UART_RBR_THR_DLL 0x68a20000 +#define ChipcommonG_UART3_UART_RBR_THR_DLL 0x68a30000 + +#define UART0_BASE_ADDR ChipcommonG_UART0_UART_RBR_THR_DLL +#define UART1_BASE_ADDR ChipcommonG_UART1_UART_RBR_THR_DLL +#define UART2_BASE_ADDR ChipcommonG_UART2_UART_RBR_THR_DLL +#define UART3_BASE_ADDR ChipcommonG_UART3_UART_RBR_THR_DLL + +#define UART_SPR_OFFSET 0x1c /* Scratch Pad Register */ + +#define LOG_LEVEL_REGISTER CRMU_SPARE_REG_3 +#define GET_LOG_LEVEL() (mmio_read_32(LOG_LEVEL_REGISTER)) +#define SET_LOG_LEVEL(x) (mmio_write_32(LOG_LEVEL_REGISTER, x)) + +#define IO_RETRY_REGISTER CRMU_SPARE_REG_4 + +#define DWC_UART_REFCLK (25 * 1000 * 1000) +#define DWC_UART_REFCLK_DIV 16 +/* Baud rate in emulation will vary based on setting of 25MHz SCLK */ +#define DWC_UART_BAUDRATE 115200 + +#define BRCM_CRASH_CONSOLE_BASE UART1_BASE_ADDR +#define BRCM_CRASH_CONSOLE_REFCLK DWC_UART_REFCLK +#define BRCM_CRASH_CONSOLE_BAUDRATE DWC_UART_BAUDRATE + +#ifdef BOARD_CONSOLE_UART +#define PLAT_BRCM_BOOT_UART_BASE BOARD_CONSOLE_UART +#else +#define PLAT_BRCM_BOOT_UART_BASE UART1_BASE_ADDR +#endif +#define CONSOLE_UART_ID ((PLAT_BRCM_BOOT_UART_BASE >> 16) & 0x3) + +#define PLAT_BRCM_BOOT_UART_CLK_IN_HZ DWC_UART_REFCLK +#define BRCM_CONSOLE_BAUDRATE DWC_UART_BAUDRATE + +#define PLAT_BRCM_BL31_RUN_UART_BASE PLAT_BRCM_BOOT_UART_BASE +#define PLAT_BRCM_BL31_RUN_UART_CLK_IN_HZ PLAT_BRCM_BOOT_UART_CLK_IN_HZ + +/******************************************************************************* + * IOMUX related constants + ******************************************************************************/ +#define HSLS_IOPAD_BASE HSLS_MODE_SEL_CONTROL +#define MODE_SEL_CONTROL_FSEL_MASK 0x7 +#define MODE_SEL_CONTROL_FSEL_MODE0 0x0 +#define MODE_SEL_CONTROL_FSEL_MODE1 0x1 +#define MODE_SEL_CONTROL_FSEL_MODE2 0x2 +#define MODE_SEL_CONTROL_FSEL_MODE3 0x3 +#define MODE_SEL_CONTROL_FSEL_DEBUG 0x4 +#define IPROC_IOPAD_MODE_BASE (HSLS_MODE_SEL_CONTROL + 0x29c) +#define UART0_SIN_MODE_SEL_CONTROL (HSLS_MODE_SEL_CONTROL + 0x4a8) +#define UART0_SOUT_MODE_SEL_CONTROL (HSLS_MODE_SEL_CONTROL + 0x4ac) +#define UART1_SIN_MODE_SEL_CONTROL (HSLS_MODE_SEL_CONTROL + 0x3b8) +#define UART1_SOUT_MODE_SEL_CONTROL (HSLS_MODE_SEL_CONTROL + 0x3bc) +#define UARTx_SIN_MODE_SEL_CONTROL_FSEL 0 +#define UARTx_SOUT_MODE_SEL_CONTROL_FSEL 0 + +/******************************************************************************* + * PKA constants + ******************************************************************************/ +#define ICFG_PKA_MEM_PWR_CTRL (HSLS_ICFG_REGS_BASE + 0xac0) +#define ICFG_PKA_MEM_PWR_CTRL__POWERONIN BIT(0) +#define ICFG_PKA_MEM_PWR_CTRL__POWEROKIN BIT(1) +#define ICFG_PKA_MEM_PWR_CTRL__ARRPOWERONIN BIT(2) +#define ICFG_PKA_MEM_PWR_CTRL__ARRPOWEROKIN BIT(3) +#define ICFG_PKA_MEM_PWR_CTRL__POWERONOUT BIT(4) +#define ICFG_PKA_MEM_PWR_CTRL__POWEROKOUT BIT(5) +#define ICFG_PKA_MEM_PWR_CTRL__ARRPOWERONOUT BIT(6) +#define ICFG_PKA_MEM_PWR_CTRL__ARRPOWEROKOUT BIT(7) +#define ICFG_PKA_MEM_PWR_CTRL__ISO BIT(8) + +/******************************************************************************* + * RNG constants + ******************************************************************************/ +#define RNG_BASE_ADDR 0x68b20000 + +/******************************************************************************* + * Trusted Watchdog constants + ******************************************************************************/ +#define ARM_SP805_TWDG_BASE 0x68b30000 +#define ARM_SP805_TWDG_CLK_HZ ((25 * 1000 * 1000) / 2) +/* + * The TBBR document specifies a watchdog timeout of 256 seconds. SP805 + * asserts reset after two consecutive countdowns (2 x 128 = 256 sec) + */ +#define ARM_TWDG_TIMEOUT_SEC 128 +#define ARM_TWDG_LOAD_VAL (ARM_SP805_TWDG_CLK_HZ * \ + ARM_TWDG_TIMEOUT_SEC) + +/******************************************************************************* + * SOTP related constants + ******************************************************************************/ +#define SOTP_REGS_OTP_BASE 0x68b50000 +#define SOTP_CHIP_CTRL (SOTP_REGS_OTP_BASE + 0x4c) +#define SOTP_CLEAR_SYSCTRL_ALL_MASTER_NS 0 + +/******************************************************************************* + * DMAC/PL330 related constants + ******************************************************************************/ +#define DMAC_M0_IDM_IO_CONTROL_DIRECT (HSLS_IDM_REGS_BASE + 0x408) +#define BOOT_MANAGER_NS BIT(25) +#define DMAC_M0_IDM_RESET_CONTROL (HSLS_IDM_REGS_BASE + 0x800) +#define ICFG_DMAC_CONFIG_0 (HSLS_ICFG_REGS_BASE + 0x190) +#define ICFG_DMAC_CONFIG_1 (HSLS_ICFG_REGS_BASE + 0x194) +#define ICFG_DMAC_CONFIG_2 (HSLS_ICFG_REGS_BASE + 0x198) +#define BOOT_PERIPHERAL_NS 0xffffffff +#define ICFG_DMAC_CONFIG_3 (HSLS_ICFG_REGS_BASE + 0x19c) +#define BOOT_IRQ_NS 0x0000ffff +#define ICFG_DMAC_SID_ARADDR_CONTROL (HSLS_ICFG_REGS_BASE + 0xaf0) +#define ICFG_DMAC_SID_AWADDR_CONTROL (HSLS_ICFG_REGS_BASE + 0xaf4) +#define ICFG_DMAC_MEM_PWR_CTRL__POWERONIN BIT(0) +#define ICFG_DMAC_MEM_PWR_CTRL__POWEROKIN BIT(1) +#define ICFG_DMAC_MEM_PWR_CTRL__ARRPOWERONIN BIT(2) +#define ICFG_DMAC_MEM_PWR_CTRL__ARRPOWEROKIN BIT(3) +#define ICFG_DMAC_MEM_PWR_CTRL__POWERONOUT BIT(4) +#define ICFG_DMAC_MEM_PWR_CTRL__POWEROKOUT BIT(5) +#define ICFG_DMAC_MEM_PWR_CTRL__ARRPOWERONOUT BIT(6) +#define ICFG_DMAC_MEM_PWR_CTRL__ARRPOWEROKOUT BIT(7) +#define ICFG_DMAC_MEM_PWR_CTRL__ISO BIT(8) +#define ICFG_DMAC_MEM_PWR_CTRL (HSLS_ICFG_REGS_BASE + 0xadc) + +/******************************************************************************* + * PNOR related constants + ******************************************************************************/ +#define PNOR_ICFG_BASE (HSLS_ICFG_REGS_BASE + 0x780) +#define PNOR_ICFG_CS_0 PNOR_ICFG_BASE +#define PNOR_ICFG_CS_1 (PNOR_ICFG_BASE + 0x4) +#define PNOR_ICFG_CS_2 (PNOR_ICFG_BASE + 0x8) +#define PNOR_ICFG_CS_x_MASK0_MASK 0xff +#define PNOR_ICFG_CS_x_MASK0_SHIFT 8 +#define PNOR_ICFG_CS_x_MATCH0_MASK 0xff +#define PNOR_ICFG_CS_x_MATCH0_SHIFT 0 + +#define PNOR_IDM_BASE (HSLS_IDM_REGS_BASE + 0xb000) +#define PNOR_IDM_IO_CONTROL_DIRECT (PNOR_IDM_BASE + 0x408) +#define PNOR_IDM_IO_RESET_CONTROL (PNOR_IDM_BASE + 0x800) + +#define PNOR_REG_BASE 0x68c50000 +#define PNOR_REG_DIRECT_CMD (PNOR_REG_BASE + 0x010) +#define PNOR_REG_SET_CYCLES (PNOR_REG_BASE + 0x014) +#define PNOR_REG_SET_OPMODE (PNOR_REG_BASE + 0x018) +#define PNOR_REG_REFRESH_0 (PNOR_REG_BASE + 0x020) +#define PNOR_REG_PERIPH_ID0 (PNOR_REG_BASE + 0xfe0) +#define PNOR_REG_PERIPH_ID1 (PNOR_REG_BASE + 0xfe4) +#define PNOR_REG_PERIPH_ID2 (PNOR_REG_BASE + 0xfe8) +#define PNOR_REG_PERIPH_ID3 (PNOR_REG_BASE + 0xfec) +#define PNOR_REG_PERIPH_IDx_MASK 0xff + +/******************************************************************************* + * NAND related constants + ******************************************************************************/ +#define NAND_FLASH_REVISION 0x68c60000 +#define NAND_IDM_IDM_IO_CONTROL_DIRECT (HSLS_IDM_REGS_BASE + 0xa408) +#define NAND_IDM_IDM_RESET_CONTROL (HSLS_IDM_REGS_BASE + 0xa800) + +/******************************************************************************* + * eMMC related constants + ******************************************************************************/ +#define PLAT_SD_MAX_READ_LENGTH 0x400 + +#define SDIO0_EMMCSDXC_SYSADDR 0x68cf1000 +#define SDIO_IDM0_IO_CONTROL_DIRECT (HSLS_IDM_REGS_BASE + 0x2408) +#define SDIO_IDM1_IO_CONTROL_DIRECT (HSLS_IDM_REGS_BASE + 0x3408) +#define SDIO_IDM0_IDM_RESET_CONTROL (HSLS_IDM_REGS_BASE + 0x2800) +#define ICFG_SDIO0_BASE (HSLS_ICFG_REGS_BASE + 0x6e4) +#define ICFG_SDIO1_BASE (HSLS_ICFG_REGS_BASE + 0x734) +#define ICFG_SDIO0_CAP0 (ICFG_SDIO0_BASE + 0x10) +#define ICFG_SDIO0_CAP1 (ICFG_SDIO0_BASE + 0x14) +#define ICFG_SDIO0_SID (HSLS_ICFG_REGS_BASE + 0xb00) +#define ICFG_SDIO1_SID (HSLS_ICFG_REGS_BASE + 0xb08) + +/******************************************************************************* + * Bootstrap related constants + ******************************************************************************/ +#define ROM_S0_IDM_IO_STATUS (HSLS_IDM_REGS_BASE + 0x9500) + +/******************************************************************************* + * ROM related constants + ******************************************************************************/ +#define ROM_BASE_ADDR 0x6ce00000 +#define ROM_VERSION_STRING_ADDR (ROM_BASE_ADDR + 0x28000) +#define ROM_BUILD_MESSAGE_ADDR (ROM_BASE_ADDR + 0x28018) + +/******************************************************************************* + * Boot source peripheral related constants + ******************************************************************************/ +#define QSPI_CTRL_BASE_ADDR 0x68c70000 +#define QSPI_BASE_ADDR 0x70000000 +#define QSPI_SIZE 0x08000000 +#define NOR_BASE_ADDR 0x74000000 +#define NOR_SIZE 0x04000000 +#define NAND_BASE_ADDR 0x78000000 +#define NAND_SIZE 0x08000000 + +#define QSPI_IDM_RESET_CONTROL (HSLS_IDM_REGS_BASE + 0xc800) + +#define APBR_IDM_RESET_CONTROL (HSLS_IDM_REGS_BASE + 0xe800) +#define APBS_IDM_IDM_RESET_CONTROL (HSLS_IDM_REGS_BASE + 0xf800) + +#define APBX_IDM_IDM_IO_CONTROL_DIRECT (HSLS_IDM_REGS_BASE + 0x10408) +#define APBX_IDM_IDM_IO_CONTROL_DIRECT_CLK_ENABLE 0 +#define APBX_IDM_IDM_IO_CONTROL_DIRECT_WDOG_SCLK_SEL 2 +#define APBX_IDM_IDM_IO_CONTROL_DIRECT_TIM0_SCLK_SEL 4 +#define APBX_IDM_IDM_IO_CONTROL_DIRECT_TIM1_SCLK_SEL 6 +#define APBX_IDM_IDM_IO_CONTROL_DIRECT_TIM2_SCLK_SEL 8 +#define APBX_IDM_IDM_IO_CONTROL_DIRECT_TIM3_SCLK_SEL 10 +#define APBX_IDM_IDM_IO_CONTROL_DIRECT_TIM4_SCLK_SEL 12 +#define APBX_IDM_IDM_IO_CONTROL_DIRECT_TIM5_SCLK_SEL 13 +#define APBX_IDM_IDM_IO_CONTROL_DIRECT_TIM6_SCLK_SEL 14 +#define APBX_IDM_IDM_IO_CONTROL_DIRECT_TIM7_SCLK_SEL 15 + +#define APBY_IDM_IDM_IO_CONTROL_DIRECT (HSLS_IDM_REGS_BASE + 0x11408) +#define APBY_IDM_IDM_IO_CONTROL_DIRECT_CLK_ENABLE 0 +#define APBY_IDM_IDM_IO_CONTROL_DIRECT_UART0_SCLK_SEL 2 +#define APBY_IDM_IDM_IO_CONTROL_DIRECT_UART1_SCLK_SEL 4 +#define APBY_IDM_IDM_IO_CONTROL_DIRECT_UART2_SCLK_SEL 6 +#define APBY_IDM_IDM_IO_CONTROL_DIRECT_UART3_SCLK_SEL 8 + +#define APBZ_IDM_IDM_IO_CONTROL_DIRECT (HSLS_IDM_REGS_BASE + 0x12408) +#define APBZ_IDM_IDM_IO_CONTROL_DIRECT_CLK_ENABLE 0 +#define APBZ_IDM_IDM_IO_CONTROL_DIRECT_WDOG_SCLK_SEL 2 + +/******************************************************************************* + * Stingray memory map related constants + ******************************************************************************/ + +/* The last 4KB of Trusted SRAM are used as shared memory */ +#define BRCM_SHARED_RAM_SIZE 0x0 +#define BRCM_SHARED_RAM_BASE (PLAT_BRCM_TRUSTED_SRAM_BASE + \ + PLAT_BRCM_TRUSTED_SRAM_SIZE - \ + BRCM_SHARED_RAM_SIZE) + +/* Reserve 4 KB to store error logs in BL2 */ +#define BCM_ELOG_BL2_SIZE 0x00001000 +#define BCM_ELOG_BL2_BASE BL1_RW_LIMIT + +/* The remaining Trusted SRAM is used to load the BL images */ +#define BRCM_BL_RAM_BASE (PLAT_BRCM_TRUSTED_SRAM_BASE) +#define BRCM_BL_RAM_SIZE (PLAT_BRCM_TRUSTED_SRAM_SIZE - \ + BRCM_SHARED_RAM_SIZE) + +/* DDR Address where TMON temperature values are written */ +#define TMON_SHARED_DDR_ADDRESS 0x8f100000 + +/* Reserve 4 kB to pass data to BL33 */ +#define BL33_SHARED_DDR_BASE 0x8f102000 +#define BL33_SHARED_DDR_SIZE 0x1000 + +/* Default AP error logging base addr */ +#ifndef ELOG_AP_UART_LOG_BASE +#define ELOG_AP_UART_LOG_BASE 0x8f110000 +#endif + +/* Reserve 16 to store error logs in BL31 */ +#define BCM_ELOG_BL31_BASE ELOG_AP_UART_LOG_BASE +#define BCM_ELOG_BL31_SIZE 0x4000 + +/******************************************************************************* + * Non-secure DDR Map + ******************************************************************************/ +#define BRCM_DRAM1_BASE ULL(0x80000000) +#define BRCM_DRAM1_SIZE ULL(0x10000000) +#define BRCM_DRAM2_BASE ULL(0x880000000) +#define BRCM_DRAM2_SIZE ULL(0x780000000) +#define BRCM_DRAM3_BASE ULL(0x8800000000) +#define BRCM_DRAM3_SIZE ULL(0x7800000000) +#define BRCM_SHARED_DRAM_BASE BL33_SHARED_DDR_BASE +#define BRCM_SHARED_DRAM_SIZE BL33_SHARED_DDR_SIZE +#define BRCM_EXT_SRAM_BASE ULL(0x74000000) +#define BRCM_EXT_SRAM_SIZE ULL(0x4000000) + +/* Priority levels for platforms */ +#define PLAT_RAS_PRI 0x10 +#define PLAT_SDEI_CRITICAL_PRI 0x60 +#define PLAT_SDEI_NORMAL_PRI 0x70 + +/* Define a list of Group 1 Secure and Group 0 interrupts as per GICv3 */ +#define BRCM_IRQ_SEC_SGI_0 14 +#define BRCM_IRQ_SEC_SGI_1 15 + +/* RTC periodic interrupt */ +#define BRCM_IRQ_SEC_SPI_0 49 + +/* + * Macros for local power states in SR platforms encoded by State-ID field + * within the power-state parameter. + */ + +/* Local power state for power domains in Run state. */ +#define PLAT_LOCAL_STATE_RUN 0 + +/* Local power state for retention. Valid only for CPU power domains */ +#define PLAT_LOCAL_STATE_RET 1 + +/* + * Local power state for OFF/power-down. Valid for CPU and cluster power + * domains. + */ +#define PLAT_LOCAL_STATE_OFF 2 + +/* + * This macro defines the deepest retention state possible. A higher state + * id will represent an invalid or a power down state. + */ +#define PLAT_MAX_RET_STATE PLAT_LOCAL_STATE_RET + +/* + * This macro defines the deepest power down states possible. Any state ID + * higher than this is invalid. + */ +#define PLAT_MAX_OFF_STATE PLAT_LOCAL_STATE_OFF + +/* ChiMP-related constants */ + +#define NITRO_TZPC_TZPCDECPROT0clr 0x60c01808 +#define NITRO_TZPC_TZPCDECPROT0clr__DECPROT0_chimp_m_clr_R 1 + +#define NIC400_NITRO_CHIMP_S_IDM_IO_CONTROL_DIRECT 0x60e00408 + +#define CHIMP_INDIRECT_ADDR_MASK 0x3fffff +#define CHIMP_INDIRECT_BASE 0x60800000 + +#define CHIMP_REG_ECO_RESERVED 0x3042400 + +#define CHIMP_FLASH_ACCESS_DONE_BIT 2 + +/* indicate FRU table programming is done successfully */ +#define CHIMP_FRU_PROG_DONE_BIT 9 + +#define CHIMP_REG_CTRL_BPE_MODE_REG 0x0 +#define CHIMP_REG_CTRL_BPE_STAT_REG 0x4 +#define CHIMP_REG_CTRL_FSTBOOT_PTR_REG 0x8 +#define CHIMP_REG_CHIMP_REG_CTRL_BPE_MODE_REG__cm3_rst_L 1 +#define CHIMP_REG_CHIMP_REG_CTRL_BPE_MODE_REG__cm3_rst_R 1 +#define CHIMP_REG_CTRL_BASE 0x3040000 +#define CHIMP_FAST_BOOT_MODE_BIT 2 +#define CHIMP_REG_CHIMP_APE_SCPAD 0x3300000 +#define CHIMP_REG_CHIMP_SCPAD 0x3100000 + +/* Chimp health status offset in scratch pad ram */ +#define CHIMP_HEALTH_STATUS_OFFSET 0x8 +/* + * If not in NIC mode then FASTBOOT can be enabled. + * "Not in NIC mode" means that FORCE_FASTBOOT is set + * and a valid (1 or 2) fastboot type is specified. + * + * Three types of fastboot are supported: + * 0 = No fastboot. Boots Nitro/ChiMP and lets ROM loader + * initialize ChiMP from NVRAM (QSPI). + * + * 1 = Jump in place (need a flat image) + * This is intended to speedup Nitro FW boot on Palladium, + * can be used with a real chip as well. + * 2 = Jump normally with decompression + * Modus operandi for a real chip. Works also on Palladium + * Note: image decompressing takes time on Palladium. + * 3 = No fastboot support. No ChiMP bringup + * (use only for AP debug or for ChiMP's deferred setup). + */ +#define CHIMP_FASTBOOT_JUMP_DECOMPRESS 2 +#define CHIMP_FASTBOOT_JUMP_IN_PLACE 1 +#define CHIMP_FASTBOOT_NITRO_RESET 0 +/* + * Definitions for a non-Nitro access + * to QSPI PAD after the handshake + */ +#define QSPI_HOLD_N_MODE_SEL_CONTROL (HSLS_MODE_SEL_CONTROL + 0x3e8) +#define QSPI_WP_N_MODE_SEL_CONTROL (HSLS_MODE_SEL_CONTROL + 0x3ec) +#define QSPI_SCK_MODE_SEL_CONTROL (HSLS_MODE_SEL_CONTROL + 0x3f0) +#define QSPI_CS_N_MODE_SEL_CONTROL (HSLS_MODE_SEL_CONTROL + 0x3f4) +#define QSPI_MOSI_MODE_SEL_CONTROL (HSLS_MODE_SEL_CONTROL + 0x3f8) +#define QSPI_MISO_MODE_SEL_CONTROL (HSLS_MODE_SEL_CONTROL + 0x3fc) + +/******************************************************************************* + * Stream IDs for different blocks of SR + * block_id for different blocks is as follows: + * PCIE : 0x0 + * PAXC : 0x1 + * FS4 : 0x2 + * Rest of the masters(includes MHB via RNI): 0x3 + ******************************************************************************/ +#define SR_SID_VAL(block_id, subblock_id, device_num) ((block_id << 13) | \ + (subblock_id << 11) | \ + (device_num)) + +#define CRMU_STREAM_ID SR_SID_VAL(0x3, 0x0, 0x7) +#define CRMU_SID_SHIFT 5 + +#define DMAC_STREAM_ID SR_SID_VAL(0x3, 0x0, 0x0) +#define DMAC_SID_SHIFT 5 + +/* DDR SHMOO Values defines */ +#define IDRAM_SHMOO_VALUES_ADDR CRMU_IDRAM_BASE_ADDR +#define DDR_SHMOO_VALUES_ADDR 0x8f103000 +#define SHMOO_SIZE_PER_CHANNEL 0x1000 + +#endif /* SR_DEF_H */ diff --git a/plat/brcm/board/stingray/include/sr_utils.h b/plat/brcm/board/stingray/include/sr_utils.h new file mode 100644 index 0000000..b3fc735 --- /dev/null +++ b/plat/brcm/board/stingray/include/sr_utils.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2017 - 2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef SR_UTILS_H +#define SR_UTILS_H + +#include <lib/mmio.h> + +#include <chip_id.h> +#include <cmn_plat_util.h> +#include <sr_def.h> + +static inline void brcm_stingray_set_qspi_mux(int enable_ap) +{ + mmio_write_32(QSPI_HOLD_N_MODE_SEL_CONTROL, enable_ap); + mmio_write_32(QSPI_WP_N_MODE_SEL_CONTROL, enable_ap); + mmio_write_32(QSPI_SCK_MODE_SEL_CONTROL, enable_ap); + mmio_write_32(QSPI_CS_N_MODE_SEL_CONTROL, enable_ap); + mmio_write_32(QSPI_MOSI_MODE_SEL_CONTROL, enable_ap); + mmio_write_32(QSPI_MISO_MODE_SEL_CONTROL, enable_ap); +} + +static inline void brcm_stingray_set_straps(uint32_t boot_source) +{ + /* Enable software strap override */ + mmio_setbits_32(CDRU_CHIP_STRAP_CTRL, + BIT(CDRU_CHIP_STRAP_CTRL__SOFTWARE_OVERRIDE)); + + /* set straps to the next boot source */ + mmio_clrsetbits_32(CDRU_CHIP_STRAP_DATA, + BOOT_SOURCE_MASK, + boot_source); + + /* Disable software strap override */ + mmio_clrbits_32(CDRU_CHIP_STRAP_CTRL, + BIT(CDRU_CHIP_STRAP_CTRL__SOFTWARE_OVERRIDE)); +} + +#endif diff --git a/plat/brcm/board/stingray/include/swreg.h b/plat/brcm/board/stingray/include/swreg.h new file mode 100644 index 0000000..6e971ce --- /dev/null +++ b/plat/brcm/board/stingray/include/swreg.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2017 - 2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef SWREG_H +#define SWREG_H + +/* default voltage if no valid OTP */ +#define VDDC_CORE_DEF_VOLT 910000 /* 0.91v */ +#define IHOST_DEF_VOLT 940000 /* 0.94v */ + +#define B0_VDDC_CORE_DEF_VOLT 950000 /* 0.95v */ +#define B0_IHOST_DEF_VOLT 950000 /* 0.95v */ +#define B0_DDR_VDDC_DEF_VOLT 1000000 /* 1v */ + +#define SWREG_IHOST1_DIS 4 +#define SWREG_IHOST1_REG_RESETB 5 +#define SWREG_IHOST1_PMU_STABLE 2 + +enum sw_reg { + DDR_VDDC = 1, + IHOST03, + IHOST12, + IHOST_ARRAY, + DDRIO_SLAVE, + VDDC_CORE, + VDDC1, + DDRIO_MASTER +}; + +int set_swreg(enum sw_reg reg_id, uint32_t micro_volts); +int swreg_firmware_update(void); + +#endif diff --git a/plat/brcm/board/stingray/include/timer_sync.h b/plat/brcm/board/stingray/include/timer_sync.h new file mode 100644 index 0000000..1f15bb0 --- /dev/null +++ b/plat/brcm/board/stingray/include/timer_sync.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2016 - 2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef TIMER_SYNC_H +#define TIMER_SYNC_H + +void brcm_timer_sync_init(void); + +#endif diff --git a/plat/brcm/board/stingray/include/usb_phy.h b/plat/brcm/board/stingray/include/usb_phy.h new file mode 100644 index 0000000..7d83182 --- /dev/null +++ b/plat/brcm/board/stingray/include/usb_phy.h @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2017 - 2021, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef USB_PHY_H +#define USB_PHY_H + +#include <stdint.h> + +#include <common/debug.h> +#include <drivers/delay_timer.h> +#include <lib/mmio.h> + +#include <platform_def.h> + +#define DRDU2_U2PLL_NDIV_FRAC_OFFSET 0x0U + +#define DRDU2_U2PLL_NDIV_INT 0x4U + +#define DRDU2_U2PLL_CTRL 0x8U +#define DRDU2_U2PLL_LOCK BIT(6U) +#define DRDU2_U2PLL_RESETB BIT(5U) +#define DRDU2_U2PLL_PDIV_MASK 0xFU +#define DRDU2_U2PLL_PDIV_OFFSET 1U +#define DRDU2_U2PLL_SUSPEND_EN BIT(0U) + +#define DRDU2_PHY_CTRL 0x0CU +#define DRDU2_U2IDDQ BIT(30U) +#define DRDU2_U2SOFT_RST_N BIT(29U) +#define DRDU2_U2PHY_ON_FLAG BIT(22U) +#define DRDU2_U2PHY_PCTL_MASK 0xFFFFU +#define DRDU2_U2PHY_PCTL_OFFSET 6U +#define DRDU2_U2PHY_RESETB BIT(5U) +#define DRDU2_U2PHY_ISO BIT(4U) +#define DRDU2_U2AFE_BG_PWRDWNB BIT(3U) +#define DRDU2_U2AFE_PLL_PWRDWNB BIT(2U) +#define DRDU2_U2AFE_LDO_PWRDWNB BIT(1U) +#define DRDU2_U2CTRL_CORERDY BIT(0U) + +#define DRDU2_STRAP_CTRL 0x18U +#define DRDU2_FORCE_HOST_MODE BIT(5U) +#define DRDU2_FORCE_DEVICE_MODE BIT(4U) +#define BDC_USB_STP_SPD_MASK 0x7U +#define BDC_USB_STP_SPD_OFFSET 0U + +#define DRDU2_PWR_CTRL 0x1CU +#define DRDU2_U2PHY_DFE_SWITCH_PWROKIN_I BIT(2U) +#define DRDU2_U2PHY_DFE_SWITCH_PWRONIN_I BIT(1U) + +#define DRDU2_SOFT_RESET_CTRL 0x20U +#define DRDU2_BDC_AXI_SOFT_RST_N BIT(0U) + +#define USB3H_U2PLL_NDIV_FRAC 0x4U + +#define USB3H_U2PLL_NDIV_INT 0x8U + +#define USB3H_U2PLL_CTRL 0xCU +#define USB3H_U2PLL_LOCK BIT(6U) +#define USB3H_U2PLL_RESETB BIT(5U) +#define USB3H_U2PLL_PDIV_MASK 0xFU +#define USB3H_U2PLL_PDIV_OFFSET 1U + +#define USB3H_U2PHY_CTRL 0x10U +#define USB3H_U2PHY_ON_FLAG 22U +#define USB3H_U2PHY_PCTL_MASK 0xFFFFU +#define USB3H_U2PHY_PCTL_OFFSET 6U +#define USB3H_U2PHY_IDDQ BIT(29U) +#define USB3H_U2PHY_RESETB BIT(5U) +#define USB3H_U2PHY_ISO BIT(4U) +#define USB3H_U2AFE_BG_PWRDWNB BIT(3U) +#define USB3H_U2AFE_PLL_PWRDWNB BIT(2U) +#define USB3H_U2AFE_LDO_PWRDWNB BIT(1U) +#define USB3H_U2CTRL_CORERDY BIT(0U) + +#define USB3H_U3PHY_CTRL 0x14U +#define USB3H_U3SOFT_RST_N BIT(30U) +#define USB3H_U3MDIO_RESETB_I BIT(29U) +#define USB3H_U3POR_RESET_I BIT(28U) +#define USB3H_U3PHY_PCTL_MASK 0xFFFFU +#define USB3H_U3PHY_PCTL_OFFSET 2U +#define USB3H_U3PHY_RESETB BIT(1U) + +#define USB3H_U3PHY_PLL_CTRL 0x18U +#define USB3H_U3PLL_REFCLK_MASK 0x7U +#define USB3H_U3PLL_REFCLK_OFFSET 4U +#define USB3H_U3PLL_SS_LOCK BIT(3U) +#define USB3H_U3PLL_SEQ_START BIT(2U) +#define USB3H_U3SSPLL_SUSPEND_EN BIT(1U) +#define USB3H_U3PLL_RESETB BIT(0U) + +#define USB3H_PWR_CTRL 0x28U +#define USB3H_PWR_CTRL_OVERRIDE_I_R 4U +#define USB3H_PWR_CTRL_U2PHY_DFE_SWITCH_PWROKIN BIT(11U) +#define USB3H_PWR_CTRL_U2PHY_DFE_SWITCH_PWRONIN BIT(10U) + +#define USB3H_SOFT_RESET_CTRL 0x2CU +#define USB3H_XHC_AXI_SOFT_RST_N BIT(1U) + +#define USB3H_PHY_PWR_CTRL 0x38U +#define USB3H_DISABLE_USB30_P0 BIT(2U) +#define USB3H_DISABLE_EUSB_P1 BIT(1U) +#define USB3H_DISABLE_EUSB_P0 BIT(0U) + + +#define DRDU3_U2PLL_NDIV_FRAC 0x4U + +#define DRDU3_U2PLL_NDIV_INT 0x8U + +#define DRDU3_U2PLL_CTRL 0xCU +#define DRDU3_U2PLL_LOCK BIT(6U) +#define DRDU3_U2PLL_RESETB BIT(5U) +#define DRDU3_U2PLL_PDIV_MASK 0xFU +#define DRDU3_U2PLL_PDIV_OFFSET 1U + +#define DRDU3_U2PHY_CTRL 0x10U +#define DRDU3_U2PHY_IDDQ BIT(29U) +#define DRDU3_U2PHY_ON_FLAG BIT(22U) +#define DRDU3_U2PHY_PCTL_MASK 0xFFFFU +#define DRDU3_U2PHY_PCTL_OFFSET 6U +#define DRDU3_U2PHY_RESETB BIT(5U) +#define DRDU3_U2PHY_ISO BIT(4U) +#define DRDU3_U2AFE_BG_PWRDWNB BIT(3U) +#define DRDU3_U2AFE_PLL_PWRDWNB BIT(2U) +#define DRDU3_U2AFE_LDO_PWRDWNB BIT(1U) +#define DRDU3_U2CTRL_CORERDY BIT(0U) + +#define DRDU3_U3PHY_CTRL 0x14U +#define DRDU3_U3XHC_SOFT_RST_N BIT(31U) +#define DRDU3_U3BDC_SOFT_RST_N BIT(30U) +#define DRDU3_U3MDIO_RESETB_I BIT(29U) +#define DRDU3_U3POR_RESET_I BIT(28U) +#define DRDU3_U3PHY_PCTL_MASK 0xFFFFU +#define DRDU3_U3PHY_PCTL_OFFSET 2U +#define DRDU3_U3PHY_RESETB BIT(1U) + +#define DRDU3_U3PHY_PLL_CTRL 0x18U +#define DRDU3_U3PLL_REFCLK_MASK 0x7U +#define DRDU3_U3PLL_REFCLK_OFFSET 4U +#define DRDU3_U3PLL_SS_LOCK BIT(3U) +#define DRDU3_U3PLL_SEQ_START BIT(2U) +#define DRDU3_U3SSPLL_SUSPEND_EN BIT(1U) +#define DRDU3_U3PLL_RESETB BIT(0U) + +#define DRDU3_STRAP_CTRL 0x28U +#define BDC_USB_STP_SPD_MASK 0x7U +#define BDC_USB_STP_SPD_OFFSET 0U +#define BDC_USB_STP_SPD_SS 0x0U +#define BDC_USB_STP_SPD_HS 0x2U + +#define DRDU3_PWR_CTRL 0x2cU +#define DRDU3_U2PHY_DFE_SWITCH_PWROKIN BIT(12U) +#define DRDU3_U2PHY_DFE_SWITCH_PWRONIN BIT(11U) +#define DRDU3_PWR_CTRL_OVERRIDE_I_R 4U + +#define DRDU3_SOFT_RESET_CTRL 0x30U +#define DRDU3_XHC_AXI_SOFT_RST_N BIT(1U) +#define DRDU3_BDC_AXI_SOFT_RST_N BIT(0U) + +#define DRDU3_PHY_PWR_CTRL 0x3cU +#define DRDU3_DISABLE_USB30_P0 BIT(2U) +#define DRDU3_DISABLE_EUSB_P1 BIT(1U) +#define DRDU3_DISABLE_EUSB_P0 BIT(0U) + +#define PLL_REFCLK_PAD 0x0U +#define PLL_REFCLK_25MHZ 0x1U +#define PLL_REFCLK_96MHZ 0x2U +#define PLL_REFCLK_INTERNAL 0x3U +/* USB PLL lock time out for 10 ms */ +#define PLL_LOCK_RETRY_COUNT 10000U + + +#define U2PLL_NDIV_INT_VAL 0x13U +#define U2PLL_NDIV_FRAC_VAL 0x1005U +#define U2PLL_PDIV_VAL 0x1U +/* + * Using external FSM + * BIT-3:2: device mode; mode is not effect + * BIT-1: soft reset active low + */ +#define U2PHY_PCTL_VAL 0x0003U +/* Non-driving signal low */ +#define U2PHY_PCTL_NON_DRV_LOW 0x0002U +#define U3PHY_PCTL_VAL 0x0006U + +#define MAX_NR_PORTS 3U + +#define USB3H_DRDU2_PHY 1U +#define DRDU3_PHY 2U + +#define USB_HOST_MODE 1U +#define USB_DEV_MODE 2U + +#define USB3SS_PORT 0U +#define DRDU2_PORT 1U +#define USB3HS_PORT 2U + +#define DRD3SS_PORT 0U +#define DRD3HS_PORT 1U + +#define SR_USB_PHY_COUNT 2U + +#define DRDU3_PIPE_CTRL 0x68500000U +#define DRDU3H_XHC_REGS_CPLIVER 0x68501000U +#define USB3H_PIPE_CTRL 0x68510000U +#define DRD2U3H_XHC_REGS_CPLIVER 0x68511000U +#define DRDU2_U2PLL_NDIV_FRAC 0x68520000U + +#define AXI_DEBUG_CTRL 0x68500038U +#define AXI_DBG_CTRL_SSPHY_DRD_MODE_DISABLE BIT(12U) + +#define USB3H_DEBUG_CTRL 0x68510034U +#define USB3H_DBG_CTRL_SSPHY_DRD_MODE_DISABLE BIT(7U) + +typedef struct _usb_phy_port usb_phy_port_t; + +typedef struct { + uint32_t drdu2reg; + uint32_t usb3hreg; + uint32_t drdu3reg; + uint32_t phy_id; + uint32_t ports_enabled; + uint32_t initialized; + usb_phy_port_t *phy_port; +} usb_phy_t; + +struct _usb_phy_port { + uint32_t port_id; + uint32_t mode; + uint32_t enabled; + usb_phy_t *p; +}; + +struct u2_phy_ext_fsm { + uint32_t pll_ctrl_reg; + uint32_t phy_ctrl_reg; + uint32_t phy_iddq; + uint32_t pwr_ctrl_reg; + uint32_t pwr_okin; + uint32_t pwr_onin; +}; + +#endif /* USB_PHY_H */ diff --git a/plat/brcm/board/stingray/platform.mk b/plat/brcm/board/stingray/platform.mk new file mode 100644 index 0000000..aa2fe86 --- /dev/null +++ b/plat/brcm/board/stingray/platform.mk @@ -0,0 +1,304 @@ +# +# Copyright (c) 2019-2021, Broadcom +# +# SPDX-License-Identifier: BSD-3-Clause +# + +# Set the toc_flags to 1 for 100% speed operation +# Set the toc_flags to 2 for 50% speed operation +# Set the toc_flags to 3 for 25% speed operation +# Set the toc_flags bit 3 to indicate ignore the fip in UEFI copy mode +PLAT_TOC_FLAGS := 0x0 + +# Set the IHOST_PLL_FREQ to, +# 1 for full speed +# 2 for 50% speed +# 3 for 25% speed +# 0 for bypass +$(eval $(call add_define_val,IHOST_PLL_FREQ,1)) + +# Enable workaround for ERRATA_A72_859971 +ERRATA_A72_859971 := 1 + +# Cache Coherency Interconnect Driver needed +DRIVER_CC_ENABLE := 1 +$(eval $(call add_define,DRIVER_CC_ENABLE)) + +# Enable to erase eMMC +INCLUDE_EMMC_DRIVER_ERASE_CODE := 0 + +ifeq (${INCLUDE_EMMC_DRIVER_ERASE_CODE},1) +$(eval $(call add_define,INCLUDE_EMMC_DRIVER_ERASE_CODE)) +endif + +# BL31 is in DRAM +ARM_BL31_IN_DRAM := 1 + +ifneq (${USE_EMULATOR},yes) +STINGRAY_EMULATION_SETUP := 0 +ifeq (${FASTBOOT_TYPE},) +override FASTBOOT_TYPE := 0 +endif +USE_PAXB := yes +USE_PAXC := yes +USE_CHIMP := yes +endif + +USE_CRMU_SRAM := yes + +# Disable FS4 clocks - they can be reenabled when needed by linux +FS4_DISABLE_CLOCK := yes + +# Enable error logging by default for Stingray +BCM_ELOG := yes + +# Enable FRU support by default for Stingray +ifeq (${USE_FRU},) +USE_FRU := no +endif + +# Use single cluster +ifeq (${USE_SINGLE_CLUSTER},yes) +$(info Using Single Cluster) +$(eval $(call add_define,USE_SINGLE_CLUSTER)) +endif + +# Use DDR +ifeq (${USE_DDR},yes) +$(info Using DDR) +$(eval $(call add_define,USE_DDR)) +endif + +ifeq (${BOARD_CFG},) +BOARD_CFG := bcm958742t +endif + +# Use USB +ifeq (${USE_USB},yes) +$(info Using USB) +$(eval $(call add_define,USE_USB)) +endif + +# Use PAXB +ifeq (${USE_PAXB},yes) +$(info Using PAXB) +$(eval $(call add_define,USE_PAXB)) +endif + +# Use FS4 +ifeq (${USE_FS4},yes) +$(info Using FS4) +$(eval $(call add_define,USE_FS4)) +endif + +# Use FS6 +ifeq (${USE_FS6},yes) +$(info Using FS6) +$(eval $(call add_define,USE_FS6)) +endif + +# Disable FS4 clock +ifeq (${FS4_DISABLE_CLOCK},yes) +$(info Using FS4_DISABLE_CLOCK) +$(eval $(call add_define,FS4_DISABLE_CLOCK)) +endif + +ifneq (${NCSI_IO_DRIVE_STRENGTH_MA},) +$(info Using NCSI_IO_DRIVE_STRENGTH_MA) +$(eval $(call add_define,NCSI_IO_DRIVE_STRENGTH_MA)) +endif + +# Use NAND +ifeq (${USE_NAND},$(filter yes, ${USE_NAND})) +$(info Using NAND) +$(eval $(call add_define,USE_NAND)) +endif + +# Enable Broadcom error logging support +ifeq (${BCM_ELOG},yes) +$(info Using BCM_ELOG) +$(eval $(call add_define,BCM_ELOG)) +endif + +# BL31 build for standalone mode +ifeq (${STANDALONE_BL31},yes) +RESET_TO_BL31 := 1 +$(info Using RESET_TO_BL31) +endif + +# BL31 force full frequency for all CPUs +ifeq (${BL31_FORCE_CPU_FULL_FREQ},yes) +$(info Using BL31_FORCE_CPU_FULL_FREQ) +$(eval $(call add_define,BL31_FORCE_CPU_FULL_FREQ)) +endif + +# Enable non-secure accesses to CCN registers +ifeq (${BL31_CCN_NONSECURE},yes) +$(info Using BL31_CCN_NONSECURE) +$(eval $(call add_define,BL31_CCN_NONSECURE)) +endif + +# Use ChiMP +ifeq (${USE_CHIMP},yes) +$(info Using ChiMP) +$(eval $(call add_define,USE_CHIMP)) +endif + +# Use PAXC +ifeq (${USE_PAXC},yes) +$(info Using PAXC) +$(eval $(call add_define,USE_PAXC)) +ifeq (${CHIMPFW_USE_SIDELOAD},yes) +$(info Using ChiMP FW sideload) +$(eval $(call add_define,CHIMPFW_USE_SIDELOAD)) +endif +$(eval $(call add_define,FASTBOOT_TYPE)) +$(eval $(call add_define,CHIMP_FB1_ENTRY)) +endif + +ifeq (${DEFAULT_SWREG_CONFIG}, 1) +$(eval $(call add_define,DEFAULT_SWREG_CONFIG)) +endif + +ifeq (${CHIMP_ALWAYS_NEEDS_QSPI},yes) +$(eval $(call add_define,CHIMP_ALWAYS_NEEDS_QSPI)) +endif + +# For testing purposes, use memsys stubs. Remove once memsys is fully tested. +USE_MEMSYS_STUBS := yes + +# Default, use BL1_RW area +ifneq (${BL2_USE_BL1_RW},no) +$(eval $(call add_define,USE_BL1_RW)) +endif + +# Default soft reset is L3 +$(eval $(call add_define,CONFIG_SOFT_RESET_L3)) + +# Enable Chip OTP driver +DRIVER_OCOTP_ENABLE := 1 + +ifneq (${WARMBOOT_DDR_S3_SUPPORT},) +DRIVER_SPI_ENABLE := 1 +endif + +include plat/brcm/board/common/board_common.mk + +SOC_DIR := brcm/board/stingray + +PLAT_INCLUDES += -Iplat/${SOC_DIR}/include/ \ + -Iinclude/plat/brcm/common/ \ + -Iplat/brcm/common/ + +PLAT_BL_COMMON_SOURCES += lib/cpus/aarch64/cortex_a72.S \ + plat/${SOC_DIR}/aarch64/plat_helpers.S \ + drivers/ti/uart/aarch64/16550_console.S \ + plat/${SOC_DIR}/src/tz_sec.c \ + drivers/arm/tzc/tzc400.c \ + plat/${SOC_DIR}/driver/plat_emmc.c \ + plat/${SOC_DIR}/src/topology.c \ + drivers/brcm/mdio/mdio.c + +ifeq (${USE_CHIMP},yes) +PLAT_BL_COMMON_SOURCES += drivers/brcm/chimp.c +endif + +ifeq (${USE_USB},yes) +PLAT_BL_COMMON_SOURCES += plat/${SOC_DIR}/driver/usb.c \ + plat/${SOC_DIR}/driver/usb_phy.c +endif + +BL2_SOURCES += plat/${SOC_DIR}/driver/ihost_pll_config.c \ + plat/${SOC_DIR}/src/bl2_setup.c \ + plat/${SOC_DIR}/driver/swreg.c + +ifeq (${USE_DDR},yes) +PLAT_INCLUDES += -Iplat/${SOC_DIR}/driver/ddr/soc/include +else +PLAT_INCLUDES += -Iplat/${SOC_DIR}/driver/ext_sram_init +BL2_SOURCES += plat/${SOC_DIR}/driver/ext_sram_init/ext_sram_init.c +endif + +# Include GICv3 driver files +include drivers/arm/gic/v3/gicv3.mk + +BRCM_GIC_SOURCES := ${GICV3_SOURCES} \ + plat/common/plat_gicv3.c \ + plat/brcm/common/brcm_gicv3.c + +BL31_SOURCES += \ + drivers/arm/ccn/ccn.c \ + plat/brcm/board/common/timer_sync.c \ + plat/brcm/common/brcm_ccn.c \ + plat/common/plat_psci_common.c \ + plat/${SOC_DIR}/driver/ihost_pll_config.c \ + plat/${SOC_DIR}/src/bl31_setup.c \ + plat/${SOC_DIR}/src/fsx.c \ + plat/${SOC_DIR}/src/iommu.c \ + plat/${SOC_DIR}/src/sdio.c \ + ${BRCM_GIC_SOURCES} + +ifneq (${NCSI_IO_DRIVE_STRENGTH_MA},) +BL31_SOURCES += plat/${SOC_DIR}/src/ncsi.c +endif + +ifeq (${USE_PAXB},yes) +BL31_SOURCES += plat/${SOC_DIR}/src/paxb.c +BL31_SOURCES += plat/${SOC_DIR}/src/sr_paxb_phy.c +endif + +ifeq (${USE_PAXC},yes) +BL31_SOURCES += plat/${SOC_DIR}/src/paxc.c +endif + +ifdef SCP_BL2 +PLAT_INCLUDES += -Iplat/brcm/common/ + +BL2_SOURCES += plat/brcm/common/brcm_mhu.c \ + plat/brcm/common/brcm_scpi.c \ + plat/${SOC_DIR}/src/scp_utils.c \ + plat/${SOC_DIR}/src/scp_cmd.c \ + drivers/brcm/scp.c + +BL31_SOURCES += plat/brcm/common/brcm_mhu.c \ + plat/brcm/common/brcm_scpi.c \ + plat/${SOC_DIR}/src/brcm_pm_ops.c +else +BL31_SOURCES += plat/${SOC_DIR}/src/ihost_pm.c \ + plat/${SOC_DIR}/src/pm.c +endif + +ifeq (${ELOG_SUPPORT},1) +ifeq (${ELOG_STORE_MEDIA},DDR) +BL2_SOURCES += plat/brcm/board/common/bcm_elog_ddr.c +endif +endif + +ifeq (${BL31_BOOT_PRELOADED_SCP}, 1) +ifdef SCP_BL2 +SCP_CFG_DIR=$(dir ${SCP_BL2}) +PLAT_INCLUDES += -I${SCP_CFG_DIR} +endif +PLAT_INCLUDES += -Iplat/brcm/common/ + +# By default use OPTEE Assigned memory +PRELOADED_SCP_BASE ?= 0x8E000000 +PRELOADED_SCP_SIZE ?= 0x10000 +$(eval $(call add_define,PRELOADED_SCP_BASE)) +$(eval $(call add_define,PRELOADED_SCP_SIZE)) +$(eval $(call add_define,BL31_BOOT_PRELOADED_SCP)) +BL31_SOURCES += plat/${SOC_DIR}/src/scp_utils.c \ + plat/${SOC_DIR}/src/scp_cmd.c \ + drivers/brcm/scp.c +endif + +# Do not execute the startup code on warm reset. +PROGRAMMABLE_RESET_ADDRESS := 1 + +# Nitro FW, config and Crash log uses secure DDR memory +# Inaddition to above, Nitro master and slave is also secure +ifneq ($(NITRO_SECURE_ACCESS),) +$(eval $(call add_define,NITRO_SECURE_ACCESS)) +$(eval $(call add_define,DDR_NITRO_SECURE_REGION_START)) +$(eval $(call add_define,DDR_NITRO_SECURE_REGION_END)) +endif diff --git a/plat/brcm/board/stingray/src/bl2_setup.c b/plat/brcm/board/stingray/src/bl2_setup.c new file mode 100644 index 0000000..b2c8aec --- /dev/null +++ b/plat/brcm/board/stingray/src/bl2_setup.c @@ -0,0 +1,743 @@ +/* + * 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 <emmc_api.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 +} diff --git a/plat/brcm/board/stingray/src/bl31_setup.c b/plat/brcm/board/stingray/src/bl31_setup.c new file mode 100644 index 0000000..04df6a0 --- /dev/null +++ b/plat/brcm/board/stingray/src/bl31_setup.c @@ -0,0 +1,1071 @@ +/* + * Copyright (c) 2015 - 2021, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <errno.h> + +#include <common/bl_common.h> +#include <common/debug.h> +#include <cortex_a72.h> +#include <drivers/arm/sp805.h> +#include <drivers/console.h> +#include <drivers/delay_timer.h> +#include <drivers/ti/uart/uart_16550.h> +#include <lib/mmio.h> +#include <lib/utils_def.h> +#include <plat/common/common_def.h> +#include <plat/common/platform.h> + +#include <bl33_info.h> +#include <chimp.h> +#include <cmn_plat_util.h> +#include <dmu.h> +#include <fsx.h> +#include <iommu.h> +#include <ncsi.h> +#include <paxb.h> +#include <paxc.h> +#include <platform_def.h> +#ifdef USE_USB +#include <platform_usb.h> +#endif +#include <sdio.h> +#include <sr_utils.h> +#include <timer_sync.h> + +/******************************************************************************* + * Perform any BL3-1 platform setup common to ARM standard platforms + ******************************************************************************/ + +static void brcm_stingray_gain_qspi_control(void) +{ + if (boot_source_get() != BOOT_SOURCE_QSPI) { + if (bcm_chimp_is_nic_mode() && + (!bcm_chimp_handshake_done())) { + /* + * Last chance to wait for ChiMP firmware to report + * "I am done" before grabbing the QSPI + */ + WARN("ChiMP still not booted\n"); +#ifndef CHIMP_ALWAYS_NEEDS_QSPI + WARN("ChiMP is given the last chance to boot (%d s)\n", + CHIMP_HANDSHAKE_TIMEOUT_MS / 1000); + + if (!bcm_chimp_wait_handshake()) { + ERROR("ChiMP failed to boot\n"); + } else { + INFO("ChiMP booted successfully\n"); + } +#endif + } + +#ifndef CHIMP_ALWAYS_NEEDS_QSPI + INFO("AP grabs QSPI\n"); + /* + * For QSPI boot sbl/bl1 has already taken care. + * For other boot sources QSPI needs to be muxed to + * AP for exclusive use + */ + brcm_stingray_set_qspi_mux(1); + INFO("AP (bl31) gained control over QSPI\n"); +#endif + } +} + +static void brcm_stingray_dma_pl330_init(void) +{ + unsigned int val; + + VERBOSE("dma pl330 init start\n"); + + /* Set DMAC boot_manager_ns = 0x1 */ + VERBOSE(" - configure boot security state\n"); + mmio_setbits_32(DMAC_M0_IDM_IO_CONTROL_DIRECT, BOOT_MANAGER_NS); + /* Set boot_peripheral_ns[n:0] = 0xffffffff */ + mmio_write_32(ICFG_DMAC_CONFIG_2, BOOT_PERIPHERAL_NS); + /* Set boot_irq_ns[n:0] = 0x0000ffff */ + mmio_write_32(ICFG_DMAC_CONFIG_3, BOOT_IRQ_NS); + + /* Set DMAC stream_id */ + VERBOSE(" - configure stream_id = 0x6000\n"); + val = (DMAC_STREAM_ID << DMAC_SID_SHIFT); + mmio_write_32(ICFG_DMAC_SID_ARADDR_CONTROL, val); + mmio_write_32(ICFG_DMAC_SID_AWADDR_CONTROL, val); + + /* Reset DMAC */ + VERBOSE(" - reset dma pl330\n"); + + mmio_setbits_32(DMAC_M0_IDM_RESET_CONTROL, 0x1); + udelay(500); + + mmio_clrbits_32(DMAC_M0_IDM_RESET_CONTROL, 0x1); + udelay(500); + + INFO("dma pl330 init done\n"); +} + +static void brcm_stingray_spi_pl022_init(uintptr_t idm_reset_control) +{ + VERBOSE("spi pl022 init start\n"); + + /* Reset APB SPI bridge */ + VERBOSE(" - reset apb spi bridge\n"); + mmio_setbits_32(idm_reset_control, 0x1); + udelay(500); + + mmio_clrbits_32(idm_reset_control, 0x1); + udelay(500); + + INFO("spi pl022 init done\n"); +} + +#define CDRU_SATA_RESET_N \ + BIT(CDRU_MISC_RESET_CONTROL__CDRU_SATA_RESET_N_R) +#define CDRU_MISC_CLK_SATA \ + BIT(CDRU_MISC_CLK_ENABLE_CONTROL__CDRU_SATA_CLK_EN_R) +#define CCN_CONFIG_CLK_ENABLE (1 << 2) +#define MMU_CONFIG_CLK_ENABLE (0x3F << 16) + +#define SATA_SATA_TOP_CTRL_BUS_CTRL (SATA_BASE + 0x2044) +#define DMA_BIT_CTRL_MASK 0x003 +#define DMA_DESCR_ENDIAN_CTRL (DMA_BIT_CTRL_MASK << 0x002) +#define DMA_DATA_ENDIAN_CTRL (DMA_BIT_CTRL_MASK << 0x004) + +#define SATA_PORT_SATA3_PCB_REG8 (SATA_BASE + 0x2320) +#define SATA_PORT_SATA3_PCB_REG11 (SATA_BASE + 0x232c) +#define SATA_PORT_SATA3_PCB_BLOCK_ADDR (SATA_BASE + 0x233c) + +#define SATA3_AFE_TXRX_ACTRL 0x1d0 +/* TXDriver swing setting is 800mV */ +#define DFS_SWINGNOPE_VALUE (0x0 << 6) +#define DFS_SWINGNOPE_MASK (0x3 << 6) + +#define DFS_SWINGPE_VALUE (0x1 << 4) +#define DFS_SWINGPE_MASK (0x3 << 4) + +#define DFS_INJSTRENGTH_VALUE (0x0 << 4) +#define DFS_INJSTRENGTH_MASK (0x3 << 4) + +#define DFS_INJEN (0x1 << 3) + +#define SATA_CORE_MEM_CTRL (SATA_BASE + 0x3a08) +#define SATA_CORE_MEM_CTRL_ISO BIT(0) +#define SATA_CORE_MEM_CTRL_ARRPOWEROKIN BIT(1) +#define SATA_CORE_MEM_CTRL_ARRPOWERONIN BIT(2) +#define SATA_CORE_MEM_CTRL_POWEROKIN BIT(3) +#define SATA_CORE_MEM_CTRL_POWERONIN BIT(4) + +#define SATA0_IDM_RESET_CONTROL (SATA_BASE + 0x500800) +#define SATA_APBT0_IDM_IO_CONTROL_DIRECT (SATA_BASE + 0x51a408) +#define IO_CONTROL_DIRECT_CLK_ENABLE BIT(0) +#define SATA_APBT0_IDM_RESET_CONTROL (SATA_BASE + 0x51a800) +#define IDM_RESET_CONTROL_RESET BIT(0) + +#define NIC400_SATA_NOC_SECURITY1 0x6830000c +#define SATA_NOC_SECURITY1_FIELD 0xf +#define NIC400_SATA_NOC_SECURITY2 0x68300010 +#define SATA_NOC_SECURITY2_FIELD 0xf +#define NIC400_SATA_NOC_SECURITY3 0x68300014 +#define SATA_NOC_SECURITY3_FIELD 0x1 +#define NIC400_SATA_NOC_SECURITY4 0x68300018 +#define SATA_NOC_SECURITY4_FIELD 0x1 +#define NIC400_SATA_NOC_SECURITY5 0x6830001c +#define SATA_NOC_SECURITY5_FIELD 0xf +#define NIC400_SATA_NOC_SECURITY6 0x68300020 +#define SATA_NOC_SECURITY6_FIELD 0x1 +#define NIC400_SATA_NOC_SECURITY7 0x68300024 +#define SATA_NOC_SECURITY7_FIELD 0xf +#define NIC400_SATA_NOC_SECURITY8 0x68300028 +#define SATA_NOC_SECURITY8_FIELD 0xf +#define NIC400_SATA_NOC_SECURITY9 0x6830002c +#define SATA_NOC_SECURITY9_FIELD 0x1 + +#define SATA_APBT_IDM_PORT_REG(port, reg) \ + (((port/4) << 12) + reg) + +#define SATA_IDM_PORT_REG(port, reg) ((port << 12) + reg) + +#define SATA_PORT_REG(port, reg) \ + (((port%4) << 16) + ((port/4) << 20) + reg) + +#define MAX_SATA_PORTS 8 +#define USE_SATA_PORTS 8 + +#ifdef USE_SATA +static const uint8_t sr_b0_sata_port[MAX_SATA_PORTS] = { + 0, 1, 2, 3, 4, 5, 6, 7 +}; + +static uint32_t brcm_stingray_get_sata_port(unsigned int port) +{ + return sr_b0_sata_port[port]; +} + +static void brcm_stingray_sata_init(void) +{ + unsigned int port = 0; + uint32_t sata_port; + + mmio_setbits_32(CDRU_MISC_CLK_ENABLE_CONTROL, + CDRU_MISC_CLK_SATA); + + mmio_clrbits_32(CDRU_MISC_RESET_CONTROL, CDRU_SATA_RESET_N); + mmio_setbits_32(CDRU_MISC_RESET_CONTROL, CDRU_SATA_RESET_N); + + for (port = 0; port < USE_SATA_PORTS; port++) { + + sata_port = brcm_stingray_get_sata_port(port); + mmio_write_32(SATA_APBT_IDM_PORT_REG(sata_port, + SATA_APBT0_IDM_RESET_CONTROL), + 0x0); + mmio_setbits_32(SATA_APBT_IDM_PORT_REG(sata_port, + SATA_APBT0_IDM_IO_CONTROL_DIRECT), + IO_CONTROL_DIRECT_CLK_ENABLE); + mmio_write_32(SATA_IDM_PORT_REG(sata_port, + SATA0_IDM_RESET_CONTROL), + 0x0); + + mmio_setbits_32(SATA_PORT_REG(sata_port, SATA_CORE_MEM_CTRL), + SATA_CORE_MEM_CTRL_ARRPOWERONIN); + mmio_setbits_32(SATA_PORT_REG(sata_port, SATA_CORE_MEM_CTRL), + SATA_CORE_MEM_CTRL_ARRPOWEROKIN); + mmio_setbits_32(SATA_PORT_REG(sata_port, SATA_CORE_MEM_CTRL), + SATA_CORE_MEM_CTRL_POWERONIN); + mmio_setbits_32(SATA_PORT_REG(sata_port, SATA_CORE_MEM_CTRL), + SATA_CORE_MEM_CTRL_POWEROKIN); + mmio_clrbits_32(SATA_PORT_REG(sata_port, SATA_CORE_MEM_CTRL), + SATA_CORE_MEM_CTRL_ISO); + + mmio_clrbits_32(SATA_PORT_REG(sata_port, + SATA_SATA_TOP_CTRL_BUS_CTRL), + (DMA_DESCR_ENDIAN_CTRL | DMA_DATA_ENDIAN_CTRL)); + } + + mmio_setbits_32(NIC400_SATA_NOC_SECURITY1, SATA_NOC_SECURITY1_FIELD); + mmio_setbits_32(NIC400_SATA_NOC_SECURITY2, SATA_NOC_SECURITY2_FIELD); + mmio_setbits_32(NIC400_SATA_NOC_SECURITY3, SATA_NOC_SECURITY3_FIELD); + mmio_setbits_32(NIC400_SATA_NOC_SECURITY4, SATA_NOC_SECURITY4_FIELD); + mmio_setbits_32(NIC400_SATA_NOC_SECURITY5, SATA_NOC_SECURITY5_FIELD); + mmio_setbits_32(NIC400_SATA_NOC_SECURITY6, SATA_NOC_SECURITY6_FIELD); + mmio_setbits_32(NIC400_SATA_NOC_SECURITY7, SATA_NOC_SECURITY7_FIELD); + mmio_setbits_32(NIC400_SATA_NOC_SECURITY8, SATA_NOC_SECURITY8_FIELD); + mmio_setbits_32(NIC400_SATA_NOC_SECURITY9, SATA_NOC_SECURITY9_FIELD); + + INFO("sata init done\n"); +} +#else +static void poweroff_sata_pll(void) +{ + /* + * SATA subsystem is clocked by LCPLL0 which is enabled by + * default by bootrom. Poweroff the PLL if SATA is not used + */ + + /* enable isolation */ + mmio_setbits_32(CRMU_AON_CTRL1, + BIT(CRMU_AON_CTRL1__LCPLL0_ISO_IN)); + + /* Power off the SATA PLL/LDO */ + mmio_clrbits_32(CRMU_AON_CTRL1, + (BIT(CRMU_AON_CTRL1__LCPLL0_PWRON_LDO) | + BIT(CRMU_AON_CTRL1__LCPLL0_PWR_ON))); +} +#endif + +#ifdef USE_AMAC +#ifdef EMULATION_SETUP +#define ICFG_AMAC_STRAP_CONFIG (HSLS_ICFG_REGS_BASE + 0xa5c) +#define ICFG_AMAC_STRAP_DLL_BYPASS (1 << 2) +#endif +#define ICFG_AMAC_MAC_CTRL_REG (HSLS_ICFG_REGS_BASE + 0xa6c) +#define ICFG_AMAC_MAC_FULL_DUPLEX (1 << 1) +#define ICFG_AMAC_RGMII_PHY_CONFIG (HSLS_ICFG_REGS_BASE + 0xa60) +#define ICFG_AMAC_SID_CONTROL (HSLS_ICFG_REGS_BASE + 0xb10) +#define ICFG_AMAC_SID_SHIFT 5 +#define ICFG_AMAC_SID_AWADDR_OFFSET 0x0 +#define ICFG_AMAC_SID_ARADDR_OFFSET 0x4 +#define AMAC_RPHY_1000_DATARATE (1 << 20) +#define AMAC_RPHY_FULL_DUPLEX (1 << 5) +#define AMAC_RPHY_SPEED_OFFSET 2 +#define AMAC_RPHY_SPEED_MASK (7 << AMAC_RPHY_SPEED_OFFSET) +#define AMAC_RPHY_1G_SPEED (2 << AMAC_RPHY_SPEED_OFFSET) +#define ICFG_AMAC_MEM_PWR_CTRL (HSLS_ICFG_REGS_BASE + 0xa68) +#define AMAC_ISO BIT(9) +#define AMAC_STDBY BIT(8) +#define AMAC_ARRPOWEROKIN BIT(7) +#define AMAC_ARRPOWERONIN BIT(6) +#define AMAC_POWEROKIN BIT(5) +#define AMAC_POWERONIN BIT(4) + +#define AMAC_IDM0_IO_CONTROL_DIRECT (HSLS_IDM_REGS_BASE + 0x4408) +#define AMAC_IDM0_ARCACHE_OFFSET 16 +#define AMAC_IDM0_AWCACHE_OFFSET 7 +#define AMAC_IDM0_ARCACHE_MASK (0xF << AMAC_IDM0_ARCACHE_OFFSET) +#define AMAC_IDM0_AWCACHE_MASK (0xF << AMAC_IDM0_AWCACHE_OFFSET) +/* ARCACHE - AWCACHE is 0xB7 for write-back no allocate */ +#define AMAC_IDM0_ARCACHE_VAL (0xb << AMAC_IDM0_ARCACHE_OFFSET) +#define AMAC_IDM0_AWCACHE_VAL (0x7 << AMAC_IDM0_AWCACHE_OFFSET) + +static void brcm_stingray_amac_init(void) +{ + unsigned int val; + uintptr_t icfg_amac_sid = ICFG_AMAC_SID_CONTROL; + + VERBOSE("amac init start\n"); + + val = SR_SID_VAL(0x3, 0x0, 0x4) << ICFG_AMAC_SID_SHIFT; + mmio_write_32(icfg_amac_sid + ICFG_AMAC_SID_AWADDR_OFFSET, val); + mmio_write_32(icfg_amac_sid + ICFG_AMAC_SID_ARADDR_OFFSET, val); + + mmio_setbits_32(ICFG_AMAC_MEM_PWR_CTRL, AMAC_ARRPOWEROKIN); + mmio_setbits_32(ICFG_AMAC_MEM_PWR_CTRL, AMAC_ARRPOWERONIN); + mmio_setbits_32(ICFG_AMAC_MEM_PWR_CTRL, AMAC_POWEROKIN); + mmio_setbits_32(ICFG_AMAC_MEM_PWR_CTRL, AMAC_POWERONIN); + mmio_clrbits_32(ICFG_AMAC_MEM_PWR_CTRL, AMAC_ISO); + mmio_write_32(APBR_IDM_RESET_CONTROL, 0x0); + mmio_clrsetbits_32(ICFG_AMAC_RGMII_PHY_CONFIG, AMAC_RPHY_SPEED_MASK, + AMAC_RPHY_1G_SPEED); /*1 Gbps line rate*/ + /* 1000 datarate set */ + mmio_setbits_32(ICFG_AMAC_RGMII_PHY_CONFIG, AMAC_RPHY_1000_DATARATE); + /* full duplex */ + mmio_setbits_32(ICFG_AMAC_RGMII_PHY_CONFIG, AMAC_RPHY_FULL_DUPLEX); +#ifdef EMULATION_SETUP + /* DLL bypass */ + mmio_setbits_32(ICFG_AMAC_STRAP_CONFIG, ICFG_AMAC_STRAP_DLL_BYPASS); +#endif + /* serdes full duplex */ + mmio_setbits_32(ICFG_AMAC_MAC_CTRL_REG, ICFG_AMAC_MAC_FULL_DUPLEX); + mmio_clrsetbits_32(AMAC_IDM0_IO_CONTROL_DIRECT, AMAC_IDM0_ARCACHE_MASK, + AMAC_IDM0_ARCACHE_VAL); + mmio_clrsetbits_32(AMAC_IDM0_IO_CONTROL_DIRECT, AMAC_IDM0_AWCACHE_MASK, + AMAC_IDM0_AWCACHE_VAL); + INFO("amac init done\n"); +} +#endif /* USE_AMAC */ + +static void brcm_stingray_pka_meminit(void) +{ + uintptr_t icfg_mem_ctrl = ICFG_PKA_MEM_PWR_CTRL; + + VERBOSE("pka meminit start\n"); + + VERBOSE(" - arrpoweron\n"); + mmio_setbits_32(icfg_mem_ctrl, + ICFG_PKA_MEM_PWR_CTRL__ARRPOWERONIN); + while (!(mmio_read_32(icfg_mem_ctrl) & + ICFG_PKA_MEM_PWR_CTRL__ARRPOWERONOUT)) + ; + + VERBOSE(" - arrpowerok\n"); + mmio_setbits_32(icfg_mem_ctrl, + ICFG_PKA_MEM_PWR_CTRL__ARRPOWEROKIN); + while (!(mmio_read_32(icfg_mem_ctrl) & + ICFG_PKA_MEM_PWR_CTRL__ARRPOWEROKOUT)) + ; + + VERBOSE(" - poweron\n"); + mmio_setbits_32(icfg_mem_ctrl, + ICFG_PKA_MEM_PWR_CTRL__POWERONIN); + while (!(mmio_read_32(icfg_mem_ctrl) & + ICFG_PKA_MEM_PWR_CTRL__POWERONOUT)) + ; + + VERBOSE(" - powerok\n"); + mmio_setbits_32(icfg_mem_ctrl, + ICFG_PKA_MEM_PWR_CTRL__POWEROKIN); + while (!(mmio_read_32(icfg_mem_ctrl) & + ICFG_PKA_MEM_PWR_CTRL__POWEROKOUT)) + ; + + /* Wait sometime */ + mdelay(1); + + VERBOSE(" - remove isolation\n"); + mmio_clrbits_32(icfg_mem_ctrl, ICFG_PKA_MEM_PWR_CTRL__ISO); + + INFO("pka meminit done\n"); +} + +static void brcm_stingray_smmu_init(void) +{ + unsigned int val; + uintptr_t smmu_base = SMMU_BASE; + + VERBOSE("smmu init start\n"); + + /* Configure SCR0 */ + VERBOSE(" - configure scr0\n"); + val = mmio_read_32(smmu_base + 0x0); + val |= (0x1 << 12); + mmio_write_32(smmu_base + 0x0, val); + + /* Reserve context banks for secure masters */ + arm_smmu_reserve_secure_cntxt(); + + /* Print configuration */ + VERBOSE(" - scr0=0x%x scr1=0x%x scr2=0x%x\n", + mmio_read_32(smmu_base + 0x0), + mmio_read_32(smmu_base + 0x4), + mmio_read_32(smmu_base + 0x8)); + + VERBOSE(" - idr0=0x%x idr1=0x%x idr2=0x%x\n", + mmio_read_32(smmu_base + 0x20), + mmio_read_32(smmu_base + 0x24), + mmio_read_32(smmu_base + 0x28)); + + VERBOSE(" - idr3=0x%x idr4=0x%x idr5=0x%x\n", + mmio_read_32(smmu_base + 0x2c), + mmio_read_32(smmu_base + 0x30), + mmio_read_32(smmu_base + 0x34)); + + VERBOSE(" - idr6=0x%x idr7=0x%x\n", + mmio_read_32(smmu_base + 0x38), + mmio_read_32(smmu_base + 0x3c)); + + INFO("smmu init done\n"); +} + +static void brcm_stingray_dma_pl330_meminit(void) +{ + uintptr_t icfg_mem_ctrl = ICFG_DMAC_MEM_PWR_CTRL; + + VERBOSE("dmac meminit start\n"); + + VERBOSE(" - arrpoweron\n"); + mmio_setbits_32(icfg_mem_ctrl, + ICFG_DMAC_MEM_PWR_CTRL__ARRPOWERONIN); + while (!(mmio_read_32(icfg_mem_ctrl) & + ICFG_DMAC_MEM_PWR_CTRL__ARRPOWERONOUT)) + ; + + VERBOSE(" - arrpowerok\n"); + mmio_setbits_32(icfg_mem_ctrl, + ICFG_DMAC_MEM_PWR_CTRL__ARRPOWEROKIN); + while (!(mmio_read_32(icfg_mem_ctrl) & + ICFG_DMAC_MEM_PWR_CTRL__ARRPOWEROKOUT)) + ; + + VERBOSE(" - poweron\n"); + mmio_setbits_32(icfg_mem_ctrl, + ICFG_DMAC_MEM_PWR_CTRL__POWERONIN); + while (!(mmio_read_32(icfg_mem_ctrl) & + ICFG_DMAC_MEM_PWR_CTRL__POWERONOUT)) + ; + + VERBOSE(" - powerok\n"); + mmio_setbits_32(icfg_mem_ctrl, + ICFG_DMAC_MEM_PWR_CTRL__POWEROKIN); + while (!(mmio_read_32(icfg_mem_ctrl) & + ICFG_DMAC_MEM_PWR_CTRL__POWEROKOUT)) + ; + + /* Wait sometime */ + mdelay(1); + + VERBOSE(" - remove isolation\n"); + mmio_clrbits_32(icfg_mem_ctrl, ICFG_DMAC_MEM_PWR_CTRL__ISO); + + INFO("dmac meminit done\n"); +} + +/* program the crmu access ranges for allowing non sec access*/ +static void brcm_stingray_crmu_access_init(void) +{ + /* Enable 0x6641c001 - 0x6641c701 for non secure access */ + mmio_write_32(CRMU_CORE_ADDR_RANGE0_LOW, 0x6641c001); + mmio_write_32(CRMU_CORE_ADDR_RANGE0_LOW + 0x4, 0x6641c701); + + /* Enable 0x6641d001 - 0x66424b01 for non secure access */ + mmio_write_32(CRMU_CORE_ADDR_RANGE1_LOW, 0x6641d001); + mmio_write_32(CRMU_CORE_ADDR_RANGE1_LOW + 0x4, 0x66424b01); + + /* Enable 0x66425001 - 0x66425f01 for non secure access */ + mmio_write_32(CRMU_CORE_ADDR_RANGE2_LOW, 0x66425001); + mmio_write_32(CRMU_CORE_ADDR_RANGE2_LOW + 0x4, 0x66425f01); + + INFO("crmu access init done\n"); +} + +static void brcm_stingray_scr_init(void) +{ + unsigned int val; + uintptr_t scr_base = SCR_BASE; + unsigned int clr_mask = SCR_AXCACHE_CONFIG_MASK; + unsigned int set_mask = SCR_TBUX_AXCACHE_CONFIG; + + VERBOSE("scr init start\n"); + + /* awdomain=0x1 and ardomain=0x1 */ + mmio_clrsetbits_32(scr_base + 0x0, clr_mask, set_mask); + val = mmio_read_32(scr_base + 0x0); + VERBOSE(" - set tbu0_config=0x%x\n", val); + + /* awdomain=0x1 and ardomain=0x1 */ + mmio_clrsetbits_32(scr_base + 0x4, clr_mask, set_mask); + val = mmio_read_32(scr_base + 0x4); + VERBOSE(" - set tbu1_config=0x%x\n", val); + + /* awdomain=0x1 and ardomain=0x1 */ + mmio_clrsetbits_32(scr_base + 0x8, clr_mask, set_mask); + val = mmio_read_32(scr_base + 0x8); + VERBOSE(" - set tbu2_config=0x%x\n", val); + + /* awdomain=0x1 and ardomain=0x1 */ + mmio_clrsetbits_32(scr_base + 0xc, clr_mask, set_mask); + val = mmio_read_32(scr_base + 0xc); + VERBOSE(" - set tbu3_config=0x%x\n", val); + + /* awdomain=0x1 and ardomain=0x1 */ + mmio_clrsetbits_32(scr_base + 0x10, clr_mask, set_mask); + val = mmio_read_32(scr_base + 0x10); + VERBOSE(" - set tbu4_config=0x%x\n", val); + + /* awdomain=0x0 and ardomain=0x0 */ + mmio_clrbits_32(scr_base + 0x14, clr_mask); + val = mmio_read_32(scr_base + 0x14); + VERBOSE(" - set gic_config=0x%x\n", val); + + INFO("scr init done\n"); +} + +static void brcm_stingray_hsls_tzpcprot_init(void) +{ + unsigned int val; + uintptr_t tzpcdecprot_base = HSLS_TZPC_BASE; + + VERBOSE("hsls tzpcprot init start\n"); + + /* Treat third-party masters as non-secured */ + val = 0; + val |= BIT(6); /* SDIO1 */ + val |= BIT(5); /* SDIO0 */ + val |= BIT(0); /* AMAC */ + mmio_write_32(tzpcdecprot_base + 0x810, val); + + /* Print TZPC decode status registers */ + VERBOSE(" - tzpcdecprot0=0x%x\n", + mmio_read_32(tzpcdecprot_base + 0x800)); + + VERBOSE(" - tzpcdecprot1=0x%x\n", + mmio_read_32(tzpcdecprot_base + 0x80c)); + + INFO("hsls tzpcprot init done\n"); +} + +#ifdef USE_I2S +#define ICFG_AUDIO_POWER_CTRL (HSLS_ICFG_REGS_BASE + 0xaa8) +#define ICFG_AUDIO_POWER_CTRL__POWERONIN BIT(0) +#define ICFG_AUDIO_POWER_CTRL__POWEROKIN BIT(1) +#define ICFG_AUDIO_POWER_CTRL__ARRPOWERONIN BIT(2) +#define ICFG_AUDIO_POWER_CTRL__ARRPOWEROKIN BIT(3) +#define ICFG_AUDIO_POWER_CTRL__POWERONOUT BIT(4) +#define ICFG_AUDIO_POWER_CTRL__POWEROKOUT BIT(5) +#define ICFG_AUDIO_POWER_CTRL__ARRPOWERONOUT BIT(6) +#define ICFG_AUDIO_POWER_CTRL__ARRPOWEROKOUT BIT(7) +#define ICFG_AUDIO_POWER_CTRL__ISO BIT(8) +#define ICFG_AUDIO_SID_CONTROL (HSLS_ICFG_REGS_BASE + 0xaf8) +#define ICFG_AUDIO_SID_SHIFT 5 +#define ICFG_AUDIO_SID_AWADDR_OFFSET 0x0 +#define ICFG_AUDIO_SID_ARADDR_OFFSET 0x4 + +#define I2S_RESET_CONTROL (HSLS_IDM_REGS_BASE + 0x1800) +#define I2S_IDM_IO_CONTROL (HSLS_IDM_REGS_BASE + 0x1408) +#define IO_CONTROL_CLK_ENABLE BIT(0) +#define I2S_IDM0_ARCACHE_OFFSET 16 +#define I2S_IDM0_AWCACHE_OFFSET 20 +#define I2S_IDM0_ARCACHE_MASK (0xF << I2S_IDM0_ARCACHE_OFFSET) +#define I2S_IDM0_AWCACHE_MASK (0xF << I2S_IDM0_AWCACHE_OFFSET) +/* ARCACHE - AWCACHE is 0x22 Normal Non-cacheable Non-bufferable. */ +#define I2S_IDM0_ARCACHE_VAL (0x2 << I2S_IDM0_ARCACHE_OFFSET) +#define I2S_IDM0_AWCACHE_VAL (0x2 << I2S_IDM0_AWCACHE_OFFSET) + +static void brcm_stingray_audio_init(void) +{ + unsigned int val; + uintptr_t icfg_mem_ctrl = ICFG_AUDIO_POWER_CTRL; + uintptr_t icfg_audio_sid = ICFG_AUDIO_SID_CONTROL; + + mmio_write_32(I2S_RESET_CONTROL, 0x0); + + mmio_clrsetbits_32(I2S_IDM_IO_CONTROL, I2S_IDM0_ARCACHE_MASK, + I2S_IDM0_ARCACHE_VAL); + + mmio_clrsetbits_32(I2S_IDM_IO_CONTROL, I2S_IDM0_AWCACHE_MASK, + I2S_IDM0_AWCACHE_VAL); + + mmio_setbits_32(I2S_IDM_IO_CONTROL, IO_CONTROL_CLK_ENABLE); + + VERBOSE("audio meminit start\n"); + + VERBOSE(" - configure stream_id = 0x6001\n"); + val = SR_SID_VAL(0x3, 0x0, 0x1) << ICFG_AUDIO_SID_SHIFT; + mmio_write_32(icfg_audio_sid + ICFG_AUDIO_SID_AWADDR_OFFSET, val); + mmio_write_32(icfg_audio_sid + ICFG_AUDIO_SID_ARADDR_OFFSET, val); + + VERBOSE(" - arrpoweron\n"); + mmio_setbits_32(icfg_mem_ctrl, + ICFG_AUDIO_POWER_CTRL__ARRPOWERONIN); + while (!(mmio_read_32(icfg_mem_ctrl) & + ICFG_AUDIO_POWER_CTRL__ARRPOWERONOUT)) + ; + + VERBOSE(" - arrpowerok\n"); + mmio_setbits_32(icfg_mem_ctrl, + ICFG_AUDIO_POWER_CTRL__ARRPOWEROKIN); + while (!(mmio_read_32(icfg_mem_ctrl) & + ICFG_AUDIO_POWER_CTRL__ARRPOWEROKOUT)) + ; + + VERBOSE(" - poweron\n"); + mmio_setbits_32(icfg_mem_ctrl, + ICFG_AUDIO_POWER_CTRL__POWERONIN); + while (!(mmio_read_32(icfg_mem_ctrl) & + ICFG_AUDIO_POWER_CTRL__POWERONOUT)) + ; + + VERBOSE(" - powerok\n"); + mmio_setbits_32(icfg_mem_ctrl, + ICFG_AUDIO_POWER_CTRL__POWEROKIN); + while (!(mmio_read_32(icfg_mem_ctrl) & + ICFG_AUDIO_POWER_CTRL__POWEROKOUT)) + ; + + /* Wait sometime */ + mdelay(1); + + VERBOSE(" - remove isolation\n"); + mmio_clrbits_32(icfg_mem_ctrl, ICFG_AUDIO_POWER_CTRL__ISO); + + INFO("audio meminit done\n"); +} +#endif /* USE_I2S */ + +/* + * These defines do not match the regfile but they are renamed in a way such + * that they are much more readible + */ + +#define SCR_GPV_SMMU_NS (SCR_GPV_BASE + 0x28) +#define SCR_GPV_GIC500_NS (SCR_GPV_BASE + 0x34) +#define HSLS_GPV_NOR_S0_NS (HSLS_GPV_BASE + 0x14) +#define HSLS_GPV_IDM1_NS (HSLS_GPV_BASE + 0x18) +#define HSLS_GPV_IDM2_NS (HSLS_GPV_BASE + 0x1c) +#define HSLS_SDIO0_SLAVE_NS (HSLS_GPV_BASE + 0x20) +#define HSLS_SDIO1_SLAVE_NS (HSLS_GPV_BASE + 0x24) +#define HSLS_GPV_APBY_NS (HSLS_GPV_BASE + 0x2c) +#define HSLS_GPV_APBZ_NS (HSLS_GPV_BASE + 0x30) +#define HSLS_GPV_APBX_NS (HSLS_GPV_BASE + 0x34) +#define HSLS_GPV_APBS_NS (HSLS_GPV_BASE + 0x38) +#define HSLS_GPV_QSPI_S0_NS (HSLS_GPV_BASE + 0x68) +#define HSLS_GPV_APBR_NS (HSLS_GPV_BASE + 0x6c) +#define FS4_CRYPTO_GPV_RM_SLAVE_NS (FS4_CRYPTO_GPV_BASE + 0x8) +#define FS4_CRYPTO_GPV_APB_SWITCH_NS (FS4_CRYPTO_GPV_BASE + 0xc) +#define FS4_RAID_GPV_RM_SLAVE_NS (FS4_RAID_GPV_BASE + 0x8) +#define FS4_RAID_GPV_APB_SWITCH_NS (FS4_RAID_GPV_BASE + 0xc) +#define FS4_CRYPTO_IDM_NS (NIC400_FS_NOC_ROOT + 0x1c) +#define FS4_RAID_IDM_NS (NIC400_FS_NOC_ROOT + 0x28) + +#define FS4_CRYPTO_RING_COUNT 32 +#define FS4_CRYPTO_DME_COUNT 10 +#define FS4_CRYPTO_AE_COUNT 10 +#define FS4_CRYPTO_START_STREAM_ID 0x4000 +#define FS4_CRYPTO_MSI_DEVICE_ID 0x4100 + +#define FS4_RAID_RING_COUNT 32 +#define FS4_RAID_DME_COUNT 8 +#define FS4_RAID_AE_COUNT 8 +#define FS4_RAID_START_STREAM_ID 0x4200 +#define FS4_RAID_MSI_DEVICE_ID 0x4300 + +#define FS6_PKI_AXI_SLAVE_NS \ + (NIC400_FS_NOC_ROOT + NIC400_FS_NOC_SECURITY2_OFFSET) + +#define FS6_PKI_AE_DME_APB_NS \ + (NIC400_FS_NOC_ROOT + NIC400_FS_NOC_SECURITY7_OFFSET) +#define FS6_PKI_IDM_IO_CONTROL_DIRECT 0x0 +#define FS6_PKI_IDM_RESET_CONTROL 0x0 +#define FS6_PKI_RING_COUNT 32 +#define FS6_PKI_DME_COUNT 1 +#define FS6_PKI_AE_COUNT 4 +#define FS6_PKI_START_STREAM_ID 0x4000 +#define FS6_PKI_MSI_DEVICE_ID 0x4100 + +static void brcm_stingray_security_init(void) +{ + unsigned int val; + + val = mmio_read_32(SCR_GPV_SMMU_NS); + val |= BIT(0); /* SMMU NS = 1 */ + mmio_write_32(SCR_GPV_SMMU_NS, val); + + val = mmio_read_32(SCR_GPV_GIC500_NS); + val |= BIT(0); /* GIC-500 NS = 1 */ + mmio_write_32(SCR_GPV_GIC500_NS, val); + + val = mmio_read_32(HSLS_GPV_NOR_S0_NS); + val |= BIT(0); /* NOR SLAVE NS = 1 */ + mmio_write_32(HSLS_GPV_NOR_S0_NS, val); + + val = mmio_read_32(HSLS_GPV_IDM1_NS); + val |= BIT(0); /* DMA IDM NS = 1 */ + val |= BIT(1); /* I2S IDM NS = 1 */ + val |= BIT(2); /* AMAC IDM NS = 1 */ + val |= BIT(3); /* SDIO0 IDM NS = 1 */ + val |= BIT(4); /* SDIO1 IDM NS = 1 */ + val |= BIT(5); /* DS_3 IDM NS = 1 */ + mmio_write_32(HSLS_GPV_IDM1_NS, val); + + val = mmio_read_32(HSLS_GPV_IDM2_NS); + val |= BIT(2); /* QSPI IDM NS = 1 */ + val |= BIT(1); /* NOR IDM NS = 1 */ + val |= BIT(0); /* NAND IDM NS = 1 */ + mmio_write_32(HSLS_GPV_IDM2_NS, val); + + val = mmio_read_32(HSLS_GPV_APBY_NS); + val |= BIT(10); /* I2S NS = 1 */ + val |= BIT(4); /* IOPAD NS = 1 */ + val |= 0xf; /* UARTx NS = 1 */ + mmio_write_32(HSLS_GPV_APBY_NS, val); + + val = mmio_read_32(HSLS_GPV_APBZ_NS); + val |= BIT(2); /* RNG NS = 1 */ + mmio_write_32(HSLS_GPV_APBZ_NS, val); + + val = mmio_read_32(HSLS_GPV_APBS_NS); + val |= 0x3; /* SPIx NS = 1 */ + mmio_write_32(HSLS_GPV_APBS_NS, val); + + val = mmio_read_32(HSLS_GPV_APBR_NS); + val |= BIT(7); /* QSPI APB NS = 1 */ + val |= BIT(6); /* NAND APB NS = 1 */ + val |= BIT(5); /* NOR APB NS = 1 */ + val |= BIT(4); /* AMAC APB NS = 1 */ + val |= BIT(1); /* DMA S1 APB NS = 1 */ + mmio_write_32(HSLS_GPV_APBR_NS, val); + + val = mmio_read_32(HSLS_SDIO0_SLAVE_NS); + val |= BIT(0); /* SDIO0 NS = 1 */ + mmio_write_32(HSLS_SDIO0_SLAVE_NS, val); + + val = mmio_read_32(HSLS_SDIO1_SLAVE_NS); + val |= BIT(0); /* SDIO1 NS = 1 */ + mmio_write_32(HSLS_SDIO1_SLAVE_NS, val); + + val = mmio_read_32(HSLS_GPV_APBX_NS); + val |= BIT(14); /* SMBUS1 NS = 1 */ + val |= BIT(13); /* GPIO NS = 1 */ + val |= BIT(12); /* WDT NS = 1 */ + val |= BIT(11); /* SMBUS0 NS = 1 */ + val |= BIT(10); /* Timer7 NS = 1 */ + val |= BIT(9); /* Timer6 NS = 1 */ + val |= BIT(8); /* Timer5 NS = 1 */ + val |= BIT(7); /* Timer4 NS = 1 */ + val |= BIT(6); /* Timer3 NS = 1 */ + val |= BIT(5); /* Timer2 NS = 1 */ + val |= BIT(4); /* Timer1 NS = 1 */ + val |= BIT(3); /* Timer0 NS = 1 */ + val |= BIT(2); /* MDIO NS = 1 */ + val |= BIT(1); /* PWM NS = 1 */ + mmio_write_32(HSLS_GPV_APBX_NS, val); + + val = mmio_read_32(HSLS_GPV_QSPI_S0_NS); + val |= BIT(0); /* QSPI NS = 1 */ + mmio_write_32(HSLS_GPV_QSPI_S0_NS, val); + +#ifdef USE_FS4 + val = 0x1; /* FS4 Crypto rm_slave */ + mmio_write_32(FS4_CRYPTO_GPV_RM_SLAVE_NS, val); + val = 0x1; /* FS4 Crypto apb_switch */ + mmio_write_32(FS4_CRYPTO_GPV_APB_SWITCH_NS, val); + + val = 0x1; /* FS4 Raid rm_slave */ + mmio_write_32(FS4_RAID_GPV_RM_SLAVE_NS, val); + val = 0x1; /* FS4 Raid apb_switch */ + mmio_write_32(FS4_RAID_GPV_APB_SWITCH_NS, val); + + val = 0x1; /* FS4 Crypto IDM */ + mmio_write_32(FS4_CRYPTO_IDM_NS, val); + val = 0x1; /* FS4 RAID IDM */ + mmio_write_32(FS4_RAID_IDM_NS, val); +#endif + +#ifdef BL31_CCN_NONSECURE + /* Enable non-secure access to CCN registers */ + mmio_write_32(OLY_MN_REGISTERS_NODE0_SECURE_ACCESS, 0x1); +#endif + +#ifdef DDR_CTRL_PHY_NONSECURE + mmio_write_32(SCR_NOC_DDR_REGISTER_ACCESS, 0x1); +#endif + + paxc_mhb_ns_init(); + + /* unlock scr idm for non secure access */ + mmio_write_32(SCR_NOC_SECURITY0, 0xffffffff); + + INFO("security init done\r\n"); +} + +void brcm_gpio_pad_ns_init(void) +{ + /* configure all GPIO pads for non secure world access*/ + mmio_write_32(GPIO_S_CNTRL_REG, 0xffffffff); /* 128-140 gpio pads */ + mmio_write_32(GPIO_S_CNTRL_REG + 0x4, 0xffffffff); /* 96-127 gpio pad */ + mmio_write_32(GPIO_S_CNTRL_REG + 0x8, 0xffffffff); /* 64-95 gpio pad */ + mmio_write_32(GPIO_S_CNTRL_REG + 0xc, 0xffffffff); /* 32-63 gpio pad */ + mmio_write_32(GPIO_S_CNTRL_REG + 0x10, 0xffffffff); /* 0-31 gpio pad */ +} + +#ifndef USE_DDR +static void brcm_stingray_sram_ns_init(void) +{ + uintptr_t sram_root = TZC400_FS_SRAM_ROOT; + uintptr_t noc_root = NIC400_FS_NOC_ROOT; + + mmio_write_32(sram_root + GATE_KEEPER_OFFSET, 1); + mmio_write_32(sram_root + REGION_ATTRIBUTES_0_OFFSET, 0xc0000000); + mmio_write_32(sram_root + REGION_ID_ACCESS_0_OFFSET, 0x00010001); + mmio_write_32(noc_root + NIC400_FS_NOC_SECURITY4_OFFSET, 0x1); + INFO(" stingray sram ns init done.\n"); +} +#endif + +static void ccn_pre_init(void) +{ + /* + * Set WFC bit of RN-I nodes where FS4 is connected. + * This is required inorder to wait for read/write requests + * completion acknowledgment. Otherwise FS4 Ring Manager is + * getting stale data because of re-ordering of read/write + * requests at CCN level + */ + mmio_setbits_32(OLY_RNI3PDVM_REGISTERS_NODE8_AUX_CTL, + OLY_RNI3PDVM_REGISTERS_NODE8_AUX_CTL_WFC); +} + +static void ccn_post_init(void) +{ + mmio_setbits_32(OLY_HNI_REGISTERS_NODE0_PCIERC_RNI_NODEID_LIST, + SRP_RNI_PCIE_CONNECTED); + mmio_setbits_32(OLY_HNI_REGISTERS_NODE0_SA_AUX_CTL, + SA_AUX_CTL_SER_DEVNE_WR); + + mmio_clrbits_32(OLY_HNI_REGISTERS_NODE0_POS_CONTROL, + POS_CONTROL_HNI_POS_EN); + mmio_clrbits_32(OLY_HNI_REGISTERS_NODE0_SA_AUX_CTL, + SA_AUX_CTL_POS_EARLY_WR_COMP_EN); +} + +#ifndef BL31_BOOT_PRELOADED_SCP +static void crmu_init(void) +{ + /* + * Configure CRMU for using SMMU + */ + + /*Program CRMU Stream ID */ + mmio_write_32(CRMU_MASTER_AXI_ARUSER_CONFIG, + (CRMU_STREAM_ID << CRMU_SID_SHIFT)); + mmio_write_32(CRMU_MASTER_AXI_AWUSER_CONFIG, + (CRMU_STREAM_ID << CRMU_SID_SHIFT)); + + /* Create Identity mapping */ + arm_smmu_create_identity_map(DOMAIN_CRMU); + + /* Enable Client Port for Secure Masters*/ + arm_smmu_enable_secure_client_port(); +} +#endif + +static void brcm_fsx_init(void) +{ +#if defined(USE_FS4) && defined(USE_FS6) + #error "USE_FS4 and USE_FS6 should not be used together" +#endif + +#ifdef USE_FS4 + fsx_init(eFS4_CRYPTO, FS4_CRYPTO_RING_COUNT, FS4_CRYPTO_DME_COUNT, + FS4_CRYPTO_AE_COUNT, FS4_CRYPTO_START_STREAM_ID, + FS4_CRYPTO_MSI_DEVICE_ID, FS4_CRYPTO_IDM_IO_CONTROL_DIRECT, + FS4_CRYPTO_IDM_RESET_CONTROL, FS4_CRYPTO_BASE, + FS4_CRYPTO_DME_BASE); + + fsx_init(eFS4_RAID, FS4_RAID_RING_COUNT, FS4_RAID_DME_COUNT, + FS4_RAID_AE_COUNT, FS4_RAID_START_STREAM_ID, + FS4_RAID_MSI_DEVICE_ID, FS4_RAID_IDM_IO_CONTROL_DIRECT, + FS4_RAID_IDM_RESET_CONTROL, FS4_RAID_BASE, + FS4_RAID_DME_BASE); + + fsx_meminit("raid", + FS4_RAID_IDM_IO_CONTROL_DIRECT, + FS4_RAID_IDM_IO_STATUS); +#endif +} + +static void bcm_bl33_pass_info(void) +{ + struct bl33_info *info = (struct bl33_info *)BL33_SHARED_DDR_BASE; + + if (sizeof(*info) > BL33_SHARED_DDR_SIZE) + WARN("bl33 shared area not reserved\n"); + + info->version = BL33_INFO_VERSION; + info->chip.chip_id = PLAT_CHIP_ID_GET; + info->chip.rev_id = PLAT_CHIP_REV_GET; +} + +DEFINE_RENAME_SYSREG_RW_FUNCS(l2ctlr_el1, CORTEX_A72_L2CTLR_EL1) + +void plat_bcm_bl31_early_platform_setup(void *from_bl2, + bl_params_t *plat_params_from_bl2) +{ +#ifdef BL31_BOOT_PRELOADED_SCP + image_info_t scp_image_info; + + scp_image_info.image_base = PRELOADED_SCP_BASE; + scp_image_info.image_size = PRELOADED_SCP_SIZE; + plat_bcm_bl2_plat_handle_scp_bl2(&scp_image_info); +#endif + /* + * In BL31, logs are saved to DDR and we have much larger space to + * store logs. We can now afford to save all logs >= the 'INFO' level + */ + bcm_elog_init((void *)BCM_ELOG_BL31_BASE, BCM_ELOG_BL31_SIZE, + LOG_LEVEL_INFO); + + INFO("L2CTLR = 0x%lx\n", read_l2ctlr_el1()); + + brcm_timer_sync_init(); + + brcm_stingray_dma_pl330_init(); + + brcm_stingray_dma_pl330_meminit(); + + brcm_stingray_spi_pl022_init(APBS_IDM_IDM_RESET_CONTROL); + +#ifdef USE_AMAC + brcm_stingray_amac_init(); +#endif + + brcm_stingray_sdio_init(); + +#ifdef NCSI_IO_DRIVE_STRENGTH_MA + brcm_stingray_ncsi_init(); +#endif + +#ifdef USE_USB + xhci_phy_init(); +#endif + +#ifdef USE_SATA + brcm_stingray_sata_init(); +#else + poweroff_sata_pll(); +#endif + + ccn_pre_init(); + + brcm_fsx_init(); + + brcm_stingray_smmu_init(); + + brcm_stingray_pka_meminit(); + + brcm_stingray_crmu_access_init(); + + brcm_stingray_scr_init(); + + brcm_stingray_hsls_tzpcprot_init(); + +#ifdef USE_I2S + brcm_stingray_audio_init(); +#endif + + ccn_post_init(); + + paxb_init(); + + paxc_init(); + +#ifndef BL31_BOOT_PRELOADED_SCP + crmu_init(); +#endif + + /* Note: this should be last thing because + * FS4 GPV registers only work after FS4 block + * (i.e. crypto,raid,cop) is out of reset. + */ + brcm_stingray_security_init(); + + brcm_gpio_pad_ns_init(); + +#ifndef USE_DDR + brcm_stingray_sram_ns_init(); +#endif + +#ifdef BL31_FORCE_CPU_FULL_FREQ + bcm_set_ihost_pll_freq(0x0, PLL_FREQ_FULL); +#endif + + brcm_stingray_gain_qspi_control(); + +#ifdef USE_PAXC + /* + * Check that the handshake has occurred and report ChiMP status. + * This is required. Otherwise (especially on Palladium) + * Linux might have booted to the pcie stage whereas + * ChiMP has not yet booted. Note that nic_mode case has already + * been considered above. + */ + if ((boot_source_get() != BOOT_SOURCE_QSPI) && + (!bcm_chimp_is_nic_mode()) && + (!bcm_chimp_wait_handshake()) + ) { + /* Does ChiMP report an error ? */ + uint32_t err; + + err = bcm_chimp_read_ctrl(CHIMP_REG_CTRL_BPE_STAT_REG); + if ((err & CHIMP_ERROR_MASK) == 0) + /* ChiMP has not booted yet, but no error reported */ + WARN("ChiMP not booted yet, but no error reported.\n"); + } + +#if DEBUG + if (boot_source_get() != BOOT_SOURCE_QSPI) + INFO("Current ChiMP Status: 0x%x; bpe_mod reg: 0x%x\n" + "fastboot register: 0x%x; handshake register 0x%x\n", + 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)); +#endif /* DEBUG */ +#endif + +#ifdef FS4_DISABLE_CLOCK + flush_dcache_range( + PLAT_BRCM_TRUSTED_SRAM_BASE, + PLAT_BRCM_TRUSTED_SRAM_SIZE); + fs4_disable_clocks(true, true, true); +#endif + + /* pass information to BL33 through shared DDR region */ + bcm_bl33_pass_info(); + + /* + * We are not yet at the end of BL31, but we can stop log here so we do + * not need to add 'bcm_elog_exit' to the standard BL31 code. The + * benefit of capturing BL31 logs after this is very minimal in a + * production system + */ + bcm_elog_exit(); + +#if !BRCM_DISABLE_TRUSTED_WDOG + /* + * Secure watchdog was started earlier in BL2, now it's time to stop + * it + */ + sp805_stop(ARM_SP805_TWDG_BASE); +#endif +} diff --git a/plat/brcm/board/stingray/src/brcm_pm_ops.c b/plat/brcm/board/stingray/src/brcm_pm_ops.c new file mode 100644 index 0000000..5e07fac --- /dev/null +++ b/plat/brcm/board/stingray/src/brcm_pm_ops.c @@ -0,0 +1,408 @@ +/* + * Copyright (c) 2017 - 2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <errno.h> +#include <inttypes.h> + +#include <arch_helpers.h> +#include <common/debug.h> +#include <drivers/arm/ccn.h> +#include <lib/bakery_lock.h> +#include <lib/mmio.h> +#include <lib/psci/psci.h> +#include <lib/spinlock.h> + +#include <brcm_scpi.h> +#include <chimp.h> +#include <cmn_plat_util.h> +#include <plat_brcm.h> +#include <platform_def.h> +#include <sr_utils.h> + +#include "m0_cfg.h" + + +#define CORE_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL0]) +#define CLUSTER_PWR_STATE(state) \ + ((state)->pwr_domain_state[MPIDR_AFFLVL1]) +#define SYSTEM_PWR_STATE(state) ((state)->pwr_domain_state[MPIDR_AFFLVL2]) + +#define VENDOR_RST_TYPE_SHIFT 4 + +#if HW_ASSISTED_COHERENCY +/* + * On systems where participant CPUs are cache-coherent, we can use spinlocks + * instead of bakery locks. + */ +spinlock_t event_lock; +#define event_lock_get(_lock) spin_lock(&_lock) +#define event_lock_release(_lock) spin_unlock(&_lock) + +#else +/* + * Use bakery locks for state coordination as not all participants are + * cache coherent now. + */ +DEFINE_BAKERY_LOCK(event_lock); +#define event_lock_get(_lock) bakery_lock_get(&_lock) +#define event_lock_release(_lock) bakery_lock_release(&_lock) +#endif + +static int brcm_pwr_domain_on(u_register_t mpidr) +{ + /* + * SCP takes care of powering up parent power domains so we + * only need to care about level 0 + */ + scpi_set_brcm_power_state(mpidr, scpi_power_on, scpi_power_on, + scpi_power_on); + + return PSCI_E_SUCCESS; +} + +/******************************************************************************* + * Handler called when a power level has just been powered on after + * being turned off earlier. The target_state encodes the low power state that + * each level has woken up from. This handler would never be invoked with + * the system power domain uninitialized as either the primary would have taken + * care of it as part of cold boot or the first core awakened from system + * suspend would have already initialized it. + ******************************************************************************/ +static void brcm_pwr_domain_on_finish(const psci_power_state_t *target_state) +{ + unsigned long cluster_id = MPIDR_AFFLVL1_VAL(read_mpidr()); + + /* Assert that the system power domain need not be initialized */ + assert(SYSTEM_PWR_STATE(target_state) == PLAT_LOCAL_STATE_RUN); + + assert(CORE_PWR_STATE(target_state) == PLAT_LOCAL_STATE_OFF); + + /* + * Perform the common cluster specific operations i.e enable coherency + * if this cluster was off. + */ + if (CLUSTER_PWR_STATE(target_state) == PLAT_LOCAL_STATE_OFF) { + INFO("Cluster #%lu entering to snoop/dvm domain\n", cluster_id); + ccn_enter_snoop_dvm_domain(1 << cluster_id); + } + + /* Program the gic per-cpu distributor or re-distributor interface */ + plat_brcm_gic_pcpu_init(); + + /* Enable the gic cpu interface */ + plat_brcm_gic_cpuif_enable(); +} + +static void brcm_power_down_common(void) +{ + unsigned int standbywfil2, standbywfi; + uint64_t mpidr = read_mpidr_el1(); + + switch (MPIDR_AFFLVL1_VAL(mpidr)) { + case 0x0: + standbywfi = CDRU_PROC_EVENT_CLEAR__IH0_CDRU_STANDBYWFI; + standbywfil2 = CDRU_PROC_EVENT_CLEAR__IH0_CDRU_STANDBYWFIL2; + break; + case 0x1: + standbywfi = CDRU_PROC_EVENT_CLEAR__IH1_CDRU_STANDBYWFI; + standbywfil2 = CDRU_PROC_EVENT_CLEAR__IH1_CDRU_STANDBYWFIL2; + break; + case 0x2: + standbywfi = CDRU_PROC_EVENT_CLEAR__IH2_CDRU_STANDBYWFI; + standbywfil2 = CDRU_PROC_EVENT_CLEAR__IH2_CDRU_STANDBYWFIL2; + break; + case 0x3: + standbywfi = CDRU_PROC_EVENT_CLEAR__IH3_CDRU_STANDBYWFI; + standbywfil2 = CDRU_PROC_EVENT_CLEAR__IH3_CDRU_STANDBYWFIL2; + break; + default: + ERROR("Invalid cluster #%" PRIx64 "\n", MPIDR_AFFLVL1_VAL(mpidr)); + return; + } + /* Clear the WFI status bit */ + event_lock_get(event_lock); + mmio_setbits_32(CDRU_PROC_EVENT_CLEAR, + (1 << (standbywfi + MPIDR_AFFLVL0_VAL(mpidr))) | + (1 << standbywfil2)); + event_lock_release(event_lock); +} + +/* + * Helper function to inform power down state to SCP. + */ +static void brcm_scp_suspend(const psci_power_state_t *target_state) +{ + uint32_t cluster_state = scpi_power_on; + uint32_t system_state = scpi_power_on; + + /* Check if power down at system power domain level is requested */ + if (SYSTEM_PWR_STATE(target_state) == PLAT_LOCAL_STATE_OFF) + system_state = scpi_power_retention; + + /* Check if Cluster is to be turned off */ + if (CLUSTER_PWR_STATE(target_state) == PLAT_LOCAL_STATE_OFF) + cluster_state = scpi_power_off; + + /* + * Ask the SCP to power down the appropriate components depending upon + * their state. + */ + scpi_set_brcm_power_state(read_mpidr_el1(), + scpi_power_off, + cluster_state, + system_state); +} + +/* + * Helper function to turn off a CPU power domain and its parent power domains + * if applicable. Since SCPI doesn't differentiate between OFF and suspend, we + * call the suspend helper here. + */ +static void brcm_scp_off(const psci_power_state_t *target_state) +{ + brcm_scp_suspend(target_state); +} + +static void brcm_pwr_domain_off(const psci_power_state_t *target_state) +{ + unsigned long cluster_id = MPIDR_AFFLVL1_VAL(read_mpidr_el1()); + + assert(CORE_PWR_STATE(target_state) == PLAT_LOCAL_STATE_OFF); + /* Prevent interrupts from spuriously waking up this cpu */ + plat_brcm_gic_cpuif_disable(); + + /* Turn redistributor off */ + plat_brcm_gic_redistif_off(); + + /* If Cluster is to be turned off, disable coherency */ + if (CLUSTER_PWR_STATE(target_state) == PLAT_LOCAL_STATE_OFF) + ccn_exit_snoop_dvm_domain(1 << cluster_id); + + brcm_power_down_common(); + + brcm_scp_off(target_state); +} + +/******************************************************************************* + * Handler called when the CPU power domain is about to enter standby. + ******************************************************************************/ +static void brcm_cpu_standby(plat_local_state_t cpu_state) +{ + unsigned int scr; + + assert(cpu_state == PLAT_LOCAL_STATE_RET); + + scr = read_scr_el3(); + /* + * Enable the Non secure interrupt to wake the CPU. + * In GICv3 affinity routing mode, the non secure group1 interrupts use + * the PhysicalFIQ at EL3 whereas in GICv2, it uses the PhysicalIRQ. + * Enabling both the bits works for both GICv2 mode and GICv3 affinity + * routing mode. + */ + write_scr_el3(scr | SCR_IRQ_BIT | SCR_FIQ_BIT); + isb(); + dsb(); + wfi(); + + /* + * Restore SCR to the original value, synchronisation of scr_el3 is + * done by eret while el3_exit to save some execution cycles. + */ + write_scr_el3(scr); +} + +/* + * Helper function to shutdown the system via SCPI. + */ +static void __dead2 brcm_scp_sys_shutdown(void) +{ + /* + * Disable GIC CPU interface to prevent pending interrupt + * from waking up the AP from WFI. + */ + plat_brcm_gic_cpuif_disable(); + + /* Flush and invalidate data cache */ + dcsw_op_all(DCCISW); + + /* Bring Cluster out of coherency domain as its going to die */ + plat_brcm_interconnect_exit_coherency(); + + brcm_power_down_common(); + + /* Send the power down request to the SCP */ + scpi_sys_power_state(scpi_system_shutdown); + + wfi(); + ERROR("BRCM System Off: operation not handled.\n"); + panic(); +} + +/* + * Helper function to reset the system + */ +static void __dead2 brcm_scp_sys_reset(unsigned int reset_type) +{ + /* + * Disable GIC CPU interface to prevent pending interrupt + * from waking up the AP from WFI. + */ + plat_brcm_gic_cpuif_disable(); + + /* Flush and invalidate data cache */ + dcsw_op_all(DCCISW); + + /* Bring Cluster out of coherency domain as its going to die */ + plat_brcm_interconnect_exit_coherency(); + + brcm_power_down_common(); + + /* Send the system reset request to the SCP + * + * As per PSCI spec system power state could be + * 0-> Shutdown + * 1-> Reboot- Board level Reset + * 2-> Reset - SoC level Reset + * + * Spec allocates 8 bits, 2 nibble, for this. One nibble is sufficient + * for sending the state hence We are utilizing 2nd nibble for vendor + * define reset type. + */ + scpi_sys_power_state((reset_type << VENDOR_RST_TYPE_SHIFT) | + scpi_system_reboot); + + wfi(); + ERROR("BRCM System Reset: operation not handled.\n"); + panic(); +} + +static void __dead2 brcm_system_reset(void) +{ + unsigned int reset_type; + + if (bcm_chimp_is_nic_mode()) + reset_type = SOFT_RESET_L3; + else + reset_type = SOFT_SYS_RESET_L1; + + brcm_scp_sys_reset(reset_type); +} + +static int brcm_system_reset2(int is_vendor, int reset_type, + u_register_t cookie) +{ + if (!is_vendor) { + /* Architectural warm boot: only warm reset is supported */ + reset_type = SOFT_RESET_L3; + } else { + uint32_t boot_source = (uint32_t)cookie; + + boot_source &= BOOT_SOURCE_MASK; + brcm_stingray_set_straps(boot_source); + } + brcm_scp_sys_reset(reset_type); + + /* + * brcm_scp_sys_reset cannot return (it is a __dead function), + * but brcm_system_reset2 has to return some value, even in + * this case. + */ + return 0; +} + +static int brcm_validate_ns_entrypoint(uintptr_t entrypoint) +{ + /* + * Check if the non secure entrypoint lies within the non + * secure DRAM. + */ + if ((entrypoint >= BRCM_NS_DRAM1_BASE) && + (entrypoint < (BRCM_NS_DRAM1_BASE + BRCM_NS_DRAM1_SIZE))) + return PSCI_E_SUCCESS; +#ifdef __aarch64__ + if ((entrypoint >= BRCM_DRAM2_BASE) && + (entrypoint < (BRCM_DRAM2_BASE + BRCM_DRAM2_SIZE))) + return PSCI_E_SUCCESS; + + if ((entrypoint >= BRCM_DRAM3_BASE) && + (entrypoint < (BRCM_DRAM3_BASE + BRCM_DRAM3_SIZE))) + return PSCI_E_SUCCESS; +#endif + + return PSCI_E_INVALID_ADDRESS; +} + +/******************************************************************************* + * ARM standard platform handler called to check the validity of the power state + * parameter. + ******************************************************************************/ +static int brcm_validate_power_state(unsigned int power_state, + psci_power_state_t *req_state) +{ + int pstate = psci_get_pstate_type(power_state); + int pwr_lvl = psci_get_pstate_pwrlvl(power_state); + int i; + + assert(req_state); + + if (pwr_lvl > PLAT_MAX_PWR_LVL) + return PSCI_E_INVALID_PARAMS; + + /* Sanity check the requested state */ + if (pstate == PSTATE_TYPE_STANDBY) { + /* + * It's possible to enter standby only on power level 0 + * Ignore any other power level. + */ + if (pwr_lvl != MPIDR_AFFLVL0) + return PSCI_E_INVALID_PARAMS; + + req_state->pwr_domain_state[MPIDR_AFFLVL0] = + PLAT_LOCAL_STATE_RET; + } else { + for (i = MPIDR_AFFLVL0; i <= pwr_lvl; i++) + req_state->pwr_domain_state[i] = + PLAT_LOCAL_STATE_OFF; + } + + /* + * We expect the 'state id' to be zero. + */ + if (psci_get_pstate_id(power_state)) + return PSCI_E_INVALID_PARAMS; + + return PSCI_E_SUCCESS; +} + +/******************************************************************************* + * Export the platform handlers via plat_brcm_psci_pm_ops. The ARM Standard + * platform will take care of registering the handlers with PSCI. + ******************************************************************************/ +plat_psci_ops_t plat_brcm_psci_pm_ops = { + .pwr_domain_on = brcm_pwr_domain_on, + .pwr_domain_on_finish = brcm_pwr_domain_on_finish, + .pwr_domain_off = brcm_pwr_domain_off, + .cpu_standby = brcm_cpu_standby, + .system_off = brcm_scp_sys_shutdown, + .system_reset = brcm_system_reset, + .system_reset2 = brcm_system_reset2, + .validate_ns_entrypoint = brcm_validate_ns_entrypoint, + .validate_power_state = brcm_validate_power_state, +}; + +int plat_setup_psci_ops(uintptr_t sec_entrypoint, + const struct plat_psci_ops **psci_ops) +{ + *psci_ops = &plat_brcm_psci_pm_ops; + + /* Setup mailbox with entry point. */ + mmio_write_64(CRMU_CFG_BASE + offsetof(M0CFG, core_cfg.rvbar), + sec_entrypoint); + + return 0; +} diff --git a/plat/brcm/board/stingray/src/fsx.c b/plat/brcm/board/stingray/src/fsx.c new file mode 100644 index 0000000..5725a2e --- /dev/null +++ b/plat/brcm/board/stingray/src/fsx.c @@ -0,0 +1,477 @@ +/* + * Copyright (c) 2019-2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <common/debug.h> +#include <drivers/console.h> +#include <drivers/delay_timer.h> +#include <lib/mmio.h> +#include <plat/common/common_def.h> + +#include <fsx.h> +#include <platform_def.h> +#include <sr_utils.h> + +#define FS4_IDM_IO_CONTROL_DIRECT__SRAM_CLK_EN 0 + +#define FS4_IDM_IO_CONTROL_DIRECT__MEM_POWERON 11 +#define FS4_IDM_IO_CONTROL_DIRECT__MEM_POWEROK 12 +#define FS4_IDM_IO_CONTROL_DIRECT__MEM_ARRPOWERON 13 +#define FS4_IDM_IO_CONTROL_DIRECT__MEM_ARRPOWEROK 14 +#define FS4_IDM_IO_CONTROL_DIRECT__MEM_ISO 15 +#define FS4_IDM_IO_CONTROL_DIRECT__CLK_EN 31 + +#define FS4_IDM_IO_STATUS__MEM_POWERON 0 +#define FS4_IDM_IO_STATUS__MEM_POWEROK 1 +#define FS4_IDM_IO_STATUS__MEM_ARRPOWERON 2 +#define FS4_IDM_IO_STATUS__MEM_ARRPOWEROK 3 +#define FS4_IDM_IO_STATUS__MEM_ALLOK 0xf + +#define FS4_IDM_RESET_CONTROL__RESET 0 + +#define FSX_RINGx_BASE(__b, __i) \ + ((__b) + (__i) * 0x10000) + +#define FSX_RINGx_VERSION_NUMBER(__b, __i) \ + (FSX_RINGx_BASE(__b, __i) + 0x0) + +#define FSX_RINGx_MSI_DEV_ID(__b, __i) \ + (FSX_RINGx_BASE(__b, __i) + 0x44) + +#define FSX_COMM_RINGx_BASE(__b, __i) \ + ((__b) + 0x200000 + (__i) * 0x100) + +#define FSX_COMM_RINGx_CONTROL(__b, __i) \ + (FSX_COMM_RINGx_BASE(__b, __i) + 0x0) +#define FSX_COMM_RINGx_CONTROL__AXI_ID 8 +#define FSX_COMM_RINGx_CONTROL__AXI_ID_MASK 0x1f +#define FSX_COMM_RINGx_CONTROL__PRIORITY 4 +#define FSX_COMM_RINGx_CONTROL__PRIORITY_MASK 0x7 +#define FSX_COMM_RINGx_CONTROL__AE_GROUP 0 +#define FSX_COMM_RINGx_CONTROL__AE_GROUP_MASK 0x7 + +#define FSX_COMM_RINGx_MSI_DEV_ID(__b, __i) \ + (FSX_COMM_RINGx_BASE(__b, __i) + 0x4) + +#define FSX_AEx_BASE(__b, __i) \ + ((__b) + 0x202000 + (__i) * 0x100) + +#define FSX_AEx_CONTROL_REGISTER(__b, __i) \ + (FSX_AEx_BASE(__b, __i) + 0x0) +#define FSX_AEx_CONTROL_REGISTER__ACTIVE 4 +#define FSX_AEx_CONTROL_REGISTER__GROUP_ID 0 +#define FSX_AEx_CONTROL_REGISTER__GROUP_ID_MASK 0x7 + +#define FSX_COMM_RM_RING_SECURITY_SETTING 0x0 + +#define FSX_COMM_RM_SSID_CONTROL 0x4 +#define FSX_COMM_RM_SSID_CONTROL__RING_BITS 5 +#define FSX_COMM_RM_SSID_CONTROL__MASK 0x3ff + +#define FSX_COMM_RM_CONTROL_REGISTER 0x8 +#define FSX_COMM_RM_CONTROL_REGISTER__CONFIG_DONE 2 +#define FSX_COMM_RM_CONTROL_REGISTER__AE_TIMEOUT 5 +#define FSX_COMM_RM_CONTROL_REGISTER__AE_LOCKING 7 + +#define FSX_COMM_RM_TIMER_CONTROL_0 0xc +#define FSX_COMM_RM_TIMER_CONTROL_0__FAST 16 +#define FSX_COMM_RM_TIMER_CONTROL_0__MEDIUM 0 + +#define FSX_COMM_RM_TIMER_CONTROL_1 0x10 +#define FSX_COMM_RM_TIMER_CONTROL_1__SLOW 16 +#define FSX_COMM_RM_TIMER_CONTROL_1__IDLE 0 + +#define FSX_COMM_RM_BURST_BD_THRESHOLD 0x14 +#define FSX_COMM_RM_BURST_BD_THRESHOLD_LOW 0 +#define FSX_COMM_RM_BURST_BD_THRESHOLD_HIGH 16 + +#define FSX_COMM_RM_BURST_LENGTH 0x18 +#define FSX_COMM_RM_BURST_LENGTH__FOR_DDR_ADDR_GEN 16 +#define FSX_COMM_RM_BURST_LENGTH__FOR_DDR_ADDR_GEN_MASK 0x1ff +#define FSX_COMM_RM_BURST_LENGTH__FOR_TOGGLE 0 +#define FSX_COMM_RM_BURST_LENGTH__FOR_TOGGLE_MASK 0x1ff + +#define FSX_COMM_RM_FIFO_THRESHOLD 0x1c +#define FSX_COMM_RM_FIFO_THRESHOLD__BD_FIFO_FULL 16 +#define FSX_COMM_RM_FIFO_THRESHOLD__BD_FIFO_FULL_MASK 0x1ff +#define FSX_COMM_RM_FIFO_THRESHOLD__AE_FIFO_FULL 0 +#define FSX_COMM_RM_FIFO_THRESHOLD__AE_FIFO_FULL_MASK 0x1f + +#define FSX_COMM_RM_AE_TIMEOUT 0x24 + +#define FSX_COMM_RM_RING_FLUSH_TIMEOUT 0x2c + +#define FSX_COMM_RM_MEMORY_CONFIGURATION 0x30 +#define FSX_COMM_RM_MEMORY_CONFIGURATION__ARRPOWERONIN 12 +#define FSX_COMM_RM_MEMORY_CONFIGURATION__ARRPOWEROKIN 13 +#define FSX_COMM_RM_MEMORY_CONFIGURATION__POWERONIN 14 +#define FSX_COMM_RM_MEMORY_CONFIGURATION__POWEROKIN 15 + +#define FSX_COMM_RM_AXI_CONTROL 0x34 +#define FSX_COMM_RM_AXI_CONTROL__WRITE_CHANNEL_EN 28 +#define FSX_COMM_RM_AXI_CONTROL__READ_CHANNEL_EN 24 +#define FSX_COMM_RM_AXI_CONTROL__AWQOS 20 +#define FSX_COMM_RM_AXI_CONTROL__ARQOS 16 +#define FSX_COMM_RM_AXI_CONTROL__AWPROT 12 +#define FSX_COMM_RM_AXI_CONTROL__ARPROT 8 +#define FSX_COMM_RM_AXI_CONTROL__AWCACHE 4 +#define FSX_COMM_RM_AXI_CONTROL__ARCACHE 0 + +#define FSX_COMM_RM_CONFIG_INTERRUPT_STATUS_CLEAR 0x48 + +#define FSX_COMM_RM_GROUP_PKT_EXTENSION_SUPPORT 0xc0 + +#define FSX_COMM_RM_AXI_READ_BURST_THRESHOLD 0xc8 +#define FSX_COMM_RM_AXI_READ_BURST_THRESHOLD__MASK 0x1ff +#define FSX_COMM_RM_AXI_READ_BURST_THRESHOLD__MAX 16 +#define FSX_COMM_RM_AXI_READ_BURST_THRESHOLD__MIN 0 + +#define FSX_COMM_RM_GROUP_RING_COUNT 0xcc + +#define FSX_COMM_RM_MAIN_HW_INIT_DONE 0x12c +#define FSX_COMM_RM_MAIN_HW_INIT_DONE__MASK 0x1 + +#define FSX_DMEx_BASE(__b, __i) \ + ((__b) + (__i) * 0x1000) + +#define FSX_DMEx_AXI_CONTROL(__b, __i) \ + (FSX_DMEx_BASE(__b, __i) + 0x4) +#define FSX_DMEx_AXI_CONTROL__WRITE_CHANNEL_EN 28 +#define FSX_DMEx_AXI_CONTROL__READ_CHANNEL_EN 24 +#define FSX_DMEx_AXI_CONTROL__AWQOS 20 +#define FSX_DMEx_AXI_CONTROL__ARQOS 16 +#define FSX_DMEx_AXI_CONTROL__AWCACHE 4 +#define FSX_DMEx_AXI_CONTROL__ARCACHE 0 + +#define FSX_DMEx_WR_FIFO_THRESHOLD(__b, __i) \ + (FSX_DMEx_BASE(__b, __i) + 0xc) +#define FSX_DMEx_WR_FIFO_THRESHOLD__MASK 0x3ff +#define FSX_DMEx_WR_FIFO_THRESHOLD__MAX 10 +#define FSX_DMEx_WR_FIFO_THRESHOLD__MIN 0 + +#define FSX_DMEx_RD_FIFO_THRESHOLD(__b, __i) \ + (FSX_DMEx_BASE(__b, __i) + 0x14) +#define FSX_DMEx_RD_FIFO_THRESHOLD__MASK 0x3ff +#define FSX_DMEx_RD_FIFO_THRESHOLD__MAX 10 +#define FSX_DMEx_RD_FIFO_THRESHOLD__MIN 0 + +#define FS6_SUB_TOP_BASE 0x66D8F800 +#define FS6_PKI_DME_RESET 0x4 +#define PKI_DME_RESET 1 + +char *fsx_type_names[] = { + "fs4-raid", + "fs4-crypto", + "fs6-pki", +}; + +void fsx_init(eFSX_TYPE fsx_type, + unsigned int ring_count, + unsigned int dme_count, + unsigned int ae_count, + unsigned int start_stream_id, + unsigned int msi_dev_id, + uintptr_t idm_io_control_direct, + uintptr_t idm_reset_control, + uintptr_t base, + uintptr_t dme_base) +{ + int try; + unsigned int i, v, data; + uintptr_t fs4_idm_io_control_direct = idm_io_control_direct; + uintptr_t fs4_idm_reset_control = idm_reset_control; + uintptr_t fsx_comm_rm = (base + 0x203000); + + VERBOSE("fsx %s init start\n", fsx_type_names[fsx_type]); + + if (fsx_type == eFS4_RAID || fsx_type == eFS4_CRYPTO) { + /* Enable FSx engine clock */ + VERBOSE(" - enable fsx clock\n"); + mmio_write_32(fs4_idm_io_control_direct, + (1U << FS4_IDM_IO_CONTROL_DIRECT__CLK_EN)); + udelay(500); + + /* Reset FSx engine */ + VERBOSE(" - reset fsx\n"); + v = mmio_read_32(fs4_idm_reset_control); + v |= (1 << FS4_IDM_RESET_CONTROL__RESET); + mmio_write_32(fs4_idm_reset_control, v); + udelay(500); + v = mmio_read_32(fs4_idm_reset_control); + v &= ~(1 << FS4_IDM_RESET_CONTROL__RESET); + mmio_write_32(fs4_idm_reset_control, v); + } else { + /* + * Default RM and AE are out of reset, + * So only DME Reset added here + */ + v = mmio_read_32(FS6_SUB_TOP_BASE + FS6_PKI_DME_RESET); + v &= ~(PKI_DME_RESET); + mmio_write_32(FS6_SUB_TOP_BASE + FS6_PKI_DME_RESET, v); + } + + /* Wait for HW-init done */ + VERBOSE(" - wait for HW-init done\n"); + try = 10000; + do { + udelay(1); + data = mmio_read_32(fsx_comm_rm + + FSX_COMM_RM_MAIN_HW_INIT_DONE); + try--; + } while (!(data & FSX_COMM_RM_MAIN_HW_INIT_DONE__MASK) && (try > 0)); + + if (try <= 0) + ERROR("fsx_comm_rm + 0x%x: 0x%x\n", + data, FSX_COMM_RM_MAIN_HW_INIT_DONE); + + /* Make all rings non-secured */ + VERBOSE(" - make all rings non-secured\n"); + v = 0xffffffff; + mmio_write_32(fsx_comm_rm + FSX_COMM_RM_RING_SECURITY_SETTING, v); + + /* Set start stream-id for rings to */ + VERBOSE(" - set start stream-id for rings to 0x%x\n", + start_stream_id); + v = start_stream_id >> FSX_COMM_RM_SSID_CONTROL__RING_BITS; + v &= FSX_COMM_RM_SSID_CONTROL__MASK; + mmio_write_32(fsx_comm_rm + FSX_COMM_RM_SSID_CONTROL, v); + + /* Set timer configuration */ + VERBOSE(" - set timer configuration\n"); + v = 0x0271 << FSX_COMM_RM_TIMER_CONTROL_0__MEDIUM; + v |= (0x0138 << FSX_COMM_RM_TIMER_CONTROL_0__FAST); + mmio_write_32(fsx_comm_rm + FSX_COMM_RM_TIMER_CONTROL_0, v); + v = 0x09c4 << FSX_COMM_RM_TIMER_CONTROL_1__IDLE; + v |= (0x04e2 << FSX_COMM_RM_TIMER_CONTROL_1__SLOW); + mmio_write_32(fsx_comm_rm + FSX_COMM_RM_TIMER_CONTROL_1, v); + v = 0x0000f424; + mmio_write_32(fsx_comm_rm + FSX_COMM_RM_RING_FLUSH_TIMEOUT, v); + + /* Set burst length and fifo threshold */ + VERBOSE(" - set burst length, fifo and bd threshold\n"); + v = 0x0; + v |= (0x8 << FSX_COMM_RM_BURST_LENGTH__FOR_DDR_ADDR_GEN); + v |= (0x8 << FSX_COMM_RM_BURST_LENGTH__FOR_TOGGLE); + mmio_write_32(fsx_comm_rm + FSX_COMM_RM_BURST_LENGTH, v); + v = 0x0; + v |= (0x67 << FSX_COMM_RM_FIFO_THRESHOLD__BD_FIFO_FULL); + v |= (0x18 << FSX_COMM_RM_FIFO_THRESHOLD__AE_FIFO_FULL); + mmio_write_32(fsx_comm_rm + FSX_COMM_RM_FIFO_THRESHOLD, v); + v = 0x0; + v |= (0x8 << FSX_COMM_RM_BURST_BD_THRESHOLD_LOW); + v |= (0x8 << FSX_COMM_RM_BURST_BD_THRESHOLD_HIGH); + mmio_write_32(fsx_comm_rm + FSX_COMM_RM_BURST_BD_THRESHOLD, v); + + /* Set memory configuration */ + VERBOSE(" - set memory configuration\n"); + v = 0x0; + v |= (1 << FSX_COMM_RM_MEMORY_CONFIGURATION__POWERONIN); + v |= (1 << FSX_COMM_RM_MEMORY_CONFIGURATION__POWEROKIN); + v |= (1 << FSX_COMM_RM_MEMORY_CONFIGURATION__ARRPOWERONIN); + v |= (1 << FSX_COMM_RM_MEMORY_CONFIGURATION__ARRPOWEROKIN); + mmio_write_32(fsx_comm_rm + FSX_COMM_RM_MEMORY_CONFIGURATION, v); + + /* AXI configuration for RM */ + v = 0; + v |= (0x1 << FSX_COMM_RM_AXI_CONTROL__WRITE_CHANNEL_EN); + v |= (0x1 << FSX_COMM_RM_AXI_CONTROL__READ_CHANNEL_EN); + v |= (0xe << FSX_COMM_RM_AXI_CONTROL__AWQOS); + v |= (0xa << FSX_COMM_RM_AXI_CONTROL__ARQOS); + v |= (0x2 << FSX_COMM_RM_AXI_CONTROL__AWPROT); + v |= (0x2 << FSX_COMM_RM_AXI_CONTROL__ARPROT); + v |= (0xf << FSX_COMM_RM_AXI_CONTROL__AWCACHE); + v |= (0xf << FSX_COMM_RM_AXI_CONTROL__ARCACHE); + mmio_write_32(fsx_comm_rm + FSX_COMM_RM_AXI_CONTROL, v); + VERBOSE(" - set AXI control = 0x%x\n", + mmio_read_32(fsx_comm_rm + FSX_COMM_RM_AXI_CONTROL)); + v = 0x0; + v |= (0x10 << FSX_COMM_RM_AXI_READ_BURST_THRESHOLD__MAX); + v |= (0x10 << FSX_COMM_RM_AXI_READ_BURST_THRESHOLD__MIN); + mmio_write_32(fsx_comm_rm + FSX_COMM_RM_AXI_READ_BURST_THRESHOLD, v); + VERBOSE(" - set AXI read burst threshold = 0x%x\n", + mmio_read_32(fsx_comm_rm + FSX_COMM_RM_AXI_READ_BURST_THRESHOLD)); + + /* Configure group ring count for all groups */ + /* By default we schedule extended packets + * on all AEs/DMEs in a group. + */ + v = (dme_count & 0xf) << 0; + v |= (dme_count & 0xf) << 4; + v |= (dme_count & 0xf) << 8; + v |= (dme_count & 0xf) << 12; + v |= (dme_count & 0xf) << 16; + v |= (dme_count & 0xf) << 20; + v |= (dme_count & 0xf) << 24; + v |= (dme_count & 0xf) << 28; + mmio_write_32(fsx_comm_rm + FSX_COMM_RM_GROUP_RING_COUNT, v); + + /* + * Due to HW issue spurious interrupts are getting generated. + * To fix sw needs to clear the config status interrupts + * before setting CONFIG_DONE. + */ + mmio_write_32(fsx_comm_rm + + FSX_COMM_RM_CONFIG_INTERRUPT_STATUS_CLEAR, + 0xffffffff); + + /* Configure RM control */ + VERBOSE(" - configure RM control\n"); + v = mmio_read_32(fsx_comm_rm + FSX_COMM_RM_CONTROL_REGISTER); + v |= (1 << FSX_COMM_RM_CONTROL_REGISTER__AE_LOCKING); + mmio_write_32(fsx_comm_rm + FSX_COMM_RM_CONTROL_REGISTER, v); + v |= (1 << FSX_COMM_RM_CONTROL_REGISTER__CONFIG_DONE); + mmio_write_32(fsx_comm_rm + FSX_COMM_RM_CONTROL_REGISTER, v); + + /* Configure AE timeout */ + VERBOSE(" - configure AE timeout\n"); + v = 0x00003fff; + mmio_write_32(fsx_comm_rm + FSX_COMM_RM_AE_TIMEOUT, v); + + /* Initialize all AEs */ + for (i = 0; i < ae_count; i++) { + VERBOSE(" - initialize AE%d\n", i); + v = (0x1 << FSX_AEx_CONTROL_REGISTER__ACTIVE); + mmio_write_32(FSX_AEx_CONTROL_REGISTER(base, i), v); + } + + /* Initialize all DMEs */ + for (i = 0; i < dme_count; i++) { + VERBOSE(" - initialize DME%d\n", i); + v = 0; + v |= (0x1 << FSX_DMEx_AXI_CONTROL__WRITE_CHANNEL_EN); + v |= (0x1 << FSX_DMEx_AXI_CONTROL__READ_CHANNEL_EN); + v |= (0xe << FSX_DMEx_AXI_CONTROL__AWQOS); + v |= (0xa << FSX_DMEx_AXI_CONTROL__ARQOS); + v |= (0xf << FSX_DMEx_AXI_CONTROL__AWCACHE); + v |= (0xf << FSX_DMEx_AXI_CONTROL__ARCACHE); + mmio_write_32(FSX_DMEx_AXI_CONTROL(dme_base, i), v); + VERBOSE(" -- AXI_CONTROL = 0x%x\n", + mmio_read_32(FSX_DMEx_AXI_CONTROL(dme_base, i))); + v = 0; + v |= (0x4 << FSX_DMEx_WR_FIFO_THRESHOLD__MIN); + v |= (0x4 << FSX_DMEx_WR_FIFO_THRESHOLD__MAX); + mmio_write_32(FSX_DMEx_WR_FIFO_THRESHOLD(dme_base, i), v); + VERBOSE(" -- WR_FIFO_THRESHOLD = 0x%x\n", + mmio_read_32(FSX_DMEx_WR_FIFO_THRESHOLD(dme_base, i))); + v = 0; + v |= (0x4 << FSX_DMEx_RD_FIFO_THRESHOLD__MIN); + v |= (0x4 << FSX_DMEx_RD_FIFO_THRESHOLD__MAX); + mmio_write_32(FSX_DMEx_RD_FIFO_THRESHOLD(dme_base, i), v); + VERBOSE(" -- RD_FIFO_THRESHOLD = 0x%x\n", + mmio_read_32(FSX_DMEx_RD_FIFO_THRESHOLD(dme_base, i))); + } + + /* Configure ring axi id and msi device id */ + for (i = 0; i < ring_count; i++) { + VERBOSE(" - ring%d version=0x%x\n", i, + mmio_read_32(FSX_RINGx_VERSION_NUMBER(base, i))); + mmio_write_32(FSX_COMM_RINGx_MSI_DEV_ID(base, i), + msi_dev_id); + v = 0; + v |= ((i & FSX_COMM_RINGx_CONTROL__AXI_ID_MASK) << + FSX_COMM_RINGx_CONTROL__AXI_ID); + mmio_write_32(FSX_COMM_RINGx_CONTROL(base, i), v); + } + + INFO("fsx %s init done\n", fsx_type_names[fsx_type]); +} + +void fsx_meminit(const char *name, + uintptr_t idm_io_control_direct, + uintptr_t idm_io_status) +{ + int try; + unsigned int val; + + VERBOSE("fsx %s meminit start\n", name); + + VERBOSE(" - arrpoweron\n"); + mmio_setbits_32(idm_io_control_direct, + BIT(FS4_IDM_IO_CONTROL_DIRECT__MEM_ARRPOWERON)); + while (!(mmio_read_32(idm_io_status) & + BIT(FS4_IDM_IO_STATUS__MEM_ARRPOWERON))) + ; + + VERBOSE(" - arrpowerok\n"); + mmio_setbits_32(idm_io_control_direct, + (1 << FS4_IDM_IO_CONTROL_DIRECT__MEM_ARRPOWEROK)); + while (!(mmio_read_32(idm_io_status) & + BIT(FS4_IDM_IO_STATUS__MEM_ARRPOWEROK))) + ; + + VERBOSE(" - poweron\n"); + mmio_setbits_32(idm_io_control_direct, + (1 << FS4_IDM_IO_CONTROL_DIRECT__MEM_POWERON)); + while (!(mmio_read_32(idm_io_status) & + BIT(FS4_IDM_IO_STATUS__MEM_POWERON))) + ; + + VERBOSE(" - powerok\n"); + mmio_setbits_32(idm_io_control_direct, + (1 << FS4_IDM_IO_CONTROL_DIRECT__MEM_POWEROK)); + while (!(mmio_read_32(idm_io_status) & + BIT(FS4_IDM_IO_STATUS__MEM_POWEROK))) + ; + + /* Final check on all power bits */ + try = 10; + do { + val = mmio_read_32(idm_io_status); + if (val == FS4_IDM_IO_STATUS__MEM_ALLOK) + break; + + /* Wait sometime */ + mdelay(1); + + try--; + } while (try > 0); + + /* Remove memory isolation if things are fine. */ + if (try <= 0) { + INFO(" - powerup failed\n"); + } else { + VERBOSE(" - remove isolation\n"); + mmio_clrbits_32(idm_io_control_direct, + (1 << FS4_IDM_IO_CONTROL_DIRECT__MEM_ISO)); + VERBOSE(" - powerup done\n"); + } + + INFO("fsx %s meminit done\n", name); +} + +void fs4_disable_clocks(bool disable_sram, + bool disable_crypto, + bool disable_raid) +{ + VERBOSE("fs4 disable clocks start\n"); + + if (disable_sram) { + VERBOSE(" - disable sram clock\n"); + mmio_clrbits_32(FS4_SRAM_IDM_IO_CONTROL_DIRECT, + (1 << FS4_IDM_IO_CONTROL_DIRECT__SRAM_CLK_EN)); + } + + if (disable_crypto) { + VERBOSE(" - disable crypto clock\n"); + mmio_setbits_32(CDRU_GENPLL5_CONTROL1, + CDRU_GENPLL5_CONTROL1__CHNL1_CRYPTO_AE_CLK); + } + + if (disable_raid) { + VERBOSE(" - disable raid clock\n"); + mmio_setbits_32(CDRU_GENPLL5_CONTROL1, + CDRU_GENPLL5_CONTROL1__CHNL2_RAID_AE_CLK); + } + + if (disable_sram && disable_crypto && disable_raid) { + VERBOSE(" - disable root clock\n"); + mmio_setbits_32(CDRU_GENPLL5_CONTROL1, + CDRU_GENPLL5_CONTROL1__CHNL0_DME_CLK); + mmio_setbits_32(CDRU_GENPLL2_CONTROL1, + CDRU_GENPLL2_CONTROL1__CHNL6_FS4_CLK); + } + + INFO("fs4 disable clocks done\n"); +} diff --git a/plat/brcm/board/stingray/src/ihost_pm.c b/plat/brcm/board/stingray/src/ihost_pm.c new file mode 100644 index 0000000..9141d3e --- /dev/null +++ b/plat/brcm/board/stingray/src/ihost_pm.c @@ -0,0 +1,355 @@ +/* + * Copyright (c) 2016 - 2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <common/debug.h> +#include <drivers/delay_timer.h> +#include <lib/mmio.h> + +#include <dmu.h> +#include <ihost_pm.h> +#include <platform_def.h> + +#define CDRU_CCN_REGISTER_CONTROL_1__D2XS_PD_IHOST1 2 +#define CDRU_CCN_REGISTER_CONTROL_1__D2XS_PD_IHOST2 1 +#define CDRU_CCN_REGISTER_CONTROL_1__D2XS_PD_IHOST3 0 +#define CDRU_MISC_RESET_CONTROL__CDRU_IH1_RESET 9 +#define CDRU_MISC_RESET_CONTROL__CDRU_IH2_RESET 8 +#define CDRU_MISC_RESET_CONTROL__CDRU_IH3_RESET 7 +#define A72_CRM_SOFTRESETN_0 0x480 +#define A72_CRM_SOFTRESETN_1 0x484 +#define A72_CRM_DOMAIN_4_CONTROL 0x810 +#define A72_CRM_DOMAIN_4_CONTROL__DOMAIN_4_ISO_DFT 3 +#define A72_CRM_DOMAIN_4_CONTROL__DOMAIN_4_ISO_MEM 6 +#define A72_CRM_DOMAIN_4_CONTROL__DOMAIN_4_ISO_I_O 0 +#define A72_CRM_SUBSYSTEM_MEMORY_CONTROL_3 0xB4C +#define MEMORY_PDA_HI_SHIFT 0x0 +#define A72_CRM_PLL_PWR_ON 0x70 +#define A72_CRM_PLL_PWR_ON__PLL0_ISO_PLLOUT 4 +#define A72_CRM_PLL_PWR_ON__PLL0_PWRON_LDO 1 +#define A72_CRM_PLL_PWR_ON__PLL0_PWRON_PLL 0 +#define A72_CRM_SUBSYSTEM_MEMORY_CONTROL_2 0xB48 +#define A72_CRM_PLL_INTERRUPT_STATUS 0x8c +#define A72_CRM_PLL_INTERRUPT_STATUS__PLL0_LOCK_LOST_STATUS 8 +#define A72_CRM_PLL_INTERRUPT_STATUS__PLL0_LOCK_STATUS 9 +#define A72_CRM_INTERRUPT_ENABLE 0x4 +#define A72_CRM_INTERRUPT_ENABLE__PLL0_INT_ENABLE 4 +#define A72_CRM_PLL_INTERRUPT_ENABLE 0x88 +#define A72_CRM_PLL_INTERRUPT_ENABLE__PLL0_LOCK_STATUS_INT_ENB 9 +#define A72_CRM_PLL_INTERRUPT_ENABLE__PLL0_LOCK_LOST_STATUS_INT_ENB 8 +#define A72_CRM_PLL0_CFG0_CTRL 0x120 +#define A72_CRM_PLL0_CFG1_CTRL 0x124 +#define A72_CRM_PLL0_CFG2_CTRL 0x128 +#define A72_CRM_PLL0_CFG3_CTRL 0x12C +#define A72_CRM_CORE_CONFIG_DBGCTRL__DBGROMADDRV 0 +#define A72_CRM_CORE_CONFIG_DBGCTRL 0xD50 +#define A72_CRM_CORE_CONFIG_DBGROM_LO 0xD54 +#define A72_CRM_CORE_CONFIG_DBGROM_HI 0xD58 +#define A72_CRM_SUBSYSTEM_CONFIG_1__DBGL1RSTDISABLE 2 +#define A72_CRM_SOFTRESETN_0__CRYSTAL26_SOFTRESETN 0 +#define A72_CRM_SOFTRESETN_0__CRM_PLL0_SOFTRESETN 1 +#define A72_CRM_AXI_CLK_DESC 0x304 +#define A72_CRM_ACP_CLK_DESC 0x308 +#define A72_CRM_ATB_CLK_DESC 0x30C +#define A72_CRM_PCLKDBG_DESC 0x310 +#define A72_CRM_CLOCK_MODE_CONTROL 0x40 +#define A72_CRM_CLOCK_MODE_CONTROL__CLK_CHANGE_TRIGGER 0 +#define A72_CRM_CLOCK_CONTROL_0 0x200 +#define A72_CRM_CLOCK_CONTROL_0__ARM_HW_SW_ENABLE_SEL 0 +#define A72_CRM_CLOCK_CONTROL_0__AXI_HW_SW_ENABLE_SEL 2 +#define A72_CRM_CLOCK_CONTROL_0__ACP_HW_SW_ENABLE_SEL 4 +#define A72_CRM_CLOCK_CONTROL_0__ATB_HW_SW_ENABLE_SEL 6 +#define A72_CRM_CLOCK_CONTROL_0__PCLKDBG_HW_SW_ENA_SEL 8 +#define A72_CRM_CLOCK_CONTROL_1 0x204 +#define A72_CRM_CLOCK_CONTROL_1__TMON_HW_SW_ENABLE_SEL 6 +#define A72_CRM_CLOCK_CONTROL_1__APB_HW_SW_ENABLE_SEL 8 +#define A72_CRM_SOFTRESETN_0__CRYSTAL26_SOFTRESETN 0 +#define A72_CRM_SOFTRESETN_0__CRM_PLL0_SOFTRESETN 1 +#define A72_CRM_SOFTRESETN_0__AXI_SOFTRESETN 9 +#define A72_CRM_SOFTRESETN_0__ACP_SOFTRESETN 10 +#define A72_CRM_SOFTRESETN_0__ATB_SOFTRESETN 11 +#define A72_CRM_SOFTRESETN_0__PCLKDBG_SOFTRESETN 12 +#define A72_CRM_SOFTRESETN_0__TMON_SOFTRESETN 15 +#define A72_CRM_SOFTRESETN_0__L2_SOFTRESETN 3 +#define A72_CRM_SOFTRESETN_1__APB_SOFTRESETN 8 + +/* core related regs */ +#define A72_CRM_DOMAIN_0_CONTROL 0x800 +#define A72_CRM_DOMAIN_0_CONTROL__DOMAIN_0_ISO_MEM 0x6 +#define A72_CRM_DOMAIN_0_CONTROL__DOMAIN_0_ISO_I_O 0x0 +#define A72_CRM_DOMAIN_1_CONTROL 0x804 +#define A72_CRM_DOMAIN_1_CONTROL__DOMAIN_1_ISO_MEM 0x6 +#define A72_CRM_DOMAIN_1_CONTROL__DOMAIN_1_ISO_I_O 0x0 +#define A72_CRM_CORE_CONFIG_RVBA0_LO 0xD10 +#define A72_CRM_CORE_CONFIG_RVBA0_MID 0xD14 +#define A72_CRM_CORE_CONFIG_RVBA0_HI 0xD18 +#define A72_CRM_CORE_CONFIG_RVBA1_LO 0xD20 +#define A72_CRM_CORE_CONFIG_RVBA1_MID 0xD24 +#define A72_CRM_CORE_CONFIG_RVBA1_HI 0xD28 +#define A72_CRM_SUBSYSTEM_CONFIG_0 0xC80 +#define A72_CRM_SUBSYSTEM_CONFIG_0__DBGPWRDUP_CFG_SHIFT 4 +#define A72_CRM_SOFTRESETN_0__COREPOR0_SOFTRESETN 4 +#define A72_CRM_SOFTRESETN_0__COREPOR1_SOFTRESETN 5 +#define A72_CRM_SOFTRESETN_1__CORE0_SOFTRESETN 0 +#define A72_CRM_SOFTRESETN_1__DEBUG0_SOFTRESETN 4 +#define A72_CRM_SOFTRESETN_1__CORE1_SOFTRESETN 1 +#define A72_CRM_SOFTRESETN_1__DEBUG1_SOFTRESETN 5 + +#define SPROC_MEMORY_BISR 0 + +static int cluster_power_status[PLAT_BRCM_CLUSTER_COUNT] = {CLUSTER_POWER_ON, + CLUSTER_POWER_OFF, + CLUSTER_POWER_OFF, + CLUSTER_POWER_OFF}; + +void ihost_power_on_cluster(u_register_t mpidr) +{ + uint32_t rst, d2xs; + uint32_t cluster_id; + uint32_t ihost_base; +#if SPROC_MEMORY_BISR + uint32_t bisr, cnt; +#endif + cluster_id = MPIDR_AFFLVL1_VAL(mpidr); + uint32_t cluster0_freq_sel; + + if (cluster_power_status[cluster_id] == CLUSTER_POWER_ON) + return; + + cluster_power_status[cluster_id] = CLUSTER_POWER_ON; + INFO("enabling Cluster #%u\n", cluster_id); + + switch (cluster_id) { + case 1: + rst = (1 << CDRU_MISC_RESET_CONTROL__CDRU_IH1_RESET); + d2xs = (1 << CDRU_CCN_REGISTER_CONTROL_1__D2XS_PD_IHOST1); +#if SPROC_MEMORY_BISR + bisr = CRMU_BISR_PDG_MASK__CRMU_BISR_IHOST1; +#endif + break; + case 2: + rst = (1 << CDRU_MISC_RESET_CONTROL__CDRU_IH2_RESET); + d2xs = (1 << CDRU_CCN_REGISTER_CONTROL_1__D2XS_PD_IHOST2); +#if SPROC_MEMORY_BISR + bisr = CRMU_BISR_PDG_MASK__CRMU_BISR_IHOST2; +#endif + break; + case 3: + rst = (1 << CDRU_MISC_RESET_CONTROL__CDRU_IH3_RESET); + d2xs = (1 << CDRU_CCN_REGISTER_CONTROL_1__D2XS_PD_IHOST3); +#if SPROC_MEMORY_BISR + bisr = CRMU_BISR_PDG_MASK__CRMU_BISR_IHOST3; +#endif + break; + default: + ERROR("Invalid cluster :%u\n", cluster_id); + return; + } + + /* Releasing ihost resets */ + mmio_setbits_32(CDRU_MISC_RESET_CONTROL, rst); + + /* calculate cluster/ihost base address */ + ihost_base = IHOST0_BASE + cluster_id * IHOST_ADDR_SPACE; + + /* Remove Cluster IO isolation */ + mmio_clrsetbits_32(ihost_base + A72_CRM_DOMAIN_4_CONTROL, + (1 << A72_CRM_DOMAIN_4_CONTROL__DOMAIN_4_ISO_I_O), + (1 << A72_CRM_DOMAIN_4_CONTROL__DOMAIN_4_ISO_DFT) | + (1 << A72_CRM_DOMAIN_4_CONTROL__DOMAIN_4_ISO_MEM)); + + /* + * Since BISR sequence requires that all cores of cluster should + * have removed I/O isolation hence doing same here. + */ + /* Remove core0 memory IO isolations */ + mmio_clrsetbits_32(ihost_base + A72_CRM_DOMAIN_0_CONTROL, + (1 << A72_CRM_DOMAIN_0_CONTROL__DOMAIN_0_ISO_I_O), + (1 << A72_CRM_DOMAIN_0_CONTROL__DOMAIN_0_ISO_MEM)); + + /* Remove core1 memory IO isolations */ + mmio_clrsetbits_32(ihost_base + A72_CRM_DOMAIN_1_CONTROL, + (1 << A72_CRM_DOMAIN_1_CONTROL__DOMAIN_1_ISO_I_O), + (1 << A72_CRM_DOMAIN_1_CONTROL__DOMAIN_1_ISO_MEM)); + +#if SPROC_MEMORY_BISR + mmio_setbits_32(CRMU_BISR_PDG_MASK, (1 << bisr)); + + if (!(mmio_read_32(CDRU_CHIP_STRAP_DATA_LSW) & + (1 << CDRU_CHIP_STRAP_DATA_LSW__BISR_BYPASS_MODE))) { + /* BISR completion would take max 2 usec */ + cnt = 0; + while (cnt < 2) { + udelay(1); + if (mmio_read_32(CRMU_CHIP_OTPC_STATUS) & + (1 << CRMU_CHIP_OTPC_STATUS__OTP_BISR_LOAD_DONE)) + break; + cnt++; + } + } + + /* if BISR is not completed, need to be checked with ASIC team */ + if (((mmio_read_32(CRMU_CHIP_OTPC_STATUS)) & + (1 << CRMU_CHIP_OTPC_STATUS__OTP_BISR_LOAD_DONE)) == 0) { + WARN("BISR did not completed and need to be addressed\n"); + } +#endif + + /* PLL Power up. supply is already on. Turn on PLL LDO/PWR */ + mmio_write_32(ihost_base + A72_CRM_PLL_PWR_ON, + (1 << A72_CRM_PLL_PWR_ON__PLL0_ISO_PLLOUT) | + (1 << A72_CRM_PLL_PWR_ON__PLL0_PWRON_LDO) | + (1 << A72_CRM_PLL_PWR_ON__PLL0_PWRON_PLL)); + + /* 1us in spec; Doubling it to be safe*/ + udelay(2); + + /* Remove PLL output ISO */ + mmio_write_32(ihost_base + A72_CRM_PLL_PWR_ON, + (1 << A72_CRM_PLL_PWR_ON__PLL0_PWRON_LDO) | + (1 << A72_CRM_PLL_PWR_ON__PLL0_PWRON_PLL)); + + /* + * PLL0 Configuration Control Register + * these 4 registers drive the i_pll_ctrl[63:0] input of pll + * (16b per register). + * the values are derived from the spec (sections 8 and 10). + */ + + mmio_write_32(ihost_base + A72_CRM_PLL0_CFG0_CTRL, 0x00000000); + mmio_write_32(ihost_base + A72_CRM_PLL0_CFG1_CTRL, 0x00008400); + mmio_write_32(ihost_base + A72_CRM_PLL0_CFG2_CTRL, 0x00000001); + mmio_write_32(ihost_base + A72_CRM_PLL0_CFG3_CTRL, 0x00000000); + + /* Read the freq_sel from cluster 0, which is up already */ + cluster0_freq_sel = bcm_get_ihost_pll_freq(0); + bcm_set_ihost_pll_freq(cluster_id, cluster0_freq_sel); + + udelay(1); + + /* Release clock source reset */ + mmio_setbits_32(ihost_base + A72_CRM_SOFTRESETN_0, + (1 << A72_CRM_SOFTRESETN_0__CRYSTAL26_SOFTRESETN) | + (1 << A72_CRM_SOFTRESETN_0__CRM_PLL0_SOFTRESETN)); + + udelay(1); + + /* + * Integer division for clks (divider value = n+1). + * These are the divisor of ARM PLL clock frequecy. + */ + mmio_write_32(ihost_base + A72_CRM_AXI_CLK_DESC, 0x00000001); + mmio_write_32(ihost_base + A72_CRM_ACP_CLK_DESC, 0x00000001); + mmio_write_32(ihost_base + A72_CRM_ATB_CLK_DESC, 0x00000004); + mmio_write_32(ihost_base + A72_CRM_PCLKDBG_DESC, 0x0000000b); + + /* + * clock change trigger - must set to take effect after clock + * source change + */ + mmio_setbits_32(ihost_base + A72_CRM_CLOCK_MODE_CONTROL, + (1 << A72_CRM_CLOCK_MODE_CONTROL__CLK_CHANGE_TRIGGER)); + + /* turn on functional clocks */ + mmio_setbits_32(ihost_base + A72_CRM_CLOCK_CONTROL_0, + (3 << A72_CRM_CLOCK_CONTROL_0__ARM_HW_SW_ENABLE_SEL) | + (3 << A72_CRM_CLOCK_CONTROL_0__AXI_HW_SW_ENABLE_SEL) | + (3 << A72_CRM_CLOCK_CONTROL_0__ACP_HW_SW_ENABLE_SEL) | + (3 << A72_CRM_CLOCK_CONTROL_0__ATB_HW_SW_ENABLE_SEL) | + (3 << A72_CRM_CLOCK_CONTROL_0__PCLKDBG_HW_SW_ENA_SEL)); + + mmio_setbits_32(ihost_base + A72_CRM_CLOCK_CONTROL_1, + (3 << A72_CRM_CLOCK_CONTROL_1__TMON_HW_SW_ENABLE_SEL) | + (3 << A72_CRM_CLOCK_CONTROL_1__APB_HW_SW_ENABLE_SEL)); + + /* Program D2XS Power Down Registers */ + mmio_setbits_32(CDRU_CCN_REGISTER_CONTROL_1, d2xs); + + /* Program Core Config Debug ROM Address Registers */ + /* mark valid for Debug ROM base address */ + mmio_write_32(ihost_base + A72_CRM_CORE_CONFIG_DBGCTRL, + (1 << A72_CRM_CORE_CONFIG_DBGCTRL__DBGROMADDRV)); + + /* Program Lo and HI address of coresight DBG rom address */ + mmio_write_32(ihost_base + A72_CRM_CORE_CONFIG_DBGROM_LO, + (CORESIGHT_BASE_ADDR >> 12) & 0xffff); + mmio_write_32(ihost_base + A72_CRM_CORE_CONFIG_DBGROM_HI, + (CORESIGHT_BASE_ADDR >> 28) & 0xffff); + + /* + * Release soft resets of different components. + * Order: Bus clocks --> PERIPH --> L2 --> cores + */ + + /* Bus clocks soft resets */ + mmio_setbits_32(ihost_base + A72_CRM_SOFTRESETN_0, + (1 << A72_CRM_SOFTRESETN_0__CRYSTAL26_SOFTRESETN) | + (1 << A72_CRM_SOFTRESETN_0__CRM_PLL0_SOFTRESETN) | + (1 << A72_CRM_SOFTRESETN_0__AXI_SOFTRESETN) | + (1 << A72_CRM_SOFTRESETN_0__ACP_SOFTRESETN) | + (1 << A72_CRM_SOFTRESETN_0__ATB_SOFTRESETN) | + (1 << A72_CRM_SOFTRESETN_0__PCLKDBG_SOFTRESETN)); + + mmio_setbits_32(ihost_base + A72_CRM_SOFTRESETN_1, + (1 << A72_CRM_SOFTRESETN_1__APB_SOFTRESETN)); + + /* Periph component softreset */ + mmio_setbits_32(ihost_base + A72_CRM_SOFTRESETN_0, + (1 << A72_CRM_SOFTRESETN_0__TMON_SOFTRESETN)); + + /* L2 softreset */ + mmio_setbits_32(ihost_base + A72_CRM_SOFTRESETN_0, + (1 << A72_CRM_SOFTRESETN_0__L2_SOFTRESETN)); + + /* Enable and program Satellite timer */ + ihost_enable_satellite_timer(cluster_id); +} + +void ihost_power_on_secondary_core(u_register_t mpidr, uint64_t rvbar) +{ + uint32_t ihost_base; + uint32_t coreid = MPIDR_AFFLVL0_VAL(mpidr); + uint32_t cluster_id = MPIDR_AFFLVL1_VAL(mpidr); + + ihost_base = IHOST0_BASE + cluster_id * IHOST_ADDR_SPACE; + INFO("programming core #%u\n", coreid); + + if (coreid) { + /* program the entry point for core1 */ + mmio_write_32(ihost_base + A72_CRM_CORE_CONFIG_RVBA1_LO, + rvbar & 0xFFFF); + mmio_write_32(ihost_base + A72_CRM_CORE_CONFIG_RVBA1_MID, + (rvbar >> 16) & 0xFFFF); + mmio_write_32(ihost_base + A72_CRM_CORE_CONFIG_RVBA1_HI, + (rvbar >> 32) & 0xFFFF); + } else { + /* program the entry point for core */ + mmio_write_32(ihost_base + A72_CRM_CORE_CONFIG_RVBA0_LO, + rvbar & 0xFFFF); + mmio_write_32(ihost_base + A72_CRM_CORE_CONFIG_RVBA0_MID, + (rvbar >> 16) & 0xFFFF); + mmio_write_32(ihost_base + A72_CRM_CORE_CONFIG_RVBA0_HI, + (rvbar >> 32) & 0xFFFF); + } + + /* Tell debug logic which processor is up */ + mmio_setbits_32(ihost_base + A72_CRM_SUBSYSTEM_CONFIG_0, + (coreid ? + (2 << A72_CRM_SUBSYSTEM_CONFIG_0__DBGPWRDUP_CFG_SHIFT) : + (1 << A72_CRM_SUBSYSTEM_CONFIG_0__DBGPWRDUP_CFG_SHIFT))); + + /* releasing soft resets for IHOST core */ + mmio_setbits_32(ihost_base + A72_CRM_SOFTRESETN_0, + (coreid ? + (1 << A72_CRM_SOFTRESETN_0__COREPOR1_SOFTRESETN) : + (1 << A72_CRM_SOFTRESETN_0__COREPOR0_SOFTRESETN))); + + mmio_setbits_32(ihost_base + A72_CRM_SOFTRESETN_1, + (coreid ? + ((1 << A72_CRM_SOFTRESETN_1__CORE1_SOFTRESETN) | + (1 << A72_CRM_SOFTRESETN_1__DEBUG1_SOFTRESETN)) : + ((1 << A72_CRM_SOFTRESETN_1__CORE0_SOFTRESETN) | + (1 << A72_CRM_SOFTRESETN_1__DEBUG0_SOFTRESETN)))); +} diff --git a/plat/brcm/board/stingray/src/iommu.c b/plat/brcm/board/stingray/src/iommu.c new file mode 100644 index 0000000..de8b995 --- /dev/null +++ b/plat/brcm/board/stingray/src/iommu.c @@ -0,0 +1,536 @@ +/* + * Copyright (c) 2017 - 2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch_helpers.h> +#include <common/debug.h> +#include <drivers/delay_timer.h> +#include <lib/mmio.h> + +#include <iommu.h> +#include <platform_def.h> + +#define SMMU_BASE 0x64000000 +#define ARM_SMMU_MAX_NUM_CNTXT_BANK 64 +#define SMMU_CTX_BANK_IDX_SECURE_CRMU 63 +#define ARM_SMMU_NUM_SECURE_MASTER 1 +#define ARM_SMMU_NSNUMCBO (ARM_SMMU_MAX_NUM_CNTXT_BANK - \ + ARM_SMMU_NUM_SECURE_MASTER) +#define ARM_SMMU_NSNUMSMRGO (ARM_SMMU_MAX_NUM_CNTXT_BANK - \ + ARM_SMMU_NUM_SECURE_MASTER) +/* Reserved Banks. */ +#define SMMU_CTX_BANK_IDX (SMMU_CTX_BANK_IDX_SECURE_CRMU - \ + ARM_SMMU_NUM_SECURE_MASTER) +#define NUM_OF_SMRS 1 + +#define STG1_WITH_STG2_BYPASS 1 +#define ARM_LPAE_PGTBL_PHYS_CRMU 0x880000000 +#define ARM_LPAE_PGTBL_PHYS 0x880200000 +#define ARM_LPAE_PGTBL_PTE_CNT 512 +#define ARM_LPAE_PTE_L1_BLOCK_SIZE 0x40000000 +#define ARM_LPAE_PTE_L1_ADDR_MASK 0x0000FFFFC0000000UL +#define ARM_LPAE_PTE_TABLE 0x2UL +#define ARM_LPAE_PTE_VALID 0x1UL +#define ARM_LPAE_PTE_ATTRINDX 2 +#define ARM_LPAE_PTE_NS 5 +#define ARM_LPAE_PTE_AP 6 +#define ARM_LPAE_PTE_AP_EL1_RW 0x0 +#define ARM_LPAE_PTE_AP_EL0_RW 0x1 +#define ARM_LPAE_PTE_SH 8 +#define ARM_LPAE_PTE_SH_NON 0x0 +#define ARM_LPAE_PTE_SH_OUTER 0x2 +#define ARM_LPAE_PTE_SH_INNER 0x3 +#define ARM_LPAE_PTE_AF 10 +#define ARM_SMMU_RES_SIZE 0x80000 + +#define ARM_LPAE_PTE_NSTABLE 0x8000000000000000UL +#define ARM_LPAE_PTE_L1_INDEX_SHIFT 30 +#define ARM_LPAE_PTE_L1_INDEX_MASK 0x1ff +#define ARM_LPAE_PTE_L0_INDEX_SHIFT 39 +#define ARM_LPAE_PTE_L0_INDEX_MASK 0x1ff +#define ARM_LPAE_PTE_TABLE_MASK ~(0xfffUL) +/* Configuration registers */ +#define ARM_SMMU_GR0_sCR0 0x0 +#define sCR0_CLIENTPD (1 << 0) +#define sCR0_GFRE (1 << 1) +#define sCR0_GFIE (1 << 2) +#define sCR0_GCFGFRE (1 << 4) +#define sCR0_GCFGFIE (1 << 5) +#define sCR0_USFCFG (1 << 10) +#define sCR0_VMIDPNE (1 << 11) +#define sCR0_PTM (1 << 12) +#define sCR0_FB (1 << 13) +#define sCR0_VMID16EN (1 << 31) +#define sCR0_BSU_SHIFT 14 +#define sCR0_BSU_MASK 0x3 +#define ARM_SMMU_SMMU_SCR1 0x4 +#define SCR1_NSNUMCBO_MASK 0xFF +#define SCR1_NSNUMCBO_SHIFT 0x0 +#define SCR1_NSNUMSMRGO_MASK 0xFF00 +#define SCR1_NSNUMSMRGO_SHIFT 0x8 + +/* Identification registers */ +#define ARM_SMMU_GR0_ID0 0x20 +#define ARM_SMMU_GR0_ID1 0x24 +#define ARM_SMMU_GR0_ID2 0x28 +#define ARM_SMMU_GR0_ID3 0x2c +#define ARM_SMMU_GR0_ID4 0x30 +#define ARM_SMMU_GR0_ID5 0x34 +#define ARM_SMMU_GR0_ID6 0x38 +#define ARM_SMMU_GR0_ID7 0x3c +#define ARM_SMMU_GR0_sGFSR 0x48 +#define ARM_SMMU_GR0_sGFSYNR0 0x50 +#define ARM_SMMU_GR0_sGFSYNR1 0x54 +#define ARM_SMMU_GR0_sGFSYNR2 0x58 + +#define ID1_PAGESIZE (1U << 31) +#define ID1_NUMPAGENDXB_SHIFT 28 +#define ID1_NUMPAGENDXB_MASK 7 +#define ID1_NUMS2CB_SHIFT 16 +#define ID1_NUMS2CB_MASK 0xff +#define ID1_NUMCB_SHIFT 0 +#define ID1_NUMCB_MASK 0xff + +/* SMMU global address space */ +#define ARM_SMMU_GR0(smmu) ((smmu)->base) +#define ARM_SMMU_GR1(smmu) ((smmu)->base + (1 << (smmu)->pgshift)) + +/* Stream mapping registers */ +#define ARM_SMMU_GR0_SMR(n) (0x800 + (n << 2)) +#define SMR_VALID (1U << 31) +#define SMR_MASK_SHIFT 16 +#define SMR_ID_SHIFT 0 + +#define ARM_SMMU_GR0_S2CR(n) (0xc00 + (n << 2)) +#define S2CR_CBNDX_SHIFT 0 +#define S2CR_CBNDX_MASK 0xff +#define S2CR_TYPE_SHIFT 16 +#define S2CR_TYPE_MASK 0x3 + +#define ARM_SMMU_GR1_CBA2R(n) (0x800 + (n << 2)) +#define CBA2R_RW64_32BIT (0 << 0) +#define CBA2R_RW64_64BIT (1 << 0) +#define CBA2R_VMID_SHIFT 16 +#define CBA2R_VMID_MASK 0xffff + +#define ARM_SMMU_GR1_CBAR(n) (0x0 + (n << 2)) +#define CBAR_VMID_SHIFT 0 +#define CBAR_VMID_MASK 0xff +#define CBAR_S1_BPSHCFG_SHIFT 8 +#define CBAR_S1_BPSHCFG_MASK 3 +#define CBAR_S1_BPSHCFG_NSH 3 +#define CBAR_S1_MEMATTR_SHIFT 12 +#define CBAR_S1_MEMATTR_MASK 0xf +#define CBAR_S1_MEMATTR_WB 0xf +#define CBAR_TYPE_SHIFT 16 +#define CBAR_TYPE_MASK 0x3 +#define CBAR_TYPE_S2_TRANS (0 << CBAR_TYPE_SHIFT) +#define CBAR_TYPE_S1_TRANS_S2_BYPASS (1 << CBAR_TYPE_SHIFT) +#define CBAR_TYPE_S1_TRANS_S2_FAULT (2 << CBAR_TYPE_SHIFT) +#define CBAR_TYPE_S1_TRANS_S2_TRANS (3 << CBAR_TYPE_SHIFT) +#define CBAR_IRPTNDX_SHIFT 24 +#define CBAR_IRPTNDX_MASK 0xff + +/* Translation context bank */ +#define ARM_SMMU_CB_BASE(smmu) ((smmu)->base + ((smmu)->size >> 1)) +#define ARM_SMMU_CB(smmu, n) ((n) * (1 << (smmu)->pgshift)) + +#define ARM_SMMU_CB_SCTLR 0x0 +#define ARM_SMMU_CB_ACTLR 0x4 +#define ARM_SMMU_CB_RESUME 0x8 +#define ARM_SMMU_CB_TTBCR2 0x10 +#define ARM_SMMU_CB_TTBR0 0x20 +#define ARM_SMMU_CB_TTBR1 0x28 +#define ARM_SMMU_CB_TTBCR 0x30 +#define ARM_SMMU_CB_CONTEXTIDR 0x34 +#define ARM_SMMU_CB_S1_MAIR0 0x38 +#define ARM_SMMU_CB_S1_MAIR1 0x3c +#define ARM_SMMU_CB_PAR 0x50 +#define ARM_SMMU_CB_FSR 0x58 +#define ARM_SMMU_CB_FAR 0x60 +#define ARM_SMMU_CB_FSYNR0 0x68 +#define ARM_SMMU_CB_S1_TLBIVA 0x600 +#define ARM_SMMU_CB_S1_TLBIASID 0x610 +#define ARM_SMMU_CB_S1_TLBIVAL 0x620 +#define ARM_SMMU_CB_S2_TLBIIPAS2 0x630 +#define ARM_SMMU_CB_S2_TLBIIPAS2L 0x638 +#define ARM_SMMU_CB_ATS1PR 0x800 +#define ARM_SMMU_CB_ATSR 0x8f0 + +#define SCTLR_S1_ASIDPNE (1 << 12) +#define SCTLR_CFCFG (1 << 7) +#define SCTLR_CFIE (1 << 6) +#define SCTLR_CFRE (1 << 5) +#define SCTLR_E (1 << 4) +#define SCTLR_AFE (1 << 2) +#define SCTLR_TRE (1 << 1) +#define SCTLR_M (1 << 0) + +/* ARM LPAE configuration. */ +/**************************************************************/ +/* Register bits */ +#define ARM_32_LPAE_TCR_EAE (1 << 31) +#define ARM_64_LPAE_S2_TCR_RES1 (1 << 31) + +#define ARM_LPAE_TCR_EPD1 (1 << 23) + +#define ARM_LPAE_TCR_TG0_4K (0 << 14) +#define ARM_LPAE_TCR_TG0_64K (1 << 14) +#define ARM_LPAE_TCR_TG0_16K (2 << 14) + +#define ARM_LPAE_TCR_SH0_SHIFT 12 +#define ARM_LPAE_TCR_SH0_MASK 0x3 +#define ARM_LPAE_TCR_SH_NS 0 +#define ARM_LPAE_TCR_SH_OS 2 +#define ARM_LPAE_TCR_SH_IS 3 + +#define ARM_LPAE_TCR_ORGN0_SHIFT 10 +#define ARM_LPAE_TCR_IRGN0_SHIFT 8 +#define ARM_LPAE_TCR_RGN_MASK 0x3 +#define ARM_LPAE_TCR_RGN_NC 0 +#define ARM_LPAE_TCR_RGN_WBWA 1 +#define ARM_LPAE_TCR_RGN_WT 2 +#define ARM_LPAE_TCR_RGN_WB 3 + +#define ARM_LPAE_TCR_SL0_SHIFT 6 +#define ARM_LPAE_TCR_SL0_MASK 0x3 + +#define ARM_LPAE_TCR_T0SZ_SHIFT 0 +#define ARM_LPAE_TCR_SZ_MASK 0xf + +#define ARM_LPAE_TCR_PS_SHIFT 16 +#define ARM_LPAE_TCR_PS_MASK 0x7 + +#define ARM_LPAE_TCR_IPS_SHIFT 32 +#define ARM_LPAE_TCR_IPS_MASK 0x7 + +#define ARM_LPAE_TCR_PS_32_BIT 0x0ULL +#define ARM_LPAE_TCR_PS_36_BIT 0x1ULL +#define ARM_LPAE_TCR_PS_40_BIT 0x2ULL +#define ARM_LPAE_TCR_PS_42_BIT 0x3ULL +#define ARM_LPAE_TCR_PS_44_BIT 0x4ULL +#define ARM_LPAE_TCR_PS_48_BIT 0x5ULL + +#define ARM_LPAE_MAIR_ATTR_SHIFT(n) ((n) << 3) +#define ARM_LPAE_MAIR_ATTR_MASK 0xff +#define ARM_LPAE_MAIR_ATTR_DEVICE 0x04 +#define ARM_LPAE_MAIR_ATTR_NC 0x44 +#define ARM_LPAE_MAIR_ATTR_WBRWA 0xff +#define ARM_LPAE_MAIR_ATTR_IDX_NC 0 +#define ARM_LPAE_MAIR_ATTR_IDX_CACHE 1 +#define ARM_LPAE_MAIR_ATTR_IDX_DEV 2 + +#define TTBRn_ASID_SHIFT 48 +#define TTBCR2_SEP_SHIFT 15 +#define TTBCR2_SEP_UPSTREAM (0x7 << TTBCR2_SEP_SHIFT) +#define TTBCR2_AS (1 << 4) +#define TTBCR_T0SZ(ia_bits) (64 - (ia_bits)) + +#define S2CR_PRIVCFG_SHIFT 24 +#define S2CR_PRIVCFG_MASK 0x3 + +/**************************************************************/ + +uint16_t paxc_stream_ids[] = { 0x2000 }; + +uint16_t paxc_stream_ids_mask[] = { 0x1fff }; +uint16_t crmu_stream_ids[] = { CRMU_STREAM_ID }; +uint16_t crmu_stream_ids_mask[] = { 0x0 }; + +enum arm_smmu_s2cr_type { + S2CR_TYPE_TRANS, + S2CR_TYPE_BYPASS, + S2CR_TYPE_FAULT, +}; + +enum arm_smmu_s2cr_privcfg { + S2CR_PRIVCFG_DEFAULT, + S2CR_PRIVCFG_DIPAN, + S2CR_PRIVCFG_UNPRIV, + S2CR_PRIVCFG_PRIV, +}; + +struct arm_smmu_smr { + uint16_t mask; + uint16_t id; + uint32_t valid; +}; + +struct arm_smmu_s2cr { + int count; + enum arm_smmu_s2cr_type type; + enum arm_smmu_s2cr_privcfg privcfg; + uint8_t cbndx; +}; + +struct arm_smmu_cfg { + uint8_t cbndx; + uint8_t irptndx; + uint32_t cbar; +}; + +struct arm_smmu_device { + uint8_t *base; + uint32_t streams; + unsigned long size; + unsigned long pgshift; + unsigned long va_size; + unsigned long ipa_size; + unsigned long pa_size; + struct arm_smmu_smr smr[NUM_OF_SMRS]; + struct arm_smmu_s2cr s2cr[NUM_OF_SMRS]; + struct arm_smmu_cfg cfg[NUM_OF_SMRS]; + uint16_t *stream_ids; + uint16_t *stream_ids_mask; +}; + +void arm_smmu_enable_secure_client_port(void) +{ + uintptr_t smmu_base = SMMU_BASE; + + mmio_clrbits_32(smmu_base, sCR0_CLIENTPD); +} + +void arm_smmu_reserve_secure_cntxt(void) +{ + uintptr_t smmu_base = SMMU_BASE; + + mmio_clrsetbits_32(smmu_base + ARM_SMMU_SMMU_SCR1, + (SCR1_NSNUMSMRGO_MASK | SCR1_NSNUMCBO_MASK), + ((ARM_SMMU_NSNUMCBO << SCR1_NSNUMCBO_SHIFT) | + (ARM_SMMU_NSNUMSMRGO << SCR1_NSNUMSMRGO_SHIFT))); +} + +static void arm_smmu_smr_cfg(struct arm_smmu_device *smmu, uint32_t index) +{ + uint32_t idx = smmu->cfg[index].cbndx; + struct arm_smmu_smr *smr = &smmu->smr[index]; + uint32_t reg = smr->id << SMR_ID_SHIFT | smr->mask << SMR_MASK_SHIFT; + + if (smr->valid) + reg |= SMR_VALID; + + mmio_write_32((uintptr_t) (ARM_SMMU_GR0(smmu) + + ARM_SMMU_GR0_SMR(idx)), reg); +} + +static void arm_smmu_s2cr_cfg(struct arm_smmu_device *smmu, uint32_t index) +{ + uint32_t idx = smmu->cfg[index].cbndx; + struct arm_smmu_s2cr *s2cr = &smmu->s2cr[index]; + + uint32_t reg = (s2cr->type & S2CR_TYPE_MASK) << S2CR_TYPE_SHIFT | + (s2cr->cbndx & S2CR_CBNDX_MASK) << S2CR_CBNDX_SHIFT | + (s2cr->privcfg & S2CR_PRIVCFG_MASK) << S2CR_PRIVCFG_SHIFT; + + mmio_write_32((uintptr_t) (ARM_SMMU_GR0(smmu) + + ARM_SMMU_GR0_S2CR(idx)), reg); +} + +static void smmu_set_pgtbl(struct arm_smmu_device *smmu, + enum iommu_domain dom, + uint64_t *pg_table_base) +{ + int i, l0_index, l1_index; + uint64_t addr, *pte, *l0_base, *l1_base; + uint64_t addr_space_limit; + + if (dom == PCIE_PAXC) { + addr_space_limit = 0xffffffffff; + } else if (dom == DOMAIN_CRMU) { + addr_space_limit = 0xffffffff; + } else { + ERROR("dom is not supported\n"); + return; + } + + l0_base = pg_table_base; + /* clear L0 descriptors. */ + for (i = 0; i < ARM_LPAE_PGTBL_PTE_CNT; i++) + l0_base[i] = 0x0; + + addr = 0x0; + while (addr < addr_space_limit) { + /* find L0 pte */ + l0_index = ((addr >> ARM_LPAE_PTE_L0_INDEX_SHIFT) & + ARM_LPAE_PTE_L0_INDEX_MASK); + l1_base = l0_base + ((l0_index + 1) * ARM_LPAE_PGTBL_PTE_CNT); + + /* setup L0 pte if required */ + pte = l0_base + l0_index; + if (*pte == 0x0) { + *pte |= ((uint64_t)l1_base & ARM_LPAE_PTE_TABLE_MASK); + if (dom == PCIE_PAXC) + *pte |= ARM_LPAE_PTE_NSTABLE; + *pte |= ARM_LPAE_PTE_TABLE; + *pte |= ARM_LPAE_PTE_VALID; + } + + /* find L1 pte */ + l1_index = ((addr >> ARM_LPAE_PTE_L1_INDEX_SHIFT) & + ARM_LPAE_PTE_L1_INDEX_MASK); + pte = l1_base + l1_index; + + /* setup L1 pte */ + *pte = 0x0; + *pte |= (addr & ARM_LPAE_PTE_L1_ADDR_MASK); + if (addr < 0x80000000) { + *pte |= (ARM_LPAE_MAIR_ATTR_IDX_DEV << + ARM_LPAE_PTE_ATTRINDX); + if (dom == PCIE_PAXC) + *pte |= (1 << ARM_LPAE_PTE_NS); + } else { + *pte |= (ARM_LPAE_MAIR_ATTR_IDX_CACHE << + ARM_LPAE_PTE_ATTRINDX); + *pte |= (1 << ARM_LPAE_PTE_NS); + } + *pte |= (ARM_LPAE_PTE_AP_EL0_RW << ARM_LPAE_PTE_AP); + *pte |= (ARM_LPAE_PTE_SH_INNER << ARM_LPAE_PTE_SH); + *pte |= (1 << ARM_LPAE_PTE_AF); + *pte |= ARM_LPAE_PTE_VALID; + + addr += ARM_LPAE_PTE_L1_BLOCK_SIZE; + } +} + +void arm_smmu_create_identity_map(enum iommu_domain dom) +{ + struct arm_smmu_device iommu; + struct arm_smmu_device *smmu = &iommu; + uint32_t reg, reg2; + unsigned long long reg64; + uint32_t idx; + uint16_t asid; + unsigned int context_bank_index; + unsigned long long pg_table_base; + + smmu->base = (uint8_t *) SMMU_BASE; + reg = mmio_read_32((uintptr_t) (ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_ID1)); + smmu->pgshift = (reg & ID1_PAGESIZE) ? 16 : 12; + smmu->size = ARM_SMMU_RES_SIZE; + smmu->stream_ids = NULL; + + switch (dom) { + case PCIE_PAXC: + smmu->stream_ids = &paxc_stream_ids[0]; + smmu->stream_ids_mask = &paxc_stream_ids_mask[0]; + smmu->streams = ARRAY_SIZE(paxc_stream_ids); + context_bank_index = SMMU_CTX_BANK_IDX; + pg_table_base = ARM_LPAE_PGTBL_PHYS; + break; + case DOMAIN_CRMU: + smmu->stream_ids = &crmu_stream_ids[0]; + smmu->stream_ids_mask = &crmu_stream_ids_mask[0]; + smmu->streams = ARRAY_SIZE(crmu_stream_ids); + context_bank_index = SMMU_CTX_BANK_IDX_SECURE_CRMU; + pg_table_base = ARM_LPAE_PGTBL_PHYS_CRMU; + break; + default: + ERROR("domain not supported\n"); + return; + } + + if (smmu->streams > NUM_OF_SMRS) { + INFO("can not support more than %d sids\n", NUM_OF_SMRS); + return; + } + + /* set up iommu dev. */ + for (idx = 0; idx < smmu->streams; idx++) { + /* S2CR. */ + smmu->s2cr[idx].type = S2CR_TYPE_TRANS; + smmu->s2cr[idx].privcfg = S2CR_PRIVCFG_DEFAULT; + smmu->s2cr[idx].cbndx = context_bank_index; + smmu->cfg[idx].cbndx = context_bank_index; + smmu->cfg[idx].cbar = STG1_WITH_STG2_BYPASS << CBAR_TYPE_SHIFT; + arm_smmu_s2cr_cfg(smmu, idx); + + /* SMR. */ + smmu->smr[idx].mask = smmu->stream_ids_mask[idx]; + smmu->smr[idx].id = smmu->stream_ids[idx]; + smmu->smr[idx].valid = 1; + arm_smmu_smr_cfg(smmu, idx); + + /* CBA2R. 64-bit Translation */ + mmio_write_32((uintptr_t) (ARM_SMMU_GR1(smmu) + + ARM_SMMU_GR1_CBA2R(smmu->cfg[idx].cbndx)), + 0x1); + /* CBAR.*/ + reg = smmu->cfg[idx].cbar; + reg |= (CBAR_S1_BPSHCFG_NSH << CBAR_S1_BPSHCFG_SHIFT) | + (CBAR_S1_MEMATTR_WB << CBAR_S1_MEMATTR_SHIFT); + + mmio_write_32((uintptr_t) (ARM_SMMU_GR1(smmu) + + ARM_SMMU_GR1_CBAR(smmu->cfg[idx].cbndx)), + reg); + + /* TTBCR. */ + reg64 = (ARM_LPAE_TCR_SH_IS << ARM_LPAE_TCR_SH0_SHIFT) | + (ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_IRGN0_SHIFT) | + (ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_ORGN0_SHIFT); + reg64 |= ARM_LPAE_TCR_TG0_4K; + reg64 |= (ARM_LPAE_TCR_PS_40_BIT << ARM_LPAE_TCR_IPS_SHIFT); + /* ias 40 bits.*/ + reg64 |= TTBCR_T0SZ(40) << ARM_LPAE_TCR_T0SZ_SHIFT; + /* Disable speculative walks through TTBR1 */ + reg64 |= ARM_LPAE_TCR_EPD1; + reg = (uint32_t) reg64; + reg2 = (uint32_t) (reg64 >> 32); + reg2 |= TTBCR2_SEP_UPSTREAM; + reg2 |= TTBCR2_AS; + + mmio_write_32((uintptr_t) (ARM_SMMU_CB_BASE(smmu) + + ARM_SMMU_CB(smmu, smmu->cfg[idx].cbndx) + + ARM_SMMU_CB_TTBCR2), reg2); + + mmio_write_32((uintptr_t) (ARM_SMMU_CB_BASE(smmu) + + ARM_SMMU_CB(smmu, smmu->cfg[idx].cbndx) + + ARM_SMMU_CB_TTBCR), reg); + + /* TTBR0. */ + asid = smmu->cfg[idx].cbndx; + reg64 = pg_table_base; + reg64 |= (unsigned long long) asid << TTBRn_ASID_SHIFT; + + mmio_write_64((uintptr_t) (ARM_SMMU_CB_BASE(smmu) + + ARM_SMMU_CB(smmu, smmu->cfg[idx].cbndx) + + ARM_SMMU_CB_TTBR0), reg64); + /* TTBR1. */ + reg64 = 0; + reg64 |= (unsigned long long) asid << TTBRn_ASID_SHIFT; + + mmio_write_64((uintptr_t) (ARM_SMMU_CB_BASE(smmu) + + ARM_SMMU_CB(smmu, smmu->cfg[idx].cbndx) + + ARM_SMMU_CB_TTBR1), reg64); + /* MAIR. */ + reg = (ARM_LPAE_MAIR_ATTR_NC + << ARM_LPAE_MAIR_ATTR_SHIFT + (ARM_LPAE_MAIR_ATTR_IDX_NC)) | + (ARM_LPAE_MAIR_ATTR_WBRWA << + ARM_LPAE_MAIR_ATTR_SHIFT + (ARM_LPAE_MAIR_ATTR_IDX_CACHE)) | + (ARM_LPAE_MAIR_ATTR_DEVICE << + ARM_LPAE_MAIR_ATTR_SHIFT + (ARM_LPAE_MAIR_ATTR_IDX_DEV)); + + mmio_write_32((uintptr_t) (ARM_SMMU_CB_BASE(smmu) + + ARM_SMMU_CB(smmu, smmu->cfg[idx].cbndx) + + ARM_SMMU_CB_S1_MAIR0), reg); + + /* MAIR1. */ + reg = 0; + mmio_write_32((uintptr_t) (ARM_SMMU_CB_BASE(smmu) + + ARM_SMMU_CB(smmu, smmu->cfg[idx].cbndx) + + ARM_SMMU_CB_S1_MAIR1), reg); + /* SCTLR. */ + reg = SCTLR_CFIE | SCTLR_CFRE | SCTLR_AFE | SCTLR_TRE | SCTLR_M; + /* stage 1.*/ + reg |= SCTLR_S1_ASIDPNE; + mmio_write_32((uintptr_t) (ARM_SMMU_CB_BASE(smmu) + + ARM_SMMU_CB(smmu, smmu->cfg[idx].cbndx) + + ARM_SMMU_CB_SCTLR), reg); + } + smmu_set_pgtbl(smmu, dom, (uint64_t *)pg_table_base); +} diff --git a/plat/brcm/board/stingray/src/ncsi.c b/plat/brcm/board/stingray/src/ncsi.c new file mode 100644 index 0000000..58ea9e2 --- /dev/null +++ b/plat/brcm/board/stingray/src/ncsi.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2019-2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <stdbool.h> + +#include <common/debug.h> +#include <lib/mmio.h> + +#include <ncsi.h> +#include <sr_def.h> +#include <sr_utils.h> + +static const char *const io_drives[] = { + "2mA", "4mA", "6mA", "8mA", + "10mA", "12mA", "14mA", "16mA" +}; + +void brcm_stingray_ncsi_init(void) +{ + unsigned int i = 0; + unsigned int selx = 0; + +#if NCSI_IO_DRIVE_STRENGTH_MA == 2 + selx = 0x0; +#elif NCSI_IO_DRIVE_STRENGTH_MA == 4 + selx = 0x1; +#elif NCSI_IO_DRIVE_STRENGTH_MA == 6 + selx = 0x2; +#elif NCSI_IO_DRIVE_STRENGTH_MA == 8 + selx = 0x3; +#elif NCSI_IO_DRIVE_STRENGTH_MA == 10 + selx = 0x4; +#elif NCSI_IO_DRIVE_STRENGTH_MA == 12 + selx = 0x5; +#elif NCSI_IO_DRIVE_STRENGTH_MA == 14 + selx = 0x6; +#elif NCSI_IO_DRIVE_STRENGTH_MA == 16 + selx = 0x7; +#else + ERROR("Unsupported NCSI_IO_DRIVE_STRENGTH_MA. Please check it.\n"); + return; +#endif + INFO("ncsi io drives: %s\n", io_drives[selx]); + + for (i = 0; i < NITRO_NCSI_IOPAD_CONTROL_NUM; i++) { + mmio_clrsetbits_32((NITRO_NCSI_IOPAD_CONTROL_BASE + (i * 4)), + PAD_SELX_MASK, PAD_SELX_VALUE(selx)); + } + + INFO("ncsi init done\n"); +} diff --git a/plat/brcm/board/stingray/src/paxb.c b/plat/brcm/board/stingray/src/paxb.c new file mode 100644 index 0000000..89f76d0 --- /dev/null +++ b/plat/brcm/board/stingray/src/paxb.c @@ -0,0 +1,911 @@ +/* + * Copyright (c) 2016 - 2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <errno.h> +#include <stdbool.h> + +#include <common/debug.h> +#include <drivers/delay_timer.h> +#include <lib/mmio.h> + +#include <paxb.h> +#include <sr_def.h> +#include <sr_utils.h> + +#define PCIE_CORE_PWR_ARR_POWERON 0x8 +#define PCIE_CORE_PWR_ARR_POWEROK 0x4 +#define PCIE_CORE_PWR_POWERON 0x2 +#define PCIE_CORE_PWR_POWEROK 0x1 + +#define PCIE_CORE_USER_CFG (PCIE_CORE_BASE + 0x38) +#define PCIE_PAXB_SMMU_SID_CFG (PCIE_CORE_BASE + 0x60) +#ifdef SID_B8_D1_F1 +#define PAXB_SMMU_SID_CFG_BUS_WIDTH (0x8 << 8) +#define PAXB_SMMU_SID_CFG_DEV_WIDTH (0x1 << 12) +#define PAXB_SMMU_SID_CFG_FUN_WIDTH (0x1 << 16) +#else +#define PAXB_SMMU_SID_CFG_BUS_WIDTH (0x2 << 8) +#define PAXB_SMMU_SID_CFG_DEV_WIDTH (0x5 << 12) +#define PAXB_SMMU_SID_CFG_FUN_WIDTH (0x3 << 16) +#endif + +#define PAXB_APB_TIMEOUT_COUNT_OFFSET 0x034 + +/* allow up to 5 ms for each power switch to stabilize */ +#define PCIE_CORE_PWR_TIMEOUT_MS 5 + +/* wait 1 microsecond for PCIe core soft reset */ +#define PCIE_CORE_SOFT_RST_DELAY_US 1 + +/* + * List of PAXB APB registers + */ +#define PAXB_BASE 0x48000000 +#define PAXB_BASE_OFFSET 0x4000 +#define PAXB_OFFSET(core) (PAXB_BASE + \ + (core) * PAXB_BASE_OFFSET) + +#define PAXB_CLK_CTRL_OFFSET 0x000 +#define PAXB_EP_PERST_SRC_SEL_MASK (1 << 2) +#define PAXB_EP_MODE_PERST_MASK (1 << 1) +#define PAXB_RC_PCIE_RST_OUT_MASK (1 << 0) + +#define PAXB_MAX_IMAP_WINDOWS 8 +#define PAXB_IMAP_REG_WIDTH 8 +#define PAXB_IMAP0_REG_WIDTH 4 +#define PAXB_AXUSER_REG_WIDTH 4 + +#define PAXB_CFG_IND_ADDR_OFFSET 0x120 +#define PAXB_CFG_IND_DATA_OFFSET 0x124 +#define PAXB_CFG_IND_ADDR_MASK 0x1ffc +#define PAXB_CFG_CFG_TYPE_MASK 0x1 + +#define PAXB_EP_CFG_ADDR_OFFSET 0x1f8 +#define PAXB_EP_CFG_DATA_OFFSET 0x1fc +#define PAXB_EP_CFG_ADDR_MASK 0xffc +#define PAXB_EP_CFG_TYPE_MASK 0x1 + +#define PAXB_0_DEFAULT_IMAP 0xed0 +#define DEFAULT_ADDR_INVALID BIT(0) +#define PAXB_0_DEFAULT_IMAP_AXUSER 0xed8 +#define PAXB_0_DEFAULT_IMAP_AXCACHE 0xedc +#define IMAP_AXCACHE 0xff +#define OARR_VALID BIT(0) +#define IMAP_VALID BIT(0) + +#define PAXB_IMAP0_BASE_OFFSET 0xc00 +#define PAXB_IARR0_BASE_OFFSET 0xd00 +#define PAXB_IMAP0_OFFSET(idx) (PAXB_IMAP0_BASE_OFFSET + \ + (idx) * PAXB_IMAP0_REG_WIDTH) +#define PAXB_IMAP0_WINDOW_SIZE 0x1000 + +#define PAXB_IMAP2_OFFSET 0xcc0 +#define PAXB_IMAP0_REGS_TYPE_OFFSET 0xcd0 +#define PAXB_IARR2_LOWER_OFFSET 0xd10 + +#define PAXB_IMAP3_BASE_OFFSET 0xe08 +#define PAXB_IMAP3_OFFSET(idx) (PAXB_IMAP3_BASE_OFFSET + \ + (idx) * PAXB_IMAP_REG_WIDTH) + +#define PAXB_IMAP3_0_AXUSER_B_OFFSET 0xe48 +#define PAXB_IMAP3_0_AXUSER_OFFSET(idx) (PAXB_IMAP3_0_AXUSER_B_OFFSET + \ + (idx) * PAXB_AXUSER_REG_WIDTH) + +#define PAXB_IMAP4_BASE_OFFSET 0xe70 +#define PAXB_IMAP4_OFFSET(idx) (PAXB_IMAP4_BASE_OFFSET + \ + (idx) * PAXB_IMAP_REG_WIDTH) + +#define PAXB_IMAP4_0_AXUSER_B_OFFSET 0xeb0 +#define PAXB_IMAP4_0_AXUSER_OFFSET(idx) (PAXB_IMAP4_0_AXUSER_B_OFFSET + \ + (idx) * PAXB_AXUSER_REG_WIDTH) + +#define PAXB_CFG_LINK_STATUS_OFFSET 0xf0c +#define PAXB_CFG_PHYLINKUP_MASK (1 << 3) +#define PAXB_CFG_DL_ACTIVE_MASK (1 << 2) + +#define PAXB_IMAP0_0_AXUSER_OFFSET 0xf60 +#define PAXB_IMAP2_AXUSER_OFFSET 0xfe0 + +/* cacheable write-back, allocate on both reads and writes */ +#define IMAP_ARCACHE 0x0f0 +#define IMAP_AWCACHE 0xf00 +/* normal access, nonsecure access, and data access */ +/* AWQOS:0xe and ARQOS:0xa */ +/* AWPROT:0x2 and ARPROT:0x1 */ +#define IMAP_AXUSER 0x002e002a + +/* + * List of NIC security and PIPEMUX related registers + */ +#define SR_PCIE_NIC_SECURITY_BASE 0x58100000 +#define NS3Z_PCIE_NIC_SECURITY_BASE 0x48100000 + +#define GITS_TRANSLATER 0x63c30000 + +#define VENDOR_ID 0x14e4 +#define CFG_RC_DEV_ID 0x434 +#define CFG_RC_DEV_SUBID 0x438 +#define PCI_BRIDGE_CTRL_REG_OFFSET 0x43c +#define PCI_CLASS_BRIDGE_MASK 0xffff00 +#define PCI_CLASS_BRIDGE_SHIFT 8 +#define PCI_CLASS_BRIDGE_PCI 0x0604 + +/* + * List of PAXB RC configuration space registers + */ + +/* first capability list entry */ +#define PCI_CAPABILITY_LIST_OFFSET 0x34 +#define PCI_CAPABILITY_SPEED_OFFSET 0xc +#define PCI_EP_CAPABILITY_OFFSET 0x10 + +#define CFG_RC_LINK_STATUS_CTRL_2 0x0dc +#define CFG_RC_LINK_SPEED_SHIFT 0 +#define CFG_RC_LINK_SPEED_MASK (0xf << CFG_RC_LINK_SPEED_SHIFT) + +#define CFG_RC_DEVICE_CAP 0x4d4 +#define CFG_RC_DEVICE_CAP_MPS_SHIFT 0 +#define CFG_RC_DEVICE_CAP_MPS_MASK (0x7 << CFG_RC_DEVICE_CAP_MPS_SHIFT) +/* MPS 256 bytes */ +#define CFG_RC_DEVICE_CAP_MPS_256B (0x1 << CFG_RC_DEVICE_CAP_MPS_SHIFT) +/* MPS 512 bytes */ +#define CFG_RC_DEVICE_CAP_MPS_512B (0x2 << CFG_RC_DEVICE_CAP_MPS_SHIFT) + +#define CFG_RC_TL_FCIMM_NP_LIMIT 0xa10 +#define CFG_RC_TL_FCIMM_NP_VAL 0x01500000 +#define CFG_RC_TL_FCIMM_P_LIMIT 0xa14 +#define CFG_RC_TL_FCIMM_P_VAL 0x03408080 + +#define CFG_RC_LINK_CAP 0x4dc +#define CFG_RC_LINK_CAP_SPEED_SHIFT 0 +#define CFG_RC_LINK_CAP_SPEED_MASK (0xf << CFG_RC_LINK_CAP_SPEED_SHIFT) +#define CFG_RC_LINK_CAP_WIDTH_SHIFT 4 +#define CFG_RC_LINK_CAP_WIDTH_MASK (0x1f << CFG_RC_LINK_CAP_WIDTH_SHIFT) + +#define CFG_LINK_CAP_RC 0x4f0 +#define CFG_RC_DL_ACTIVE_SHIFT 0 +#define CFG_RC_DL_ACTIVE_MASK (0x1 << CFG_RC_DL_ACTIVE_SHIFT) +#define CFG_RC_SLOT_CLK_SHIFT 1 +#define CFG_RC_SLOT_CLK_MASK (0x1 << CFG_RC_SLOT_CLK_SHIFT) + +#define CFG_ROOT_CAP_RC 0x4f8 +#define CFG_ROOT_CAP_LTR_SHIFT 1 +#define CFG_ROOT_CAP_LTR_MASK (0x1 << CFG_ROOT_CAP_LTR_SHIFT) + +#define CFG_RC_CLKREQ_ENABLED 0x4fc +#define CFG_RC_CLKREQ_ENABLED_SHIFT 0 +#define CFG_RC_CLKREQ_ENABLED_MASK (0x1 << CFG_RC_CLKREQ_ENABLED_SHIFT) + +#define CFG_RC_COEFF_ADDR 0x638 + +#define CFG_RC_TL_CTRL_0 0x800 +#define RC_MEM_DW_CHK_MASK 0x03fe + +#define CFG_RC_PDL_CTRL_4 0x1010 +#define NPH_FC_INIT_SHIFT 24 +#define NPH_FC_INIT_MASK (U(0xff) << NPH_FC_INIT_SHIFT) +#define PD_FC_INIT_SHIFT 12 +#define PD_FC_INIT_MASK (0xffff << PD_FC_INIT_SHIFT) + +#define CFG_RC_PDL_CTRL_5 0x1014 +#define PH_INIT_SHIFT 0 +#define PH_INIT_MASK (0xff << PH_INIT_SHIFT) + +#define DL_STATUS_OFFSET 0x1048 +#define PHYLINKUP BIT(13) + +#define PH_INIT 0x10 +#define PD_FC_INIT 0x100 +#define NPH_FC_INIT 0x8 + +#define SRP_PH_INIT 0x7F +#define SRP_PD_FC_INIT 0x200 +#define SRP_NPH_FC_INIT 0x7F + +#define CFG_ADDR_BUS_NUM_SHIFT 20 +#define CFG_ADDR_DEV_NUM_SHIFT 15 +#define CFG_ADDR_FUNC_NUM_SHIFT 12 +#define CFG_ADDR_REG_NUM_SHIFT 2 +#define CFG_ADDR_REG_NUM_MASK 0x00000ffc +#define CFG_ADDR_CFG_TYPE_MASK 0x00000003 + +#define DL_LINK_UP_TIMEOUT_MS 1000 + +#define CFG_RETRY_STATUS 0xffff0001 +#define CRS_TIMEOUT_MS 5000 + +/* create EP config data to write */ +#define DEF_BUS_NO 1 /* default bus 1 */ +#define DEF_SLOT_NO 0 /* default slot 0 */ +#define DEF_FN_NO 0 /* default fn 0 */ + +#define EP_CONFIG_VAL(bus_no, slot, fn, where) \ + (((bus_no) << CFG_ADDR_BUS_NUM_SHIFT) | \ + ((slot) << CFG_ADDR_DEV_NUM_SHIFT) | \ + ((fn) << CFG_ADDR_FUNC_NUM_SHIFT) | \ + ((where) & CFG_ADDR_REG_NUM_MASK) | \ + (1 & CFG_ADDR_CFG_TYPE_MASK)) + +/* PAXB security offset */ +#define PAXB_SECURITY_IDM_OFFSET 0x1c +#define PAXB_SECURITY_APB_OFFSET 0x24 +#define PAXB_SECURITY_ECAM_OFFSET 0x3c + +#define paxb_get_config(type) paxb_get_##type##_config() + +static unsigned int paxb_sec_reg_offset[] = { + 0x0c, /* PAXB0 AXI */ + 0x10, /* PAXB1 AXI */ + 0x14, /* PAXB2 AXI */ + 0x18, /* PAXB3 AXI */ + 0x20, /* PAXB4 AXI */ + 0x28, /* PAXB5 AXI */ + 0x2c, /* PAXB6 AXI */ + 0x30, /* PAXB7 AXI */ + 0x24, /* PAXB APB */ +}; + +const paxb_cfg *paxb; + +/* + * Given a PIPEMUX strap and PCIe core index, this function returns 1 if a + * PCIe core needs to be enabled + */ +int pcie_core_needs_enable(unsigned int core_idx) +{ + if (paxb->core_needs_enable) + return paxb->core_needs_enable(core_idx); + + return 0; +} + +static void pcie_set_default_tx_coeff(uint32_t core_idx, uint32_t link_width) +{ + unsigned int lanes = 0; + uint32_t data, addr; + + addr = CFG_RC_COEFF_ADDR; + for (lanes = 0; lanes < link_width; lanes = lanes + 2) { + data = paxb_rc_cfg_read(core_idx, addr); + data &= 0xf0f0f0f0; + data |= (7 & 0xf); + data |= (7 & 0xf) << 8; + data |= (7 & 0xf) << 16; + data |= (7 & 0xf) << 24; + + paxb_rc_cfg_write(core_idx, addr, data); + addr += 4; + } +} + +static int paxb_rc_link_init(void) +{ + uint32_t val, link_speed; + unsigned int link_width; + uint32_t core_idx; + + for (core_idx = 0; core_idx < paxb->num_cores; core_idx++) { + if (!pcie_core_needs_enable(core_idx)) + continue; + + link_width = paxb->get_link_width(core_idx); + if (!link_width) { + ERROR("Unsupported PIPEMUX\n"); + return -EOPNOTSUPP; + } + + link_speed = paxb->get_link_speed(); + /* program RC's link cap reg to advertise proper link width */ + val = paxb_rc_cfg_read(core_idx, CFG_RC_LINK_CAP); + val &= ~CFG_RC_LINK_CAP_WIDTH_MASK; + val |= (link_width << CFG_RC_LINK_CAP_WIDTH_SHIFT); + paxb_rc_cfg_write(core_idx, CFG_RC_LINK_CAP, val); + + /* program RC's link cap reg to advertise proper link speed */ + val = paxb_rc_cfg_read(core_idx, CFG_RC_LINK_CAP); + val &= ~CFG_RC_LINK_CAP_SPEED_MASK; + val |= link_speed << CFG_RC_LINK_CAP_SPEED_SHIFT; + paxb_rc_cfg_write(core_idx, CFG_RC_LINK_CAP, val); + + /* also need to program RC's link status control register */ + val = paxb_rc_cfg_read(core_idx, CFG_RC_LINK_STATUS_CTRL_2); + val &= ~(CFG_RC_LINK_SPEED_MASK); + val |= link_speed << CFG_RC_LINK_SPEED_SHIFT; + paxb_rc_cfg_write(core_idx, CFG_RC_LINK_STATUS_CTRL_2, val); + +#ifdef WAR_PLX_PRESET_PARITY_FAIL + /* WAR to avoid crash with PLX switch in GEN3*/ + /* While PRESET, PLX switch is not fixing parity so disabled */ + val = paxb_rc_cfg_read(core_idx, CFG_RC_REG_PHY_CTL_10); + val &= ~(PHY_CTL_10_GEN3_MATCH_PARITY); + paxb_rc_cfg_write(core_idx, CFG_RC_REG_PHY_CTL_10, val); +#endif + pcie_set_default_tx_coeff(core_idx, link_width); + } + return 0; +} + +#ifdef PAXB_LINKUP +static void paxb_perst_ctrl(unsigned int core_idx, bool assert) +{ + uint32_t clk_ctrl = PAXB_OFFSET(core_idx) + PAXB_CLK_CTRL_OFFSET; + + if (assert) { + mmio_clrbits_32(clk_ctrl, PAXB_EP_PERST_SRC_SEL_MASK | + PAXB_EP_MODE_PERST_MASK | + PAXB_RC_PCIE_RST_OUT_MASK); + udelay(250); + } else { + mmio_setbits_32(clk_ctrl, PAXB_RC_PCIE_RST_OUT_MASK); + mdelay(100); + } +} + +static void paxb_start_link_up(void) +{ + unsigned int core_idx; + uint32_t val, timeout; + + for (core_idx = 0; core_idx < paxb->num_cores; core_idx++) { + if (!pcie_core_needs_enable(core_idx)) + continue; + + /* toggle PERST */ + paxb_perst_ctrl(core_idx, true); + paxb_perst_ctrl(core_idx, false); + + timeout = DL_LINK_UP_TIMEOUT_MS; + /* wait for Link up */ + do { + val = mmio_read_32(PAXB_OFFSET(core_idx) + + PAXB_CFG_LINK_STATUS_OFFSET); + if (val & PAXB_CFG_DL_ACTIVE_MASK) + break; + + mdelay(1); + } while (--timeout); + + if (!timeout) + ERROR("PAXB core %u link is down\n", core_idx); + } +} +#endif + +static void pcie_core_soft_reset(unsigned int core_idx) +{ + uint32_t offset = core_idx * PCIE_CORE_PWR_OFFSET; + uintptr_t ctrl = (uintptr_t)(PCIE_CORE_SOFT_RST_CFG_BASE + offset); + + /* Put PCIe core in soft reset */ + mmio_clrbits_32(ctrl, PCIE_CORE_SOFT_RST); + + /* Wait for 1 us before pulling PCIe core out of soft reset */ + udelay(PCIE_CORE_SOFT_RST_DELAY_US); + + mmio_setbits_32(ctrl, PCIE_CORE_SOFT_RST); +} + +static int pcie_core_pwron_switch(uintptr_t ctrl, uintptr_t status, + uint32_t mask) +{ + uint32_t val; + unsigned int timeout = PCIE_CORE_PWR_TIMEOUT_MS; + + /* enable switch */ + mmio_setbits_32(ctrl, mask); + + /* now wait for it to stabilize */ + do { + val = mmio_read_32(status); + if ((val & mask) == mask) + return 0; + mdelay(1); + } while (--timeout); + + return -EIO; +} + +static int pcie_core_pwr_seq(uintptr_t ctrl, uintptr_t status) +{ + int ret; + + /* + * Enable the switch with the following sequence: + * 1. Array weak switch output switch + * 2. Array strong switch + * 3. Weak switch output acknowledge + * 4. Strong switch output acknowledge + */ + ret = pcie_core_pwron_switch(ctrl, status, PCIE_CORE_PWR_ARR_POWERON); + if (ret) + return ret; + + ret = pcie_core_pwron_switch(ctrl, status, PCIE_CORE_PWR_ARR_POWEROK); + if (ret) + return ret; + + ret = pcie_core_pwron_switch(ctrl, status, PCIE_CORE_PWR_POWERON); + if (ret) + return ret; + + ret = pcie_core_pwron_switch(ctrl, status, PCIE_CORE_PWR_POWEROK); + if (ret) + return ret; + + return 0; +} + +/* + * This function enables PCIe core and PAXB memory buffer power, and then + * remove the PCIe core from isolation + */ +static int pcie_core_pwr_init(unsigned int core_idx) +{ + int ret; + uint32_t offset = core_idx * PCIE_CORE_PWR_OFFSET; + uintptr_t ctrl, status; + + /* enable mem power to PCIe core */ + ctrl = (uintptr_t)(PCIE_CORE_MEM_PWR_BASE + offset); + status = (uintptr_t)(PCIE_CORE_MEM_PWR_STATUS_BASE + offset); + ret = pcie_core_pwr_seq(ctrl, status); + if (ret) { + ERROR("PCIe core mem power failed\n"); + return ret; + } + + /* now enable mem power to PAXB wrapper */ + ctrl = (uintptr_t)(PCIE_PAXB_MEM_PWR_BASE + offset); + status = (uintptr_t)(PCIE_PAXB_MEM_PWR_STATUS_BASE + offset); + ret = pcie_core_pwr_seq(ctrl, status); + if (ret) { + ERROR("PAXB mem power failed\n"); + return ret; + } + + /* now remove power isolation */ + ctrl = (uintptr_t)(PCIE_CORE_ISO_CFG_BASE + offset); + mmio_clrbits_32(ctrl, PCIE_CORE_ISO | PCIE_CORE_MEM_ISO); + + return 0; +} + +static void pcie_ss_reset(void) +{ + mmio_setbits_32(CDRU_MISC_RESET_CONTROL, + 1 << CDRU_MISC_RESET_CONTROL__CDRU_PCIE_RESET_N_R); +} + +/* + * This function reads the PIPEMUX strap, figures out all the PCIe cores that + * need to be enabled and enable the mem power for those cores + */ +static int pcie_cores_init(void) +{ + int ret = 0; + uint32_t core_idx; + + if (paxb->pipemux_init) { + ret = paxb->pipemux_init(); + if (ret) + return ret; + } + + /* bring PCIe subsystem out of reset */ + pcie_ss_reset(); + + /* power up all PCIe cores that will be used as RC */ + for (core_idx = 0; core_idx < paxb->num_cores; core_idx++) { + if (!pcie_core_needs_enable(core_idx)) + continue; + + ret = pcie_core_pwr_init(core_idx); + if (ret) { + ERROR("PCIe core %u power up failed\n", core_idx); + return ret; + } + + pcie_core_soft_reset(core_idx); + + VERBOSE("PCIe core %u is powered up\n", core_idx); + } + + return ret; +} + +void paxb_rc_cfg_write(unsigned int core_idx, unsigned int where, + uint32_t val) +{ + mmio_write_32(PAXB_OFFSET(core_idx) + PAXB_CFG_IND_ADDR_OFFSET, + (where & PAXB_CFG_IND_ADDR_MASK) | + PAXB_CFG_CFG_TYPE_MASK); + mmio_write_32(PAXB_OFFSET(core_idx) + PAXB_CFG_IND_DATA_OFFSET, val); +} + +unsigned int paxb_rc_cfg_read(unsigned int core_idx, unsigned int where) +{ + unsigned int val; + + mmio_write_32(PAXB_OFFSET(core_idx) + PAXB_CFG_IND_ADDR_OFFSET, + (where & PAXB_CFG_IND_ADDR_MASK) | + PAXB_CFG_CFG_TYPE_MASK); + val = mmio_read_32(PAXB_OFFSET(core_idx) + PAXB_CFG_IND_DATA_OFFSET); + + return val; +} + +static void paxb_cfg_mps(void) +{ + uint32_t val, core_idx, mps; + + for (core_idx = 0; core_idx < paxb->num_cores; core_idx++) { + if (!pcie_core_needs_enable(core_idx)) + continue; + + val = paxb_rc_cfg_read(core_idx, CFG_RC_DEVICE_CAP); + val &= ~CFG_RC_DEVICE_CAP_MPS_MASK; + mps = CFG_RC_DEVICE_CAP_MPS_256B; + if (core_idx == 0 || core_idx == 1 || + core_idx == 6 || core_idx == 7) { + mps = CFG_RC_DEVICE_CAP_MPS_512B; + } + val |= mps; + paxb_rc_cfg_write(core_idx, CFG_RC_DEVICE_CAP, val); + } +} + +static void paxb_cfg_dev_id(void) +{ + uint32_t val, core_idx; + uint32_t device_id; + + device_id = paxb->device_id; + + for (core_idx = 0; core_idx < paxb->num_cores; core_idx++) { + if (!pcie_core_needs_enable(core_idx)) + continue; + + /* Set Core in RC mode */ + mmio_setbits_32(PCIE_CORE_USER_CFG + + (core_idx * PCIE_CORE_PWR_OFFSET), 1); + + /* force class to PCI_CLASS_BRIDGE_PCI (0x0604) */ + val = paxb_rc_cfg_read(core_idx, PCI_BRIDGE_CTRL_REG_OFFSET); + val &= ~PCI_CLASS_BRIDGE_MASK; + val |= (PCI_CLASS_BRIDGE_PCI << PCI_CLASS_BRIDGE_SHIFT); + paxb_rc_cfg_write(core_idx, PCI_BRIDGE_CTRL_REG_OFFSET, val); + + val = (VENDOR_ID << 16) | device_id; + paxb_rc_cfg_write(core_idx, CFG_RC_DEV_ID, val); + + val = (device_id << 16) | VENDOR_ID; + paxb_rc_cfg_write(core_idx, CFG_RC_DEV_SUBID, val); + } +} + +static void paxb_cfg_tgt_trn(void) +{ + uint32_t val, core_idx; + + /* + * Disable all mem Rd/Wr size check so it allows target read/write + * transactions to be more than stipulated DW. As a result, PAXB root + * complex will not abort these read/write transcations beyond + * stipulated limit + */ + for (core_idx = 0; core_idx < paxb->num_cores; core_idx++) { + if (!pcie_core_needs_enable(core_idx)) + continue; + + val = paxb_rc_cfg_read(core_idx, CFG_RC_TL_CTRL_0); + val &= ~(RC_MEM_DW_CHK_MASK); + paxb_rc_cfg_write(core_idx, CFG_RC_TL_CTRL_0, val); + } +} + +static void paxb_cfg_pdl_ctrl(void) +{ + uint32_t val, core_idx; + uint32_t nph, ph, pd; + + /* increase the credit counter to 4 for non-posted header */ + for (core_idx = 0; core_idx < paxb->num_cores; core_idx++) { + if (!pcie_core_needs_enable(core_idx)) + continue; + + nph = NPH_FC_INIT; + ph = PH_INIT; + pd = PD_FC_INIT; + + if (core_idx == 0 || core_idx == 1 || + core_idx == 6 || core_idx == 7) { + nph = SRP_NPH_FC_INIT; + ph = SRP_PH_INIT; + pd = SRP_PD_FC_INIT; + } + val = paxb_rc_cfg_read(core_idx, CFG_RC_PDL_CTRL_4); + val &= ~NPH_FC_INIT_MASK; + val &= ~PD_FC_INIT_MASK; + val = val | (nph << NPH_FC_INIT_SHIFT); + val = val | (pd << PD_FC_INIT_SHIFT); + paxb_rc_cfg_write(core_idx, CFG_RC_PDL_CTRL_4, val); + + val = paxb_rc_cfg_read(core_idx, CFG_RC_PDL_CTRL_5); + val &= ~PH_INIT_MASK; + val = val | (ph << PH_INIT_SHIFT); + paxb_rc_cfg_write(core_idx, CFG_RC_PDL_CTRL_5, val); + + /* + * ASIC to give more optmized value after further investigation. + * till then this is important to have to get similar + * performance on all the slots. + */ + paxb_rc_cfg_write(core_idx, CFG_RC_TL_FCIMM_NP_LIMIT, + CFG_RC_TL_FCIMM_NP_VAL); + + paxb_rc_cfg_write(core_idx, CFG_RC_TL_FCIMM_P_LIMIT, + CFG_RC_TL_FCIMM_P_VAL); + } +} + +static void paxb_cfg_clkreq(void) +{ + uint32_t val, core_idx; + + for (core_idx = 0; core_idx < paxb->num_cores; core_idx++) { + if (!pcie_core_needs_enable(core_idx)) + continue; + + val = paxb_rc_cfg_read(core_idx, CFG_RC_CLKREQ_ENABLED); + val &= ~CFG_RC_CLKREQ_ENABLED_MASK; + paxb_rc_cfg_write(core_idx, CFG_RC_CLKREQ_ENABLED, val); + } +} + +static void paxb_cfg_dl_active(bool enable) +{ + uint32_t val, core_idx; + + for (core_idx = 0; core_idx < paxb->num_cores; core_idx++) { + if (!pcie_core_needs_enable(core_idx)) + continue; + + val = paxb_rc_cfg_read(core_idx, CFG_LINK_CAP_RC); + if (enable) + val |= CFG_RC_DL_ACTIVE_MASK; + else + val &= ~CFG_RC_DL_ACTIVE_MASK; + paxb_rc_cfg_write(core_idx, CFG_LINK_CAP_RC, val); + } +} + +static void paxb_cfg_LTR(int enable) +{ + uint32_t val, core_idx; + + for (core_idx = 0; core_idx < paxb->num_cores; core_idx++) { + if (!pcie_core_needs_enable(core_idx)) + continue; + + val = paxb_rc_cfg_read(core_idx, CFG_ROOT_CAP_RC); + if (enable) + val |= CFG_ROOT_CAP_LTR_MASK; + else + val &= ~CFG_ROOT_CAP_LTR_MASK; + paxb_rc_cfg_write(core_idx, CFG_ROOT_CAP_RC, val); + } +} + +static void paxb_ib_regs_bypass(void) +{ + unsigned int i, j; + + for (i = 0; i < paxb->num_cores; i++) { + if (!pcie_core_needs_enable(i)) + continue; + + /* Configure Default IMAP window */ + mmio_write_32(PAXB_OFFSET(i) + PAXB_0_DEFAULT_IMAP, + DEFAULT_ADDR_INVALID); + mmio_write_32(PAXB_OFFSET(i) + PAXB_0_DEFAULT_IMAP_AXUSER, + IMAP_AXUSER); + mmio_write_32(PAXB_OFFSET(i) + PAXB_0_DEFAULT_IMAP_AXCACHE, + IMAP_AXCACHE); + + /* Configure MSI IMAP window */ + mmio_setbits_32(PAXB_OFFSET(i) + + PAXB_IMAP0_REGS_TYPE_OFFSET, + 0x1); + mmio_write_32(PAXB_OFFSET(i) + PAXB_IARR0_BASE_OFFSET, + GITS_TRANSLATER | OARR_VALID); + for (j = 0; j < PAXB_MAX_IMAP_WINDOWS; j++) { + mmio_write_32(PAXB_OFFSET(i) + PAXB_IMAP0_OFFSET(j), + (GITS_TRANSLATER + + (j * PAXB_IMAP0_WINDOW_SIZE)) | + IMAP_VALID); + } + } +} + +static void paxb_ib_regs_init(void) +{ + unsigned int core_idx; + + for (core_idx = 0; core_idx < paxb->num_cores; core_idx++) { + if (!pcie_core_needs_enable(core_idx)) + continue; + + /* initialize IARR2 to zero */ + mmio_write_32(PAXB_OFFSET(core_idx) + PAXB_IARR2_LOWER_OFFSET, + 0x0); + mmio_setbits_32(PAXB_OFFSET(core_idx) + + PAXB_IMAP0_REGS_TYPE_OFFSET, + 0x1); + } +} + +static void paxb_cfg_apb_timeout(void) +{ + unsigned int core_idx; + + for (core_idx = 0; core_idx < paxb->num_cores; core_idx++) { + if (!pcie_core_needs_enable(core_idx)) + continue; + + /* allow unlimited timeout */ + mmio_write_32(PAXB_OFFSET(core_idx) + + PAXB_APB_TIMEOUT_COUNT_OFFSET, + 0xFFFFFFFF); + } +} + +static void paxb_smmu_cfg(void) +{ + unsigned int core_idx; + uint32_t offset; + uint32_t val; + + for (core_idx = 0; core_idx < paxb->num_cores; core_idx++) { + if (!pcie_core_needs_enable(core_idx)) + continue; + + offset = core_idx * PCIE_CORE_PWR_OFFSET; + val = mmio_read_32(PCIE_PAXB_SMMU_SID_CFG + offset); + val &= ~(0xFFF00); + val |= (PAXB_SMMU_SID_CFG_FUN_WIDTH | + PAXB_SMMU_SID_CFG_DEV_WIDTH | + PAXB_SMMU_SID_CFG_BUS_WIDTH); + mmio_write_32(PCIE_PAXB_SMMU_SID_CFG + offset, val); + val = mmio_read_32(PCIE_PAXB_SMMU_SID_CFG + offset); + VERBOSE("smmu cfg reg 0x%x\n", val); + } +} + +static void paxb_cfg_coherency(void) +{ + unsigned int i, j; + + for (i = 0; i < paxb->num_cores; i++) { + if (!pcie_core_needs_enable(i)) + continue; + +#ifdef USE_DDR + mmio_write_32(PAXB_OFFSET(i) + PAXB_IMAP2_OFFSET, + IMAP_ARCACHE | IMAP_AWCACHE); +#endif + + mmio_write_32(PAXB_OFFSET(i) + PAXB_IMAP0_0_AXUSER_OFFSET, + IMAP_AXUSER); + + mmio_write_32(PAXB_OFFSET(i) + PAXB_IMAP2_AXUSER_OFFSET, + IMAP_AXUSER); + + for (j = 0; j < PAXB_MAX_IMAP_WINDOWS; j++) { +#ifdef USE_DDR + mmio_write_32(PAXB_OFFSET(i) + PAXB_IMAP3_OFFSET(j), + IMAP_ARCACHE | IMAP_AWCACHE); + mmio_write_32(PAXB_OFFSET(i) + PAXB_IMAP4_OFFSET(j), + IMAP_ARCACHE | IMAP_AWCACHE); +#endif + /* zero out IMAP0 mapping windows for MSI/MSI-X */ + mmio_write_32(PAXB_OFFSET(i) + PAXB_IMAP0_OFFSET(j), + 0x0); + + mmio_write_32(PAXB_OFFSET(i) + + PAXB_IMAP3_0_AXUSER_OFFSET(j), + IMAP_AXUSER); + mmio_write_32(PAXB_OFFSET(i) + + PAXB_IMAP4_0_AXUSER_OFFSET(j), + IMAP_AXUSER); + } + } +} + +/* + * This function configures all PAXB related blocks to allow non-secure access + */ +void paxb_ns_init(enum paxb_type type) +{ + unsigned int reg; + + switch (type) { + case PAXB_SR: + for (reg = 0; reg < ARRAY_SIZE(paxb_sec_reg_offset); reg++) { + + mmio_setbits_32(SR_PCIE_NIC_SECURITY_BASE + + paxb_sec_reg_offset[reg], 0x1); + } + /* Enabled all PAXB's relevant IDM blocks access in non-secure mode */ + mmio_setbits_32(SR_PCIE_NIC_SECURITY_BASE + PAXB_SECURITY_IDM_OFFSET, + 0xffff); + break; + case PAXB_NS3Z: + mmio_setbits_32(NS3Z_PCIE_NIC_SECURITY_BASE + + paxb_sec_reg_offset[0], 0x1); + mmio_setbits_32(NS3Z_PCIE_NIC_SECURITY_BASE + + PAXB_SECURITY_IDM_OFFSET, 0xffff); + mmio_setbits_32(NS3Z_PCIE_NIC_SECURITY_BASE + + PAXB_SECURITY_APB_OFFSET, 0x7); + mmio_setbits_32(NS3Z_PCIE_NIC_SECURITY_BASE + + PAXB_SECURITY_ECAM_OFFSET, 0x1); + break; + } +} + +static int paxb_set_config(void) +{ + paxb = paxb_get_config(sr); + if (paxb) + return 0; + + return -ENODEV; +} + +void paxb_init(void) +{ + int ret; + + ret = paxb_set_config(); + if (ret) + return; + + paxb_ns_init(paxb->type); + + ret = pcie_cores_init(); + if (ret) + return; + + if (paxb->phy_init) { + ret = paxb->phy_init(); + if (ret) + return; + } + + paxb_cfg_dev_id(); + paxb_cfg_tgt_trn(); + paxb_cfg_pdl_ctrl(); + if (paxb->type == PAXB_SR) { + paxb_ib_regs_init(); + paxb_cfg_coherency(); + } else + paxb_ib_regs_bypass(); + + paxb_cfg_apb_timeout(); + paxb_smmu_cfg(); + paxb_cfg_clkreq(); + paxb_rc_link_init(); + + /* Stingray Doesn't support LTR */ + paxb_cfg_LTR(false); + paxb_cfg_dl_active(true); + + paxb_cfg_mps(); + +#ifdef PAXB_LINKUP + paxb_start_link_up(); +#endif + INFO("PAXB init done\n"); +} diff --git a/plat/brcm/board/stingray/src/paxc.c b/plat/brcm/board/stingray/src/paxc.c new file mode 100644 index 0000000..44af4b0 --- /dev/null +++ b/plat/brcm/board/stingray/src/paxc.c @@ -0,0 +1,267 @@ +/* + * Copyright (c) 2017 - 2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <common/debug.h> +#include <lib/mmio.h> + +#include <iommu.h> +#include <platform_def.h> +#include <sr_utils.h> + +#define PAXC_BASE 0x60400000 +#define PAXC_AXI_CFG_PF 0x10 +#define PAXC_AXI_CFG_PF_OFFSET(pf) (PAXC_AXI_CFG_PF + (pf) * 4) +#define PAXC_ARPROT_PF_CFG 0x40 +#define PAXC_AWPROT_PF_CFG 0x44 + +#define PAXC_ARQOS_PF_CFG 0x48 +#define PAXC_ARQOS_VAL 0xaaaaaaaa + +#define PAXC_AWQOS_PF_CFG 0x4c +#define PAXC_AWQOS_VAL 0xeeeeeeee + +#define PAXC_CFG_IND_ADDR_OFFSET 0x1f0 +#define PAXC_CFG_IND_ADDR_MASK 0xffc +#define PAXC_CFG_IND_DATA_OFFSET 0x1f4 + +/* offsets for PAXC root complex configuration space registers */ + +#define PAXC_CFG_ID_OFFSET 0x434 +#define PAXC_RC_VENDOR_ID 0x14e4 +#define PAXC_RC_VENDOR_ID_SHIFT 16 + +#define PAXC_RC_DEVICE_ID 0xd750 + +#define PAXC_CFG_LINK_CAP_OFFSET 0x4dc +#define PAXC_RC_LINK_CAP_SPD_SHIFT 0 +#define PAXC_RC_LINK_CAP_SPD_MASK (0xf << PAXC_RC_LINK_CAP_SPD_SHIFT) +#define PAXC_RC_LINK_CAP_SPD 3 +#define PAXC_RC_LINK_CAP_WIDTH_SHIFT 4 +#define PAXC_RC_LINK_CAP_WIDTH_MASK (0x1f << PAXC_RC_LINK_CAP_WIDTH_SHIFT) +#define PAXC_RC_LINK_CAP_WIDTH 16 + +/* offsets for MHB registers */ + +#define MHB_BASE 0x60401000 +#define MHB_MEM_PWR_STATUS_PAXC (MHB_BASE + 0x1c0) +#define MHB_PWR_ARR_POWERON 0x8 +#define MHB_PWR_ARR_POWEROK 0x4 +#define MHB_PWR_POWERON 0x2 +#define MHB_PWR_POWEROK 0x1 +#define MHB_PWR_STATUS_MASK (MHB_PWR_ARR_POWERON | \ + MHB_PWR_ARR_POWEROK | \ + MHB_PWR_POWERON | \ + MHB_PWR_POWEROK) + +/* max number of PFs from Nitro that PAXC sees */ +#define MAX_NR_NITRO_PF 8 + +#ifdef EMULATION_SETUP +static void paxc_reg_dump(void) +{ +} +#else +/* total number of PAXC registers */ +#define NR_PAXC_REGS 53 +static void paxc_reg_dump(void) +{ + uint32_t idx, offset = 0; + + VERBOSE("PAXC register dump start\n"); + for (idx = 0; idx < NR_PAXC_REGS; idx++, offset += 4) + VERBOSE("offset: 0x%x val: 0x%x\n", offset, + mmio_read_32(PAXC_BASE + offset)); + VERBOSE("PAXC register dump end\n"); +} +#endif /* EMULATION_SETUP */ + +#ifdef EMULATION_SETUP +static void mhb_reg_dump(void) +{ +} +#else +#define NR_MHB_REGS 227 +static void mhb_reg_dump(void) +{ + uint32_t idx, offset = 0; + + VERBOSE("MHB register dump start\n"); + for (idx = 0; idx < NR_MHB_REGS; idx++, offset += 4) + VERBOSE("offset: 0x%x val: 0x%x\n", offset, + mmio_read_32(MHB_BASE + offset)); + VERBOSE("MHB register dump end\n"); +} +#endif /* EMULATION_SETUP */ + +static void paxc_rc_cfg_write(uint32_t where, uint32_t val) +{ + mmio_write_32(PAXC_BASE + PAXC_CFG_IND_ADDR_OFFSET, + where & PAXC_CFG_IND_ADDR_MASK); + mmio_write_32(PAXC_BASE + PAXC_CFG_IND_DATA_OFFSET, val); +} + +static uint32_t paxc_rc_cfg_read(uint32_t where) +{ + mmio_write_32(PAXC_BASE + PAXC_CFG_IND_ADDR_OFFSET, + where & PAXC_CFG_IND_ADDR_MASK); + return mmio_read_32(PAXC_BASE + PAXC_CFG_IND_DATA_OFFSET); +} + +/* + * Function to program PAXC root complex link capability register + */ +static void paxc_cfg_link_cap(void) +{ + uint32_t val; + + val = paxc_rc_cfg_read(PAXC_CFG_LINK_CAP_OFFSET); + val &= ~(PAXC_RC_LINK_CAP_SPD_MASK | PAXC_RC_LINK_CAP_WIDTH_MASK); + val |= (PAXC_RC_LINK_CAP_SPD << PAXC_RC_LINK_CAP_SPD_SHIFT) | + (PAXC_RC_LINK_CAP_WIDTH << PAXC_RC_LINK_CAP_WIDTH_SHIFT); + paxc_rc_cfg_write(PAXC_CFG_LINK_CAP_OFFSET, val); +} + +/* + * Function to program PAXC root complex vendor ID and device ID + */ +static void paxc_cfg_id(void) +{ + uint32_t val; + + val = (PAXC_RC_VENDOR_ID << PAXC_RC_VENDOR_ID_SHIFT) | + PAXC_RC_DEVICE_ID; + paxc_rc_cfg_write(PAXC_CFG_ID_OFFSET, val); +} + +void paxc_init(void) +{ + unsigned int pf_index; + unsigned int val; + + val = mmio_read_32(MHB_MEM_PWR_STATUS_PAXC); + if ((val & MHB_PWR_STATUS_MASK) != MHB_PWR_STATUS_MASK) { + INFO("PAXC not powered\n"); + return; + } + + paxc_cfg_id(); + paxc_cfg_link_cap(); + + paxc_reg_dump(); + mhb_reg_dump(); + +#ifdef USE_DDR + /* + * Set AWCACHE and ARCACHE to 0xff (Cacheable write-back, + * allocate on both reads and writes) per + * recommendation from the ASIC team + */ + val = 0xff; +#else + /* disable IO cache if non-DDR memory is used, e.g., external SRAM */ + val = 0x0; +#endif + for (pf_index = 0; pf_index < MAX_NR_NITRO_PF; pf_index++) + mmio_write_32(PAXC_BASE + PAXC_AXI_CFG_PF_OFFSET(pf_index), + val); + + /* + * Set ARPROT and AWPROT to enable non-secure access from + * PAXC to all PFs, PF0 to PF7 + */ + mmio_write_32(PAXC_BASE + PAXC_ARPROT_PF_CFG, 0x22222222); + mmio_write_32(PAXC_BASE + PAXC_AWPROT_PF_CFG, 0x22222222); + + mmio_write_32(PAXC_BASE + PAXC_ARQOS_PF_CFG, PAXC_ARQOS_VAL); + mmio_write_32(PAXC_BASE + PAXC_AWQOS_PF_CFG, PAXC_AWQOS_VAL); + + INFO("PAXC init done\n"); +} + +/* + * These defines do not match the regfile but they are renamed in a way such + * that they are much more readible + */ + +#define MHB_NIC_SECURITY_BASE 0x60500000 +#define MHB_NIC_PAXC_AXI_NS 0x0008 +#define MHB_NIC_IDM_NS 0x000c +#define MHB_NIC_MHB_APB_NS 0x0010 +#define MHB_NIC_NITRO_AXI_NS 0x0014 +#define MHB_NIC_PCIE_AXI_NS 0x0018 +#define MHB_NIC_PAXC_APB_NS 0x001c +#define MHB_NIC_EP_APB_NS 0x0020 + +#define MHB_NIC_PAXC_APB_S_IDM_SHIFT 5 +#define MHB_NIC_EP_APB_S_IDM_SHIFT 4 +#define MHB_NIC_MHB_APB_S_IDM_SHIFT 3 +#define MHB_NIC_PAXC_AXI_S_IDM_SHIFT 2 +#define MHB_NIC_PCIE_AXI_S_IDM_SHIFT 1 +#define MHB_NIC_NITRO_AXI_S_IDM_SHIFT 0 + +#define NIC400_NITRO_TOP_NIC_SECURITY_BASE 0x60d00000 + +#define NITRO_NIC_SECURITY_3_SHIFT 0x14 +#define NITRO_NIC_SECURITY_4_SHIFT 0x18 +#define NITRO_NIC_SECURITY_5_SHIFT 0x1c +#define NITRO_NIC_SECURITY_6_SHIFT 0x20 + +void paxc_mhb_ns_init(void) +{ + unsigned int val; + uintptr_t mhb_nic_gpv = MHB_NIC_SECURITY_BASE; +#ifndef NITRO_SECURE_ACCESS + uintptr_t nic400_nitro_gpv = NIC400_NITRO_TOP_NIC_SECURITY_BASE; +#endif /* NITRO_SECURE_ACCESS */ + + /* set PAXC AXI to allow non-secure access */ + val = mmio_read_32(mhb_nic_gpv + MHB_NIC_PAXC_AXI_NS); + val |= 0x1; + mmio_write_32(mhb_nic_gpv + MHB_NIC_PAXC_AXI_NS, val); + + /* set various MHB IDM interfaces to allow non-secure access */ + val = mmio_read_32(mhb_nic_gpv + MHB_NIC_IDM_NS); + val |= (0x1 << MHB_NIC_PAXC_APB_S_IDM_SHIFT); + val |= (0x1 << MHB_NIC_EP_APB_S_IDM_SHIFT); + val |= (0x1 << MHB_NIC_MHB_APB_S_IDM_SHIFT); + val |= (0x1 << MHB_NIC_PAXC_AXI_S_IDM_SHIFT); + val |= (0x1 << MHB_NIC_PCIE_AXI_S_IDM_SHIFT); + val |= (0x1 << MHB_NIC_NITRO_AXI_S_IDM_SHIFT); + mmio_write_32(mhb_nic_gpv + MHB_NIC_IDM_NS, val); + + /* set MHB APB to allow non-secure access */ + val = mmio_read_32(mhb_nic_gpv + MHB_NIC_MHB_APB_NS); + val |= 0x1; + mmio_write_32(mhb_nic_gpv + MHB_NIC_MHB_APB_NS, val); + + /* set Nitro AXI to allow non-secure access */ + val = mmio_read_32(mhb_nic_gpv + MHB_NIC_NITRO_AXI_NS); + val |= 0x1; + mmio_write_32(mhb_nic_gpv + MHB_NIC_NITRO_AXI_NS, val); + + /* set PCIe AXI to allow non-secure access */ + val = mmio_read_32(mhb_nic_gpv + MHB_NIC_PCIE_AXI_NS); + val |= 0x1; + mmio_write_32(mhb_nic_gpv + MHB_NIC_PCIE_AXI_NS, val); + + /* set PAXC APB to allow non-secure access */ + val = mmio_read_32(mhb_nic_gpv + MHB_NIC_PAXC_APB_NS); + val |= 0x1; + mmio_write_32(mhb_nic_gpv + MHB_NIC_PAXC_APB_NS, val); + + /* set EP APB to allow non-secure access */ + val = mmio_read_32(mhb_nic_gpv + MHB_NIC_EP_APB_NS); + val |= 0x1; + mmio_write_32(mhb_nic_gpv + MHB_NIC_EP_APB_NS, val); + +#ifndef NITRO_SECURE_ACCESS + /* Set NIC400 to allow non-secure access */ + mmio_setbits_32(nic400_nitro_gpv + NITRO_NIC_SECURITY_3_SHIFT, 0x1); + mmio_setbits_32(nic400_nitro_gpv + NITRO_NIC_SECURITY_4_SHIFT, 0x1); + mmio_setbits_32(nic400_nitro_gpv + NITRO_NIC_SECURITY_5_SHIFT, 0x1); + mmio_setbits_32(nic400_nitro_gpv + NITRO_NIC_SECURITY_6_SHIFT, 0x1); +#endif /* NITRO_SECURE_ACCESS */ +} diff --git a/plat/brcm/board/stingray/src/pm.c b/plat/brcm/board/stingray/src/pm.c new file mode 100644 index 0000000..a5ac2e7 --- /dev/null +++ b/plat/brcm/board/stingray/src/pm.c @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2015 - 2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <errno.h> + +#include <arch.h> +#include <arch_helpers.h> +#include <common/debug.h> +#include <drivers/arm/ccn.h> +#include <drivers/delay_timer.h> +#include <lib/bakery_lock.h> +#include <lib/mmio.h> +#include <lib/psci/psci.h> +#include <lib/spinlock.h> +#include <plat/common/platform.h> + +#ifdef USE_PAXC +#include <chimp.h> +#endif +#include <cmn_plat_util.h> +#include <ihost_pm.h> +#include <plat_brcm.h> +#include <platform_def.h> + +static uint64_t plat_sec_entrypoint; + +/******************************************************************************* + * SR handler called when a power domain is about to be turned on. The + * mpidr determines the CPU to be turned on. + ******************************************************************************/ +static int brcm_pwr_domain_on(u_register_t mpidr) +{ + int cpuid; + + cpuid = plat_brcm_calc_core_pos(mpidr); + INFO("mpidr :%lu, cpuid:%d\n", mpidr, cpuid); + +#ifdef USE_SINGLE_CLUSTER + if (cpuid > 1) + return PSCI_E_INTERN_FAIL; +#endif + + ihost_power_on_cluster(mpidr); + + ihost_power_on_secondary_core(mpidr, plat_sec_entrypoint); + + return PSCI_E_SUCCESS; +} + +/******************************************************************************* + * SR handler called when a power domain has just been powered on after + * being turned off earlier. The target_state encodes the low power state that + * each level has woken up from. + ******************************************************************************/ +static void brcm_pwr_domain_on_finish(const psci_power_state_t *target_state) +{ + unsigned long cluster_id = MPIDR_AFFLVL1_VAL(read_mpidr()); + + assert(target_state->pwr_domain_state[MPIDR_AFFLVL0] == + PLAT_LOCAL_STATE_OFF); + + if (target_state->pwr_domain_state[MPIDR_AFFLVL1] == + PLAT_LOCAL_STATE_OFF) { + INFO("Cluster #%lu entering to snoop/dvm domain\n", cluster_id); + ccn_enter_snoop_dvm_domain(1 << cluster_id); + } + + /* Enable the gic cpu interface */ + plat_brcm_gic_pcpu_init(); + + /* Program the gic per-cpu distributor or re-distributor interface */ + plat_brcm_gic_cpuif_enable(); + + INFO("Gic Initialization done for this affinity instance\n"); +} + +static void __dead2 brcm_system_reset(void) +{ + uint32_t reset_type = SOFT_SYS_RESET_L1; + +#ifdef USE_PAXC + if (bcm_chimp_is_nic_mode()) + reset_type = SOFT_RESET_L3; +#endif + INFO("System rebooting - L%d...\n", reset_type); + + plat_soft_reset(reset_type); + + /* Prevent the function to return due to the attribute */ + while (1) + ; +} + +static int brcm_system_reset2(int is_vendor, int reset_type, + u_register_t cookie) +{ + INFO("System rebooting - L%d...\n", reset_type); + + plat_soft_reset(reset_type); + + /* + * plat_soft_reset cannot return (it is a __dead function), + * but brcm_system_reset2 has to return some value, even in + * this case. + */ + return 0; +} + +/******************************************************************************* + * Export the platform handlers via plat_brcm_psci_pm_ops. The ARM Standard + * platform will take care of registering the handlers with PSCI. + ******************************************************************************/ +const plat_psci_ops_t plat_brcm_psci_pm_ops = { + .pwr_domain_on = brcm_pwr_domain_on, + .pwr_domain_on_finish = brcm_pwr_domain_on_finish, + .system_reset = brcm_system_reset, + .system_reset2 = brcm_system_reset2 +}; + +int plat_setup_psci_ops(uintptr_t sec_entrypoint, + const plat_psci_ops_t **psci_ops) +{ + *psci_ops = &plat_brcm_psci_pm_ops; + plat_sec_entrypoint = sec_entrypoint; + + return 0; +} diff --git a/plat/brcm/board/stingray/src/scp_cmd.c b/plat/brcm/board/stingray/src/scp_cmd.c new file mode 100644 index 0000000..2aa9519 --- /dev/null +++ b/plat/brcm/board/stingray/src/scp_cmd.c @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2017-2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch_helpers.h> +#include <common/bl_common.h> +#include <drivers/delay_timer.h> + +#include <platform_def.h> +#include <scp.h> +#include <scp_cmd.h> + +#include "m0_ipc.h" + +/* + * Reads a response from CRMU MAILBOX + * Assumes that access has been granted and locked. + * Note that this is just a temporary implementation until + * channels are introduced + */ +static void scp_read_response(crmu_response_t *resp) +{ + uint32_t code; + + code = mmio_read_32(CRMU_MAIL_BOX0); + resp->completed = code & MCU_IPC_CMD_DONE_MASK; + resp->cmd = code & SCP_CMD_MASK; + resp->ret = (code & MCU_IPC_CMD_REPLY_MASK) >> MCU_IPC_CMD_REPLY_SHIFT; +} + +/* + * Send a command to SCP and wait for timeout us. + * Return: 0 on success + * -1 if there was no proper reply from SCP + * >0 if there was a response from MCU, but + * command completed with an error. + */ +int scp_send_cmd(uint32_t cmd, uint32_t param, uint32_t timeout) +{ + int ret = -1; + + mmio_write_32(CRMU_MAIL_BOX0, cmd); + mmio_write_32(CRMU_MAIL_BOX1, param); + do { + crmu_response_t scp_resp; + + udelay(1); + scp_read_response(&scp_resp); + if (scp_resp.completed && + (scp_resp.cmd == cmd)) { + /* This command has completed */ + ret = scp_resp.ret; + break; + } + } while (--timeout); + + return ret; +} diff --git a/plat/brcm/board/stingray/src/scp_utils.c b/plat/brcm/board/stingray/src/scp_utils.c new file mode 100644 index 0000000..1d82cef --- /dev/null +++ b/plat/brcm/board/stingray/src/scp_utils.c @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2017-2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <string.h> + +#include <arch_helpers.h> +#include <common/bl_common.h> +#include <common/debug.h> +#include <drivers/delay_timer.h> + +#include <bcm_elog_ddr.h> +#include <brcm_mhu.h> +#include <brcm_scpi.h> +#include <chimp.h> +#include <cmn_plat_util.h> +#include <ddr_init.h> +#include <scp.h> +#include <scp_cmd.h> +#include <scp_utils.h> + +#include "m0_cfg.h" +#include "m0_ipc.h" + +#ifdef BCM_ELOG +static void prepare_elog(void) +{ +#if (CLEAN_DDR && !defined(MMU_DISABLED)) + /* + * Now DDR has been initialized. We want to copy all the logs in SRAM + * into DDR so we will have much more space to store the logs in the + * next boot stage + */ + bcm_elog_copy_log((void *)BCM_ELOG_BL31_BASE, + MIN(BCM_ELOG_BL2_SIZE, BCM_ELOG_BL31_SIZE) + ); + + /* + * We are almost at the end of BL2, and we can stop log here so we do + * not need to add 'bcm_elog_exit' to the standard BL2 code. The + * benefit of capturing BL2 logs after this is very minimal in a + * production system. + */ + bcm_elog_exit(); +#endif + + /* + * Notify CRMU that now it should pull logs from DDR instead of from + * FS4 SRAM. + */ + SCP_WRITE_CFG(flash_log.can_use_ddr, 1); +} +#endif + +bool is_crmu_alive(void) +{ + return (scp_send_cmd(MCU_IPC_MCU_CMD_NOP, 0, SCP_CMD_DEFAULT_TIMEOUT_US) + == 0); +} + +bool bcm_scp_issue_sys_reset(void) +{ + return (scp_send_cmd(MCU_IPC_MCU_CMD_L1_RESET, 0, + SCP_CMD_DEFAULT_TIMEOUT_US)); +} + +/* + * Note that this is just a temporary implementation until + * channels are introduced + */ + +int plat_bcm_bl2_plat_handle_scp_bl2(image_info_t *scp_bl2_image_info) +{ + int scp_patch_activated, scp_patch_version; +#ifndef EMULATION_SETUP + uint8_t active_ch_bitmap, i; +#endif + uint32_t reset_state = 0; + uint32_t mcu_ap_init_param = 0; + + /* + * First check if SCP patch has already been loaded + * Send NOP command and see if there is a valid response + */ + scp_patch_activated = + (scp_send_cmd(MCU_IPC_MCU_CMD_NOP, 0, + SCP_CMD_DEFAULT_TIMEOUT_US) == 0); + if (scp_patch_activated) { + INFO("SCP Patch is already active.\n"); + + reset_state = SCP_READ_CFG(board_cfg.reset_state); + mcu_ap_init_param = SCP_READ_CFG(board_cfg.mcu_init_param); + + /* Clear reset state, it's been already read */ + SCP_WRITE_CFG(board_cfg.reset_state, 0); + + if (mcu_ap_init_param & MCU_PATCH_LOADED_BY_NITRO) { + /* + * Reset "MCU_PATCH_LOADED_BY_NITRO" flag, but + * Preserve any other flags we don't deal with here + */ + INFO("AP booted by Nitro\n"); + SCP_WRITE_CFG( + board_cfg.mcu_init_param, + mcu_ap_init_param & + ~MCU_PATCH_LOADED_BY_NITRO + ); + } + } else { + /* + * MCU Patch not loaded, so load it. + * MCU patch stamps critical points in REG9 (debug test-point) + * Display its last content here. This helps to locate + * where crash occurred if a CRMU watchdog kicked in. + */ + int ret; + + INFO("MCU Patch Point: 0x%x\n", + mmio_read_32(CRMU_IHOST_SW_PERSISTENT_REG9)); + + ret = download_scp_patch((void *)scp_bl2_image_info->image_base, + scp_bl2_image_info->image_size); + if (ret != 0) + return ret; + + VERBOSE("SCP Patch loaded OK.\n"); + + ret = scp_send_cmd(MCU_IPC_MCU_CMD_INIT, + MCU_PATCH_LOADED_BY_AP, + SCP_CMD_SCP_BOOT_TIMEOUT_US); + if (ret) { + ERROR("SCP Patch could not initialize; error %d\n", + ret); + return ret; + } + + INFO("SCP Patch successfully initialized.\n"); + } + + scp_patch_version = scp_send_cmd(MCU_IPC_MCU_CMD_GET_FW_VERSION, 0, + SCP_CMD_DEFAULT_TIMEOUT_US); + INFO("SCP Patch version :0x%x\n", scp_patch_version); + + /* Next block just reports current AVS voltages (if applicable) */ + { + uint16_t vcore_mv, ihost03_mv, ihost12_mv; + + vcore_mv = SCP_READ_CFG16(vcore.millivolts) + + SCP_READ_CFG8(vcore.avs_cfg.additive_margin); + ihost03_mv = SCP_READ_CFG16(ihost03.millivolts) + + SCP_READ_CFG8(ihost03.avs_cfg.additive_margin); + ihost12_mv = SCP_READ_CFG16(ihost12.millivolts) + + SCP_READ_CFG8(ihost12.avs_cfg.additive_margin); + + if (vcore_mv || ihost03_mv || ihost12_mv) { + INFO("AVS voltages from cfg (including margin)\n"); + if (vcore_mv > 0) + INFO("%s\tVCORE: %dmv\n", + SCP_READ_CFG8(vcore.avs_cfg.avs_set) ? + "*" : "n/a", vcore_mv); + if (ihost03_mv > 0) + INFO("%s\tIHOST03: %dmv\n", + SCP_READ_CFG8(ihost03.avs_cfg.avs_set) ? + "*" : "n/a", ihost03_mv); + if (ihost12_mv > 0) + INFO("%s\tIHOST12: %dmv\n", + SCP_READ_CFG8(ihost12.avs_cfg.avs_set) ? + "*" : "n/a", ihost12_mv); + } else { + INFO("AVS settings not applicable\n"); + } + } + +#if (CLEAN_DDR && !defined(MMU_DISABLED) && !defined(EMULATION_SETUP)) + /* This will clean the DDR and enable ECC if set */ + check_ddr_clean(); +#endif + +#if (WARMBOOT_DDR_S3_SUPPORT && ELOG_STORE_MEDIA_DDR) + elog_init_ddr_log(); +#endif + +#ifdef BCM_ELOG + /* Prepare ELOG to use DDR */ + prepare_elog(); +#endif + +#ifndef EMULATION_SETUP + /* Ask ddr_init to save obtained DDR information into DDR */ + ddr_info_save(); +#endif + + /* + * Configure TMON DDR address. + * This cfg is common for all cases + */ + SCP_WRITE_CFG(tmon_cfg.ddr_desc, TMON_SHARED_DDR_ADDRESS); + + if (reset_state == SOFT_RESET_L3 && !mcu_ap_init_param) { + INFO("SCP configuration after L3 RESET done.\n"); + return 0; + } + + if (bcm_chimp_is_nic_mode()) + /* Configure AP WDT to not reset the NIC interface */ + SCP_WRITE_CFG(board_cfg.apwdt_reset_type, SOFT_RESET_L3); + +#if (WARMBOOT_DDR_S3_SUPPORT && ELOG_STORE_MEDIA_DDR) + /* When AP WDog triggers perform L3 reset if DDR err logging enabled */ + SCP_WRITE_CFG(board_cfg.apwdt_reset_type, SOFT_RESET_L3); +#endif + +#ifndef EMULATION_SETUP + +#ifdef DDR_SCRUB_ENA + ddr_scrub_enable(); +#endif + /* Fill the Active channel information */ + active_ch_bitmap = get_active_ddr_channel(); + for (i = 0; i < MAX_NR_DDR_CH; i++) + SCP_WRITE_CFG(ddr_cfg.ddr_cfg[i], + (active_ch_bitmap & BIT(i)) ? 1 : 0); +#endif + return 0; +} diff --git a/plat/brcm/board/stingray/src/sdio.c b/plat/brcm/board/stingray/src/sdio.c new file mode 100644 index 0000000..aa2b71a --- /dev/null +++ b/plat/brcm/board/stingray/src/sdio.c @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2019-2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <errno.h> +#include <stdbool.h> + +#include <common/debug.h> +#include <drivers/delay_timer.h> +#include <lib/mmio.h> + +#include <sdio.h> +#include <sr_def.h> +#include <sr_utils.h> + +const SDIO_CFG sr_sdio0_cfg = { + .cfg_base = SR_IPROC_SDIO0_CFG_BASE, + .sid_base = SR_IPROC_SDIO0_SID_BASE, + .io_ctrl_base = SR_IPROC_SDIO0_IOCTRL_BASE, + .pad_base = SR_IPROC_SDIO0_PAD_BASE, +}; +const SDIO_CFG sr_sdio1_cfg = { + .cfg_base = SR_IPROC_SDIO1_CFG_BASE, + .sid_base = SR_IPROC_SDIO1_SID_BASE, + .io_ctrl_base = SR_IPROC_SDIO1_IOCTRL_BASE, + .pad_base = SR_IPROC_SDIO1_PAD_BASE, +}; + +void brcm_stingray_sdio_init(void) +{ + unsigned int val; + const SDIO_CFG *sdio0_cfg, *sdio1_cfg; + + sdio0_cfg = &sr_sdio0_cfg; + sdio1_cfg = &sr_sdio1_cfg; + + INFO("set sdio0 caps\n"); + /* SDIO0 CAPS0 */ + val = SDIO0_CAP0_CFG; + INFO("caps0 0x%x\n", val); + mmio_write_32(sdio0_cfg->cfg_base + ICFG_SDIO_CAP0, val); + + /* SDIO0 CAPS1 */ + val = SDIO0_CAP1_CFG; + INFO("caps1 0x%x\n", val); + mmio_write_32(sdio0_cfg->cfg_base + ICFG_SDIO_CAP1, val); + + mmio_write_32(sdio0_cfg->cfg_base + ICFG_SDIO_STRAPSTATUS_0, + SDIO_PRESETVAL0); + mmio_write_32(sdio0_cfg->cfg_base + ICFG_SDIO_STRAPSTATUS_1, + SDIO_PRESETVAL1); + mmio_write_32(sdio0_cfg->cfg_base + ICFG_SDIO_STRAPSTATUS_2, + SDIO_PRESETVAL2); + mmio_write_32(sdio0_cfg->cfg_base + ICFG_SDIO_STRAPSTATUS_3, + SDIO_PRESETVAL3); + mmio_write_32(sdio0_cfg->cfg_base + ICFG_SDIO_STRAPSTATUS_4, + SDIO_PRESETVAL4); + + val = SR_SID_VAL(0x3, 0x0, 0x2) << SDIO_SID_SHIFT; + mmio_write_32(sdio0_cfg->sid_base + ICFG_SDIO_SID_ARADDR, val); + mmio_write_32(sdio0_cfg->sid_base + ICFG_SDIO_SID_AWADDR, val); + + val = mmio_read_32(sdio0_cfg->io_ctrl_base); + val &= ~(0xff << 23); /* Clear ARCACHE and AWCACHE */ + val |= (0xb7 << 23); /* Set ARCACHE and AWCACHE */ + mmio_write_32(sdio0_cfg->io_ctrl_base, val); + + mmio_clrsetbits_32(sdio0_cfg->pad_base + PAD_SDIO_CLK, + PAD_SDIO_MASK, PAD_SDIO_VALUE); + mmio_clrsetbits_32(sdio0_cfg->pad_base + PAD_SDIO_DATA0, + PAD_SDIO_MASK, PAD_SDIO_VALUE); + mmio_clrsetbits_32(sdio0_cfg->pad_base + PAD_SDIO_DATA1, + PAD_SDIO_MASK, PAD_SDIO_VALUE); + mmio_clrsetbits_32(sdio0_cfg->pad_base + PAD_SDIO_DATA2, + PAD_SDIO_MASK, PAD_SDIO_VALUE); + mmio_clrsetbits_32(sdio0_cfg->pad_base + PAD_SDIO_DATA3, + PAD_SDIO_MASK, PAD_SDIO_VALUE); + mmio_clrsetbits_32(sdio0_cfg->pad_base + PAD_SDIO_DATA4, + PAD_SDIO_MASK, PAD_SDIO_VALUE); + mmio_clrsetbits_32(sdio0_cfg->pad_base + PAD_SDIO_DATA5, + PAD_SDIO_MASK, PAD_SDIO_VALUE); + mmio_clrsetbits_32(sdio0_cfg->pad_base + PAD_SDIO_DATA6, + PAD_SDIO_MASK, PAD_SDIO_VALUE); + mmio_clrsetbits_32(sdio0_cfg->pad_base + PAD_SDIO_DATA7, + PAD_SDIO_MASK, PAD_SDIO_VALUE); + mmio_clrsetbits_32(sdio0_cfg->pad_base + PAD_SDIO_CMD, + PAD_SDIO_MASK, PAD_SDIO_VALUE); + + INFO("set sdio1 caps\n"); + + /* SDIO1 CAPS0 */ + val = SDIO1_CAP0_CFG; + INFO("caps0 0x%x\n", val); + mmio_write_32(sdio1_cfg->cfg_base + ICFG_SDIO_CAP0, val); + /* SDIO1 CAPS1 */ + val = SDIO1_CAP1_CFG; + INFO("caps1 0x%x\n", val); + mmio_write_32(sdio1_cfg->cfg_base + ICFG_SDIO_CAP1, val); + + mmio_write_32(sdio1_cfg->cfg_base + ICFG_SDIO_STRAPSTATUS_0, + SDIO_PRESETVAL0); + mmio_write_32(sdio1_cfg->cfg_base + ICFG_SDIO_STRAPSTATUS_1, + SDIO_PRESETVAL1); + mmio_write_32(sdio1_cfg->cfg_base + ICFG_SDIO_STRAPSTATUS_2, + SDIO_PRESETVAL2); + mmio_write_32(sdio1_cfg->cfg_base + ICFG_SDIO_STRAPSTATUS_3, + SDIO_PRESETVAL3); + mmio_write_32(sdio1_cfg->cfg_base + ICFG_SDIO_STRAPSTATUS_4, + SDIO_PRESETVAL4); + + val = SR_SID_VAL(0x3, 0x0, 0x3) << SDIO_SID_SHIFT; + mmio_write_32(sdio1_cfg->sid_base + ICFG_SDIO_SID_ARADDR, val); + mmio_write_32(sdio1_cfg->sid_base + ICFG_SDIO_SID_AWADDR, val); + + val = mmio_read_32(sdio1_cfg->io_ctrl_base); + val &= ~(0xff << 23); /* Clear ARCACHE and AWCACHE */ + val |= (0xb7 << 23); /* Set ARCACHE and AWCACHE */ + mmio_write_32(sdio1_cfg->io_ctrl_base, val); + + mmio_clrsetbits_32(sdio1_cfg->pad_base + PAD_SDIO_CLK, + PAD_SDIO_MASK, PAD_SDIO_VALUE); + mmio_clrsetbits_32(sdio1_cfg->pad_base + PAD_SDIO_DATA0, + PAD_SDIO_MASK, PAD_SDIO_VALUE); + mmio_clrsetbits_32(sdio1_cfg->pad_base + PAD_SDIO_DATA1, + PAD_SDIO_MASK, PAD_SDIO_VALUE); + mmio_clrsetbits_32(sdio1_cfg->pad_base + PAD_SDIO_DATA2, + PAD_SDIO_MASK, PAD_SDIO_VALUE); + mmio_clrsetbits_32(sdio1_cfg->pad_base + PAD_SDIO_DATA3, + PAD_SDIO_MASK, PAD_SDIO_VALUE); + mmio_clrsetbits_32(sdio1_cfg->pad_base + PAD_SDIO_DATA4, + PAD_SDIO_MASK, PAD_SDIO_VALUE); + mmio_clrsetbits_32(sdio1_cfg->pad_base + PAD_SDIO_DATA5, + PAD_SDIO_MASK, PAD_SDIO_VALUE); + mmio_clrsetbits_32(sdio1_cfg->pad_base + PAD_SDIO_DATA6, + PAD_SDIO_MASK, PAD_SDIO_VALUE); + mmio_clrsetbits_32(sdio1_cfg->pad_base + PAD_SDIO_DATA7, + PAD_SDIO_MASK, PAD_SDIO_VALUE); + mmio_clrsetbits_32(sdio1_cfg->pad_base + PAD_SDIO_CMD, + PAD_SDIO_MASK, PAD_SDIO_VALUE); + + INFO("sdio init done\n"); +} diff --git a/plat/brcm/board/stingray/src/sr_paxb_phy.c b/plat/brcm/board/stingray/src/sr_paxb_phy.c new file mode 100644 index 0000000..7380e09 --- /dev/null +++ b/plat/brcm/board/stingray/src/sr_paxb_phy.c @@ -0,0 +1,806 @@ +/* + * Copyright (c) 2019-2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <errno.h> +#include <stdbool.h> + +#include <common/debug.h> +#include <drivers/delay_timer.h> +#include <lib/mmio.h> + +#include <paxb.h> +#include <sr_def.h> +#include <sr_utils.h> + +/* total number of PCIe Phys */ +#define NUM_OF_PCIE_SERDES 8 + +#define CFG_RC_PMI_ADDR 0x1130 +#define PMI_RX_TERM_SEQ ((0x1 << 27) | (0x1ff << 16) | (0xd090)) +#define PMI_RX_TERM_VAL 0x4c00 +#define PMI_PLL_CTRL_4 0xd0b4 +#define PMI_SERDES_CLK_ENABLE (1 << 12) + +#define WAR_PLX_PRESET_PARITY_FAIL + +#define CFG_RC_REG_PHY_CTL_10 0x1838 +#define PHY_CTL_10_GEN3_MATCH_PARITY (1 << 15) + +#define PMI_X8_CORE0_7_PATCH_SEQ ((0x1 << 27) | (0x1ff << 16) | (0xd2a5)) +#define PMI_X8_CORE0_7_PATCH_VAL 0xd864 + +#define PMI_ADDR_BCAST(addr) ((0x1 << 27) | (0x1ff << 16) | (addr)) +#define PMI_ADDR_LANE0(addr) ((0x1 << 27) | (addr)) +#define PMI_ADDR_LANE1(addr) ((0x1 << 27) | (0x1 << 16) | (addr)) + +#define MERLIN16_PCIE_BLK2_PWRMGMT_7 ((0x1 << 27) | (0x1ff << 16) | 0x1208) +#define MERLIN16_PCIE_BLK2_PWRMGMT_8 ((0x1 << 27) | (0x1ff << 16) | 0x1209) +#define MERLIN16_AMS_TX_CTRL_5 ((0x1 << 27) | (0x1ff << 16) | 0xd0a5) +#define MERLIN16_AMS_TX_CTRL_5_VAL \ + ((1 << 13) | (1 << 12) | (1 << 11) | (1 << 10)) +#define MERLIN16_PCIE_BLK2_PWRMGMT_7_VAL 0x96 +#define MERLIN16_PCIE_BLK2_PWRMGMT_8_VAL 0x12c + +#define CFG_RC_PMI_WDATA 0x1134 +#define CFG_RC_WCMD_SHIFT 31 +#define CFG_RC_WCMD_MASK ((uint32_t)1U << CFG_RC_WCMD_SHIFT) +#define CFG_RC_RCMD_SHIFT 30 +#define CFG_RC_RCMD_MASK ((uint32_t)1U << CFG_RC_RCMD_SHIFT) +#define CFG_RC_RWCMD_MASK (CFG_RC_RCMD_MASK | CFG_RC_WCMD_MASK) +#define CFG_RC_PMI_RDATA 0x1138 +#define CFG_RC_RACK_SHIFT 31 +#define CFG_RC_RACK_MASK ((uint32_t)1U << CFG_RC_RACK_SHIFT) + +/* allow up to 5 ms for PMI write to finish */ +#define PMI_TIMEOUT_MS 5 + +/* in 2x8 RC mode, one needs to patch up Serdes 3 and 7 for link to come up */ +#define SERDES_PATCH_PIPEMUX_INDEX 0x3 +#define SERDES_PATCH_INDEX 0x8 + +#define DSC_UC_CTRL 0xd00d +#define DSC_UC_CTRL_RDY_CMD (1 << 7) +#define LANE_DBG_RST_CTRL 0xd164 +#define UC_A_CLK_CTRL0 0xd200 +#define UC_A_RST_CTRL0 0xd201 +#define UC_A_AHB_CTRL0 0xd202 +#define UC_A_AHB_STAT0 0xd203 +#define UC_A_AHB_WADDR_LSW 0xd204 +#define UC_A_AHB_WADDR_MSW 0xd205 +#define UC_A_AHB_WDATA_LSW 0xd206 +#define UC_A_AHB_WDATA_MSW 0xd207 +#define UC_A_AHB_RADDR_LSW 0xd208 +#define UC_A_AHB_RADDR_MSW 0xd209 +#define UC_A_AHB_RDATA_LSW 0xd20a +#define UC_A_AHB_RDATA_MSW 0xd20b +#define UC_VERSION_NUM 0xd230 +#define DSC_SM_CTL22 0xd267 +#define UC_DBG1 0xd251 + +#define LOAD_UC_CHECK 0 +#define UC_RAM_INIT_TIMEOUT 100 +#define UC_RAM_CONTROL 0xd225 +#define UC_INIT_TIMEOUT 100 +#define SIZE_ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) +#define SZ_4 4 +#define GET_2_BYTES(p, i) ((uint16_t)p[i] | (uint16_t)p[i+1] << 8) + +/* + * List of PCIe LCPLL related registers + * + * LCPLL channel 0 provides the Serdes pad clock when running in RC mode + */ +#define PCIE_LCPLL_BASE 0x40000000 + +#define PCIE_LCPLL_CTRL0_OFFSET 0x00 +#define PCIE_LCPLL_RESETB_SHIFT 31 +#define PCIE_LCPLL_RESETB_MASK BIT(PCIE_LCPLL_RESETB_SHIFT) +#define PCIE_LCPLL_P_RESETB_SHIFT 30 +#define PCIE_LCPLL_P_RESETB_MASK BIT(PCIE_LCPLL_P_RESETB_SHIFT) + +#define PCIE_LCPLL_CTRL3_OFFSET 0x0c +#define PCIE_LCPLL_EN_CTRL_SHIFT 16 +#define PCIE_LCPLL_CM_ENA 0x1a +#define PCIE_LCPLL_CM_BUF_ENA 0x18 +#define PCIE_LCPLL_D2C2_ENA 0x2 +#define PCIE_LCPLL_REF_CLK_SHIFT 1 +#define PCIE_LCPLL_REF_CLK_MASK BIT(PCIE_LCPLL_REF_CLK_SHIFT) +#define PCIE_LCPLL_CTRL13_OFFSET 0x34 +#define PCIE_LCPLL_D2C2_CTRL_SHIFT 16 +#define PCIE_LCPLL_D2C2_TERM_DISC 0xe0 + +#define PCIE_LCPLL_STATUS_OFFSET 0x40 +#define PCIE_LCPLL_LOCK_SHIFT 12 +#define PCIE_LCPLL_LOCK_MASK BIT(PCIE_LCPLL_LOCK_SHIFT) + +#define PCIE_PIPE_MUX_RC_MODE_OVERRIDE_CFG 0x114 +#define PCIE_TX_CLKMASTER_CTRL_OVERRIDE_CFG 0x11c + +/* wait 500 microseconds for PCIe LCPLL to power up */ +#define PCIE_LCPLL_DELAY_US 500 + +/* allow up to 5 ms for PCIe LCPLL VCO to lock */ +#define PCIE_LCPLL_TIMEOUT_MS 5 + +#define PCIE_PIPE_MUX_CONFIGURATION_CFG 0x4000010c + +#define PCIE_PIPEMUX_SHIFT 19 +#define PCIE_PIPEMUX_MASK 0xf + +/* keep track of PIPEMUX index to use */ +static unsigned int pipemux_idx; + +/* + * PCIe PIPEMUX lookup table + * + * Each array index represents a PIPEMUX strap setting + * The array element represents a bitmap where a set bit means the PCIe core + * needs to be enabled as RC + */ +static uint8_t pipemux_table[] = { + /* PIPEMUX = 0, EP 1x16 */ + 0x00, + /* PIPEMUX = 1, EP 1x8 + RC 1x8, core 7 */ + 0x80, + /* PIPEMUX = 2, EP 4x4 */ + 0x00, + /* PIPEMUX = 3, RC 2x8, cores 0, 7 */ + 0x81, + /* PIPEMUX = 4, RC 4x4, cores 0, 1, 6, 7 */ + 0xc3, + /* PIPEMUX = 5, RC 8x2, all 8 cores */ + 0xff, + /* PIPEMUX = 6, RC 3x4 + 2x2, cores 0, 2, 3, 6, 7 */ + 0xcd, + /* PIPEMUX = 7, RC 1x4 + 6x2, cores 0, 2, 3, 4, 5, 6, 7 */ + 0xfd, + /* PIPEMUX = 8, EP 1x8 + RC 4x2, cores 4, 5, 6, 7 */ + 0xf0, + /* PIPEMUX = 9, EP 1x8 + RC 2x4, cores 6, 7 */ + 0xc0, + /* PIPEMUX = 10, EP 2x4 + RC 2x4, cores 1, 6 */ + 0x42, + /* PIPEMUX = 11, EP 2x4 + RC 4x2, cores 2, 3, 4, 5 */ + 0x3c, + /* PIPEMUX = 12, EP 1x4 + RC 6x2, cores 2, 3, 4, 5, 6, 7 */ + 0xfc, + /* PIPEMUX = 13, RC 2x4 + RC 1x4 + 2x2, cores 2, 3, 6 */ + 0x4c, +}; + +/* + * Return 1 if pipemux strap is supported + */ +static int pipemux_strap_is_valid(uint32_t pipemux) +{ + if (pipemux < ARRAY_SIZE(pipemux_table)) + return 1; + else + return 0; +} + +/* + * Read the PCIe PIPEMUX from strap + */ +static uint32_t pipemux_strap_read(void) +{ + uint32_t pipemux; + + pipemux = mmio_read_32(PCIE_PIPE_MUX_CONFIGURATION_CFG); + pipemux &= PCIE_PIPEMUX_MASK; + if (pipemux == PCIE_PIPEMUX_MASK) { + /* read the PCIe PIPEMUX strap setting */ + pipemux = mmio_read_32(CDRU_CHIP_STRAP_DATA_LSW); + pipemux >>= PCIE_PIPEMUX_SHIFT; + pipemux &= PCIE_PIPEMUX_MASK; + } + + return pipemux; +} + +/* + * Store the PIPEMUX index (set for each boot) + */ +static void pipemux_save_index(unsigned int idx) +{ + pipemux_idx = idx; +} + +static int paxb_sr_core_needs_enable(unsigned int core_idx) +{ + return !!((pipemux_table[pipemux_idx] >> core_idx) & 0x1); +} + +static int pipemux_sr_init(void) +{ + uint32_t pipemux; + + /* read the PCIe PIPEMUX strap setting */ + pipemux = pipemux_strap_read(); + if (!pipemux_strap_is_valid(pipemux)) { + ERROR("Invalid PCIe PIPEMUX strap %u\n", pipemux); + return -EIO; + } + + /* no PCIe RC is needed */ + if (!pipemux_table[pipemux]) { + WARN("PIPEMUX indicates no PCIe RC required\n"); + return -ENODEV; + } + + /* save the PIPEMUX strap */ + pipemux_save_index(pipemux); + + return 0; +} + +/* + * PCIe RC serdes link width + * + * The array is first organized in rows as indexed by the PIPEMUX setting. + * Within each row, eight lane width entries are specified -- one entry + * per PCIe core, from 0 to 7. + * + * Note: The EP lanes/cores are not mapped in this table! EP cores are + * controlled and thus configured by Nitro. + */ +static uint8_t link_width_table[][NUM_OF_SR_PCIE_CORES] = { + /* PIPEMUX = 0, EP 1x16 */ + {0, 0, 0, 0, 0, 0, 0, 0}, + /* PIPEMUX = 1, EP 1x8 + RC 1x8, core 7 */ + {0, 0, 0, 0, 0, 0, 0, 8}, + /* PIPEMUX = 2, EP 4x4 */ + {0, 0, 0, 0, 0, 0, 0, 0}, + /* PIPEMUX = 3, RC 2x8, cores 0, 7 */ + {8, 0, 0, 0, 0, 0, 0, 8}, + /* PIPEMUX = 4, RC 4x4, cores 0, 1, 6, 7 */ + {4, 4, 0, 0, 0, 0, 4, 4}, + /* PIPEMUX = 5, RC 8x2, all 8 cores */ + {2, 2, 2, 2, 2, 2, 2, 2}, + /* PIPEMUX = 6, RC 3x4 (cores 0, 6, 7), RC 2x2 (cores 2, 3) */ + {4, 0, 2, 2, 0, 0, 4, 4}, + /* PIPEMUX = 7, RC 1x4 (core 0), RC 6x2 (cores 2, 3, 4, 5, 6, 7 */ + {4, 0, 2, 2, 2, 2, 2, 2}, + /* PIPEMUX = 8, EP 1x8 + RC 4x2 (cores 4, 5, 6, 7) */ + {0, 0, 0, 0, 2, 2, 2, 2}, + /* PIPEMUX = 9, EP 1x8 + RC 2x4 (cores 6, 7) */ + {0, 0, 0, 0, 0, 0, 4, 4}, + /* PIPEMUX = 10, EP 2x4 + RC 2x4 (cores 1, 6) */ + {0, 4, 0, 0, 0, 0, 4, 0}, + /* PIPEMUX = 11, EP 2x4 + RC 4x2 (cores 2, 3, 4, 5) */ + {0, 0, 2, 2, 2, 2, 0, 0}, + /* PIPEMUX = 12, EP 1x4 + RC 6x2 (cores 2, 3, 4, 5, 6, 7) */ + {0, 0, 2, 2, 2, 2, 2, 2}, + /* PIPEMUX = 13, EP 2x4 + RC 1x4 (core 6) + RC 2x2 (cores 2, 3) */ + {0, 0, 2, 2, 0, 0, 4, 0} +}; + +/* + * function for writes to the Serdes registers through the PMI interface + */ +static int paxb_pmi_write(unsigned int core_idx, uint32_t pmi, uint32_t val) +{ + uint32_t status; + unsigned int timeout = PMI_TIMEOUT_MS; + + paxb_rc_cfg_write(core_idx, CFG_RC_PMI_ADDR, pmi); + + val &= ~CFG_RC_RWCMD_MASK; + val |= CFG_RC_WCMD_MASK; + paxb_rc_cfg_write(core_idx, CFG_RC_PMI_WDATA, val); + + do { + status = paxb_rc_cfg_read(core_idx, CFG_RC_PMI_WDATA); + + /* wait for write command bit to clear */ + if ((status & CFG_RC_WCMD_MASK) == 0) + return 0; + } while (--timeout); + + return -EIO; +} + +/* + * function for reads from the Serdes registers through the PMI interface + */ +static int paxb_pmi_read(unsigned int core_idx, uint32_t pmi, uint32_t *val) +{ + uint32_t status; + unsigned int timeout = PMI_TIMEOUT_MS; + + paxb_rc_cfg_write(core_idx, CFG_RC_PMI_ADDR, pmi); + + paxb_rc_cfg_write(core_idx, CFG_RC_PMI_WDATA, CFG_RC_RCMD_MASK); + + do { + status = paxb_rc_cfg_read(core_idx, CFG_RC_PMI_RDATA); + + /* wait for read ack bit set */ + if ((status & CFG_RC_RACK_MASK)) { + *val = paxb_rc_cfg_read(core_idx, CFG_RC_PMI_RDATA); + return 0; + } + } while (--timeout); + + return -EIO; +} + + +#ifndef BOARD_PCIE_EXT_CLK +/* + * PCIe Override clock lookup table + * + * Each array index represents pcie override clock has been done + * by CFW or not. + */ +static uint8_t pcie_override_clk_table[] = { + /* PIPEMUX = 0, EP 1x16 */ + 0x0, + /* PIPEMUX = 1, EP 1x8 + RC 1x8, core 7 */ + 0x1, + /* PIPEMUX = 2, EP 4x4 */ + 0x0, + /* PIPEMUX = 3, RC 2x8, cores 0, 7 */ + 0x0, + /* PIPEMUX = 4, RC 4x4, cores 0, 1, 6, 7 */ + 0x0, + /* PIPEMUX = 5, RC 8x2, all 8 cores */ + 0x0, + /* PIPEMUX = 6, RC 3x4 + 2x2, cores 0, 2, 3, 6, 7 */ + 0x0, + /* PIPEMUX = 7, RC 1x4 + 6x2, cores 0, 2, 3, 4, 5, 6, 7 */ + 0x0, + /* PIPEMUX = 8, EP 1x8 + RC 4x2, cores 4, 5, 6, 7 */ + 0x0, + /* PIPEMUX = 9, EP 1x8 + RC 2x4, cores 6, 7 */ + 0x0, + /* PIPEMUX = 10, EP 2x4 + RC 2x4, cores 1, 6 */ + 0x0, + /* PIPEMUX = 11, EP 2x4 + RC 4x2, cores 2, 3, 4, 5 */ + 0x0, + /* PIPEMUX = 12, EP 1x4 + RC 6x2, cores 2, 3, 4, 5, 6, 7 */ + 0x0, + /* PIPEMUX = 13, RC 2x4 + RC 1x4 + 2x2, cores 2, 3, 6 */ + 0x0, +}; + +/* + * Bring up LCPLL channel 0 reference clock for PCIe serdes used in RC mode + */ +static int pcie_lcpll_init(void) +{ + uintptr_t reg; + unsigned int timeout = PCIE_LCPLL_TIMEOUT_MS; + uint32_t val; + + if (pcie_override_clk_table[pipemux_idx]) { + /* + * Check rc_mode_override again to avoid halt + * because of cfw uninitialized lcpll. + */ + reg = (uintptr_t)(PCIE_LCPLL_BASE + + PCIE_PIPE_MUX_RC_MODE_OVERRIDE_CFG); + val = mmio_read_32(reg); + if (val & 0x1) + return 0; + else + return -ENODEV; + } + + /* power on PCIe LCPLL and its LDO */ + reg = (uintptr_t)CRMU_AON_CTRL1; + mmio_setbits_32(reg, CRMU_PCIE_LCPLL_PWR_ON_MASK | + CRMU_PCIE_LCPLL_PWRON_LDO_MASK); + udelay(PCIE_LCPLL_DELAY_US); + + /* remove isolation */ + mmio_clrbits_32(reg, CRMU_PCIE_LCPLL_ISO_IN_MASK); + udelay(PCIE_LCPLL_DELAY_US); + + /* disconnect termination */ + reg = (uintptr_t)(PCIE_LCPLL_BASE + PCIE_LCPLL_CTRL13_OFFSET); + mmio_setbits_32(reg, PCIE_LCPLL_D2C2_TERM_DISC << + PCIE_LCPLL_D2C2_CTRL_SHIFT); + + /* enable CML buf1/2 and D2C2 */ + reg = (uintptr_t)(PCIE_LCPLL_BASE + PCIE_LCPLL_CTRL3_OFFSET); + mmio_setbits_32(reg, PCIE_LCPLL_CM_ENA << PCIE_LCPLL_EN_CTRL_SHIFT); + + /* select diff clock mux out as ref clock */ + mmio_clrbits_32(reg, PCIE_LCPLL_REF_CLK_MASK); + + /* delay for 500 microseconds per ASIC spec for PCIe LCPLL */ + udelay(PCIE_LCPLL_DELAY_US); + + /* now bring PCIe LCPLL out of reset */ + reg = (uintptr_t)(PCIE_LCPLL_BASE + PCIE_LCPLL_CTRL0_OFFSET); + mmio_setbits_32(reg, PCIE_LCPLL_RESETB_MASK); + + /* wait for PLL to lock */ + reg = (uintptr_t)(PCIE_LCPLL_BASE + PCIE_LCPLL_STATUS_OFFSET); + do { + val = mmio_read_32(reg); + if ((val & PCIE_LCPLL_LOCK_MASK) == PCIE_LCPLL_LOCK_MASK) { + /* now bring the post divider out of reset */ + reg = (uintptr_t)(PCIE_LCPLL_BASE + + PCIE_LCPLL_CTRL0_OFFSET); + mmio_setbits_32(reg, PCIE_LCPLL_P_RESETB_MASK); + VERBOSE("PCIe LCPLL locked\n"); + return 0; + } + mdelay(1); + } while (--timeout); + + ERROR("PCIe LCPLL failed to lock\n"); + return -EIO; +} +#else +/* + * Bring up EXT CLK reference clock for PCIe serdes used in RC mode + * XTAL_BYPASS (3 << 0) + * INTR_LC_REF (5 << 0) + * PD_CML_LC_REF_OUT (1 << 4) + * PD_CML_REF_CH_OUT (1 << 8) + * CLK_MASTER_SEL (1 << 11) + * CLK_MASTER_CTRL_A (1 << 12) + * CLK_MASTER_CTRL_B (2 << 14) + */ +static const uint16_t pcie_ext_clk[][NUM_OF_PCIE_SERDES] = { + /* PIPEMUX = 0, EP 1x16 */ + {0}, + /* PIPEMUX = 1, EP 1x8 + RC 1x8, core 7 */ + {0}, + /* PIPEMUX = 2, EP 4x4 */ + {0}, + /* PIPEMUX = 3, RC 2x8, cores 0, 7 */ + {0x8803, 0x9115, 0x9115, 0x1115, 0x8803, 0x9115, 0x9115, 0x1115}, + /* PIPEMUX = 4, RC 4x4, cores 0, 1, 6, 7 */ + {0x8803, 0x1115, 0x8915, 0x1115, 0x8803, 0x1115, 0x8915, 0x1115,}, + /* PIPEMUX = 5, RC 8x2, all 8 cores */ + {0x0803, 0x0915, 0x0915, 0x0915, 0x0803, 0x0915, 0x0915, 0x0915,}, + /* PIPEMUX = 6, RC 3x4 + 2x2, cores 0, 2, 3, 6, 7 */ + {0}, + /* PIPEMUX = 7, RC 1x4 + 6x2, cores 0, 2, 3, 4, 5, 6, 7 */ + {0}, + /* PIPEMUX = 8, EP 1x8 + RC 4x2, cores 4, 5, 6, 7 */ + {0}, + /* PIPEMUX = 9, EP 1x8 + RC 2x4, cores 6, 7 */ + {0}, + /* PIPEMUX = 10, EP 2x4 + RC 2x4, cores 1, 6 */ + {0}, + /* PIPEMUX = 11, EP 2x4 + RC 4x2, cores 2, 3, 4, 5 */ + {0}, + /* PIPEMUX = 12, EP 1x4 + RC 6x2, cores 2, 3, 4, 5, 6, 7 */ + {0}, + /* PIPEMUX = 13, RC 2x4 + RC 1x4 + 2x2, cores 2, 3, 6 */ + {0}, +}; + +static void pcie_ext_clk_init(void) +{ + unsigned int serdes; + uint32_t val; + + for (serdes = 0; serdes < NUM_OF_PCIE_SERDES; serdes++) { + val = pcie_ext_clk[pipemux_idx][serdes]; + if (!val) + return; + mmio_write_32(PCIE_CORE_RESERVED_CFG + + serdes * PCIE_CORE_PWR_OFFSET, val); + } + /* disable CML buf1/2 and enable D2C2 */ + mmio_clrsetbits_32((PCIE_LCPLL_BASE + PCIE_LCPLL_CTRL3_OFFSET), + PCIE_LCPLL_CM_BUF_ENA << PCIE_LCPLL_EN_CTRL_SHIFT, + PCIE_LCPLL_D2C2_ENA << PCIE_LCPLL_EN_CTRL_SHIFT); + mmio_write_32(PCIE_LCPLL_BASE + PCIE_TX_CLKMASTER_CTRL_OVERRIDE_CFG, 1); + INFO("Overriding Clocking - using REF clock from PAD...\n"); +} +#endif + +static int load_uc(unsigned int core_idx) +{ + return 0; +} + +static int paxb_serdes_gate_clock(unsigned int core_idx, int gate_clk) +{ + unsigned int link_width, serdes, nr_serdes; + uintptr_t pmi_base; + unsigned int rdata; + uint32_t core_offset = core_idx * PCIE_CORE_PWR_OFFSET; + + link_width = paxb->get_link_width(core_idx); + if (!link_width) { + ERROR("Unsupported PIPEMUX\n"); + return -EOPNOTSUPP; + } + + nr_serdes = link_width / 2; + pmi_base = (uintptr_t)(PCIE_CORE_PMI_CFG_BASE + core_offset); + + for (serdes = 0; serdes < nr_serdes; serdes++) { + mmio_write_32(pmi_base, serdes); + paxb_pmi_read(core_idx, PMI_ADDR_LANE0(PMI_PLL_CTRL_4), &rdata); + if (!gate_clk) + rdata |= PMI_SERDES_CLK_ENABLE; + else + rdata &= ~PMI_SERDES_CLK_ENABLE; + paxb_pmi_write(core_idx, PMI_ADDR_BCAST(PMI_PLL_CTRL_4), rdata); + } + return 0; +} + +static int paxb_gen3_serdes_init(unsigned int core_idx, uint32_t nSerdes) +{ + uint32_t rdata; + int serdes; + uintptr_t pmi_base; + unsigned int timeout; + unsigned int reg_d230, reg_d267; + + + pmi_base = (uintptr_t)(PCIE_CORE_PMI_CFG_BASE + + (core_idx * PCIE_CORE_PWR_OFFSET)); + + for (serdes = 0; serdes < nSerdes; serdes++) { + /* select the PMI interface */ + mmio_write_32(pmi_base, serdes); + + /* Clock enable */ + paxb_pmi_write(core_idx, PMI_ADDR_BCAST(UC_A_CLK_CTRL0), + 0x3); + + /* Release reset of master */ + paxb_pmi_write(core_idx, PMI_ADDR_BCAST(UC_A_RST_CTRL0), + 0x1); + + /* clearing PRAM memory */ + paxb_pmi_write(core_idx, PMI_ADDR_BCAST(UC_A_AHB_CTRL0), + 0x100); + + timeout = UC_RAM_INIT_TIMEOUT; + do { + paxb_pmi_read(core_idx, + PMI_ADDR_LANE0(UC_A_AHB_STAT0), + &rdata); + } while ((rdata & 0x01) == 0 && timeout--); + + if (!timeout) + return -EIO; + + timeout = UC_RAM_INIT_TIMEOUT; + do { + paxb_pmi_read(core_idx, + PMI_ADDR_LANE1(UC_A_AHB_STAT0), + &rdata); + } while ((rdata & 0x01) == 0 && timeout--); + + if (!timeout) + return -EIO; + + /* clearing PRAM memory */ + paxb_pmi_write(core_idx, PMI_ADDR_BCAST(UC_A_AHB_CTRL0), + 0); + + /* to identify 2 lane serdes */ + paxb_pmi_write(core_idx, PMI_ADDR_BCAST(UC_DBG1), 0x1); + + /* De-Assert Pram & master resets */ + paxb_pmi_write(core_idx, PMI_ADDR_BCAST(UC_A_RST_CTRL0), + 0x9); + + if (load_uc(core_idx)) + return -EIO; + + /* UC UC ready for command */ + paxb_pmi_read(core_idx, PMI_ADDR_LANE0(DSC_UC_CTRL), + &rdata); + rdata |= DSC_UC_CTRL_RDY_CMD; + paxb_pmi_write(core_idx, PMI_ADDR_LANE0(DSC_UC_CTRL), + rdata); + + paxb_pmi_read(core_idx, PMI_ADDR_LANE1(DSC_UC_CTRL), + &rdata); + rdata |= DSC_UC_CTRL_RDY_CMD; + paxb_pmi_write(core_idx, PMI_ADDR_LANE1(DSC_UC_CTRL), + rdata); + + /* Lane reset */ + paxb_pmi_write(core_idx, + PMI_ADDR_BCAST(LANE_DBG_RST_CTRL), 0x3); + + /* De-Assert Core and Master resets */ + paxb_pmi_write(core_idx, PMI_ADDR_BCAST(UC_A_RST_CTRL0), + 0x3); + + timeout = UC_INIT_TIMEOUT; + while (timeout--) { + paxb_pmi_read(core_idx, + PMI_ADDR_LANE0(UC_VERSION_NUM), + ®_d230); + paxb_pmi_read(core_idx, + PMI_ADDR_LANE0(DSC_SM_CTL22), + ®_d267); + + if (((reg_d230 & 0xffff) != 0) & + ((reg_d267 & 0xc000) == 0xc000)) { + break; + } + mdelay(1); + } + + if (!timeout) + return -EIO; + + timeout = UC_INIT_TIMEOUT; + while (timeout--) { + paxb_pmi_read(core_idx, + PMI_ADDR_LANE1(UC_VERSION_NUM), + ®_d230); + paxb_pmi_read(core_idx, + PMI_ADDR_LANE1(DSC_SM_CTL22), + ®_d267); + + if (((reg_d230 & 0xffff) != 0) & + ((reg_d267 & 0xc000) == 0xc000)) { + break; + } + mdelay(1); + } + + if (!timeout) + return -EIO; + } + return 0; +} + +static int pcie_serdes_requires_patch(unsigned int serdes_idx) +{ + if (pipemux_idx != SERDES_PATCH_PIPEMUX_INDEX) + return 0; + + return !!((SERDES_PATCH_INDEX >> serdes_idx) & 0x1); +} + +static void pcie_tx_coeff_p7(unsigned int core_idx) +{ + paxb_pmi_write(core_idx, PMI_ADDR_BCAST(0xd11b), 0x00aa); + paxb_pmi_write(core_idx, PMI_ADDR_BCAST(0xd11c), 0x1155); + paxb_pmi_write(core_idx, PMI_ADDR_BCAST(0xd11d), 0x2449); + paxb_pmi_write(core_idx, PMI_ADDR_BCAST(0xd11e), 0x000f); + paxb_pmi_write(core_idx, PMI_ADDR_BCAST(0xd307), 0x0001); +} + + +static unsigned int paxb_sr_get_rc_link_width(unsigned int core_idx) +{ + return link_width_table[pipemux_idx][core_idx]; +} + +static uint32_t paxb_sr_get_rc_link_speed(void) +{ + return GEN3_LINK_SPEED; +} + + +static int paxb_serdes_init(unsigned int core_idx, unsigned int nr_serdes) +{ + uint32_t core_offset = core_idx * PCIE_CORE_PWR_OFFSET; + unsigned int serdes; + uintptr_t pmi_base; + int ret; + + /* + * Each serdes has a x2 link width + * + * Use PAXB to patch the serdes for proper RX termination through the + * PMI interface + */ + pmi_base = (uintptr_t)(PCIE_CORE_PMI_CFG_BASE + core_offset); + for (serdes = 0; serdes < nr_serdes; serdes++) { + /* select the PMI interface */ + mmio_write_32(pmi_base, serdes); + + /* patch Serdes for RX termination */ + ret = paxb_pmi_write(core_idx, PMI_RX_TERM_SEQ, + PMI_RX_TERM_VAL); + if (ret) + goto err_pmi; + + ret = paxb_pmi_write(core_idx, MERLIN16_PCIE_BLK2_PWRMGMT_7, + MERLIN16_PCIE_BLK2_PWRMGMT_7_VAL); + if (ret) + goto err_pmi; + + ret = paxb_pmi_write(core_idx, MERLIN16_PCIE_BLK2_PWRMGMT_8, + MERLIN16_PCIE_BLK2_PWRMGMT_8_VAL); + if (ret) + goto err_pmi; + + ret = paxb_pmi_write(core_idx, MERLIN16_AMS_TX_CTRL_5, + MERLIN16_AMS_TX_CTRL_5_VAL); + if (ret) + goto err_pmi; + + pcie_tx_coeff_p7(core_idx); + + if (pcie_serdes_requires_patch(serdes)) { + if (((core_idx == 0) || (core_idx == 7))) { + ret = paxb_pmi_write(core_idx, + PMI_X8_CORE0_7_PATCH_SEQ, + PMI_X8_CORE0_7_PATCH_VAL); + if (ret) + goto err_pmi; + } + } + } + + return 0; + +err_pmi: + ERROR("PCIe PMI write failed\n"); + return ret; +} + +static int paxb_sr_phy_init(void) +{ + int ret; + unsigned int core_idx; + +#ifndef BOARD_PCIE_EXT_CLK + ret = pcie_lcpll_init(); + if (ret) + return ret; +#else + pcie_ext_clk_init(); +#endif + + for (core_idx = 0; core_idx < paxb->num_cores; core_idx++) { + if (!pcie_core_needs_enable(core_idx)) + continue; + unsigned int link_width; + + paxb_serdes_gate_clock(core_idx, 0); + + link_width = paxb->get_link_width(core_idx); + if (!link_width) { + ERROR("Unsupported PIPEMUX\n"); + return -EOPNOTSUPP; + } + + ret = paxb_serdes_init(core_idx, link_width / 2); + if (ret) { + ERROR("PCIe serdes initialization failed for core %u\n", + core_idx); + return ret; + } + + + ret = paxb_gen3_serdes_init(core_idx, link_width / 2); + if (ret) { + ERROR("PCIe GEN3 serdes initialization failed\n"); + return ret; + } + + } + return 0; +} + +const paxb_cfg sr_paxb_cfg = { + .type = PAXB_SR, + .device_id = SR_B0_DEVICE_ID, + .pipemux_init = pipemux_sr_init, + .phy_init = paxb_sr_phy_init, + .core_needs_enable = paxb_sr_core_needs_enable, + .num_cores = NUM_OF_SR_PCIE_CORES, + .get_link_width = paxb_sr_get_rc_link_width, + .get_link_speed = paxb_sr_get_rc_link_speed, +}; + +const paxb_cfg *paxb_get_sr_config(void) +{ + return &sr_paxb_cfg; +} diff --git a/plat/brcm/board/stingray/src/topology.c b/plat/brcm/board/stingray/src/topology.c new file mode 100644 index 0000000..24718e5 --- /dev/null +++ b/plat/brcm/board/stingray/src/topology.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2019-2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#include <stdint.h> + +#include <plat_brcm.h> +#include <platform_def.h> + +/* + * On Stingray, the system power level is the highest power level. + * The first entry in the power domain descriptor specifies the + * number of system power domains i.e. 1. + */ +#define SR_PWR_DOMAINS_AT_MAX_PWR_LVL 1 + +/* + * The Stingray power domain tree descriptor. The cluster power domains + * are arranged so that when the PSCI generic code creates the power + * domain tree, the indices of the CPU power domain nodes it allocates + * match the linear indices returned by plat_core_pos_by_mpidr() + * i.e. CLUSTER0 CPUs are allocated indices from 0 to 1 and the higher + * indices for other Cluster CPUs. + */ +const unsigned char sr_power_domain_tree_desc[] = { + /* No of root nodes */ + SR_PWR_DOMAINS_AT_MAX_PWR_LVL, + /* No of children for the root node */ + BRCM_CLUSTER_COUNT, + /* No of children for the first cluster node */ + PLATFORM_CLUSTER0_CORE_COUNT, + /* No of children for the second cluster node */ + PLATFORM_CLUSTER1_CORE_COUNT, + /* No of children for the third cluster node */ + PLATFORM_CLUSTER2_CORE_COUNT, + /* No of children for the fourth cluster node */ + PLATFORM_CLUSTER3_CORE_COUNT, +}; + +/******************************************************************************* + * This function returns the Stingray topology tree information. + ******************************************************************************/ +const unsigned char *plat_get_power_domain_tree_desc(void) +{ + return sr_power_domain_tree_desc; +} + +int plat_core_pos_by_mpidr(u_register_t mpidr) +{ + return plat_brcm_calc_core_pos(mpidr); +} diff --git a/plat/brcm/board/stingray/src/tz_sec.c b/plat/brcm/board/stingray/src/tz_sec.c new file mode 100644 index 0000000..07b12a7 --- /dev/null +++ b/plat/brcm/board/stingray/src/tz_sec.c @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2016 - 2020, Broadcom + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <common/debug.h> +#include <drivers/arm/tzc400.h> +#include <lib/mmio.h> + +#include <cmn_sec.h> +#include <platform_def.h> + +/* + * Trust Zone controllers + */ +#define TZC400_FS_SRAM_ROOT 0x66d84000 + +/* + * TZPC Master configure registers + */ + +/* TZPC_TZPCDECPROT0set */ +#define TZPC0_MASTER_NS_BASE 0x68b40804 +#define TZPC0_SATA3_BIT 5 +#define TZPC0_SATA2_BIT 4 +#define TZPC0_SATA1_BIT 3 +#define TZPC0_SATA0_BIT 2 +#define TZPC0_USB3H1_BIT 1 +#define TZPC0_USB3H0_BIT 0 +#define TZPC0_MASTER_SEC_DEFAULT 0 + +/* TZPC_TZPCDECPROT1set */ +#define TZPC1_MASTER_NS_BASE 0x68b40810 +#define TZPC1_SDIO1_BIT 6 +#define TZPC1_SDIO0_BIT 5 +#define TZPC1_AUDIO0_BIT 4 +#define TZPC1_USB2D_BIT 3 +#define TZPC1_USB2H1_BIT 2 +#define TZPC1_USB2H0_BIT 1 +#define TZPC1_AMAC0_BIT 0 +#define TZPC1_MASTER_SEC_DEFAULT 0 + + +struct tz_sec_desc { + uintptr_t addr; + uint32_t val; +}; + +static const struct tz_sec_desc tz_master_defaults[] = { +{ TZPC0_MASTER_NS_BASE, TZPC0_MASTER_SEC_DEFAULT }, +{ TZPC1_MASTER_NS_BASE, TZPC1_MASTER_SEC_DEFAULT } +}; + +/* + * Initialize the TrustZone Controller for SRAM partitioning. + */ +static void bcm_tzc_setup(void) +{ + VERBOSE("Configuring SRAM TrustZone Controller\n"); + + /* Init the TZASC controller */ + tzc400_init(TZC400_FS_SRAM_ROOT); + + /* + * Close the entire SRAM space + * Region 0 covers the entire SRAM space + * None of the NS device can access it. + */ + tzc400_configure_region0(TZC_REGION_S_RDWR, 0); + + /* Do raise an exception if a NS device tries to access secure memory */ + tzc400_set_action(TZC_ACTION_ERR); +} + +/* + * Configure TZ Master as NS_MASTER or SECURE_MASTER + * To set a Master to non-secure, use *_SET registers + * To set a Master to secure, use *_CLR registers (set + 0x4 address) + */ +static void tz_master_set(uint32_t base, uint32_t value, uint32_t ns) +{ + if (ns == SECURE_MASTER) { + mmio_write_32(base + 4, value); + } else { + mmio_write_32(base, value); + } +} + +/* + * Initialize the secure environment for sdio. + */ +void plat_tz_sdio_ns_master_set(uint32_t ns) +{ + tz_master_set(TZPC1_MASTER_NS_BASE, + 1 << TZPC1_SDIO0_BIT, + ns); +} + +/* + * Initialize the secure environment for usb. + */ +void plat_tz_usb_ns_master_set(uint32_t ns) +{ + tz_master_set(TZPC1_MASTER_NS_BASE, + 1 << TZPC1_USB2H0_BIT, + ns); +} + +/* + * Set masters to default configuration. + * + * DMA security settings are programmed into the PL-330 controller and + * are not set by iProc TZPC registers. + * DMA always comes up as secure master (*NS bit is 0). + * + * Because the default reset values of TZPC are 0 (== Secure), + * ARM Verilog code makes all masters, including PCIe, come up as + * secure. + * However, SOTP has a bit called SOTP_ALLMASTER_NS that overrides + * TZPC and makes all masters non-secure for AB devices. + * + * Hence we first set all the TZPC bits to program all masters, + * including PCIe, as non-secure, then set the CLEAR_ALLMASTER_NS bit + * so that the SOTP_ALLMASTER_NS cannot override TZPC. + * now security settings for each masters come from TZPC + * (which makes all masters other than DMA as non-secure). + * + * During the boot, all masters other than DMA Ctrlr + list + * are non-secure in an AB Prod/AB Dev/AB Pending device. + * + */ +void plat_tz_master_default_cfg(void) +{ + int i; + + /* Configure default secure and non-secure TZ Masters */ + for (i = 0; i < ARRAY_SIZE(tz_master_defaults); i++) { + tz_master_set(tz_master_defaults[i].addr, + tz_master_defaults[i].val, + SECURE_MASTER); + tz_master_set(tz_master_defaults[i].addr, + ~tz_master_defaults[i].val, + NS_MASTER); + } + + /* Clear all master NS */ + mmio_setbits_32(SOTP_CHIP_CTRL, + 1 << SOTP_CLEAR_SYSCTRL_ALL_MASTER_NS); + + /* Initialize TZ controller and Set SRAM to secure */ + bcm_tzc_setup(); +} diff --git a/plat/brcm/common/brcm_bl2_mem_params_desc.c b/plat/brcm/common/brcm_bl2_mem_params_desc.c new file mode 100644 index 0000000..aed99d9 --- /dev/null +++ b/plat/brcm/common/brcm_bl2_mem_params_desc.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <common/bl_common.h> +#include <common/desc_image_load.h> +#include <plat/common/platform.h> + +#include <platform_def.h> + +/******************************************************************************* + * Following descriptor provides BL image/ep information that gets used + * by BL2 to load the images and also subset of this information is + * passed to next BL image. The image loading sequence is managed by + * populating the images in required loading order. The image execution + * sequence is managed by populating the `next_handoff_image_id` with + * the next executable image id. + ******************************************************************************/ +static bl_mem_params_node_t bl2_mem_params_descs[] = { +#ifdef SCP_BL2_BASE + /* Fill SCP_BL2 related information if it exists */ + { + .image_id = SCP_BL2_IMAGE_ID, + + SET_STATIC_PARAM_HEAD(ep_info, PARAM_IMAGE_BINARY, + VERSION_2, entry_point_info_t, SECURE | NON_EXECUTABLE), + + SET_STATIC_PARAM_HEAD(image_info, PARAM_IMAGE_BINARY, + VERSION_2, image_info_t, 0), + .image_info.image_base = SCP_BL2_BASE, + .image_info.image_max_size = PLAT_MAX_SCP_BL2_SIZE, + + .next_handoff_image_id = INVALID_IMAGE_ID, + }, +#endif /* SCP_BL2_BASE */ + + /* Fill BL31 related information */ + { + .image_id = BL31_IMAGE_ID, + + SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, + VERSION_2, entry_point_info_t, + SECURE | EXECUTABLE | EP_FIRST_EXE), + .ep_info.pc = BL31_BASE, + .ep_info.spsr = SPSR_64(MODE_EL3, MODE_SP_ELX, + DISABLE_ALL_EXCEPTIONS), +#if DEBUG + .ep_info.args.arg3 = BRCM_BL31_PLAT_PARAM_VAL, +#endif + + SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, + VERSION_2, image_info_t, IMAGE_ATTRIB_PLAT_SETUP), + .image_info.image_base = BL31_BASE, + .image_info.image_max_size = BL31_LIMIT - BL31_BASE, + +#ifdef BL32_BASE + .next_handoff_image_id = BL32_IMAGE_ID, +#else + .next_handoff_image_id = BL33_IMAGE_ID, +#endif + }, + +#ifdef BL32_BASE + /* Fill BL32 related information */ + { + .image_id = BL32_IMAGE_ID, + + SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, + VERSION_2, entry_point_info_t, SECURE | EXECUTABLE), + .ep_info.pc = BL32_BASE, + + SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, + VERSION_2, image_info_t, 0), + .image_info.image_base = BL32_BASE, + .image_info.image_max_size = BL32_LIMIT - BL32_BASE, + + .next_handoff_image_id = BL33_IMAGE_ID, + }, +#endif /* BL32_BASE */ + + /* Fill BL33 related information */ + { + .image_id = BL33_IMAGE_ID, + SET_STATIC_PARAM_HEAD(ep_info, PARAM_EP, + VERSION_2, entry_point_info_t, NON_SECURE | EXECUTABLE), +#ifdef PRELOADED_BL33_BASE + .ep_info.pc = PRELOADED_BL33_BASE, + + SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, + VERSION_2, image_info_t, IMAGE_ATTRIB_SKIP_LOADING), +#else + .ep_info.pc = PLAT_BRCM_NS_IMAGE_OFFSET, + + SET_STATIC_PARAM_HEAD(image_info, PARAM_EP, + VERSION_2, image_info_t, 0), + .image_info.image_base = PLAT_BRCM_NS_IMAGE_OFFSET, + .image_info.image_max_size = BRCM_DRAM1_SIZE, +#endif /* PRELOADED_BL33_BASE */ + + .next_handoff_image_id = INVALID_IMAGE_ID, + } +}; + +REGISTER_BL_IMAGE_DESCS(bl2_mem_params_descs) diff --git a/plat/brcm/common/brcm_bl2_setup.c b/plat/brcm/common/brcm_bl2_setup.c new file mode 100644 index 0000000..9a7153b --- /dev/null +++ b/plat/brcm/common/brcm_bl2_setup.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <string.h> + +#include <arch_helpers.h> +#include <common/bl_common.h> +#include <common/debug.h> +#include <common/desc_image_load.h> +#include <drivers/arm/sp804_delay_timer.h> +#include <lib/mmio.h> + +#include <bcm_console.h> +#include <platform_def.h> +#include <plat/brcm/common/plat_brcm.h> + +/* Data structure which holds the extents of the trusted SRAM for BL2 */ +static meminfo_t bl2_tzram_layout __aligned(CACHE_WRITEBACK_GRANULE); + +/* Weak definitions may be overridden in specific BRCM platform */ +#pragma weak plat_bcm_bl2_platform_setup +#pragma weak plat_bcm_bl2_plat_arch_setup +#pragma weak plat_bcm_security_setup +#pragma weak plat_bcm_bl2_plat_handle_scp_bl2 +#pragma weak plat_bcm_bl2_early_platform_setup + +void plat_bcm_bl2_early_platform_setup(void) +{ +} + +void plat_bcm_bl2_platform_setup(void) +{ +} + +void plat_bcm_bl2_plat_arch_setup(void) +{ +} + +void plat_bcm_security_setup(void) +{ +} + +void bcm_bl2_early_platform_setup(uintptr_t tb_fw_config, + meminfo_t *mem_layout) +{ + /* Initialize the console to provide early debug support */ + bcm_console_boot_init(); + + /* Setup the BL2 memory layout */ + bl2_tzram_layout = *mem_layout; + + /* Initialise the IO layer and register platform IO devices */ + plat_brcm_io_setup(); + + /* Log HW reset event */ + INFO("RESET: 0x%x\n", + mmio_read_32(CRMU_RESET_EVENT_LOG)); +} + +void bl2_early_platform_setup2(u_register_t arg0, u_register_t arg1, + u_register_t arg2, u_register_t arg3) +{ + /* SoC specific setup */ + plat_bcm_bl2_early_platform_setup(); + + /* Initialize delay timer driver using SP804 dual timer 0 */ + sp804_timer_init(SP804_TIMER0_BASE, + SP804_TIMER0_CLKMULT, SP804_TIMER0_CLKDIV); + + /* BRCM platforms generic setup */ + bcm_bl2_early_platform_setup((uintptr_t)arg0, (meminfo_t *)arg1); +} + +/* + * Perform Broadcom platform setup. + */ +void bcm_bl2_platform_setup(void) +{ + /* Initialize the secure environment */ + plat_bcm_security_setup(); +} + +void bl2_platform_setup(void) +{ + bcm_bl2_platform_setup(); + plat_bcm_bl2_platform_setup(); +} + +/******************************************************************************* + * Perform the very early platform specific architectural setup here. At the + * moment this is only initializes the mmu in a quick and dirty way. + ******************************************************************************/ +void bcm_bl2_plat_arch_setup(void) +{ +#ifndef MMU_DISABLED + if (!(read_sctlr_el1() & SCTLR_M_BIT)) { + const mmap_region_t bl_regions[] = { + MAP_REGION_FLAT(bl2_tzram_layout.total_base, + bl2_tzram_layout.total_size, + MT_MEMORY | MT_RW | MT_SECURE), + MAP_REGION_FLAT(BL_CODE_BASE, + BL_CODE_END - BL_CODE_BASE, + MT_CODE | MT_SECURE), + MAP_REGION_FLAT(BL_RO_DATA_BASE, + BL_RO_DATA_END - BL_RO_DATA_BASE, + MT_RO_DATA | MT_SECURE), +#if USE_COHERENT_MEM + MAP_REGION_FLAT(BL_COHERENT_RAM_BASE, + BL_COHERENT_RAM_END - + BL_COHERENT_RAM_BASE, + MT_DEVICE | MT_RW | MT_SECURE), +#endif + {0} + }; + + setup_page_tables(bl_regions, plat_brcm_get_mmap()); + enable_mmu_el1(0); + } +#endif +} + +void bl2_plat_arch_setup(void) +{ +#ifdef ENA_MMU_BEFORE_DDR_INIT + /* + * Once MMU is enabled before DDR, MEMORY TESTS + * get affected as read/write transaction might occures from + * caches. So For running memory test, one should not set this + * flag. + */ + bcm_bl2_plat_arch_setup(); + plat_bcm_bl2_plat_arch_setup(); +#else + plat_bcm_bl2_plat_arch_setup(); + bcm_bl2_plat_arch_setup(); +#endif +} + +int bcm_bl2_handle_post_image_load(unsigned int image_id) +{ + int err = 0; + + bl_mem_params_node_t *bl_mem_params = get_bl_mem_params_node(image_id); + + assert(bl_mem_params); + + switch (image_id) { + case BL32_IMAGE_ID: + bl_mem_params->ep_info.spsr = brcm_get_spsr_for_bl32_entry(); + break; + + case BL33_IMAGE_ID: + /* BL33 expects to receive the primary CPU MPID (through r0) */ + bl_mem_params->ep_info.args.arg0 = 0xffff & read_mpidr(); + bl_mem_params->ep_info.spsr = brcm_get_spsr_for_bl33_entry(); + break; + +#ifdef SCP_BL2_BASE + case SCP_BL2_IMAGE_ID: + /* The subsequent handling of SCP_BL2 is platform specific */ + err = bcm_bl2_handle_scp_bl2(&bl_mem_params->image_info); + if (err) + WARN("Failure in platform-specific handling of SCP_BL2 image.\n"); + break; +#endif + default: + /* Do nothing in default case */ + break; + } + + return err; +} + +/******************************************************************************* + * This function can be used by the platforms to update/use image + * information for given `image_id`. + ******************************************************************************/ +int bcm_bl2_plat_handle_post_image_load(unsigned int image_id) +{ + return bcm_bl2_handle_post_image_load(image_id); +} + +int bl2_plat_handle_post_image_load(unsigned int image_id) +{ + return bcm_bl2_plat_handle_post_image_load(image_id); +} + +#ifdef SCP_BL2_BASE +int plat_bcm_bl2_plat_handle_scp_bl2(image_info_t *scp_bl2_image_info) +{ + return 0; +} + +int bcm_bl2_handle_scp_bl2(image_info_t *scp_bl2_image_info) +{ + return plat_bcm_bl2_plat_handle_scp_bl2(scp_bl2_image_info); +} +#endif diff --git a/plat/brcm/common/brcm_bl31_setup.c b/plat/brcm/common/brcm_bl31_setup.c new file mode 100644 index 0000000..d3fa83d --- /dev/null +++ b/plat/brcm/common/brcm_bl31_setup.c @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> + +#include <arch.h> +#include <arch_helpers.h> +#include <common/bl_common.h> +#include <common/debug.h> +#include <drivers/arm/sp804_delay_timer.h> +#include <lib/utils.h> +#include <plat/common/platform.h> + +#include <bcm_console.h> +#include <plat_brcm.h> +#include <platform_def.h> + +#ifdef BL33_SHARED_DDR_BASE +struct bl33_info *bl33_info = (struct bl33_info *)BL33_SHARED_DDR_BASE; +#endif + +/* + * Placeholder variables for copying the arguments that have been passed to + * BL31 from BL2. + */ +static entry_point_info_t bl32_image_ep_info; +static entry_point_info_t bl33_image_ep_info; + +/* Weak definitions may be overridden in specific BRCM platform */ +#pragma weak plat_bcm_bl31_early_platform_setup +#pragma weak plat_brcm_pwrc_setup +#pragma weak plat_brcm_security_setup + +void plat_brcm_security_setup(void) +{ + +} + +void plat_brcm_pwrc_setup(void) +{ + +} + +void plat_bcm_bl31_early_platform_setup(void *from_bl2, + bl_params_t *plat_params_from_bl2) +{ + +} + +/******************************************************************************* + * Return a pointer to the 'entry_point_info' structure of the next image for + * the security state specified. BL33 corresponds to the non-secure image type + * while BL32 corresponds to the secure image type. A NULL pointer is returned + * if the image does not exist. + ******************************************************************************/ +struct entry_point_info *bl31_plat_get_next_image_ep_info(uint32_t type) +{ + entry_point_info_t *next_image_info; + + assert(sec_state_is_valid(type)); + next_image_info = (type == NON_SECURE) + ? &bl33_image_ep_info : &bl32_image_ep_info; + /* + * None of the images on the ARM development platforms can have 0x0 + * as the entrypoint + */ + if (next_image_info->pc) + return next_image_info; + else + return NULL; +} + +/******************************************************************************* + * Perform any BL31 early platform setup common to ARM standard platforms. + * Here is an opportunity to copy parameters passed by the calling EL (S-EL1 + * in BL2 & EL3 in BL1) before they are lost (potentially). This needs to be + * done before the MMU is initialized so that the memory layout can be used + * while creating page tables. BL2 has flushed this information to memory, so + * we are guaranteed to pick up good data. + ******************************************************************************/ +void __init brcm_bl31_early_platform_setup(void *from_bl2, + uintptr_t soc_fw_config, + uintptr_t hw_config, + void *plat_params_from_bl2) +{ + /* Initialize the console to provide early debug support */ + bcm_console_boot_init(); + + /* Initialize delay timer driver using SP804 dual timer 0 */ + sp804_timer_init(SP804_TIMER0_BASE, + SP804_TIMER0_CLKMULT, SP804_TIMER0_CLKDIV); + +#if RESET_TO_BL31 + /* There are no parameters from BL2 if BL31 is a reset vector */ + assert(from_bl2 == NULL); + assert(plat_params_from_bl2 == NULL); + +# ifdef BL32_BASE + /* Populate entry point information for BL32 */ + SET_PARAM_HEAD(&bl32_image_ep_info, + PARAM_EP, + VERSION_1, + 0); + SET_SECURITY_STATE(bl32_image_ep_info.h.attr, SECURE); + bl32_image_ep_info.pc = BL32_BASE; + bl32_image_ep_info.spsr = brcm_get_spsr_for_bl32_entry(); +# endif /* BL32_BASE */ + + /* Populate entry point information for BL33 */ + SET_PARAM_HEAD(&bl33_image_ep_info, + PARAM_EP, + VERSION_1, + 0); + /* + * Tell BL31 where the non-trusted software image + * is located and the entry state information + */ + bl33_image_ep_info.pc = plat_get_ns_image_entrypoint(); + + bl33_image_ep_info.spsr = brcm_get_spsr_for_bl33_entry(); + SET_SECURITY_STATE(bl33_image_ep_info.h.attr, NON_SECURE); + +# if ARM_LINUX_KERNEL_AS_BL33 + /* + * According to the file ``Documentation/arm64/booting.txt`` of the + * Linux kernel tree, Linux expects the physical address of the device + * tree blob (DTB) in x0, while x1-x3 are reserved for future use and + * must be 0. + */ + bl33_image_ep_info.args.arg0 = (u_register_t)PRELOADED_DTB_BASE; + bl33_image_ep_info.args.arg1 = 0U; + bl33_image_ep_info.args.arg2 = 0U; + bl33_image_ep_info.args.arg3 = 0U; +# endif + +#else /* RESET_TO_BL31 */ + + /* + * In debug builds, we pass a special value in 'plat_params_from_bl2' + * to verify platform parameters from BL2 to BL31. + * In release builds, it's not used. + */ + assert(((unsigned long long)plat_params_from_bl2) == + BRCM_BL31_PLAT_PARAM_VAL); + + /* + * Check params passed from BL2 should not be NULL + */ + bl_params_t *params_from_bl2 = (bl_params_t *)from_bl2; + + assert(params_from_bl2 != NULL); + assert(params_from_bl2->h.type == PARAM_BL_PARAMS); + assert(params_from_bl2->h.version >= VERSION_2); + + bl_params_node_t *bl_params = params_from_bl2->head; + + /* + * Copy BL33 and BL32 (if present), entry point information. + * They are stored in Secure RAM, in BL2's address space. + */ + while (bl_params != NULL) { + if (bl_params->image_id == BL32_IMAGE_ID && + bl_params->image_info->h.attr != IMAGE_ATTRIB_SKIP_LOADING) + bl32_image_ep_info = *bl_params->ep_info; + + if (bl_params->image_id == BL33_IMAGE_ID) + bl33_image_ep_info = *bl_params->ep_info; + + bl_params = bl_params->next_params_info; + } + + if (bl33_image_ep_info.pc == 0U) + panic(); +#endif /* RESET_TO_BL31 */ + +#ifdef BL33_SHARED_DDR_BASE + /* Pass information to BL33 thorugh x0 */ + bl33_image_ep_info.args.arg0 = (u_register_t)BL33_SHARED_DDR_BASE; + bl33_image_ep_info.args.arg1 = 0ULL; + bl33_image_ep_info.args.arg2 = 0ULL; + bl33_image_ep_info.args.arg3 = 0ULL; +#endif +} + +void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1, + u_register_t arg2, u_register_t arg3) +{ +#ifdef BL31_LOG_LEVEL + SET_LOG_LEVEL(BL31_LOG_LEVEL); +#endif + + brcm_bl31_early_platform_setup((void *)arg0, arg1, arg2, (void *)arg3); + + plat_bcm_bl31_early_platform_setup((void *)arg0, (void *)arg3); + +#ifdef DRIVER_CC_ENABLE + /* + * Initialize Interconnect for this cluster during cold boot. + * No need for locks as no other CPU is active. + */ + plat_brcm_interconnect_init(); + + /* + * Enable Interconnect coherency for the primary CPU's cluster. + * Earlier bootloader stages might already do this (e.g. Trusted + * Firmware's BL1 does it) but we can't assume so. There is no harm in + * executing this code twice anyway. + * Platform specific PSCI code will enable coherency for other + * clusters. + */ + plat_brcm_interconnect_enter_coherency(); +#endif +} + +/******************************************************************************* + * Perform any BL31 platform setup common to ARM standard platforms + ******************************************************************************/ +void brcm_bl31_platform_setup(void) +{ + /* Initialize the GIC driver, cpu and distributor interfaces */ + plat_brcm_gic_driver_init(); + plat_brcm_gic_init(); + + /* Initialize power controller before setting up topology */ + plat_brcm_pwrc_setup(); +} + +/******************************************************************************* + * Perform any BL31 platform runtime setup prior to BL31 exit common to ARM + * standard platforms + * Perform BL31 platform setup + ******************************************************************************/ +void brcm_bl31_plat_runtime_setup(void) +{ + console_switch_state(CONSOLE_FLAG_RUNTIME); + + /* Initialize the runtime console */ + bcm_console_runtime_init(); +} + +void bl31_platform_setup(void) +{ + brcm_bl31_platform_setup(); + + /* Initialize the secure environment */ + plat_brcm_security_setup(); +} + +void bl31_plat_runtime_setup(void) +{ + brcm_bl31_plat_runtime_setup(); +} + +/******************************************************************************* + * Perform the very early platform specific architectural setup shared between + * ARM standard platforms. This only does basic initialization. Later + * architectural setup (bl31_arch_setup()) does not do anything platform + * specific. + ******************************************************************************/ +void __init brcm_bl31_plat_arch_setup(void) +{ +#ifndef MMU_DISABLED + const mmap_region_t bl_regions[] = { + MAP_REGION_FLAT(BL31_BASE, BL31_END - BL31_BASE, + MT_MEMORY | MT_RW | MT_SECURE), + MAP_REGION_FLAT(BL_CODE_BASE, BL_CODE_END - BL_CODE_BASE, + MT_CODE | MT_SECURE), + MAP_REGION_FLAT(BL_RO_DATA_BASE, + BL_RO_DATA_END - BL_RO_DATA_BASE, + MT_RO_DATA | MT_SECURE), +#if USE_COHERENT_MEM + MAP_REGION_FLAT(BL_COHERENT_RAM_BASE, + BL_COHERENT_RAM_END - BL_COHERENT_RAM_BASE, + MT_DEVICE | MT_RW | MT_SECURE), +#endif + {0} + }; + + setup_page_tables(bl_regions, plat_brcm_get_mmap()); + + enable_mmu_el3(0); +#endif +} + +void __init bl31_plat_arch_setup(void) +{ + brcm_bl31_plat_arch_setup(); +} diff --git a/plat/brcm/common/brcm_ccn.c b/plat/brcm/common/brcm_ccn.c new file mode 100644 index 0000000..9396aaa --- /dev/null +++ b/plat/brcm/common/brcm_ccn.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <arch.h> +#include <arch_helpers.h> +#include <drivers/arm/ccn.h> + +#include <platform_def.h> + +static const unsigned char master_to_rn_id_map[] = { + PLAT_BRCM_CLUSTER_TO_CCN_ID_MAP +}; + +static const ccn_desc_t bcm_ccn_desc = { + .periphbase = PLAT_BRCM_CCN_BASE, + .num_masters = ARRAY_SIZE(master_to_rn_id_map), + .master_to_rn_id_map = master_to_rn_id_map +}; + +void plat_brcm_interconnect_init(void) +{ + ccn_init(&bcm_ccn_desc); +} + +void plat_brcm_interconnect_enter_coherency(void) +{ + ccn_enter_snoop_dvm_domain(1 << MPIDR_AFFLVL1_VAL(read_mpidr_el1())); +} + +void plat_brcm_interconnect_exit_coherency(void) +{ + ccn_exit_snoop_dvm_domain(1 << MPIDR_AFFLVL1_VAL(read_mpidr_el1())); +} diff --git a/plat/brcm/common/brcm_common.c b/plat/brcm/common/brcm_common.c new file mode 100644 index 0000000..f23719d --- /dev/null +++ b/plat/brcm/common/brcm_common.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> + +#include <arch.h> +#include <arch_helpers.h> +#include <common/debug.h> +#include <plat/common/platform.h> + +#include <plat_brcm.h> +#include <platform_def.h> + +/* Weak definitions may be overridden in specific BRCM platform */ +#pragma weak plat_get_ns_image_entrypoint +#pragma weak plat_brcm_get_mmap + +uintptr_t plat_get_ns_image_entrypoint(void) +{ +#ifdef PRELOADED_BL33_BASE + return PRELOADED_BL33_BASE; +#else + return PLAT_BRCM_NS_IMAGE_OFFSET; +#endif +} + +uint32_t brcm_get_spsr_for_bl32_entry(void) +{ + /* + * The Secure Payload Dispatcher service is responsible for + * setting the SPSR prior to entry into the BL32 image. + */ + return 0; +} + +uint32_t brcm_get_spsr_for_bl33_entry(void) +{ + unsigned int mode; + uint32_t spsr; + + /* Figure out what mode we enter the non-secure world in */ + mode = el_implemented(2) ? MODE_EL2 : MODE_EL1; + + /* + * TODO: Consider the possibility of specifying the SPSR in + * the FIP ToC and allowing the platform to have a say as + * well. + */ + spsr = SPSR_64(mode, MODE_SP_ELX, DISABLE_ALL_EXCEPTIONS); + return spsr; +} + +const mmap_region_t *plat_brcm_get_mmap(void) +{ + return plat_brcm_mmap; +} diff --git a/plat/brcm/common/brcm_gicv3.c b/plat/brcm/common/brcm_gicv3.c new file mode 100644 index 0000000..c4137c0 --- /dev/null +++ b/plat/brcm/common/brcm_gicv3.c @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <drivers/arm/gicv3.h> +#include <plat/common/platform.h> + +#include <platform_def.h> + +/* The GICv3 driver only needs to be initialized in EL3 */ +static uintptr_t brcm_rdistif_base_addrs[PLATFORM_CORE_COUNT]; + +static const interrupt_prop_t brcm_interrupt_props[] = { + /* G1S interrupts */ + PLAT_BRCM_G1S_IRQ_PROPS(INTR_GROUP1S), + /* G0 interrupts */ + PLAT_BRCM_G0_IRQ_PROPS(INTR_GROUP0) +}; + +/* + * MPIDR hashing function for translating MPIDRs read from GICR_TYPER register + * to core position. + * + * Calculating core position is dependent on MPIDR_EL1.MT bit. However, affinity + * values read from GICR_TYPER don't have an MT field. To reuse the same + * translation used for CPUs, we insert MT bit read from the PE's MPIDR into + * that read from GICR_TYPER. + * + * Assumptions: + * + * - All CPUs implemented in the system have MPIDR_EL1.MT bit set; + * - No CPUs implemented in the system use affinity level 3. + */ +static unsigned int brcm_gicv3_mpidr_hash(u_register_t mpidr) +{ + mpidr |= (read_mpidr_el1() & MPIDR_MT_MASK); + return plat_core_pos_by_mpidr(mpidr); +} + +static const gicv3_driver_data_t brcm_gic_data = { + .gicd_base = PLAT_BRCM_GICD_BASE, + .gicr_base = PLAT_BRCM_GICR_BASE, + .interrupt_props = brcm_interrupt_props, + .interrupt_props_num = ARRAY_SIZE(brcm_interrupt_props), + .rdistif_num = PLATFORM_CORE_COUNT, + .rdistif_base_addrs = brcm_rdistif_base_addrs, + .mpidr_to_core_pos = brcm_gicv3_mpidr_hash +}; + +void plat_brcm_gic_driver_init(void) +{ + /* TODO Check if this is required to be initialized here + * after getting initialized in EL3, should we re-init this here + * in S-EL1 + */ + gicv3_driver_init(&brcm_gic_data); +} + +void plat_brcm_gic_init(void) +{ + gicv3_distif_init(); + gicv3_rdistif_init(plat_my_core_pos()); + gicv3_cpuif_enable(plat_my_core_pos()); +} + +void plat_brcm_gic_cpuif_enable(void) +{ + gicv3_cpuif_enable(plat_my_core_pos()); +} + +void plat_brcm_gic_cpuif_disable(void) +{ + gicv3_cpuif_disable(plat_my_core_pos()); +} + +void plat_brcm_gic_pcpu_init(void) +{ + gicv3_rdistif_init(plat_my_core_pos()); +} + +void plat_brcm_gic_redistif_on(void) +{ + gicv3_rdistif_on(plat_my_core_pos()); +} + +void plat_brcm_gic_redistif_off(void) +{ + gicv3_rdistif_off(plat_my_core_pos()); +} diff --git a/plat/brcm/common/brcm_image_load.c b/plat/brcm/common/brcm_image_load.c new file mode 100644 index 0000000..ba02bda --- /dev/null +++ b/plat/brcm/common/brcm_image_load.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <common/bl_common.h> +#include <common/desc_image_load.h> +#include <plat/common/platform.h> + +#pragma weak plat_flush_next_bl_params +#pragma weak plat_get_bl_image_load_info +#pragma weak plat_get_next_bl_params + +/******************************************************************************* + * This function flushes the data structures so that they are visible + * in memory for the next BL image. + ******************************************************************************/ +void plat_flush_next_bl_params(void) +{ + flush_bl_params_desc(); +} + +/******************************************************************************* + * This function returns the list of loadable images. + ******************************************************************************/ +struct bl_load_info *plat_get_bl_image_load_info(void) +{ + return get_bl_load_info_from_mem_params_desc(); +} + +/******************************************************************************* + * This function returns the list of executable images. + ******************************************************************************/ +struct bl_params *plat_get_next_bl_params(void) +{ + bl_params_t *next_bl_params = get_next_bl_params_from_mem_params_desc(); + + populate_next_bl_params_config(next_bl_params); + return next_bl_params; +} diff --git a/plat/brcm/common/brcm_io_storage.c b/plat/brcm/common/brcm_io_storage.c new file mode 100644 index 0000000..66ec292 --- /dev/null +++ b/plat/brcm/common/brcm_io_storage.c @@ -0,0 +1,408 @@ +/* + * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <string.h> + +#include <common/debug.h> +#include <drivers/io/io_driver.h> +#include <drivers/io/io_fip.h> +#include <drivers/io/io_memmap.h> +#include <drivers/io/io_storage.h> +#include <tools_share/firmware_image_package.h> + +#include <cmn_plat_def.h> +#include <cmn_plat_util.h> +#include <plat_brcm.h> +#include <platform_def.h> + +/* IO devices */ +static const io_dev_connector_t *fip_dev_con; +static uintptr_t fip_dev_handle; +static const io_dev_connector_t *memmap_dev_con; +static uintptr_t memmap_dev_handle; + +static const io_block_spec_t fip_block_spec = { + .offset = PLAT_BRCM_FIP_BASE, + .length = PLAT_BRCM_FIP_MAX_SIZE +}; + +static const io_block_spec_t qspi_fip_block_spec = { + .offset = PLAT_BRCM_FIP_QSPI_BASE, + .length = PLAT_BRCM_FIP_MAX_SIZE +}; + +static const io_block_spec_t nand_fip_block_spec = { + .offset = PLAT_BRCM_FIP_NAND_BASE, + .length = PLAT_BRCM_FIP_MAX_SIZE +}; + +static const io_uuid_spec_t bl2_uuid_spec = { + .uuid = UUID_TRUSTED_BOOT_FIRMWARE_BL2, +}; + +static const io_uuid_spec_t scp_bl2_uuid_spec = { + .uuid = UUID_SCP_FIRMWARE_SCP_BL2, +}; + +static const io_uuid_spec_t bl31_uuid_spec = { + .uuid = UUID_EL3_RUNTIME_FIRMWARE_BL31, +}; + +static const io_uuid_spec_t bl32_uuid_spec = { + .uuid = UUID_SECURE_PAYLOAD_BL32, +}; + +static const io_uuid_spec_t bl32_extra1_uuid_spec = { + .uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA1, +}; + +static const io_uuid_spec_t bl32_extra2_uuid_spec = { + .uuid = UUID_SECURE_PAYLOAD_BL32_EXTRA2, +}; + +static const io_uuid_spec_t bl33_uuid_spec = { + .uuid = UUID_NON_TRUSTED_FIRMWARE_BL33, +}; + +static const io_uuid_spec_t tb_fw_config_uuid_spec = { + .uuid = UUID_TB_FW_CONFIG, +}; + +static const io_uuid_spec_t hw_config_uuid_spec = { + .uuid = UUID_HW_CONFIG, +}; + +static const io_uuid_spec_t soc_fw_config_uuid_spec = { + .uuid = UUID_SOC_FW_CONFIG, +}; + +static const io_uuid_spec_t tos_fw_config_uuid_spec = { + .uuid = UUID_TOS_FW_CONFIG, +}; + +static const io_uuid_spec_t nt_fw_config_uuid_spec = { + .uuid = UUID_NT_FW_CONFIG, +}; + +#if TRUSTED_BOARD_BOOT +static const io_uuid_spec_t tb_fw_cert_uuid_spec = { + .uuid = UUID_TRUSTED_BOOT_FW_CERT, +}; + +static const io_uuid_spec_t trusted_key_cert_uuid_spec = { + .uuid = UUID_TRUSTED_KEY_CERT, +}; + +static const io_uuid_spec_t scp_fw_key_cert_uuid_spec = { + .uuid = UUID_SCP_FW_KEY_CERT, +}; + +static const io_uuid_spec_t soc_fw_key_cert_uuid_spec = { + .uuid = UUID_SOC_FW_KEY_CERT, +}; + +static const io_uuid_spec_t tos_fw_key_cert_uuid_spec = { + .uuid = UUID_TRUSTED_OS_FW_KEY_CERT, +}; + +static const io_uuid_spec_t nt_fw_key_cert_uuid_spec = { + .uuid = UUID_NON_TRUSTED_FW_KEY_CERT, +}; + +static const io_uuid_spec_t scp_fw_cert_uuid_spec = { + .uuid = UUID_SCP_FW_CONTENT_CERT, +}; + +static const io_uuid_spec_t soc_fw_cert_uuid_spec = { + .uuid = UUID_SOC_FW_CONTENT_CERT, +}; + +static const io_uuid_spec_t tos_fw_cert_uuid_spec = { + .uuid = UUID_TRUSTED_OS_FW_CONTENT_CERT, +}; + +static const io_uuid_spec_t nt_fw_cert_uuid_spec = { + .uuid = UUID_NON_TRUSTED_FW_CONTENT_CERT, +}; +#endif /* TRUSTED_BOARD_BOOT */ + +static int open_fip(const uintptr_t spec); +static int open_memmap(const uintptr_t spec); +static int open_qspi(const uintptr_t spec); +static int open_nand(const uintptr_t spec); + +struct plat_io_policy { + uintptr_t *dev_handle; + uintptr_t image_spec; + int (*check)(const uintptr_t spec); +}; + +/* By default, BRCM platforms load images from the FIP */ +static const struct plat_io_policy policies[] = { + [FIP_IMAGE_ID] = { + &memmap_dev_handle, + (uintptr_t)&fip_block_spec, + open_memmap + }, + [BL2_IMAGE_ID] = { + &fip_dev_handle, + (uintptr_t)&bl2_uuid_spec, + open_fip + }, + [SCP_BL2_IMAGE_ID] = { + &fip_dev_handle, + (uintptr_t)&scp_bl2_uuid_spec, + open_fip + }, + [BL31_IMAGE_ID] = { + &fip_dev_handle, + (uintptr_t)&bl31_uuid_spec, + open_fip + }, + [BL32_IMAGE_ID] = { + &fip_dev_handle, + (uintptr_t)&bl32_uuid_spec, + open_fip + }, + [BL32_EXTRA1_IMAGE_ID] = { + &fip_dev_handle, + (uintptr_t)&bl32_extra1_uuid_spec, + open_fip + }, + [BL32_EXTRA2_IMAGE_ID] = { + &fip_dev_handle, + (uintptr_t)&bl32_extra2_uuid_spec, + open_fip + }, + [BL33_IMAGE_ID] = { + &fip_dev_handle, + (uintptr_t)&bl33_uuid_spec, + open_fip + }, + [TB_FW_CONFIG_ID] = { + &fip_dev_handle, + (uintptr_t)&tb_fw_config_uuid_spec, + open_fip + }, + [HW_CONFIG_ID] = { + &fip_dev_handle, + (uintptr_t)&hw_config_uuid_spec, + open_fip + }, + [SOC_FW_CONFIG_ID] = { + &fip_dev_handle, + (uintptr_t)&soc_fw_config_uuid_spec, + open_fip + }, + [TOS_FW_CONFIG_ID] = { + &fip_dev_handle, + (uintptr_t)&tos_fw_config_uuid_spec, + open_fip + }, + [NT_FW_CONFIG_ID] = { + &fip_dev_handle, + (uintptr_t)&nt_fw_config_uuid_spec, + open_fip + }, +#if TRUSTED_BOARD_BOOT + [TRUSTED_BOOT_FW_CERT_ID] = { + &fip_dev_handle, + (uintptr_t)&tb_fw_cert_uuid_spec, + open_fip + }, + [TRUSTED_KEY_CERT_ID] = { + &fip_dev_handle, + (uintptr_t)&trusted_key_cert_uuid_spec, + open_fip + }, + [SCP_FW_KEY_CERT_ID] = { + &fip_dev_handle, + (uintptr_t)&scp_fw_key_cert_uuid_spec, + open_fip + }, + [SOC_FW_KEY_CERT_ID] = { + &fip_dev_handle, + (uintptr_t)&soc_fw_key_cert_uuid_spec, + open_fip + }, + [TRUSTED_OS_FW_KEY_CERT_ID] = { + &fip_dev_handle, + (uintptr_t)&tos_fw_key_cert_uuid_spec, + open_fip + }, + [NON_TRUSTED_FW_KEY_CERT_ID] = { + &fip_dev_handle, + (uintptr_t)&nt_fw_key_cert_uuid_spec, + open_fip + }, + [SCP_FW_CONTENT_CERT_ID] = { + &fip_dev_handle, + (uintptr_t)&scp_fw_cert_uuid_spec, + open_fip + }, + [SOC_FW_CONTENT_CERT_ID] = { + &fip_dev_handle, + (uintptr_t)&soc_fw_cert_uuid_spec, + open_fip + }, + [TRUSTED_OS_FW_CONTENT_CERT_ID] = { + &fip_dev_handle, + (uintptr_t)&tos_fw_cert_uuid_spec, + open_fip + }, + [NON_TRUSTED_FW_CONTENT_CERT_ID] = { + &fip_dev_handle, + (uintptr_t)&nt_fw_cert_uuid_spec, + open_fip + }, +#endif /* TRUSTED_BOARD_BOOT */ +}; + +/* By default, BRCM platforms load images from the FIP */ +static const struct plat_io_policy boot_source_policies[] = { + [BOOT_SOURCE_QSPI] = { + &memmap_dev_handle, + (uintptr_t)&qspi_fip_block_spec, + open_qspi + }, + [BOOT_SOURCE_NAND] = { + &memmap_dev_handle, + (uintptr_t)&nand_fip_block_spec, + open_nand + }, +}; + +/* Weak definitions may be overridden in specific brcm platform */ +#pragma weak plat_brcm_io_setup +#pragma weak plat_brcm_process_flags + +static int open_fip(const uintptr_t spec) +{ + int result; + uintptr_t local_image_handle; + + /* See if a Firmware Image Package is available */ + result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID); + if (result == 0) { + result = io_open(fip_dev_handle, spec, &local_image_handle); + if (result == 0) { + VERBOSE("Using FIP\n"); + io_close(local_image_handle); + } + } + return result; +} + + +static int open_memmap(const uintptr_t spec) +{ + int result; + uintptr_t local_image_handle; + + result = io_dev_init(memmap_dev_handle, (uintptr_t)NULL); + if (result == 0) { + result = io_open(memmap_dev_handle, spec, &local_image_handle); + if (result == 0) { + VERBOSE("Using Memmap\n"); + io_close(local_image_handle); + } + } + return result; +} + +static int open_qspi(const uintptr_t spec) +{ + return open_memmap(spec); +} + +static int open_nand(const uintptr_t spec) +{ + return open_memmap(spec); +} + + +void brcm_io_setup(void) +{ + int io_result; + uint32_t boot_source; + + io_result = register_io_dev_fip(&fip_dev_con); + assert(io_result == 0); + + io_result = register_io_dev_memmap(&memmap_dev_con); + assert(io_result == 0); + + /* Open connections to devices and cache the handles */ + io_result = io_dev_open(fip_dev_con, (uintptr_t)NULL, + &fip_dev_handle); + assert(io_result == 0); + + boot_source = boot_source_get(); + switch (boot_source) { + case BOOT_SOURCE_QSPI: + case BOOT_SOURCE_NAND: + default: + io_result = io_dev_open(memmap_dev_con, (uintptr_t)NULL, + &memmap_dev_handle); + break; + } + assert(io_result == 0); + + /* Ignore improbable errors in release builds */ + (void)io_result; +} + +void plat_brcm_io_setup(void) +{ + brcm_io_setup(); +} + +void plat_brcm_process_flags(uint16_t plat_toc_flags __unused) +{ + WARN("%s not implemented\n", __func__); +} + +/* + * Return an IO device handle and specification which can be used to access + * an image. Use this to enforce platform load policy + */ +int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle, + uintptr_t *image_spec) +{ + int result; + const struct plat_io_policy *policy; + uint32_t boot_source; + uint16_t lcl_plat_toc_flg; + + assert(image_id < ARRAY_SIZE(policies)); + + boot_source = boot_source_get(); + if (image_id == FIP_IMAGE_ID) + policy = &boot_source_policies[boot_source]; + else + policy = &policies[image_id]; + + result = policy->check(policy->image_spec); + if (result == 0) { + *image_spec = policy->image_spec; + *dev_handle = *(policy->dev_handle); + + if (image_id == TRUSTED_BOOT_FW_CERT_ID) { + /* + * Process the header flags to perform + * such custom actions as speeding up PLL. + * CERT seems to be the first image accessed + * by BL1 so this is where we process the flags. + */ + fip_dev_get_plat_toc_flag((io_dev_info_t *)fip_dev_handle, + &lcl_plat_toc_flg); + plat_brcm_process_flags(lcl_plat_toc_flg); + } + } + + return result; +} diff --git a/plat/brcm/common/brcm_mhu.c b/plat/brcm/common/brcm_mhu.c new file mode 100644 index 0000000..56f44e0 --- /dev/null +++ b/plat/brcm/common/brcm_mhu.c @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> + +#include <arch_helpers.h> +#include <drivers/delay_timer.h> +#include <lib/bakery_lock.h> + +#include <brcm_mhu.h> +#include <platform_def.h> + +#include "m0_ipc.h" + +#define PLAT_MHU_INTR_REG AP_TO_SCP_MAILBOX1 + +/* SCP MHU secure channel registers */ +#define SCP_INTR_S_STAT CRMU_IHOST_SW_PERSISTENT_REG11 +#define SCP_INTR_S_SET CRMU_IHOST_SW_PERSISTENT_REG11 +#define SCP_INTR_S_CLEAR CRMU_IHOST_SW_PERSISTENT_REG11 + +/* CPU MHU secure channel registers */ +#define CPU_INTR_S_STAT CRMU_IHOST_SW_PERSISTENT_REG10 +#define CPU_INTR_S_SET CRMU_IHOST_SW_PERSISTENT_REG10 +#define CPU_INTR_S_CLEAR CRMU_IHOST_SW_PERSISTENT_REG10 + +static DEFINE_BAKERY_LOCK(bcm_lock); + +/* + * Slot 31 is reserved because the MHU hardware uses this register bit to + * indicate a non-secure access attempt. The total number of available slots is + * therefore 31 [30:0]. + */ +#define MHU_MAX_SLOT_ID 30 + +void mhu_secure_message_start(unsigned int slot_id) +{ + int iter = 1000000; + + assert(slot_id <= MHU_MAX_SLOT_ID); + + bakery_lock_get(&bcm_lock); + /* Make sure any previous command has finished */ + do { + if (!(mmio_read_32(PLAT_BRCM_MHU_BASE + CPU_INTR_S_STAT) & + (1 << slot_id))) + break; + + udelay(1); + + } while (--iter); + + assert(iter != 0); +} + +void mhu_secure_message_send(unsigned int slot_id) +{ + uint32_t response, iter = 1000000; + + assert(slot_id <= MHU_MAX_SLOT_ID); + assert(!(mmio_read_32(PLAT_BRCM_MHU_BASE + CPU_INTR_S_STAT) & + (1 << slot_id))); + + /* Send command to SCP */ + mmio_setbits_32(PLAT_BRCM_MHU_BASE + CPU_INTR_S_SET, 1 << slot_id); + mmio_write_32(CRMU_MAIL_BOX0, MCU_IPC_MCU_CMD_SCPI); + mmio_write_32(PLAT_BRCM_MHU_BASE + PLAT_MHU_INTR_REG, 0x1); + + /* Wait until IPC transport acknowledges reception of SCP command */ + do { + response = mmio_read_32(CRMU_MAIL_BOX0); + if ((response & ~MCU_IPC_CMD_REPLY_MASK) == + (MCU_IPC_CMD_DONE_MASK | MCU_IPC_MCU_CMD_SCPI)) + break; + + udelay(1); + + } while (--iter); + + assert(iter != 0); +} + +uint32_t mhu_secure_message_wait(void) +{ + /* Wait for response from SCP */ + uint32_t response, iter = 1000000; + + do { + response = mmio_read_32(PLAT_BRCM_MHU_BASE + SCP_INTR_S_STAT); + if (!response) + break; + + udelay(1); + } while (--iter); + assert(iter != 0); + + return response; +} + +void mhu_secure_message_end(unsigned int slot_id) +{ + assert(slot_id <= MHU_MAX_SLOT_ID); + + /* + * Clear any response we got by writing one in the relevant slot bit to + * the CLEAR register + */ + mmio_clrbits_32(PLAT_BRCM_MHU_BASE + SCP_INTR_S_CLEAR, 1 << slot_id); + bakery_lock_release(&bcm_lock); +} + +void mhu_secure_init(void) +{ + bakery_lock_init(&bcm_lock); + + /* + * The STAT register resets to zero. Ensure it is in the expected state, + * as a stale or garbage value would make us think it's a message we've + * already sent. + */ + mmio_write_32(PLAT_BRCM_MHU_BASE + CPU_INTR_S_STAT, 0); + mmio_write_32(PLAT_BRCM_MHU_BASE + SCP_INTR_S_STAT, 0); +} + +void plat_brcm_pwrc_setup(void) +{ + mhu_secure_init(); +} diff --git a/plat/brcm/common/brcm_mhu.h b/plat/brcm/common/brcm_mhu.h new file mode 100644 index 0000000..6c89a34 --- /dev/null +++ b/plat/brcm/common/brcm_mhu.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef BRCM_MHU_H +#define BRCM_MHU_H + +#include <stdint.h> + +void mhu_secure_message_start(unsigned int slot_id); +void mhu_secure_message_send(unsigned int slot_id); +uint32_t mhu_secure_message_wait(void); +void mhu_secure_message_end(unsigned int slot_id); + +void mhu_secure_init(void); + +#endif /* BRCM_MHU_H */ diff --git a/plat/brcm/common/brcm_scpi.c b/plat/brcm/common/brcm_scpi.c new file mode 100644 index 0000000..0a703cb --- /dev/null +++ b/plat/brcm/common/brcm_scpi.c @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <assert.h> +#include <string.h> + +#include <arch_helpers.h> +#include <common/debug.h> +#include <lib/utils.h> +#include <plat/common/platform.h> + +#include <brcm_mhu.h> +#include <brcm_scpi.h> +#include <platform_def.h> + +#define SCPI_SHARED_MEM_SCP_TO_AP (PLAT_SCP_COM_SHARED_MEM_BASE) +#define SCPI_SHARED_MEM_AP_TO_SCP (PLAT_SCP_COM_SHARED_MEM_BASE \ + + 0x100) + +/* Header and payload addresses for commands from AP to SCP */ +#define SCPI_CMD_HEADER_AP_TO_SCP \ + ((scpi_cmd_t *) SCPI_SHARED_MEM_AP_TO_SCP) +#define SCPI_CMD_PAYLOAD_AP_TO_SCP \ + ((void *) (SCPI_SHARED_MEM_AP_TO_SCP + sizeof(scpi_cmd_t))) + +/* Header and payload addresses for responses from SCP to AP */ +#define SCPI_RES_HEADER_SCP_TO_AP \ + ((scpi_cmd_t *) SCPI_SHARED_MEM_SCP_TO_AP) +#define SCPI_RES_PAYLOAD_SCP_TO_AP \ + ((void *) (SCPI_SHARED_MEM_SCP_TO_AP + sizeof(scpi_cmd_t))) + +/* ID of the MHU slot used for the SCPI protocol */ +#define SCPI_MHU_SLOT_ID 0 + +static void scpi_secure_message_start(void) +{ + mhu_secure_message_start(SCPI_MHU_SLOT_ID); +} + +static void scpi_secure_message_send(size_t payload_size) +{ + /* + * Ensure that any write to the SCPI payload area is seen by SCP before + * we write to the MHU register. If these 2 writes were reordered by + * the CPU then SCP would read stale payload data + */ + dmbst(); + + mhu_secure_message_send(SCPI_MHU_SLOT_ID); +} + +static void scpi_secure_message_receive(scpi_cmd_t *cmd) +{ + uint32_t mhu_status; + + assert(cmd != NULL); + + mhu_status = mhu_secure_message_wait(); + + /* Expect an SCPI message, reject any other protocol */ + if (mhu_status != (1 << SCPI_MHU_SLOT_ID)) { + ERROR("MHU: Unexpected protocol (MHU status: 0x%x)\n", + mhu_status); + panic(); + } + + /* + * Ensure that any read to the SCPI payload area is done after reading + * the MHU register. If these 2 reads were reordered then the CPU would + * read invalid payload data + */ + dmbld(); + + memcpy(cmd, (void *) SCPI_SHARED_MEM_SCP_TO_AP, sizeof(*cmd)); +} + +static void scpi_secure_message_end(void) +{ + mhu_secure_message_end(SCPI_MHU_SLOT_ID); +} + +int scpi_wait_ready(void) +{ + scpi_cmd_t scpi_cmd; + + VERBOSE("Waiting for SCP_READY command...\n"); + + /* Get a message from the SCP */ + scpi_secure_message_start(); + scpi_secure_message_receive(&scpi_cmd); + scpi_secure_message_end(); + + /* We are expecting 'SCP Ready', produce correct error if it's not */ + scpi_status_t status = SCP_OK; + + if (scpi_cmd.id != SCPI_CMD_SCP_READY) { + ERROR("Unexpected SCP command: expected #%u, received #%u\n", + SCPI_CMD_SCP_READY, scpi_cmd.id); + status = SCP_E_SUPPORT; + } else if (scpi_cmd.size != 0) { + ERROR("SCP_READY cmd has incorrect size: expected 0, got %u\n", + scpi_cmd.size); + status = SCP_E_SIZE; + } + + VERBOSE("Sending response for SCP_READY command\n"); + + /* + * Send our response back to SCP. + * We are using the same SCPI header, just update the status field. + */ + scpi_cmd.status = status; + scpi_secure_message_start(); + memcpy((void *) SCPI_SHARED_MEM_AP_TO_SCP, &scpi_cmd, sizeof(scpi_cmd)); + scpi_secure_message_send(0); + scpi_secure_message_end(); + + return status == SCP_OK ? 0 : -1; +} + +void scpi_set_brcm_power_state(unsigned int mpidr, + scpi_power_state_t cpu_state, scpi_power_state_t cluster_state, + scpi_power_state_t brcm_state) +{ + scpi_cmd_t *cmd; + uint32_t state = 0; + uint32_t *payload_addr; + +#if ARM_PLAT_MT + /* + * The current SCPI driver only caters for single-threaded platforms. + * Hence we ignore the thread ID (which is always 0) for such platforms. + */ + state |= (mpidr >> MPIDR_AFF1_SHIFT) & 0x0f; /* CPU ID */ + state |= ((mpidr >> MPIDR_AFF2_SHIFT) & 0x0f) << 4; /* Cluster ID */ +#else + state |= mpidr & 0x0f; /* CPU ID */ + state |= (mpidr & 0xf00) >> 4; /* Cluster ID */ +#endif /* ARM_PLAT_MT */ + + state |= cpu_state << 8; + state |= cluster_state << 12; + state |= brcm_state << 16; + + scpi_secure_message_start(); + + /* Populate the command header */ + cmd = SCPI_CMD_HEADER_AP_TO_SCP; + cmd->id = SCPI_CMD_SET_POWER_STATE; + cmd->set = SCPI_SET_NORMAL; + cmd->sender = 0; + cmd->size = sizeof(state); + /* Populate the command payload */ + payload_addr = SCPI_CMD_PAYLOAD_AP_TO_SCP; + *payload_addr = state; + scpi_secure_message_send(sizeof(state)); + + /* + * SCP does not reply to this command in order to avoid MHU interrupts + * from the sender, which could interfere with its power state request. + */ + scpi_secure_message_end(); +} + +/* + * Query and obtain power state from SCP. + * + * In response to the query, SCP returns power states of all CPUs in all + * clusters of the system. The returned response is then filtered based on the + * supplied MPIDR. Power states of requested cluster and CPUs within are updated + * via. supplied non-NULL pointer arguments. + * + * Returns 0 on success, or -1 on errors. + */ +int scpi_get_brcm_power_state(unsigned int mpidr, unsigned int *cpu_state_p, + unsigned int *cluster_state_p) +{ + scpi_cmd_t *cmd; + scpi_cmd_t response; + int power_state, cpu, cluster, rc = -1; + + /* + * Extract CPU and cluster membership of the given MPIDR. SCPI caters + * for only up to 0xf clusters, and 8 CPUs per cluster + */ + cpu = mpidr & MPIDR_AFFLVL_MASK; + cluster = (mpidr >> MPIDR_AFF1_SHIFT) & MPIDR_AFFLVL_MASK; + if (cpu >= 8 || cluster >= 0xf) + return -1; + + scpi_secure_message_start(); + + /* Populate request headers */ + zeromem(SCPI_CMD_HEADER_AP_TO_SCP, sizeof(*cmd)); + cmd = SCPI_CMD_HEADER_AP_TO_SCP; + cmd->id = SCPI_CMD_GET_POWER_STATE; + + /* + * Send message and wait for SCP's response + */ + scpi_secure_message_send(0); + scpi_secure_message_receive(&response); + + if (response.status != SCP_OK) + goto exit; + + /* Validate SCP response */ + if (!CHECK_RESPONSE(response, cluster)) + goto exit; + + /* Extract power states for required cluster */ + power_state = *(((uint16_t *) SCPI_RES_PAYLOAD_SCP_TO_AP) + cluster); + if (CLUSTER_ID(power_state) != cluster) + goto exit; + + /* Update power state via. pointers */ + if (cluster_state_p) + *cluster_state_p = CLUSTER_POWER_STATE(power_state); + if (cpu_state_p) + *cpu_state_p = CPU_POWER_STATE(power_state); + rc = 0; + +exit: + scpi_secure_message_end(); + return rc; +} + +uint32_t scpi_sys_power_state(scpi_system_state_t system_state) +{ + scpi_cmd_t *cmd; + uint8_t *payload_addr; + + scpi_secure_message_start(); + + /* Populate the command header */ + cmd = SCPI_CMD_HEADER_AP_TO_SCP; + cmd->id = SCPI_CMD_SYS_POWER_STATE; + cmd->set = 0; + cmd->sender = 0; + cmd->size = sizeof(*payload_addr); + /* Populate the command payload */ + payload_addr = SCPI_CMD_PAYLOAD_AP_TO_SCP; + *payload_addr = system_state & 0xff; + scpi_secure_message_send(sizeof(*payload_addr)); + + scpi_secure_message_end(); + + return SCP_OK; +} diff --git a/plat/brcm/common/brcm_scpi.h b/plat/brcm/common/brcm_scpi.h new file mode 100644 index 0000000..f3b658f --- /dev/null +++ b/plat/brcm/common/brcm_scpi.h @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2019-2020, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef BRCM_SCPI_H +#define BRCM_SCPI_H + +#include <stddef.h> +#include <stdint.h> + +/* + * An SCPI command consists of a header and a payload. + * The following structure describes the header. It is 64-bit long. + */ +typedef struct { + /* Command ID */ + uint32_t id : 7; + /* Set ID. Identifies whether this is a standard or extended command. */ + uint32_t set : 1; + /* Sender ID to match a reply. The value is sender specific. */ + uint32_t sender : 8; + /* Size of the payload in bytes (0 - 511) */ + uint32_t size : 9; + uint32_t reserved : 7; + /* + * Status indicating the success of a command. + * See the enum below. + */ + uint32_t status; +} scpi_cmd_t; + +typedef enum { + SCPI_SET_NORMAL = 0, /* Normal SCPI commands */ + SCPI_SET_EXTENDED /* Extended SCPI commands */ +} scpi_set_t; + +enum { + SCP_OK = 0, /* Success */ + SCP_E_PARAM, /* Invalid parameter(s) */ + SCP_E_ALIGN, /* Invalid alignment */ + SCP_E_SIZE, /* Invalid size */ + SCP_E_HANDLER, /* Invalid handler or callback */ + SCP_E_ACCESS, /* Invalid access or permission denied */ + SCP_E_RANGE, /* Value out of range */ + SCP_E_TIMEOUT, /* Time out has ocurred */ + SCP_E_NOMEM, /* Invalid memory area or pointer */ + SCP_E_PWRSTATE, /* Invalid power state */ + SCP_E_SUPPORT, /* Feature not supported or disabled */ + SCPI_E_DEVICE, /* Device error */ + SCPI_E_BUSY, /* Device is busy */ +}; + +typedef uint32_t scpi_status_t; +typedef enum { + SCPI_CMD_SCP_READY = 0x01, + SCPI_CMD_SET_POWER_STATE = 0x03, + SCPI_CMD_GET_POWER_STATE = 0x04, + SCPI_CMD_SYS_POWER_STATE = 0x05 +} scpi_command_t; + +/* + * Macros to parse SCP response to GET_POWER_STATE command + * + * [3:0] : cluster ID + * [7:4] : cluster state: 0 = on; 3 = off; rest are reserved + * [15:8]: on/off state for individual CPUs in the cluster + * + * Payload is in little-endian + */ +#define CLUSTER_ID(_resp) ((_resp) & 0xf) +#define CLUSTER_POWER_STATE(_resp) (((_resp) >> 4) & 0xf) + +/* Result is a bit mask of CPU on/off states in the cluster */ +#define CPU_POWER_STATE(_resp) (((_resp) >> 8) & 0xff) + +/* + * For GET_POWER_STATE, SCP returns the power states of every cluster. The + * size of response depends on the number of clusters in the system. The + * SCP-to-AP payload contains 2 bytes per cluster. Make sure the response is + * large enough to contain power states of a given cluster + */ +#define CHECK_RESPONSE(_resp, _clus) (_resp.size >= (((_clus) + 1) * 2)) + +typedef enum { + scpi_power_on = 0, + scpi_power_retention = 1, + scpi_power_off = 3, +} scpi_power_state_t; + +typedef enum { + scpi_system_shutdown = 0, + scpi_system_reboot = 1, + scpi_system_reset = 2 +} scpi_system_state_t; + +extern int scpi_wait_ready(void); +extern void scpi_set_brcm_power_state(unsigned int mpidr, + scpi_power_state_t cpu_state, + scpi_power_state_t cluster_state, + scpi_power_state_t css_state); +int scpi_get_brcm_power_state(unsigned int mpidr, unsigned int *cpu_state_p, + unsigned int *cluster_state_p); +uint32_t scpi_sys_power_state(scpi_system_state_t system_state); + +#endif /* BRCM_SCPI_H */ |