GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)

This commit is contained in:
lai
2026-09-06 03:52:57 +08:00
commit b1928b41c0
21813 changed files with 4413081 additions and 0 deletions
@@ -0,0 +1,428 @@
/*
* Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
#include <assert_macros.S>
#include <cortex_a57.h>
#include <cpu_macros.S>
#include <platform_def.h>
#include <tegra_def.h>
#include <tegra_platform.h>
#define MIDR_PN_CORTEX_A57 0xD07
/*******************************************************************************
* Implementation defined ACTLR_EL3 bit definitions
******************************************************************************/
#define ACTLR_ELx_L2ACTLR_BIT (U(1) << 6)
#define ACTLR_ELx_L2ECTLR_BIT (U(1) << 5)
#define ACTLR_ELx_L2CTLR_BIT (U(1) << 4)
#define ACTLR_ELx_CPUECTLR_BIT (U(1) << 1)
#define ACTLR_ELx_CPUACTLR_BIT (U(1) << 0)
#define ACTLR_ELx_ENABLE_ALL_ACCESS (ACTLR_ELx_L2ACTLR_BIT | \
ACTLR_ELx_L2ECTLR_BIT | \
ACTLR_ELx_L2CTLR_BIT | \
ACTLR_ELx_CPUECTLR_BIT | \
ACTLR_ELx_CPUACTLR_BIT)
/* Global functions */
.globl plat_is_my_cpu_primary
.globl plat_my_core_pos
.globl plat_get_my_entrypoint
.globl plat_secondary_cold_boot_setup
.globl platform_mem_init
.globl plat_crash_console_init
.globl plat_crash_console_putc
.globl plat_crash_console_flush
.weak plat_core_pos_by_mpidr
.globl tegra_secure_entrypoint
.globl plat_reset_handler
/* Global variables */
.globl tegra_sec_entry_point
.globl ns_image_entrypoint
.globl tegra_bl31_phys_base
.globl tegra_console_base
/* ---------------------
* Common CPU init code
* ---------------------
*/
.macro cpu_init_common
/* ------------------------------------------------
* We enable procesor retention, L2/CPUECTLR NS
* access and ECC/Parity protection for A57 CPUs
* ------------------------------------------------
*/
mrs x0, midr_el1
mov x1, #(MIDR_PN_MASK << MIDR_PN_SHIFT)
and x0, x0, x1
lsr x0, x0, #MIDR_PN_SHIFT
cmp x0, #MIDR_PN_CORTEX_A57
b.ne 1f
/* ---------------------------
* Enable processor retention
* ---------------------------
*/
mrs x0, CORTEX_A57_L2ECTLR_EL1
mov x1, #RETENTION_ENTRY_TICKS_512
bic x0, x0, #CORTEX_A57_L2ECTLR_RET_CTRL_MASK
orr x0, x0, x1
msr CORTEX_A57_L2ECTLR_EL1, x0
isb
mrs x0, CORTEX_A57_ECTLR_EL1
mov x1, #RETENTION_ENTRY_TICKS_512
bic x0, x0, #CORTEX_A57_ECTLR_CPU_RET_CTRL_MASK
orr x0, x0, x1
msr CORTEX_A57_ECTLR_EL1, x0
isb
/* -------------------------------------------------------
* Enable L2 and CPU ECTLR RW access from non-secure world
* -------------------------------------------------------
*/
mrs x0, actlr_el3
mov x1, #ACTLR_ELx_ENABLE_ALL_ACCESS
orr x0, x0, x1
msr actlr_el3, x0
mrs x0, actlr_el2
mov x1, #ACTLR_ELx_ENABLE_ALL_ACCESS
orr x0, x0, x1
msr actlr_el2, x0
isb
/* --------------------------------
* Enable the cycle count register
* --------------------------------
*/
1: mrs x0, pmcr_el0
ubfx x0, x0, #11, #5 // read PMCR.N field
mov x1, #1
lsl x0, x1, x0
sub x0, x0, #1 // mask of event counters
orr x0, x0, #0x80000000 // disable overflow intrs
msr pmintenclr_el1, x0
msr pmuserenr_el0, x1 // enable user mode access
/* ----------------------------------------------------------------
* Allow non-privileged access to CNTVCT: Set CNTKCTL (Kernel Count
* register), bit 1 (EL0VCTEN) to enable access to CNTVCT/CNTFRQ
* registers from EL0.
* ----------------------------------------------------------------
*/
mrs x0, cntkctl_el1
orr x0, x0, #EL0VCTEN_BIT
msr cntkctl_el1, x0
.endm
/* -----------------------------------------------------
* unsigned int plat_is_my_cpu_primary(void);
*
* This function checks if this is the Primary CPU
* -----------------------------------------------------
*/
func plat_is_my_cpu_primary
mrs x0, mpidr_el1
and x0, x0, #(MPIDR_CLUSTER_MASK | MPIDR_CPU_MASK)
cmp x0, #TEGRA_PRIMARY_CPU
cset x0, eq
ret
endfunc plat_is_my_cpu_primary
/* ----------------------------------------------------------
* unsigned int plat_my_core_pos(void);
*
* result: CorePos = CoreId + (ClusterId * cpus per cluster)
* Registers clobbered: x0, x8
* ----------------------------------------------------------
*/
func plat_my_core_pos
mov x8, x30
mrs x0, mpidr_el1
bl plat_core_pos_by_mpidr
ret x8
endfunc plat_my_core_pos
/* -----------------------------------------------------
* unsigned long plat_get_my_entrypoint (void);
*
* Main job of this routine is to distinguish between
* a cold and warm boot. If the tegra_sec_entry_point for
* this CPU is present, then it's a warm boot.
*
* -----------------------------------------------------
*/
func plat_get_my_entrypoint
adr x1, tegra_sec_entry_point
ldr x0, [x1]
ret
endfunc plat_get_my_entrypoint
/* -----------------------------------------------------
* void plat_secondary_cold_boot_setup (void);
*
* This function performs any platform specific actions
* needed for a secondary cpu after a cold reset. Right
* now this is a stub function.
* -----------------------------------------------------
*/
func plat_secondary_cold_boot_setup
mov x0, #0
ret
endfunc plat_secondary_cold_boot_setup
/* --------------------------------------------------------
* void platform_mem_init (void);
*
* Any memory init, relocation to be done before the
* platform boots. Called very early in the boot process.
* --------------------------------------------------------
*/
func platform_mem_init
mov x0, #0
ret
endfunc platform_mem_init
/* ---------------------------------------------------
* Function to handle a platform reset and store
* input parameters passed by BL2.
* ---------------------------------------------------
*/
func plat_reset_handler
/* ----------------------------------------------------
* Verify if we are running from BL31_BASE address
* ----------------------------------------------------
*/
adr x18, bl31_entrypoint
mov x17, #BL31_BASE
cmp x18, x17
b.eq 1f
/* ----------------------------------------------------
* Copy the entire BL31 code to BL31_BASE if we are not
* running from it already
* ----------------------------------------------------
*/
mov x0, x17
mov x1, x18
adr x2, __RELA_END__
sub x2, x2, x18
_loop16:
cmp x2, #16
b.lo _loop1
ldp x3, x4, [x1], #16
stp x3, x4, [x0], #16
sub x2, x2, #16
b _loop16
/* copy byte per byte */
_loop1:
cbz x2, _end
ldrb w3, [x1], #1
strb w3, [x0], #1
subs x2, x2, #1
b.ne _loop1
/* ----------------------------------------------------
* Jump to BL31_BASE and start execution again
* ----------------------------------------------------
*/
_end: mov x0, x20
mov x1, x21
br x17
1:
/* -----------------------------------
* derive and save the phys_base addr
* -----------------------------------
*/
adr x17, tegra_bl31_phys_base
ldr x18, [x17]
cbnz x18, 1f
adr x18, bl31_entrypoint
str x18, [x17]
1: cpu_init_common
ret
endfunc plat_reset_handler
/* ------------------------------------------------------
* int32_t plat_core_pos_by_mpidr(u_register_t mpidr)
*
* This function implements a part of the critical
* interface between the psci generic layer and the
* platform that allows the former to query the platform
* to convert an MPIDR to a unique linear index. An error
* code (-1) is returned in case the MPIDR is invalid.
*
* Clobbers: x0-x3
* ------------------------------------------------------
*/
func plat_core_pos_by_mpidr
lsr x1, x0, #MPIDR_AFF0_SHIFT
and x1, x1, #MPIDR_AFFLVL_MASK /* core id */
lsr x2, x0, #MPIDR_AFF1_SHIFT
and x2, x2, #MPIDR_AFFLVL_MASK /* cluster id */
/* core_id >= PLATFORM_MAX_CPUS_PER_CLUSTER */
mov x0, #-1
cmp x1, #(PLATFORM_MAX_CPUS_PER_CLUSTER - 1)
b.gt 1f
/* cluster_id >= PLATFORM_CLUSTER_COUNT */
cmp x2, #(PLATFORM_CLUSTER_COUNT - 1)
b.gt 1f
/* CorePos = CoreId + (ClusterId * cpus per cluster) */
mov x3, #PLATFORM_MAX_CPUS_PER_CLUSTER
mul x3, x3, x2
add x0, x1, x3
1:
ret
endfunc plat_core_pos_by_mpidr
/* ----------------------------------------
* Secure entrypoint function for CPU boot
* ----------------------------------------
*/
func tegra_secure_entrypoint _align=6
#if ERRATA_TEGRA_INVALIDATE_BTB_AT_BOOT
/* --------------------------------------------------------
* Skip the invalidate BTB workaround for Tegra210B01 SKUs.
* --------------------------------------------------------
*/
mov x0, #TEGRA_MISC_BASE
add x0, x0, #HARDWARE_REVISION_OFFSET
ldr w1, [x0]
lsr w1, w1, #CHIP_ID_SHIFT
and w1, w1, #CHIP_ID_MASK
cmp w1, #TEGRA_CHIPID_TEGRA21 /* T210? */
b.ne 2f
ldr w1, [x0]
lsr w1, w1, #MAJOR_VERSION_SHIFT
and w1, w1, #MAJOR_VERSION_MASK
cmp w1, #0x02 /* T210 B01? */
b.eq 2f
/* -------------------------------------------------------
* Invalidate BTB along with I$ to remove any stale
* entries from the branch predictor array.
* -------------------------------------------------------
*/
mrs x0, CORTEX_A57_CPUACTLR_EL1
orr x0, x0, #1
msr CORTEX_A57_CPUACTLR_EL1, x0 /* invalidate BTB and I$ together */
dsb sy
isb
ic iallu /* actual invalidate */
dsb sy
isb
mrs x0, CORTEX_A57_CPUACTLR_EL1
bic x0, x0, #1
msr CORTEX_A57_CPUACTLR_EL1, X0 /* restore original CPUACTLR_EL1 */
dsb sy
isb
.rept 7
nop /* wait */
.endr
/* -----------------------------------------------
* Extract OSLK bit and check if it is '1'. This
* bit remains '0' for A53 on warm-resets. If '1',
* turn off regional clock gating and request warm
* reset.
* -----------------------------------------------
*/
mrs x0, oslsr_el1
and x0, x0, #2
mrs x1, mpidr_el1
bics xzr, x0, x1, lsr #7 /* 0 = slow cluster or warm reset */
b.eq restore_oslock
mov x0, xzr
msr oslar_el1, x0 /* os lock stays 0 across warm reset */
mov x3, #3
movz x4, #0x8000, lsl #48
msr CORTEX_A57_CPUACTLR_EL1, x4 /* turn off RCG */
isb
msr rmr_el3, x3 /* request warm reset */
isb
dsb sy
1: wfi
b 1b
/* --------------------------------------------------
* These nops are here so that speculative execution
* won't harm us before we are done with warm reset.
* --------------------------------------------------
*/
.rept 65
nop
.endr
2:
/* --------------------------------------------------
* Do not insert instructions here
* --------------------------------------------------
*/
#endif
/* --------------------------------------------------
* Restore OS Lock bit
* --------------------------------------------------
*/
restore_oslock:
mov x0, #1
msr oslar_el1, x0
/* --------------------------------------------------
* Get secure world's entry point and jump to it
* --------------------------------------------------
*/
bl plat_get_my_entrypoint
br x0
endfunc tegra_secure_entrypoint
.data
.align 3
/* --------------------------------------------------
* CPU Secure entry point - resume from suspend
* --------------------------------------------------
*/
tegra_sec_entry_point:
.quad 0
/* --------------------------------------------------
* NS world's cold boot entry point
* --------------------------------------------------
*/
ns_image_entrypoint:
.quad 0
/* --------------------------------------------------
* BL31's physical base address
* --------------------------------------------------
*/
tegra_bl31_phys_base:
.quad 0
/* --------------------------------------------------
* UART controller base for console init
* --------------------------------------------------
*/
tegra_console_base:
.quad 0
@@ -0,0 +1,366 @@
/*
* Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <errno.h>
#include <inttypes.h>
#include <stddef.h>
#include <string.h>
#include <platform_def.h>
#include <arch.h>
#include <arch_helpers.h>
#include <bl31/bl31.h>
#include <common/bl_common.h>
#include <common/debug.h>
#include <cortex_a57.h>
#include <denver.h>
#include <drivers/console.h>
#include <lib/mmio.h>
#include <lib/utils.h>
#include <lib/utils_def.h>
#include <plat/common/platform.h>
#include <memctrl.h>
#include <profiler.h>
#include <smmu.h>
#include <tegra_def.h>
#include <tegra_platform.h>
#include <tegra_private.h>
/* length of Trusty's input parameters (in bytes) */
#define TRUSTY_PARAMS_LEN_BYTES (4096*2)
/*******************************************************************************
* Declarations of linker defined symbols which will help us find the layout
* of trusted SRAM
******************************************************************************/
IMPORT_SYM(uint64_t, __RW_START__, BL31_RW_START);
extern uint64_t tegra_bl31_phys_base;
static entry_point_info_t bl33_image_ep_info, bl32_image_ep_info;
static plat_params_from_bl2_t plat_bl31_params_from_bl2 = {
.tzdram_size = TZDRAM_SIZE
};
#ifdef SPD_trusty
static aapcs64_params_t bl32_args;
#endif
/*******************************************************************************
* This variable holds the non-secure image entry address
******************************************************************************/
extern uint64_t ns_image_entrypoint;
/*******************************************************************************
* Return a pointer to the 'entry_point_info' structure of the next image for
* security state specified. BL33 corresponds to the non-secure image type
* while BL32 corresponds to the secure image type.
******************************************************************************/
entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type)
{
entry_point_info_t *ep = NULL;
/* return BL32 entry point info if it is valid */
if (type == NON_SECURE) {
ep = &bl33_image_ep_info;
} else if ((type == SECURE) && (bl32_image_ep_info.pc != 0U)) {
ep = &bl32_image_ep_info;
}
return ep;
}
/*******************************************************************************
* Return a pointer to the 'plat_params_from_bl2_t' structure. The BL2 image
* passes this platform specific information.
******************************************************************************/
plat_params_from_bl2_t *bl31_get_plat_params(void)
{
return &plat_bl31_params_from_bl2;
}
/*******************************************************************************
* Perform any BL31 specific platform actions. Populate the BL33 and BL32 image
* info.
******************************************************************************/
void bl31_early_platform_setup2(u_register_t arg0, u_register_t arg1,
u_register_t arg2, u_register_t arg3)
{
struct tegra_bl31_params *arg_from_bl2 = (struct tegra_bl31_params *) arg0;
plat_params_from_bl2_t *plat_params = (plat_params_from_bl2_t *)arg1;
int32_t ret;
/*
* For RESET_TO_BL31 systems, BL31 is the first bootloader to run so
* there's no argument to relay from a previous bootloader. Platforms
* might use custom ways to get arguments.
*/
if (arg_from_bl2 == NULL) {
arg_from_bl2 = plat_get_bl31_params();
}
if (plat_params == NULL) {
plat_params = plat_get_bl31_plat_params();
}
/*
* Copy BL3-3, BL3-2 entry point information.
* They are stored in Secure RAM, in BL2's address space.
*/
assert(arg_from_bl2 != NULL);
assert(arg_from_bl2->bl33_ep_info != NULL);
bl33_image_ep_info = *arg_from_bl2->bl33_ep_info;
if (arg_from_bl2->bl32_ep_info != NULL) {
bl32_image_ep_info = *arg_from_bl2->bl32_ep_info;
#ifdef SPD_trusty
/* save BL32 boot parameters */
memcpy(&bl32_args, &arg_from_bl2->bl32_ep_info->args, sizeof(bl32_args));
#endif
}
/*
* Parse platform specific parameters
*/
assert(plat_params != NULL);
plat_bl31_params_from_bl2.tzdram_base = plat_params->tzdram_base;
plat_bl31_params_from_bl2.tzdram_size = plat_params->tzdram_size;
plat_bl31_params_from_bl2.uart_id = plat_params->uart_id;
plat_bl31_params_from_bl2.l2_ecc_parity_prot_dis = plat_params->l2_ecc_parity_prot_dis;
plat_bl31_params_from_bl2.sc7entry_fw_size = plat_params->sc7entry_fw_size;
plat_bl31_params_from_bl2.sc7entry_fw_base = plat_params->sc7entry_fw_base;
/*
* It is very important that we run either from TZDRAM or TZSRAM base.
* Add an explicit check here.
*/
if ((plat_bl31_params_from_bl2.tzdram_base != (uint64_t)BL31_BASE) &&
(TEGRA_TZRAM_BASE != BL31_BASE)) {
panic();
}
/*
* Enable console for the platform
*/
plat_enable_console(plat_params->uart_id);
/*
* The previous bootloader passes the base address of the shared memory
* location to store the boot profiler logs. Sanity check the
* address and initialise the profiler library, if it looks ok.
*/
ret = bl31_check_ns_address(plat_params->boot_profiler_shmem_base,
PROFILER_SIZE_BYTES);
if (ret == (int32_t)0) {
/* store the membase for the profiler lib */
plat_bl31_params_from_bl2.boot_profiler_shmem_base =
plat_params->boot_profiler_shmem_base;
/* initialise the profiler library */
boot_profiler_init(plat_params->boot_profiler_shmem_base,
TEGRA_TMRUS_BASE);
}
/*
* Add timestamp for platform early setup entry.
*/
boot_profiler_add_record("[TF] early setup entry");
/*
* Initialize delay timer
*/
tegra_delay_timer_init();
/* Early platform setup for Tegra SoCs */
plat_early_platform_setup();
/*
* Add timestamp for platform early setup exit.
*/
boot_profiler_add_record("[TF] early setup exit");
INFO("BL3-1: Boot CPU: %s Processor [%lx]\n",
(((read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK)
== DENVER_IMPL) ? "Denver" : "ARM", read_mpidr());
}
#ifdef SPD_trusty
void plat_trusty_set_boot_args(aapcs64_params_t *args)
{
/*
* arg0 = TZDRAM aperture available for BL32
* arg1 = BL32 boot params
* arg2 = EKS Blob Length
* arg3 = Boot Profiler Carveout Base
*/
args->arg0 = bl32_args.arg0;
args->arg1 = bl32_args.arg2;
/* update EKS size */
args->arg2 = bl32_args.arg4;
/* Profiler Carveout Base */
args->arg3 = bl32_args.arg5;
}
#endif
/*******************************************************************************
* Initialize the gic, configure the SCR.
******************************************************************************/
void bl31_platform_setup(void)
{
/*
* Add timestamp for platform setup entry.
*/
boot_profiler_add_record("[TF] plat setup entry");
/* Initialize the gic cpu and distributor interfaces */
plat_gic_setup();
/*
* Setup secondary CPU POR infrastructure.
*/
plat_secondary_setup();
/*
* Initial Memory Controller configuration.
*/
tegra_memctrl_setup();
/*
* Late setup handler to allow platforms to performs additional
* functionality.
* This handler gets called with MMU enabled.
*/
plat_late_platform_setup();
/*
* Add timestamp for platform setup exit.
*/
boot_profiler_add_record("[TF] plat setup exit");
INFO("BL3-1: Tegra platform setup complete\n");
}
/*******************************************************************************
* Perform any BL3-1 platform runtime setup prior to BL3-1 cold boot exit
******************************************************************************/
void bl31_plat_runtime_setup(void)
{
/*
* Platform specific runtime setup
*/
plat_runtime_setup();
/*
* Add final timestamp before exiting BL31.
*/
boot_profiler_add_record("[TF] bl31 exit");
boot_profiler_deinit();
}
/*******************************************************************************
* Perform the very early platform specific architectural setup here. At the
* moment this only intializes the mmu in a quick and dirty way.
******************************************************************************/
void bl31_plat_arch_setup(void)
{
uint64_t rw_start = BL31_RW_START;
uint64_t rw_size = BL_END - BL31_RW_START;
uint64_t rodata_start = BL_RO_DATA_BASE;
uint64_t rodata_size = BL_RO_DATA_END - BL_RO_DATA_BASE;
uint64_t code_base = BL_CODE_BASE;
uint64_t code_size = BL_CODE_END - BL_CODE_BASE;
const mmap_region_t *plat_mmio_map = NULL;
const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
/*
* Add timestamp for arch setup entry.
*/
boot_profiler_add_record("[TF] arch setup entry");
/* add MMIO space */
plat_mmio_map = plat_get_mmio_map();
if (plat_mmio_map != NULL) {
mmap_add(plat_mmio_map);
} else {
WARN("MMIO map not available\n");
}
/* add memory regions */
mmap_add_region(rw_start, rw_start,
rw_size,
MT_MEMORY | MT_RW | MT_SECURE);
mmap_add_region(rodata_start, rodata_start,
rodata_size,
MT_RO_DATA | MT_SECURE);
mmap_add_region(code_base, code_base,
code_size,
MT_CODE | MT_SECURE);
/* map TZDRAM used by BL31 as coherent memory */
if (TEGRA_TZRAM_BASE == tegra_bl31_phys_base) {
mmap_add_region(params_from_bl2->tzdram_base,
params_from_bl2->tzdram_base,
BL31_SIZE,
MT_DEVICE | MT_RW | MT_SECURE);
}
/* set up translation tables */
init_xlat_tables();
/* enable the MMU */
enable_mmu_el3(0);
/*
* Add timestamp for arch setup exit.
*/
boot_profiler_add_record("[TF] arch setup exit");
INFO("BL3-1: Tegra: MMU enabled\n");
}
/*******************************************************************************
* Check if the given NS DRAM range is valid
******************************************************************************/
int32_t bl31_check_ns_address(uint64_t base, uint64_t size_in_bytes)
{
uint64_t end = base + size_in_bytes - U(1);
/*
* Sanity check the input values
*/
if ((base == 0U) || (size_in_bytes == 0U)) {
ERROR("NS address 0x%" PRIx64 " (%" PRId64 " bytes) is invalid\n",
base, size_in_bytes);
return -EINVAL;
}
/*
* Check if the NS DRAM address is valid
*/
if ((base < TEGRA_DRAM_BASE) || (base >= TEGRA_DRAM_END) ||
(end > TEGRA_DRAM_END)) {
ERROR("NS address 0x%" PRIx64 " is out-of-bounds!\n", base);
return -EFAULT;
}
/*
* TZDRAM aperture contains the BL31 and BL32 images, so we need
* to check if the NS DRAM range overlaps the TZDRAM aperture.
*/
if ((base < (uint64_t)TZDRAM_END) && (end > tegra_bl31_phys_base)) {
ERROR("NS address 0x%" PRIx64 " overlaps TZDRAM!\n", base);
return -ENOTSUP;
}
/* valid NS address */
return 0;
}
@@ -0,0 +1,59 @@
#
# Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
# Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
PLAT_INCLUDES := -Iplat/nvidia/tegra/include/drivers \
-Iplat/nvidia/tegra/include/lib \
-Iplat/nvidia/tegra/include
include lib/xlat_tables_v2/xlat_tables.mk
PLAT_BL_COMMON_SOURCES += ${XLAT_TABLES_LIB_SRCS}
TEGRA_COMMON := plat/nvidia/tegra/common
TEGRA_DRIVERS := plat/nvidia/tegra/drivers
TEGRA_LIBS := plat/nvidia/tegra/lib
# Include GICv3 driver files
include drivers/arm/gic/v3/gicv3.mk
TEGRA_GICv3_SOURCES := $(GICV3_SOURCES) \
plat/common/plat_gicv3.c \
${TEGRA_COMMON}/tegra_gicv3.c
# Include GICv2 driver files
include drivers/arm/gic/v2/gicv2.mk
TEGRA_GICv2_SOURCES := ${GICV2_SOURCES} \
plat/common/plat_gicv2.c \
${TEGRA_COMMON}/tegra_gicv2.c
TEGRA_GICv3_SOURCES := drivers/arm/gic/common/gic_common.c \
drivers/arm/gic/v3/arm_gicv3_common.c \
drivers/arm/gic/v3/gicv3_main.c \
drivers/arm/gic/v3/gicv3_helpers.c \
plat/common/plat_gicv3.c \
${TEGRA_COMMON}/tegra_gicv3.c
BL31_SOURCES += drivers/delay_timer/delay_timer.c \
drivers/io/io_storage.c \
plat/common/aarch64/crash_console_helpers.S \
${TEGRA_LIBS}/debug/profiler.c \
${TEGRA_COMMON}/aarch64/tegra_helpers.S \
${TEGRA_LIBS}/debug/profiler.c \
${TEGRA_COMMON}/tegra_bl31_setup.c \
${TEGRA_COMMON}/tegra_delay_timer.c \
${TEGRA_COMMON}/tegra_fiq_glue.c \
${TEGRA_COMMON}/tegra_io_storage.c \
${TEGRA_COMMON}/tegra_platform.c \
${TEGRA_COMMON}/tegra_pm.c \
${TEGRA_COMMON}/tegra_sip_calls.c \
${TEGRA_COMMON}/tegra_sdei.c
ifneq ($(ENABLE_STACK_PROTECTOR), 0)
BL31_SOURCES += ${TEGRA_COMMON}/tegra_stack_protector.c
endif
ifeq (${EL3_EXCEPTION_HANDLING},1)
BL31_SOURCES += plat/common/aarch64/plat_ehf.c
endif
@@ -0,0 +1,57 @@
/*
* Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <drivers/delay_timer.h>
#include <lib/mmio.h>
#include <lib/utils_def.h>
#include <plat/common/platform.h>
#include <tegra_def.h>
#include <tegra_private.h>
static uint32_t tegra_timer_get_value(void)
{
/* enable cntps_tval_el1 timer, mask interrupt */
write_cntps_ctl_el1(CNTP_CTL_IMASK_BIT | CNTP_CTL_ENABLE_BIT);
/*
* Generic delay timer implementation expects the timer to be a down
* counter. The value is clipped from 64 to 32 bits.
*/
return (uint32_t)(read_cntps_tval_el1());
}
/*
* Initialise the architecture provided counter as the delay timer.
*/
void tegra_delay_timer_init(void)
{
static timer_ops_t tegra_timer_ops;
/* Value in ticks */
uint32_t multiplier = MHZ_TICKS_PER_SEC;
/* Value in ticks per second (Hz) */
uint32_t divider = plat_get_syscnt_freq2();
/* Reduce multiplier and divider by dividing them repeatedly by 10 */
while (((multiplier % 10U) == 0U) && ((divider % 10U) == 0U)) {
multiplier /= 10U;
divider /= 10U;
}
/* enable cntps_tval_el1 timer, mask interrupt */
write_cntps_ctl_el1(CNTP_CTL_IMASK_BIT | CNTP_CTL_ENABLE_BIT);
/* register the timer */
tegra_timer_ops.get_timer_value = tegra_timer_get_value;
tegra_timer_ops.clk_mult = multiplier;
tegra_timer_ops.clk_div = divider;
timer_init(&tegra_timer_ops);
}
@@ -0,0 +1,149 @@
/*
* Copyright (c) 2016-2020, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <arch_helpers.h>
#include <bl31/interrupt_mgmt.h>
#include <bl31/ehf.h>
#include <common/bl_common.h>
#include <common/debug.h>
#include <context.h>
#include <denver.h>
#include <lib/el3_runtime/context_mgmt.h>
#include <plat/common/platform.h>
#if ENABLE_WDT_LEGACY_FIQ_HANDLING
#include <flowctrl.h>
#endif
#include <tegra_def.h>
#include <tegra_private.h>
/* Legacy FIQ used by earlier Tegra platforms */
#define LEGACY_FIQ_PPI_WDT 28U
/*******************************************************************************
* Static variables
******************************************************************************/
static uint64_t ns_fiq_handler_addr;
static uint32_t fiq_handler_active;
static pcpu_fiq_state_t fiq_state[PLATFORM_CORE_COUNT];
/*******************************************************************************
* Handler for FIQ interrupts
******************************************************************************/
static int tegra_fiq_interrupt_handler(unsigned int id, unsigned int flags,
void *handle, void *cookie)
{
cpu_context_t *ctx = cm_get_context(NON_SECURE);
el3_state_t *el3state_ctx = get_el3state_ctx(ctx);
uint32_t cpu = plat_my_core_pos();
(void)flags;
(void)handle;
(void)cookie;
/*
* Jump to NS world only if the NS world's FIQ handler has
* been registered
*/
if (ns_fiq_handler_addr != 0U) {
/*
* The FIQ was generated when the execution was in the non-secure
* world. Save the context registers to start with.
*/
cm_el1_sysregs_context_save(NON_SECURE);
/*
* Save elr_el3 and spsr_el3 from the saved context, and overwrite
* the context with the NS fiq_handler_addr and SPSR value.
*/
fiq_state[cpu].elr_el3 = read_ctx_reg((el3state_ctx), (uint32_t)(CTX_ELR_EL3));
fiq_state[cpu].spsr_el3 = read_ctx_reg((el3state_ctx), (uint32_t)(CTX_SPSR_EL3));
/*
* Set the new ELR to continue execution in the NS world using the
* FIQ handler registered earlier.
*/
cm_set_elr_el3(NON_SECURE, ns_fiq_handler_addr);
}
#if ENABLE_WDT_LEGACY_FIQ_HANDLING
/*
* Tegra platforms that use LEGACY_FIQ as the watchdog timer FIQ
* need to issue an IPI to other CPUs, to allow them to handle
* the "system hung" scenario. This interrupt is passed to the GICD
* via the Flow Controller. So, once we receive this interrupt,
* disable the routing so that we can mark it as "complete" in the
* GIC later.
*/
if (id == LEGACY_FIQ_PPI_WDT) {
tegra_fc_disable_fiq_to_ccplex_routing();
}
#endif
/*
* Mark this interrupt as complete to avoid a FIQ storm.
*/
plat_ic_end_of_interrupt(id);
return 0;
}
/*******************************************************************************
* Setup handler for FIQ interrupts
******************************************************************************/
void tegra_fiq_handler_setup(void)
{
/* return if already registered */
if (fiq_handler_active == 0U) {
/*
* Register an interrupt handler for FIQ interrupts generated for
* NS interrupt sources
*/
ehf_register_priority_handler(PLAT_TEGRA_WDT_PRIO, tegra_fiq_interrupt_handler);
/* handler is now active */
fiq_handler_active = 1;
}
}
/*******************************************************************************
* Validate and store NS world's entrypoint for FIQ interrupts
******************************************************************************/
void tegra_fiq_set_ns_entrypoint(uint64_t entrypoint)
{
ns_fiq_handler_addr = entrypoint;
}
/*******************************************************************************
* Handler to return the NS EL1/EL0 CPU context
******************************************************************************/
int32_t tegra_fiq_get_intr_context(void)
{
cpu_context_t *ctx = cm_get_context(NON_SECURE);
gp_regs_t *gpregs_ctx = get_gpregs_ctx(ctx);
const el1_sysregs_t *el1state_ctx = get_el1_sysregs_ctx(ctx);
uint32_t cpu = plat_my_core_pos();
uint64_t val;
/*
* We store the ELR_EL3, SPSR_EL3, SP_EL0 and SP_EL1 registers so
* that el3_exit() sends these values back to the NS world.
*/
write_ctx_reg((gpregs_ctx), (uint32_t)(CTX_GPREG_X0), (fiq_state[cpu].elr_el3));
write_ctx_reg((gpregs_ctx), (uint32_t)(CTX_GPREG_X1), (fiq_state[cpu].spsr_el3));
val = read_ctx_reg((gpregs_ctx), (uint32_t)(CTX_GPREG_SP_EL0));
write_ctx_reg((gpregs_ctx), (uint32_t)(CTX_GPREG_X2), (val));
val = read_ctx_reg((el1state_ctx), (uint32_t)(CTX_SP_EL1));
write_ctx_reg((gpregs_ctx), (uint32_t)(CTX_GPREG_X3), (val));
return 0;
}
@@ -0,0 +1,72 @@
/*
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <platform_def.h>
#include <common/bl_common.h>
#include <drivers/arm/gicv2.h>
#include <lib/utils.h>
#include <plat/common/platform.h>
#include <tegra_private.h>
#include <tegra_def.h>
static unsigned int tegra_target_masks[PLATFORM_CORE_COUNT];
/******************************************************************************
* Tegra common helper to setup the GICv2 driver data.
*****************************************************************************/
void tegra_gic_setup(const interrupt_prop_t *interrupt_props,
unsigned int interrupt_props_num)
{
/*
* Tegra GIC configuration settings
*/
static gicv2_driver_data_t tegra_gic_data;
/*
* Register Tegra GICv2 driver
*/
tegra_gic_data.gicd_base = TEGRA_GICD_BASE;
tegra_gic_data.gicc_base = TEGRA_GICC_BASE;
tegra_gic_data.interrupt_props = interrupt_props;
tegra_gic_data.interrupt_props_num = interrupt_props_num;
tegra_gic_data.target_masks = tegra_target_masks;
tegra_gic_data.target_masks_num = ARRAY_SIZE(tegra_target_masks);
gicv2_driver_init(&tegra_gic_data);
}
/******************************************************************************
* Tegra common helper to initialize the GICv2 only driver.
*****************************************************************************/
void tegra_gic_init(void)
{
gicv2_distif_init();
gicv2_pcpu_distif_init();
gicv2_set_pe_target_mask(plat_my_core_pos());
gicv2_cpuif_enable();
}
/******************************************************************************
* Tegra common helper to disable the GICv2 CPU interface
*****************************************************************************/
void tegra_gic_cpuif_deactivate(void)
{
gicv2_cpuif_disable();
}
/******************************************************************************
* Tegra common helper to initialize the per cpu distributor interface
* in GICv2
*****************************************************************************/
void tegra_gic_pcpu_init(void)
{
gicv2_pcpu_distif_init();
gicv2_set_pe_target_mask(plat_my_core_pos());
gicv2_cpuif_enable();
}
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <common/bl_common.h>
#include <drivers/arm/gicv3.h>
#include <lib/utils.h>
#include <plat/common/platform.h>
#include <platform_def.h>
#include <tegra_private.h>
#include <tegra_def.h>
/* The GICv3 driver only needs to be initialized in EL3 */
static uintptr_t rdistif_base_addrs[PLATFORM_CORE_COUNT];
static unsigned int plat_tegra_mpidr_to_core_pos(unsigned long mpidr)
{
return (unsigned int)plat_core_pos_by_mpidr(mpidr);
}
/******************************************************************************
* Tegra common helper to setup the GICv3 driver data.
*****************************************************************************/
void tegra_gic_setup(const interrupt_prop_t *interrupt_props,
unsigned int interrupt_props_num)
{
/*
* Tegra GIC configuration settings
*/
static gicv3_driver_data_t tegra_gic_data;
/*
* Register Tegra GICv3 driver
*/
tegra_gic_data.gicd_base = TEGRA_GICD_BASE;
tegra_gic_data.gicr_base = TEGRA_GICR_BASE;
tegra_gic_data.rdistif_num = PLATFORM_CORE_COUNT;
tegra_gic_data.rdistif_base_addrs = rdistif_base_addrs;
tegra_gic_data.mpidr_to_core_pos = plat_tegra_mpidr_to_core_pos;
tegra_gic_data.interrupt_props = interrupt_props;
tegra_gic_data.interrupt_props_num = interrupt_props_num;
gicv3_driver_init(&tegra_gic_data);
/* initialize the GICD and GICR */
tegra_gic_init();
}
/******************************************************************************
* Tegra common helper to initialize the GICv3 only driver.
*****************************************************************************/
void tegra_gic_init(void)
{
gicv3_distif_init();
gicv3_rdistif_init(plat_my_core_pos());
gicv3_cpuif_enable(plat_my_core_pos());
}
/******************************************************************************
* Tegra common helper to disable the GICv3 CPU interface
*****************************************************************************/
void tegra_gic_cpuif_deactivate(void)
{
gicv3_cpuif_disable(plat_my_core_pos());
}
/******************************************************************************
* Tegra common helper to initialize the per cpu distributor interface
* in GICv3
*****************************************************************************/
void tegra_gic_pcpu_init(void)
{
gicv3_rdistif_init(plat_my_core_pos());
gicv3_cpuif_enable(plat_my_core_pos());
}
@@ -0,0 +1,20 @@
/*
* Copyright (c) 2019, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <errno.h>
#include <plat/common/platform.h>
/*
* Return an IO device handle and specification which can be used to access
* an image. Use this to enforce platform load policy.
*
* This function is not supported at this time
*/
int plat_get_image_source(unsigned int image_id, uintptr_t *dev_handle,
uintptr_t *image_spec)
{
return -ENOTSUP;
}
@@ -0,0 +1,309 @@
/*
* Copyright (c) 2016-2021, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2020-2021, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <assert.h>
#include <lib/mmio.h>
#include <lib/smccc.h>
#include <services/arm_arch_svc.h>
#include <tegra_def.h>
#include <tegra_platform.h>
#include <tegra_private.h>
/*******************************************************************************
* Tegra platforms
******************************************************************************/
typedef enum tegra_platform {
TEGRA_PLATFORM_SILICON = 0U,
TEGRA_PLATFORM_QT,
TEGRA_PLATFORM_FPGA,
TEGRA_PLATFORM_EMULATION,
TEGRA_PLATFORM_LINSIM,
TEGRA_PLATFORM_UNIT_FPGA,
TEGRA_PLATFORM_VIRT_DEV_KIT,
TEGRA_PLATFORM_MAX,
} tegra_platform_t;
/*******************************************************************************
* Tegra macros defining all the SoC minor versions
******************************************************************************/
#define TEGRA_MINOR_QT U(0)
#define TEGRA_MINOR_FPGA U(1)
#define TEGRA_MINOR_ASIM_QT U(2)
#define TEGRA_MINOR_ASIM_LINSIM U(3)
#define TEGRA_MINOR_DSIM_ASIM_LINSIM U(4)
#define TEGRA_MINOR_UNIT_FPGA U(5)
#define TEGRA_MINOR_VIRT_DEV_KIT U(6)
/*******************************************************************************
* Tegra macros defining all the SoC pre_si_platform
******************************************************************************/
#define TEGRA_PRE_SI_QT U(1)
#define TEGRA_PRE_SI_FPGA U(2)
#define TEGRA_PRE_SI_UNIT_FPGA U(3)
#define TEGRA_PRE_SI_ASIM_QT U(4)
#define TEGRA_PRE_SI_ASIM_LINSIM U(5)
#define TEGRA_PRE_SI_DSIM_ASIM_LINSIM U(6)
#define TEGRA_PRE_SI_VDK U(8)
/*
* Read the chip ID value
*/
static uint32_t tegra_get_chipid(void)
{
return mmio_read_32(TEGRA_MISC_BASE + HARDWARE_REVISION_OFFSET);
}
/*
* Read the chip's major version from chip ID value
*/
uint32_t tegra_get_chipid_major(void)
{
return (tegra_get_chipid() >> MAJOR_VERSION_SHIFT) & MAJOR_VERSION_MASK;
}
/*
* Read the chip's minor version from the chip ID value
*/
uint32_t tegra_get_chipid_minor(void)
{
return (tegra_get_chipid() >> MINOR_VERSION_SHIFT) & MINOR_VERSION_MASK;
}
/*
* Read the chip's pre_si_platform valus from the chip ID value
*/
static uint32_t tegra_get_chipid_pre_si_platform(void)
{
return (tegra_get_chipid() >> PRE_SI_PLATFORM_SHIFT) & PRE_SI_PLATFORM_MASK;
}
bool tegra_chipid_is_t186(void)
{
uint32_t chip_id = (tegra_get_chipid() >> CHIP_ID_SHIFT) & CHIP_ID_MASK;
return (chip_id == TEGRA_CHIPID_TEGRA18);
}
bool tegra_chipid_is_t210(void)
{
uint32_t chip_id = (tegra_get_chipid() >> CHIP_ID_SHIFT) & CHIP_ID_MASK;
return (chip_id == TEGRA_CHIPID_TEGRA21);
}
bool tegra_chipid_is_t210_b01(void)
{
return (tegra_chipid_is_t210() && (tegra_get_chipid_major() == 0x2U));
}
bool tegra_chipid_is_t194(void)
{
uint32_t chip_id = (tegra_get_chipid() >> CHIP_ID_SHIFT) & CHIP_ID_MASK;
return (chip_id == TEGRA_CHIPID_TEGRA19);
}
/*
* Read the chip ID value and derive the platform
*/
static tegra_platform_t tegra_get_platform(void)
{
uint32_t major, minor, pre_si_platform;
tegra_platform_t ret;
/* get the major/minor chip ID values */
major = tegra_get_chipid_major();
minor = tegra_get_chipid_minor();
pre_si_platform = tegra_get_chipid_pre_si_platform();
if (major == 0U) {
/*
* The minor version number is used by simulation platforms
*/
switch (minor) {
/*
* Cadence's QuickTurn emulation system is a Solaris-based
* chip emulation system
*/
case TEGRA_MINOR_QT:
case TEGRA_MINOR_ASIM_QT:
ret = TEGRA_PLATFORM_QT;
break;
/*
* FPGAs are used during early software/hardware development
*/
case TEGRA_MINOR_FPGA:
ret = TEGRA_PLATFORM_FPGA;
break;
/*
* Linsim is a reconfigurable, clock-driven, mixed RTL/cmodel
* simulation framework.
*/
case TEGRA_MINOR_ASIM_LINSIM:
case TEGRA_MINOR_DSIM_ASIM_LINSIM:
ret = TEGRA_PLATFORM_LINSIM;
break;
/*
* Unit FPGAs run the actual hardware block IP on the FPGA with
* the other parts of the system using Linsim.
*/
case TEGRA_MINOR_UNIT_FPGA:
ret = TEGRA_PLATFORM_UNIT_FPGA;
break;
/*
* The Virtualizer Development Kit (VDK) is the standard chip
* development from Synopsis.
*/
case TEGRA_MINOR_VIRT_DEV_KIT:
ret = TEGRA_PLATFORM_VIRT_DEV_KIT;
break;
default:
ret = TEGRA_PLATFORM_MAX;
break;
}
} else if (pre_si_platform > 0U) {
switch (pre_si_platform) {
/*
* Cadence's QuickTurn emulation system is a Solaris-based
* chip emulation system
*/
case TEGRA_PRE_SI_QT:
case TEGRA_PRE_SI_ASIM_QT:
ret = TEGRA_PLATFORM_QT;
break;
/*
* FPGAs are used during early software/hardware development
*/
case TEGRA_PRE_SI_FPGA:
ret = TEGRA_PLATFORM_FPGA;
break;
/*
* Linsim is a reconfigurable, clock-driven, mixed RTL/cmodel
* simulation framework.
*/
case TEGRA_PRE_SI_ASIM_LINSIM:
case TEGRA_PRE_SI_DSIM_ASIM_LINSIM:
ret = TEGRA_PLATFORM_LINSIM;
break;
/*
* Unit FPGAs run the actual hardware block IP on the FPGA with
* the other parts of the system using Linsim.
*/
case TEGRA_PRE_SI_UNIT_FPGA:
ret = TEGRA_PLATFORM_UNIT_FPGA;
break;
/*
* The Virtualizer Development Kit (VDK) is the standard chip
* development from Synopsis.
*/
case TEGRA_PRE_SI_VDK:
ret = TEGRA_PLATFORM_VIRT_DEV_KIT;
break;
default:
ret = TEGRA_PLATFORM_MAX;
break;
}
} else {
/* Actual silicon platforms have a non-zero major version */
ret = TEGRA_PLATFORM_SILICON;
}
return ret;
}
bool tegra_platform_is_silicon(void)
{
return ((tegra_get_platform() == TEGRA_PLATFORM_SILICON) ? true : false);
}
bool tegra_platform_is_qt(void)
{
return ((tegra_get_platform() == TEGRA_PLATFORM_QT) ? true : false);
}
bool tegra_platform_is_linsim(void)
{
tegra_platform_t plat = tegra_get_platform();
return (((plat == TEGRA_PLATFORM_LINSIM) ||
(plat == TEGRA_PLATFORM_UNIT_FPGA)) ? true : false);
}
bool tegra_platform_is_fpga(void)
{
return ((tegra_get_platform() == TEGRA_PLATFORM_FPGA) ? true : false);
}
bool tegra_platform_is_emulation(void)
{
return (tegra_get_platform() == TEGRA_PLATFORM_EMULATION);
}
bool tegra_platform_is_unit_fpga(void)
{
return ((tegra_get_platform() == TEGRA_PLATFORM_UNIT_FPGA) ? true : false);
}
bool tegra_platform_is_virt_dev_kit(void)
{
return ((tegra_get_platform() == TEGRA_PLATFORM_VIRT_DEV_KIT) ? true : false);
}
/*
* This function returns soc version which mainly consist of below fields
*
* soc_version[30:24] = JEP-106 continuation code for the SiP
* soc_version[23:16] = JEP-106 identification code with parity bit for the SiP
* soc_version[0:15] = chip identification
*/
int32_t plat_get_soc_version(void)
{
uint32_t chip_id = ((tegra_get_chipid() >> CHIP_ID_SHIFT) & CHIP_ID_MASK);
uint32_t manfid = SOC_ID_SET_JEP_106(JEDEC_NVIDIA_BKID, JEDEC_NVIDIA_MFID);
return (int32_t)(manfid | (chip_id & SOC_ID_IMPL_DEF_MASK));
}
/*
* This function returns soc revision in below format
*
* soc_revision[8:15] = major version number
* soc_revision[0:7] = minor version number
*/
int32_t plat_get_soc_revision(void)
{
return (int32_t)(((tegra_get_chipid_major() << 8) | tegra_get_chipid_minor()) &
SOC_ID_REV_MASK);
}
/*****************************************************************************
* plat_is_smccc_feature_available() - This function checks whether SMCCC feature
* is availabile for the platform or not.
* @fid: SMCCC function id
*
* Return SMC_ARCH_CALL_SUCCESS if SMCCC feature is available and
* SMC_ARCH_CALL_NOT_SUPPORTED otherwise.
*****************************************************************************/
int32_t plat_is_smccc_feature_available(u_register_t fid)
{
switch (fid) {
case SMCCC_ARCH_SOC_ID:
return SMC_ARCH_CALL_SUCCESS;
default:
return SMC_ARCH_CALL_NOT_SUPPORTED;
}
}
@@ -0,0 +1,329 @@
/*
* Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <platform_def.h>
#include <arch_helpers.h>
#include <common/bl_common.h>
#include <common/debug.h>
#include <context.h>
#include <drivers/console.h>
#include <lib/el3_runtime/context_mgmt.h>
#include <lib/mmio.h>
#include <lib/psci/psci.h>
#include <plat/common/platform.h>
#include <memctrl.h>
#include <pmc.h>
#include <tegra_def.h>
#include <tegra_platform.h>
#include <tegra_private.h>
extern uint64_t tegra_bl31_phys_base;
extern uint64_t tegra_sec_entry_point;
/*******************************************************************************
* This handler is called by the PSCI implementation during the `SYSTEM_SUSPEND`
* call to get the `power_state` parameter. This allows the platform to encode
* the appropriate State-ID field within the `power_state` parameter which can
* be utilized in `pwr_domain_suspend()` to suspend to system affinity level.
******************************************************************************/
static void tegra_get_sys_suspend_power_state(psci_power_state_t *req_state)
{
/* all affinities use system suspend state id */
for (uint32_t i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++) {
req_state->pwr_domain_state[i] = PSTATE_ID_SOC_POWERDN;
}
}
/*******************************************************************************
* Handler called when an affinity instance is about to enter standby.
******************************************************************************/
static void tegra_cpu_standby(plat_local_state_t cpu_state)
{
u_register_t saved_scr_el3;
(void)cpu_state;
/* Tegra SoC specific handler */
if (tegra_soc_cpu_standby(cpu_state) != PSCI_E_SUCCESS)
ERROR("%s failed\n", __func__);
saved_scr_el3 = read_scr_el3();
/*
* As per ARM ARM D1.17.2, any physical IRQ interrupt received by the
* PE will be treated as a wake-up event, if SCR_EL3.IRQ is set to '1',
* irrespective of the value of the PSTATE.I bit value.
*/
write_scr_el3(saved_scr_el3 | SCR_IRQ_BIT);
/*
* Enter standby state
*
* dsb & isb is good practice before using wfi to enter low power states
*/
dsb();
isb();
wfi();
/*
* Restore saved scr_el3 that has IRQ bit cleared as we don't want EL3
* handling any further interrupts
*/
write_scr_el3(saved_scr_el3);
}
/*******************************************************************************
* Handler called when an affinity instance is about to be turned on. The
* level and mpidr determine the affinity instance.
******************************************************************************/
static int32_t tegra_pwr_domain_on(u_register_t mpidr)
{
return tegra_soc_pwr_domain_on(mpidr);
}
/*******************************************************************************
* Handler called when a power domain is about to be turned off. The
* target_state encodes the power state that each level should transition to.
******************************************************************************/
static void tegra_pwr_domain_off(const psci_power_state_t *target_state)
{
(void)tegra_soc_pwr_domain_off(target_state);
/* disable GICC */
tegra_gic_cpuif_deactivate();
}
/*******************************************************************************
* Handler called when a power domain is about to be suspended. The
* target_state encodes the power state that each level should transition to.
* This handler is called with SMP and data cache enabled, when
* HW_ASSISTED_COHERENCY = 0
******************************************************************************/
void tegra_pwr_domain_suspend_pwrdown_early(const psci_power_state_t *target_state)
{
tegra_soc_pwr_domain_suspend_pwrdown_early(target_state);
}
/*******************************************************************************
* Handler called when a power domain is about to be suspended. The
* target_state encodes the power state that each level should transition to.
******************************************************************************/
static void tegra_pwr_domain_suspend(const psci_power_state_t *target_state)
{
(void)tegra_soc_pwr_domain_suspend(target_state);
/* disable GICC */
tegra_gic_cpuif_deactivate();
}
/*******************************************************************************
* Handler called at the end of the power domain suspend sequence. The
* target_state encodes the power state that each level should transition to.
******************************************************************************/
static __dead2 void tegra_pwr_domain_power_down_wfi(const psci_power_state_t
*target_state)
{
/* call the chip's power down handler */
(void)tegra_soc_pwr_domain_power_down_wfi(target_state);
/* Disable console if we are entering deep sleep. */
if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] ==
PSTATE_ID_SOC_POWERDN) {
INFO("%s: complete. Entering System Suspend...\n", __func__);
console_flush();
console_switch_state(0);
}
wfi();
panic();
}
/*******************************************************************************
* 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 tegra_pwr_domain_on_finish(const psci_power_state_t *target_state)
{
const plat_params_from_bl2_t *plat_params;
/*
* Check if we are exiting from deep sleep.
*/
if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] ==
PSTATE_ID_SOC_POWERDN) {
/*
* On entering System Suspend state, the GIC loses power
* completely. Initialize the GIC global distributor and
* GIC cpu interfaces.
*/
tegra_gic_init();
/* Restart console output. */
console_switch_state(CONSOLE_FLAG_RUNTIME);
/*
* Restore Memory Controller settings as it loses state
* during system suspend.
*/
tegra_memctrl_restore_settings();
/*
* Security configuration to allow DRAM/device access.
*/
plat_params = bl31_get_plat_params();
tegra_memctrl_tzdram_setup(plat_params->tzdram_base,
(uint32_t)plat_params->tzdram_size);
} else {
/*
* Initialize the GIC cpu and distributor interfaces
*/
tegra_gic_pcpu_init();
}
/*
* Reset hardware settings.
*/
(void)tegra_soc_pwr_domain_on_finish(target_state);
}
/*******************************************************************************
* Handler called when a power domain has just been powered on after
* having been suspended earlier. The target_state encodes the low power state
* that each level has woken up from.
******************************************************************************/
static void tegra_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
{
tegra_pwr_domain_on_finish(target_state);
}
/*******************************************************************************
* Handler called when the system wants to be powered off
******************************************************************************/
static __dead2 void tegra_system_off(void)
{
INFO("Powering down system...\n");
tegra_soc_prepare_system_off();
}
/*******************************************************************************
* Handler called when the system wants to be restarted.
******************************************************************************/
static __dead2 void tegra_system_reset(void)
{
INFO("Restarting system...\n");
/* per-SoC system reset handler */
(void)tegra_soc_prepare_system_reset();
/* wait for the system to reset */
for (;;) {
;
}
}
/*******************************************************************************
* Handler called to check the validity of the power state parameter.
******************************************************************************/
static int32_t tegra_validate_power_state(uint32_t power_state,
psci_power_state_t *req_state)
{
assert(req_state != NULL);
return tegra_soc_validate_power_state(power_state, req_state);
}
/*******************************************************************************
* Platform handler called to check the validity of the non secure entrypoint.
******************************************************************************/
static int32_t tegra_validate_ns_entrypoint(uintptr_t entrypoint)
{
int32_t ret = PSCI_E_INVALID_ADDRESS;
/*
* Check if the non secure entrypoint lies within the non
* secure DRAM.
*/
if ((entrypoint >= TEGRA_DRAM_BASE) && (entrypoint <= TEGRA_DRAM_END)) {
ret = PSCI_E_SUCCESS;
}
return ret;
}
/*******************************************************************************
* Export the platform handlers to enable psci to invoke them
******************************************************************************/
static plat_psci_ops_t tegra_plat_psci_ops = {
.cpu_standby = tegra_cpu_standby,
.pwr_domain_on = tegra_pwr_domain_on,
.pwr_domain_off = tegra_pwr_domain_off,
.pwr_domain_suspend_pwrdown_early = tegra_pwr_domain_suspend_pwrdown_early,
.pwr_domain_suspend = tegra_pwr_domain_suspend,
.pwr_domain_on_finish = tegra_pwr_domain_on_finish,
.pwr_domain_suspend_finish = tegra_pwr_domain_suspend_finish,
.pwr_domain_pwr_down_wfi = tegra_pwr_domain_power_down_wfi,
.system_off = tegra_system_off,
.system_reset = tegra_system_reset,
.validate_power_state = tegra_validate_power_state,
.validate_ns_entrypoint = tegra_validate_ns_entrypoint,
.get_sys_suspend_power_state = tegra_get_sys_suspend_power_state,
};
/*******************************************************************************
* Export the platform specific power ops and initialize Power Controller
******************************************************************************/
int plat_setup_psci_ops(uintptr_t sec_entrypoint,
const plat_psci_ops_t **psci_ops)
{
psci_power_state_t target_state = { { PSCI_LOCAL_STATE_RUN } };
/*
* Flush entrypoint variable to PoC since it will be
* accessed after a reset with the caches turned off.
*/
tegra_sec_entry_point = sec_entrypoint;
flush_dcache_range((uint64_t)&tegra_sec_entry_point, sizeof(uint64_t));
/*
* Reset hardware settings.
*/
(void)tegra_soc_pwr_domain_on_finish(&target_state);
/*
* Disable System Suspend if the platform does not
* support it
*/
if (!plat_supports_system_suspend()) {
tegra_plat_psci_ops.get_sys_suspend_power_state = NULL;
}
/*
* Initialize PSCI ops struct
*/
*psci_ops = &tegra_plat_psci_ops;
return 0;
}
/*******************************************************************************
* Platform handler to calculate the proper target power level at the
* specified affinity level
******************************************************************************/
plat_local_state_t plat_get_target_pwr_state(unsigned int lvl,
const plat_local_state_t *states,
unsigned int ncpu)
{
return tegra_soc_get_target_pwr_state(lvl, states, ncpu);
}
@@ -0,0 +1,56 @@
/*
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/* SDEI configuration for Tegra platforms */
#include <platform_def.h>
#include <bl31/ehf.h>
#include <common/bl_common.h>
#include <common/debug.h>
#include <lib/utils_def.h>
#include <services/sdei.h>
/* Private event mappings */
static sdei_ev_map_t tegra_sdei_private[] = {
/* Event 0 definition */
SDEI_DEFINE_EVENT_0(TEGRA_SDEI_SGI_PRIVATE),
/* Dynamic private events */
SDEI_PRIVATE_EVENT(TEGRA_SDEI_DP_EVENT_0, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC),
SDEI_PRIVATE_EVENT(TEGRA_SDEI_DP_EVENT_1, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC),
SDEI_PRIVATE_EVENT(TEGRA_SDEI_DP_EVENT_2, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC),
/* General purpose explicit events */
SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_0, SDEI_MAPF_CRITICAL),
SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_1, SDEI_MAPF_CRITICAL),
SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_2, SDEI_MAPF_CRITICAL),
SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_3, SDEI_MAPF_CRITICAL),
SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_4, SDEI_MAPF_CRITICAL),
SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_5, SDEI_MAPF_CRITICAL),
SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_6, SDEI_MAPF_CRITICAL),
SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_7, SDEI_MAPF_CRITICAL),
SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_8, SDEI_MAPF_CRITICAL),
SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_9, SDEI_MAPF_CRITICAL),
SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_10, SDEI_MAPF_CRITICAL),
SDEI_EXPLICIT_EVENT(TEGRA_SDEI_EP_EVENT_11, SDEI_MAPF_CRITICAL)
};
/* Shared event mappings */
static sdei_ev_map_t tegra_sdei_shared[] = {
/* Dynamic shared events */
SDEI_SHARED_EVENT(TEGRA_SDEI_DS_EVENT_0, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC),
SDEI_SHARED_EVENT(TEGRA_SDEI_DS_EVENT_1, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC),
SDEI_SHARED_EVENT(TEGRA_SDEI_DS_EVENT_2, SDEI_DYN_IRQ, SDEI_MAPF_DYNAMIC)
};
void plat_sdei_setup(void)
{
INFO("SDEI platform setup\n");
}
/* Export Tegra SDEI events */
REGISTER_SDEI_MAP(tegra_sdei_private, tegra_sdei_shared);
@@ -0,0 +1,158 @@
/*
* Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <errno.h>
#include <arch.h>
#include <arch_helpers.h>
#include <common/bl_common.h>
#include <common/debug.h>
#include <common/runtime_svc.h>
#include <lib/mmio.h>
#include <memctrl.h>
#include <tegra_platform.h>
#include <tegra_private.h>
/*******************************************************************************
* Common Tegra SiP SMCs
******************************************************************************/
#define TEGRA_SIP_NEW_VIDEOMEM_REGION 0x82000003
#define TEGRA_SIP_FIQ_NS_ENTRYPOINT 0x82000005
#define TEGRA_SIP_FIQ_NS_GET_CONTEXT 0x82000006
/*******************************************************************************
* This function is responsible for handling all SiP calls
******************************************************************************/
uintptr_t tegra_sip_handler(uint32_t smc_fid,
u_register_t x1,
u_register_t x2,
u_register_t x3,
u_register_t x4,
void *cookie,
void *handle,
u_register_t flags)
{
uint32_t regval, local_x2_32 = (uint32_t)x2;
int32_t err;
/* Check if this is a SoC specific SiP */
err = plat_sip_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags);
if (err == 0) {
SMC_RET1(handle, (uint64_t)err);
} else {
switch (smc_fid) {
case TEGRA_SIP_NEW_VIDEOMEM_REGION:
/* Check whether Video memory resize is enabled */
if (mmio_read_32(TEGRA_MC_BASE + MC_VIDEO_PROTECT_REG_CTRL)
!= MC_VIDEO_PROTECT_WRITE_ACCESS_ENABLED) {
ERROR("Video Memory Resize isn't enabled! \n");
SMC_RET1(handle, (uint64_t)-ENOTSUP);
}
/*
* Check if Video Memory overlaps TZDRAM (contains bl31/bl32)
* or falls outside of the valid DRAM range
*/
err = bl31_check_ns_address(x1, local_x2_32);
if (err != 0) {
SMC_RET1(handle, (uint64_t)err);
}
/*
* Check if Video Memory is aligned to 1MB.
*/
if (((x1 & 0xFFFFFU) != 0U) || ((local_x2_32 & 0xFFFFFU) != 0U)) {
ERROR("Unaligned Video Memory base address!\n");
SMC_RET1(handle, (uint64_t)-ENOTSUP);
}
/*
* The GPU is the user of the Video Memory region. In order to
* transition to the new memory region smoothly, we program the
* new base/size ONLY if the GPU is in reset mode.
*/
regval = mmio_read_32(TEGRA_CAR_RESET_BASE +
TEGRA_GPU_RESET_REG_OFFSET);
if ((regval & GPU_RESET_BIT) == 0U) {
ERROR("GPU not in reset! Video Memory setup failed\n");
SMC_RET1(handle, (uint64_t)-ENOTSUP);
}
/* new video memory carveout settings */
tegra_memctrl_videomem_setup(x1, local_x2_32);
/*
* Ensure again that GPU is still in reset after VPR resize
*/
regval = mmio_read_32(TEGRA_CAR_RESET_BASE +
TEGRA_GPU_RESET_REG_OFFSET);
if ((regval & GPU_RESET_BIT) == 0U) {
mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_GPU_RESET_GPU_SET_OFFSET,
GPU_SET_BIT);
}
SMC_RET1(handle, 0);
/*
* The NS world registers the address of its handler to be
* used for processing the FIQ. This is normally used by the
* NS FIQ debugger driver to detect system hangs by programming
* a watchdog timer to fire a FIQ interrupt.
*/
case TEGRA_SIP_FIQ_NS_ENTRYPOINT:
if (x1 == 0U) {
SMC_RET1(handle, SMC_UNK);
}
/*
* TODO: Check if x1 contains a valid DRAM address
*/
/* store the NS world's entrypoint */
tegra_fiq_set_ns_entrypoint(x1);
SMC_RET1(handle, 0);
/*
* The NS world's FIQ handler issues this SMC to get the NS EL1/EL0
* CPU context when the FIQ interrupt was triggered. This allows the
* NS world to understand the CPU state when the watchdog interrupt
* triggered.
*/
case TEGRA_SIP_FIQ_NS_GET_CONTEXT:
/* retrieve context registers when FIQ triggered */
(void)tegra_fiq_get_intr_context();
SMC_RET0(handle);
default:
ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid);
break;
}
}
SMC_RET1(handle, SMC_UNK);
}
/* Define a runtime service descriptor for fast SMC calls */
DECLARE_RT_SVC(
tegra_sip_fast,
(OEN_SIP_START),
(OEN_SIP_END),
(SMC_TYPE_FAST),
(NULL),
(tegra_sip_handler)
);
@@ -0,0 +1,28 @@
/*
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdint.h>
#include <arch_helpers.h>
#include <lib/mmio.h>
#include <plat/common/platform.h>
#include <platform_def.h>
u_register_t plat_get_stack_protector_canary(void)
{
u_register_t seed;
/*
* Ideally, a random number should be returned instead. As the
* platform does not have any random number generator, this is
* better than nothing, but not really secure.
*/
seed = mmio_read_32(TEGRA_MISC_BASE + HARDWARE_REVISION_OFFSET);
seed <<= 32;
seed |= mmio_read_32(TEGRA_TMRUS_BASE);
return seed ^ read_cntpct_el0();
}
@@ -0,0 +1,231 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <assert.h>
#include <bpmp.h>
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <errno.h>
#include <lib/mmio.h>
#include <plat/common/platform.h>
#include <stdbool.h>
#include <string.h>
#include <tegra_def.h>
#define BPMP_TIMEOUT 500 /* 500ms */
static uint32_t channel_base[NR_CHANNELS];
static uint32_t bpmp_init_state = BPMP_INIT_PENDING;
static uint32_t channel_field(unsigned int ch)
{
return mmio_read_32(TEGRA_RES_SEMA_BASE + STA_OFFSET) & CH_MASK(ch);
}
static bool master_free(unsigned int ch)
{
return channel_field(ch) == MA_FREE(ch);
}
static bool master_acked(unsigned int ch)
{
return channel_field(ch) == MA_ACKD(ch);
}
static void signal_slave(unsigned int ch)
{
mmio_write_32(TEGRA_RES_SEMA_BASE + CLR_OFFSET, CH_MASK(ch));
}
static void free_master(unsigned int ch)
{
mmio_write_32(TEGRA_RES_SEMA_BASE + CLR_OFFSET,
MA_ACKD(ch) ^ MA_FREE(ch));
}
/* should be called with local irqs disabled */
int32_t tegra_bpmp_send_receive_atomic(int mrq, const void *ob_data, int ob_sz,
void *ib_data, int ib_sz)
{
unsigned int ch = (unsigned int)plat_my_core_pos();
mb_data_t *p = (mb_data_t *)(uintptr_t)channel_base[ch];
int32_t ret = -ETIMEDOUT, timeout = 0;
if (bpmp_init_state == BPMP_INIT_COMPLETE) {
/* loop until BPMP is free */
for (timeout = 0; timeout < BPMP_TIMEOUT; timeout++) {
if (master_free(ch) == true) {
break;
}
mdelay(1);
}
if (timeout != BPMP_TIMEOUT) {
/* generate the command struct */
p->code = mrq;
p->flags = DO_ACK;
(void)memcpy((void *)p->data, ob_data, (size_t)ob_sz);
/* signal command ready to the BPMP */
signal_slave(ch);
mmio_write_32(TEGRA_PRI_ICTLR_BASE + CPU_IEP_FIR_SET,
(1U << INT_SHR_SEM_OUTBOX_FULL));
/* loop until the command is executed */
for (timeout = 0; timeout < BPMP_TIMEOUT; timeout++) {
if (master_acked(ch) == true) {
break;
}
mdelay(1);
}
if (timeout != BPMP_TIMEOUT) {
/* get the command response */
(void)memcpy(ib_data, (const void *)p->data,
(size_t)ib_sz);
/* return error code */
ret = p->code;
/* free this channel */
free_master(ch);
}
}
} else {
/* return error code */
ret = -EINVAL;
}
if (timeout == BPMP_TIMEOUT) {
ERROR("Timed out waiting for bpmp's response\n");
}
return ret;
}
int tegra_bpmp_init(void)
{
uint32_t val, base, timeout = BPMP_TIMEOUT;
unsigned int ch;
int ret = 0;
if (bpmp_init_state == BPMP_INIT_PENDING) {
/* check if the bpmp processor is alive. */
do {
val = mmio_read_32(TEGRA_RES_SEMA_BASE + STA_OFFSET);
if (val != SIGN_OF_LIFE) {
mdelay(1);
timeout--;
}
} while ((val != SIGN_OF_LIFE) && (timeout > 0U));
if (val == SIGN_OF_LIFE) {
/* check if clock for the atomics block is enabled */
val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_ENB_V);
if ((val & CAR_ENABLE_ATOMICS) == 0) {
ERROR("Clock to the atomics block is disabled\n");
}
/* check if the atomics block is out of reset */
val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_CLR_V);
if ((val & CAR_ENABLE_ATOMICS) == CAR_ENABLE_ATOMICS) {
ERROR("Reset to the atomics block is asserted\n");
}
/* base address to get the result from Atomics */
base = TEGRA_ATOMICS_BASE + RESULT0_REG_OFFSET;
/* channel area is setup by BPMP before signaling handshake */
for (ch = 0; ch < NR_CHANNELS; ch++) {
/* issue command to get the channel base address */
mmio_write_32(base, (ch << TRIGGER_ID_SHIFT) |
ATOMIC_CMD_GET);
/* get the base address for the channel */
channel_base[ch] = mmio_read_32(base);
/* increment result register offset */
base += 4U;
}
/* mark state as "initialized" */
bpmp_init_state = BPMP_INIT_COMPLETE;
/* the channel values have to be visible across all cpus */
flush_dcache_range((uint64_t)channel_base,
sizeof(channel_base));
flush_dcache_range((uint64_t)&bpmp_init_state,
sizeof(bpmp_init_state));
INFO("%s: done\n", __func__);
} else {
ERROR("BPMP not powered on\n");
/* bpmp is not present in the system */
bpmp_init_state = BPMP_NOT_PRESENT;
/* communication timed out */
ret = -ETIMEDOUT;
}
}
return ret;
}
void tegra_bpmp_suspend(void)
{
/* freeze the interface */
if (bpmp_init_state == BPMP_INIT_COMPLETE) {
bpmp_init_state = BPMP_SUSPEND_ENTRY;
flush_dcache_range((uint64_t)&bpmp_init_state,
sizeof(bpmp_init_state));
}
}
void tegra_bpmp_resume(void)
{
uint32_t val, timeout = 0;
if (bpmp_init_state == BPMP_SUSPEND_ENTRY) {
/* check if the bpmp processor is alive. */
do {
val = mmio_read_32(TEGRA_RES_SEMA_BASE + STA_OFFSET);
if (val != SIGN_OF_LIFE) {
mdelay(1);
timeout++;
}
} while ((val != SIGN_OF_LIFE) && (timeout < BPMP_TIMEOUT));
if (val == SIGN_OF_LIFE) {
INFO("%s: BPMP took %d ms to resume\n", __func__, timeout);
/* mark state as "initialized" */
bpmp_init_state = BPMP_INIT_COMPLETE;
/* state has to be visible across all cpus */
flush_dcache_range((uint64_t)&bpmp_init_state,
sizeof(bpmp_init_state));
} else {
ERROR("BPMP not powered on\n");
}
}
}
@@ -0,0 +1,345 @@
/*
* Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <bpmp_ipc.h>
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <errno.h>
#include <lib/mmio.h>
#include <lib/utils_def.h>
#include <stdbool.h>
#include <string.h>
#include <tegra_def.h>
#include "intf.h"
#include "ivc.h"
/**
* Holds IVC channel data
*/
struct ccplex_bpmp_channel_data {
/* Buffer for incoming data */
struct frame_data *ib;
/* Buffer for outgoing data */
struct frame_data *ob;
};
static struct ccplex_bpmp_channel_data s_channel;
static struct ivc ivc_ccplex_bpmp_channel;
/*
* Helper functions to access the HSP doorbell registers
*/
static inline uint32_t hsp_db_read(uint32_t reg)
{
return mmio_read_32((uint32_t)(TEGRA_HSP_DBELL_BASE + reg));
}
static inline void hsp_db_write(uint32_t reg, uint32_t val)
{
mmio_write_32((uint32_t)(TEGRA_HSP_DBELL_BASE + reg), val);
}
/*******************************************************************************
* IVC wrappers for CCPLEX <-> BPMP communication.
******************************************************************************/
static void tegra_bpmp_ring_bpmp_doorbell(void);
/*
* Get the next frame where data can be written.
*/
static struct frame_data *tegra_bpmp_get_next_out_frame(void)
{
struct frame_data *frame;
const struct ivc *ch = &ivc_ccplex_bpmp_channel;
frame = (struct frame_data *)tegra_ivc_write_get_next_frame(ch);
if (frame == NULL) {
ERROR("%s: Error in getting next frame, exiting\n", __func__);
} else {
s_channel.ob = frame;
}
return frame;
}
static void tegra_bpmp_signal_slave(void)
{
(void)tegra_ivc_write_advance(&ivc_ccplex_bpmp_channel);
tegra_bpmp_ring_bpmp_doorbell();
}
static int32_t tegra_bpmp_free_master(void)
{
return tegra_ivc_read_advance(&ivc_ccplex_bpmp_channel);
}
static bool tegra_bpmp_slave_acked(void)
{
struct frame_data *frame;
bool ret = true;
frame = (struct frame_data *)tegra_ivc_read_get_next_frame(&ivc_ccplex_bpmp_channel);
if (frame == NULL) {
ret = false;
} else {
s_channel.ib = frame;
}
return ret;
}
static struct frame_data *tegra_bpmp_get_cur_in_frame(void)
{
return s_channel.ib;
}
/*
* Enables BPMP to ring CCPlex doorbell
*/
static void tegra_bpmp_enable_ccplex_doorbell(void)
{
uint32_t reg;
reg = hsp_db_read(HSP_DBELL_1_ENABLE);
reg |= HSP_MASTER_BPMP_BIT;
hsp_db_write(HSP_DBELL_1_ENABLE, reg);
}
/*
* CCPlex rings the BPMP doorbell
*/
static void tegra_bpmp_ring_bpmp_doorbell(void)
{
/*
* Any writes to this register has the same effect,
* uses master ID of the write transaction and set
* corresponding flag.
*/
hsp_db_write(HSP_DBELL_3_TRIGGER, HSP_MASTER_CCPLEX_BIT);
}
/*
* Returns true if CCPLex can ring BPMP doorbell, otherwise false.
* This also signals that BPMP is up and ready.
*/
static bool tegra_bpmp_can_ccplex_ring_doorbell(void)
{
uint32_t reg;
/* check if ccplex can communicate with bpmp */
reg = hsp_db_read(HSP_DBELL_3_ENABLE);
return ((reg & HSP_MASTER_CCPLEX_BIT) != 0U);
}
static int32_t tegra_bpmp_wait_for_slave_ack(void)
{
uint32_t timeout = TIMEOUT_RESPONSE_FROM_BPMP_US;
while (!tegra_bpmp_slave_acked() && (timeout != 0U)) {
udelay(1);
timeout--;
};
return ((timeout == 0U) ? -ETIMEDOUT : 0);
}
/*
* Notification from the ivc layer
*/
static void tegra_bpmp_ivc_notify(const struct ivc *ivc)
{
(void)(ivc);
tegra_bpmp_ring_bpmp_doorbell();
}
/*
* Atomic send/receive API, which means it waits until slave acks
*/
static int32_t tegra_bpmp_ipc_send_req_atomic(uint32_t mrq, void *p_out,
uint32_t size_out, void *p_in, uint32_t size_in)
{
struct frame_data *frame = tegra_bpmp_get_next_out_frame();
const struct frame_data *f_in = NULL;
int32_t ret = 0;
void *p_fdata;
if ((p_out == NULL) || (size_out > IVC_DATA_SZ_BYTES) ||
(frame == NULL)) {
ERROR("%s: invalid parameters, exiting\n", __func__);
return -EINVAL;
}
/* prepare the command frame */
frame->mrq = mrq;
frame->flags = FLAG_DO_ACK;
p_fdata = frame->data;
(void)memcpy(p_fdata, p_out, (size_t)size_out);
/* signal the slave */
tegra_bpmp_signal_slave();
/* wait for slave to ack */
ret = tegra_bpmp_wait_for_slave_ack();
if (ret < 0) {
ERROR("%s: wait for slave failed (%d)\n", __func__, ret);
return ret;
}
/* retrieve the response frame */
if ((size_in <= IVC_DATA_SZ_BYTES) && (p_in != NULL)) {
f_in = tegra_bpmp_get_cur_in_frame();
if (f_in != NULL) {
ERROR("Failed to get next input frame!\n");
} else {
(void)memcpy(p_in, p_fdata, (size_t)size_in);
}
}
ret = tegra_bpmp_free_master();
if (ret < 0) {
ERROR("%s: free master failed (%d)\n", __func__, ret);
}
return ret;
}
/*
* Initializes the BPMP<--->CCPlex communication path.
*/
int32_t tegra_bpmp_ipc_init(void)
{
size_t msg_size;
uint32_t frame_size, timeout;
int32_t error = 0;
/* allow bpmp to ring CCPLEX's doorbell */
tegra_bpmp_enable_ccplex_doorbell();
/* wait for BPMP to actually ring the doorbell */
timeout = TIMEOUT_RESPONSE_FROM_BPMP_US;
while ((timeout != 0U) && !tegra_bpmp_can_ccplex_ring_doorbell()) {
udelay(1); /* bpmp turn-around time */
timeout--;
}
if (timeout == 0U) {
ERROR("%s: BPMP firmware is not ready\n", __func__);
return -ENOTSUP;
}
INFO("%s: BPMP handshake completed\n", __func__);
msg_size = tegra_ivc_align(IVC_CMD_SZ_BYTES);
frame_size = (uint32_t)tegra_ivc_total_queue_size(msg_size);
if (frame_size > TEGRA_BPMP_IPC_CH_MAP_SIZE) {
ERROR("%s: carveout size is not sufficient\n", __func__);
return -EINVAL;
}
error = tegra_ivc_init(&ivc_ccplex_bpmp_channel,
(uint32_t)TEGRA_BPMP_IPC_RX_PHYS_BASE,
(uint32_t)TEGRA_BPMP_IPC_TX_PHYS_BASE,
1U, frame_size, tegra_bpmp_ivc_notify);
if (error != 0) {
ERROR("%s: IVC init failed (%d)\n", __func__, error);
} else {
/* reset channel */
tegra_ivc_channel_reset(&ivc_ccplex_bpmp_channel);
/* wait for notification from BPMP */
while (tegra_ivc_channel_notified(&ivc_ccplex_bpmp_channel) != 0) {
/*
* Interrupt BPMP with doorbell each time after
* tegra_ivc_channel_notified() returns non zero
* value.
*/
tegra_bpmp_ring_bpmp_doorbell();
}
INFO("%s: All communication channels initialized\n", __func__);
}
return error;
}
/* Handler to reset a hardware module */
int32_t tegra_bpmp_ipc_reset_module(uint32_t rst_id)
{
int32_t ret;
struct mrq_reset_request req = {
.cmd = (uint32_t)CMD_RESET_MODULE,
.reset_id = rst_id
};
/* only GPCDMA/XUSB_PADCTL resets are supported */
assert((rst_id == TEGRA_RESET_ID_XUSB_PADCTL) ||
(rst_id == TEGRA_RESET_ID_GPCDMA));
ret = tegra_bpmp_ipc_send_req_atomic(MRQ_RESET, &req,
(uint32_t)sizeof(req), NULL, 0);
if (ret != 0) {
ERROR("%s: failed for module %d with error %d\n", __func__,
rst_id, ret);
}
return ret;
}
int tegra_bpmp_ipc_enable_clock(uint32_t clk_id)
{
int ret;
struct mrq_clk_request req;
/* only SE clocks are supported */
if (clk_id != TEGRA_CLK_SE) {
return -ENOTSUP;
}
/* prepare the MRQ_CLK command */
req.cmd_and_id = make_mrq_clk_cmd(CMD_CLK_ENABLE, clk_id);
ret = tegra_bpmp_ipc_send_req_atomic(MRQ_CLK, &req, (uint32_t)sizeof(req),
NULL, 0);
if (ret != 0) {
ERROR("%s: failed for module %d with error %d\n", __func__,
clk_id, ret);
}
return ret;
}
int tegra_bpmp_ipc_disable_clock(uint32_t clk_id)
{
int ret;
struct mrq_clk_request req;
/* only SE clocks are supported */
if (clk_id != TEGRA_CLK_SE) {
return -ENOTSUP;
}
/* prepare the MRQ_CLK command */
req.cmd_and_id = make_mrq_clk_cmd(CMD_CLK_DISABLE, clk_id);
ret = tegra_bpmp_ipc_send_req_atomic(MRQ_CLK, &req, (uint32_t)sizeof(req),
NULL, 0);
if (ret != 0) {
ERROR("%s: failed for module %d with error %d\n", __func__,
clk_id, ret);
}
return ret;
}
@@ -0,0 +1,127 @@
/*
* Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef BPMP_INTF_H
#define BPMP_INTF_H
/**
* Flags used in IPC req
*/
#define FLAG_DO_ACK (U(1) << 0)
#define FLAG_RING_DOORBELL (U(1) << 1)
/* Bit 1 is designated for CCPlex in secure world */
#define HSP_MASTER_CCPLEX_BIT (U(1) << 1)
/* Bit 19 is designated for BPMP in non-secure world */
#define HSP_MASTER_BPMP_BIT (U(1) << 19)
/* Timeout to receive response from BPMP is 1 sec */
#define TIMEOUT_RESPONSE_FROM_BPMP_US U(1000000) /* in microseconds */
/**
* IVC protocol defines and command/response frame
*/
/**
* IVC specific defines
*/
#define IVC_CMD_SZ_BYTES U(128)
#define IVC_DATA_SZ_BYTES U(120)
/**
* Holds frame data for an IPC request
*/
struct frame_data {
/* Identification as to what kind of data is being transmitted */
uint32_t mrq;
/* Flags for slave as to how to respond back */
uint32_t flags;
/* Actual data being sent */
uint8_t data[IVC_DATA_SZ_BYTES];
};
/**
* Commands send to the BPMP firmware
*/
/**
* MRQ command codes
*/
#define MRQ_RESET U(20)
#define MRQ_CLK U(22)
/**
* Reset sub-commands
*/
#define CMD_RESET_ASSERT U(1)
#define CMD_RESET_DEASSERT U(2)
#define CMD_RESET_MODULE U(3)
/**
* Used by the sender of an #MRQ_RESET message to request BPMP to
* assert or deassert a given reset line.
*/
struct __attribute__((packed)) mrq_reset_request {
/* reset action to perform (mrq_reset_commands) */
uint32_t cmd;
/* id of the reset to affected */
uint32_t reset_id;
};
/**
* MRQ_CLK sub-commands
*
*/
enum {
CMD_CLK_GET_RATE = U(1),
CMD_CLK_SET_RATE = U(2),
CMD_CLK_ROUND_RATE = U(3),
CMD_CLK_GET_PARENT = U(4),
CMD_CLK_SET_PARENT = U(5),
CMD_CLK_IS_ENABLED = U(6),
CMD_CLK_ENABLE = U(7),
CMD_CLK_DISABLE = U(8),
CMD_CLK_GET_ALL_INFO = U(14),
CMD_CLK_GET_MAX_CLK_ID = U(15),
CMD_CLK_MAX,
};
/**
* Used by the sender of an #MRQ_CLK message to control clocks. The
* clk_request is split into several sub-commands. Some sub-commands
* require no additional data. Others have a sub-command specific
* payload
*
* |sub-command |payload |
* |----------------------------|-----------------------|
* |CMD_CLK_GET_RATE |- |
* |CMD_CLK_SET_RATE |clk_set_rate |
* |CMD_CLK_ROUND_RATE |clk_round_rate |
* |CMD_CLK_GET_PARENT |- |
* |CMD_CLK_SET_PARENT |clk_set_parent |
* |CMD_CLK_IS_ENABLED |- |
* |CMD_CLK_ENABLE |- |
* |CMD_CLK_DISABLE |- |
* |CMD_CLK_GET_ALL_INFO |- |
* |CMD_CLK_GET_MAX_CLK_ID |- |
*
*/
struct mrq_clk_request {
/**
* sub-command and clock id concatenated to 32-bit word.
* - bits[31..24] is the sub-cmd.
* - bits[23..0] is the clock id
*/
uint32_t cmd_and_id;
};
/**
* Macro to prepare the MRQ_CLK sub-command
*/
#define make_mrq_clk_cmd(cmd, id) (((cmd) << 24) | (id & 0xFFFFFF))
#endif /* BPMP_INTF_H */
@@ -0,0 +1,654 @@
/*
* Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <assert.h>
#include <common/debug.h>
#include <errno.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include "ivc.h"
/*
* IVC channel reset protocol.
*
* Each end uses its tx_channel.state to indicate its synchronization state.
*/
enum {
/*
* This value is zero for backwards compatibility with services that
* assume channels to be initially zeroed. Such channels are in an
* initially valid state, but cannot be asynchronously reset, and must
* maintain a valid state at all times.
*
* The transmitting end can enter the established state from the sync or
* ack state when it observes the receiving endpoint in the ack or
* established state, indicating that has cleared the counters in our
* rx_channel.
*/
ivc_state_established = U(0),
/*
* If an endpoint is observed in the sync state, the remote endpoint is
* allowed to clear the counters it owns asynchronously with respect to
* the current endpoint. Therefore, the current endpoint is no longer
* allowed to communicate.
*/
ivc_state_sync = U(1),
/*
* When the transmitting end observes the receiving end in the sync
* state, it can clear the w_count and r_count and transition to the ack
* state. If the remote endpoint observes us in the ack state, it can
* return to the established state once it has cleared its counters.
*/
ivc_state_ack = U(2)
};
/*
* This structure is divided into two-cache aligned parts, the first is only
* written through the tx_channel pointer, while the second is only written
* through the rx_channel pointer. This delineates ownership of the cache lines,
* which is critical to performance and necessary in non-cache coherent
* implementations.
*/
struct ivc_channel_header {
struct {
/* fields owned by the transmitting end */
uint32_t w_count;
uint32_t state;
uint32_t w_rsvd[IVC_CHHDR_TX_FIELDS - 2];
};
struct {
/* fields owned by the receiving end */
uint32_t r_count;
uint32_t r_rsvd[IVC_CHHDR_RX_FIELDS - 1];
};
};
static inline bool ivc_channel_empty(const struct ivc *ivc,
volatile const struct ivc_channel_header *ch)
{
/*
* This function performs multiple checks on the same values with
* security implications, so sample the counters' current values in
* shared memory to ensure that these checks use the same values.
*/
uint32_t wr_count = ch->w_count;
uint32_t rd_count = ch->r_count;
bool ret = false;
(void)ivc;
/*
* Perform an over-full check to prevent denial of service attacks where
* a server could be easily fooled into believing that there's an
* extremely large number of frames ready, since receivers are not
* expected to check for full or over-full conditions.
*
* Although the channel isn't empty, this is an invalid case caused by
* a potentially malicious peer, so returning empty is safer, because it
* gives the impression that the channel has gone silent.
*/
if (((wr_count - rd_count) > ivc->nframes) || (wr_count == rd_count)) {
ret = true;
}
return ret;
}
static inline bool ivc_channel_full(const struct ivc *ivc,
volatile const struct ivc_channel_header *ch)
{
uint32_t wr_count = ch->w_count;
uint32_t rd_count = ch->r_count;
(void)ivc;
/*
* Invalid cases where the counters indicate that the queue is over
* capacity also appear full.
*/
return ((wr_count - rd_count) >= ivc->nframes);
}
static inline uint32_t ivc_channel_avail_count(const struct ivc *ivc,
volatile const struct ivc_channel_header *ch)
{
uint32_t wr_count = ch->w_count;
uint32_t rd_count = ch->r_count;
(void)ivc;
/*
* This function isn't expected to be used in scenarios where an
* over-full situation can lead to denial of service attacks. See the
* comment in ivc_channel_empty() for an explanation about special
* over-full considerations.
*/
return (wr_count - rd_count);
}
static inline void ivc_advance_tx(struct ivc *ivc)
{
ivc->tx_channel->w_count++;
if (ivc->w_pos == (ivc->nframes - (uint32_t)1U)) {
ivc->w_pos = 0U;
} else {
ivc->w_pos++;
}
}
static inline void ivc_advance_rx(struct ivc *ivc)
{
ivc->rx_channel->r_count++;
if (ivc->r_pos == (ivc->nframes - (uint32_t)1U)) {
ivc->r_pos = 0U;
} else {
ivc->r_pos++;
}
}
static inline int32_t ivc_check_read(const struct ivc *ivc)
{
/*
* tx_channel->state is set locally, so it is not synchronized with
* state from the remote peer. The remote peer cannot reset its
* transmit counters until we've acknowledged its synchronization
* request, so no additional synchronization is required because an
* asynchronous transition of rx_channel->state to ivc_state_ack is not
* allowed.
*/
if (ivc->tx_channel->state != ivc_state_established) {
return -ECONNRESET;
}
/*
* Avoid unnecessary invalidations when performing repeated accesses to
* an IVC channel by checking the old queue pointers first.
* Synchronization is only necessary when these pointers indicate empty
* or full.
*/
if (!ivc_channel_empty(ivc, ivc->rx_channel)) {
return 0;
}
return ivc_channel_empty(ivc, ivc->rx_channel) ? -ENOMEM : 0;
}
static inline int32_t ivc_check_write(const struct ivc *ivc)
{
if (ivc->tx_channel->state != ivc_state_established) {
return -ECONNRESET;
}
if (!ivc_channel_full(ivc, ivc->tx_channel)) {
return 0;
}
return ivc_channel_full(ivc, ivc->tx_channel) ? -ENOMEM : 0;
}
bool tegra_ivc_can_read(const struct ivc *ivc)
{
return ivc_check_read(ivc) == 0;
}
bool tegra_ivc_can_write(const struct ivc *ivc)
{
return ivc_check_write(ivc) == 0;
}
bool tegra_ivc_tx_empty(const struct ivc *ivc)
{
return ivc_channel_empty(ivc, ivc->tx_channel);
}
static inline uintptr_t calc_frame_offset(uint32_t frame_index,
uint32_t frame_size, uint32_t frame_offset)
{
return ((uintptr_t)frame_index * (uintptr_t)frame_size) +
(uintptr_t)frame_offset;
}
static void *ivc_frame_pointer(const struct ivc *ivc,
volatile const struct ivc_channel_header *ch,
uint32_t frame)
{
assert(frame < ivc->nframes);
return (void *)((uintptr_t)(&ch[1]) +
calc_frame_offset(frame, ivc->frame_size, 0));
}
int32_t tegra_ivc_read(struct ivc *ivc, void *buf, size_t max_read)
{
const void *src;
int32_t result;
if (buf == NULL) {
return -EINVAL;
}
if (max_read > ivc->frame_size) {
return -E2BIG;
}
result = ivc_check_read(ivc);
if (result != 0) {
return result;
}
/*
* Order observation of w_pos potentially indicating new data before
* data read.
*/
dmbish();
src = ivc_frame_pointer(ivc, ivc->rx_channel, ivc->r_pos);
(void)memcpy(buf, src, max_read);
ivc_advance_rx(ivc);
/*
* Ensure our write to r_pos occurs before our read from w_pos.
*/
dmbish();
/*
* Notify only upon transition from full to non-full.
* The available count can only asynchronously increase, so the
* worst possible side-effect will be a spurious notification.
*/
if (ivc_channel_avail_count(ivc, ivc->rx_channel) == (ivc->nframes - (uint32_t)1U)) {
ivc->notify(ivc);
}
return (int32_t)max_read;
}
/* directly peek at the next frame rx'ed */
void *tegra_ivc_read_get_next_frame(const struct ivc *ivc)
{
if (ivc_check_read(ivc) != 0) {
return NULL;
}
/*
* Order observation of w_pos potentially indicating new data before
* data read.
*/
dmbld();
return ivc_frame_pointer(ivc, ivc->rx_channel, ivc->r_pos);
}
int32_t tegra_ivc_read_advance(struct ivc *ivc)
{
/*
* No read barriers or synchronization here: the caller is expected to
* have already observed the channel non-empty. This check is just to
* catch programming errors.
*/
int32_t result = ivc_check_read(ivc);
if (result != 0) {
return result;
}
ivc_advance_rx(ivc);
/*
* Ensure our write to r_pos occurs before our read from w_pos.
*/
dmbish();
/*
* Notify only upon transition from full to non-full.
* The available count can only asynchronously increase, so the
* worst possible side-effect will be a spurious notification.
*/
if (ivc_channel_avail_count(ivc, ivc->rx_channel) == (ivc->nframes - (uint32_t)1U)) {
ivc->notify(ivc);
}
return 0;
}
int32_t tegra_ivc_write(struct ivc *ivc, const void *buf, size_t size)
{
void *p;
int32_t result;
if ((buf == NULL) || (ivc == NULL)) {
return -EINVAL;
}
if (size > ivc->frame_size) {
return -E2BIG;
}
result = ivc_check_write(ivc);
if (result != 0) {
return result;
}
p = ivc_frame_pointer(ivc, ivc->tx_channel, ivc->w_pos);
(void)memset(p, 0, ivc->frame_size);
(void)memcpy(p, buf, size);
/*
* Ensure that updated data is visible before the w_pos counter
* indicates that it is ready.
*/
dmbst();
ivc_advance_tx(ivc);
/*
* Ensure our write to w_pos occurs before our read from r_pos.
*/
dmbish();
/*
* Notify only upon transition from empty to non-empty.
* The available count can only asynchronously decrease, so the
* worst possible side-effect will be a spurious notification.
*/
if (ivc_channel_avail_count(ivc, ivc->tx_channel) == 1U) {
ivc->notify(ivc);
}
return (int32_t)size;
}
/* directly poke at the next frame to be tx'ed */
void *tegra_ivc_write_get_next_frame(const struct ivc *ivc)
{
if (ivc_check_write(ivc) != 0) {
return NULL;
}
return ivc_frame_pointer(ivc, ivc->tx_channel, ivc->w_pos);
}
/* advance the tx buffer */
int32_t tegra_ivc_write_advance(struct ivc *ivc)
{
int32_t result = ivc_check_write(ivc);
if (result != 0) {
return result;
}
/*
* Order any possible stores to the frame before update of w_pos.
*/
dmbst();
ivc_advance_tx(ivc);
/*
* Ensure our write to w_pos occurs before our read from r_pos.
*/
dmbish();
/*
* Notify only upon transition from empty to non-empty.
* The available count can only asynchronously decrease, so the
* worst possible side-effect will be a spurious notification.
*/
if (ivc_channel_avail_count(ivc, ivc->tx_channel) == (uint32_t)1U) {
ivc->notify(ivc);
}
return 0;
}
void tegra_ivc_channel_reset(const struct ivc *ivc)
{
ivc->tx_channel->state = ivc_state_sync;
ivc->notify(ivc);
}
/*
* ===============================================================
* IVC State Transition Table - see tegra_ivc_channel_notified()
* ===============================================================
*
* local remote action
* ----- ------ -----------------------------------
* SYNC EST <none>
* SYNC ACK reset counters; move to EST; notify
* SYNC SYNC reset counters; move to ACK; notify
* ACK EST move to EST; notify
* ACK ACK move to EST; notify
* ACK SYNC reset counters; move to ACK; notify
* EST EST <none>
* EST ACK <none>
* EST SYNC reset counters; move to ACK; notify
*
* ===============================================================
*/
int32_t tegra_ivc_channel_notified(struct ivc *ivc)
{
uint32_t peer_state;
/* Copy the receiver's state out of shared memory. */
peer_state = ivc->rx_channel->state;
if (peer_state == (uint32_t)ivc_state_sync) {
/*
* Order observation of ivc_state_sync before stores clearing
* tx_channel.
*/
dmbld();
/*
* Reset tx_channel counters. The remote end is in the SYNC
* state and won't make progress until we change our state,
* so the counters are not in use at this time.
*/
ivc->tx_channel->w_count = 0U;
ivc->rx_channel->r_count = 0U;
ivc->w_pos = 0U;
ivc->r_pos = 0U;
/*
* Ensure that counters appear cleared before new state can be
* observed.
*/
dmbst();
/*
* Move to ACK state. We have just cleared our counters, so it
* is now safe for the remote end to start using these values.
*/
ivc->tx_channel->state = ivc_state_ack;
/*
* Notify remote end to observe state transition.
*/
ivc->notify(ivc);
} else if ((ivc->tx_channel->state == (uint32_t)ivc_state_sync) &&
(peer_state == (uint32_t)ivc_state_ack)) {
/*
* Order observation of ivc_state_sync before stores clearing
* tx_channel.
*/
dmbld();
/*
* Reset tx_channel counters. The remote end is in the ACK
* state and won't make progress until we change our state,
* so the counters are not in use at this time.
*/
ivc->tx_channel->w_count = 0U;
ivc->rx_channel->r_count = 0U;
ivc->w_pos = 0U;
ivc->r_pos = 0U;
/*
* Ensure that counters appear cleared before new state can be
* observed.
*/
dmbst();
/*
* Move to ESTABLISHED state. We know that the remote end has
* already cleared its counters, so it is safe to start
* writing/reading on this channel.
*/
ivc->tx_channel->state = ivc_state_established;
/*
* Notify remote end to observe state transition.
*/
ivc->notify(ivc);
} else if (ivc->tx_channel->state == (uint32_t)ivc_state_ack) {
/*
* At this point, we have observed the peer to be in either
* the ACK or ESTABLISHED state. Next, order observation of
* peer state before storing to tx_channel.
*/
dmbld();
/*
* Move to ESTABLISHED state. We know that we have previously
* cleared our counters, and we know that the remote end has
* cleared its counters, so it is safe to start writing/reading
* on this channel.
*/
ivc->tx_channel->state = ivc_state_established;
/*
* Notify remote end to observe state transition.
*/
ivc->notify(ivc);
} else {
/*
* There is no need to handle any further action. Either the
* channel is already fully established, or we are waiting for
* the remote end to catch up with our current state. Refer
* to the diagram in "IVC State Transition Table" above.
*/
}
return ((ivc->tx_channel->state == (uint32_t)ivc_state_established) ? 0 : -EAGAIN);
}
size_t tegra_ivc_align(size_t size)
{
return (size + (IVC_ALIGN - 1U)) & ~(IVC_ALIGN - 1U);
}
size_t tegra_ivc_total_queue_size(size_t queue_size)
{
if ((queue_size & (IVC_ALIGN - 1U)) != 0U) {
ERROR("queue_size (%d) must be %d-byte aligned\n",
(int32_t)queue_size, IVC_ALIGN);
return 0;
}
return queue_size + sizeof(struct ivc_channel_header);
}
static int32_t check_ivc_params(uintptr_t queue_base1, uintptr_t queue_base2,
uint32_t nframes, uint32_t frame_size)
{
assert((offsetof(struct ivc_channel_header, w_count)
& (IVC_ALIGN - 1U)) == 0U);
assert((offsetof(struct ivc_channel_header, r_count)
& (IVC_ALIGN - 1U)) == 0U);
assert((sizeof(struct ivc_channel_header) & (IVC_ALIGN - 1U)) == 0U);
if (((uint64_t)nframes * (uint64_t)frame_size) >= 0x100000000ULL) {
ERROR("nframes * frame_size overflows\n");
return -EINVAL;
}
/*
* The headers must at least be aligned enough for counters
* to be accessed atomically.
*/
if ((queue_base1 & (IVC_ALIGN - 1U)) != 0U) {
ERROR("ivc channel start not aligned: %lx\n", queue_base1);
return -EINVAL;
}
if ((queue_base2 & (IVC_ALIGN - 1U)) != 0U) {
ERROR("ivc channel start not aligned: %lx\n", queue_base2);
return -EINVAL;
}
if ((frame_size & (IVC_ALIGN - 1U)) != 0U) {
ERROR("frame size not adequately aligned: %u\n",
frame_size);
return -EINVAL;
}
if (queue_base1 < queue_base2) {
if ((queue_base1 + ((uint64_t)frame_size * nframes)) > queue_base2) {
ERROR("queue regions overlap: %lx + %x, %x\n",
queue_base1, frame_size,
frame_size * nframes);
return -EINVAL;
}
} else {
if ((queue_base2 + ((uint64_t)frame_size * nframes)) > queue_base1) {
ERROR("queue regions overlap: %lx + %x, %x\n",
queue_base2, frame_size,
frame_size * nframes);
return -EINVAL;
}
}
return 0;
}
int32_t tegra_ivc_init(struct ivc *ivc, uintptr_t rx_base, uintptr_t tx_base,
uint32_t nframes, uint32_t frame_size,
ivc_notify_function notify)
{
int32_t result;
/* sanity check input params */
if ((ivc == NULL) || (notify == NULL)) {
return -EINVAL;
}
result = check_ivc_params(rx_base, tx_base, nframes, frame_size);
if (result != 0) {
return result;
}
/*
* All sizes that can be returned by communication functions should
* fit in a 32-bit integer.
*/
if (frame_size > (1u << 31)) {
return -E2BIG;
}
ivc->rx_channel = (struct ivc_channel_header *)rx_base;
ivc->tx_channel = (struct ivc_channel_header *)tx_base;
ivc->notify = notify;
ivc->frame_size = frame_size;
ivc->nframes = nframes;
ivc->w_pos = 0U;
ivc->r_pos = 0U;
INFO("%s: done\n", __func__);
return 0;
}
@@ -0,0 +1,50 @@
/*
* Copyright (c) 2017-2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef BPMP_IVC_H
#define BPMP_IVC_H
#include <lib/utils_def.h>
#include <stdint.h>
#include <stddef.h>
#define IVC_ALIGN U(64)
#define IVC_CHHDR_TX_FIELDS U(16)
#define IVC_CHHDR_RX_FIELDS U(16)
struct ivc_channel_header;
struct ivc {
struct ivc_channel_header *rx_channel;
struct ivc_channel_header *tx_channel;
uint32_t w_pos;
uint32_t r_pos;
void (*notify)(const struct ivc *);
uint32_t nframes;
uint32_t frame_size;
};
/* callback handler for notify on receiving a response */
typedef void (* ivc_notify_function)(const struct ivc *);
int32_t tegra_ivc_init(struct ivc *ivc, uintptr_t rx_base, uintptr_t tx_base,
uint32_t nframes, uint32_t frame_size,
ivc_notify_function notify);
size_t tegra_ivc_total_queue_size(size_t queue_size);
size_t tegra_ivc_align(size_t size);
int32_t tegra_ivc_channel_notified(struct ivc *ivc);
void tegra_ivc_channel_reset(const struct ivc *ivc);
int32_t tegra_ivc_write_advance(struct ivc *ivc);
void *tegra_ivc_write_get_next_frame(const struct ivc *ivc);
int32_t tegra_ivc_write(struct ivc *ivc, const void *buf, size_t size);
int32_t tegra_ivc_read_advance(struct ivc *ivc);
void *tegra_ivc_read_get_next_frame(const struct ivc *ivc);
int32_t tegra_ivc_read(struct ivc *ivc, void *buf, size_t max_read);
bool tegra_ivc_tx_empty(const struct ivc *ivc);
bool tegra_ivc_can_write(const struct ivc *ivc);
bool tegra_ivc_can_read(const struct ivc *ivc);
#endif /* BPMP_IVC_H */
@@ -0,0 +1,322 @@
/*
* Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <arch_helpers.h>
#include <cortex_a53.h>
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <lib/mmio.h>
#include <flowctrl.h>
#include <lib/utils_def.h>
#include <pmc.h>
#include <tegra_def.h>
#define CLK_RST_DEV_L_SET 0x300
#define CLK_RST_DEV_L_CLR 0x304
#define CLK_BPMP_RST (1 << 1)
#define EVP_BPMP_RESET_VECTOR 0x200
static const uint64_t flowctrl_offset_cpu_csr[4] = {
(TEGRA_FLOWCTRL_BASE + FLOWCTRL_CPU0_CSR),
(TEGRA_FLOWCTRL_BASE + FLOWCTRL_CPU1_CSR),
(TEGRA_FLOWCTRL_BASE + FLOWCTRL_CPU1_CSR + 8),
(TEGRA_FLOWCTRL_BASE + FLOWCTRL_CPU1_CSR + 16)
};
static const uint64_t flowctrl_offset_halt_cpu[4] = {
(TEGRA_FLOWCTRL_BASE + FLOWCTRL_HALT_CPU0_EVENTS),
(TEGRA_FLOWCTRL_BASE + FLOWCTRL_HALT_CPU1_EVENTS),
(TEGRA_FLOWCTRL_BASE + FLOWCTRL_HALT_CPU1_EVENTS + 8),
(TEGRA_FLOWCTRL_BASE + FLOWCTRL_HALT_CPU1_EVENTS + 16)
};
static const uint64_t flowctrl_offset_cc4_ctrl[4] = {
(TEGRA_FLOWCTRL_BASE + FLOWCTRL_CC4_CORE0_CTRL),
(TEGRA_FLOWCTRL_BASE + FLOWCTRL_CC4_CORE0_CTRL + 4),
(TEGRA_FLOWCTRL_BASE + FLOWCTRL_CC4_CORE0_CTRL + 8),
(TEGRA_FLOWCTRL_BASE + FLOWCTRL_CC4_CORE0_CTRL + 12)
};
static inline void tegra_fc_cc4_ctrl(int cpu_id, uint32_t val)
{
mmio_write_32(flowctrl_offset_cc4_ctrl[cpu_id], val);
val = mmio_read_32(flowctrl_offset_cc4_ctrl[cpu_id]);
}
static inline void tegra_fc_cpu_csr(int cpu_id, uint32_t val)
{
mmio_write_32(flowctrl_offset_cpu_csr[cpu_id], val);
val = mmio_read_32(flowctrl_offset_cpu_csr[cpu_id]);
}
static inline void tegra_fc_halt_cpu(int cpu_id, uint32_t val)
{
mmio_write_32(flowctrl_offset_halt_cpu[cpu_id], val);
val = mmio_read_32(flowctrl_offset_halt_cpu[cpu_id]);
}
static void tegra_fc_prepare_suspend(int cpu_id, uint32_t csr)
{
uint32_t val;
val = FLOWCTRL_HALT_GIC_IRQ | FLOWCTRL_HALT_GIC_FIQ |
FLOWCTRL_HALT_LIC_IRQ | FLOWCTRL_HALT_LIC_FIQ |
FLOWCTRL_WAITEVENT;
tegra_fc_halt_cpu(cpu_id, val);
val = FLOWCTRL_CSR_INTR_FLAG | FLOWCTRL_CSR_EVENT_FLAG |
FLOWCTRL_CSR_ENABLE | (FLOWCTRL_WAIT_WFI_BITMAP << cpu_id);
tegra_fc_cpu_csr(cpu_id, val | csr);
}
/*******************************************************************************
* After this, no core can wake from C7 until the action is reverted.
* If a wake up event is asserted, the FC state machine will stall until
* the action is reverted.
******************************************************************************/
void tegra_fc_ccplex_pgexit_lock(void)
{
unsigned int i, cpu = read_mpidr() & MPIDR_CPU_MASK;
uint32_t flags = tegra_fc_read_32(FLOWCTRL_FC_SEQ_INTERCEPT) & ~INTERCEPT_IRQ_PENDING;;
uint32_t icept_cpu_flags[] = {
INTERCEPT_EXIT_PG_CORE0,
INTERCEPT_EXIT_PG_CORE1,
INTERCEPT_EXIT_PG_CORE2,
INTERCEPT_EXIT_PG_CORE3
};
/* set the intercept flags */
for (i = 0; i < ARRAY_SIZE(icept_cpu_flags); i++) {
/* skip current CPU */
if (i == cpu)
continue;
/* enable power gate exit intercept locks */
flags |= icept_cpu_flags[i];
}
tegra_fc_write_32(FLOWCTRL_FC_SEQ_INTERCEPT, flags);
(void)tegra_fc_read_32(FLOWCTRL_FC_SEQ_INTERCEPT);
}
/*******************************************************************************
* Revert the ccplex powergate exit locks
******************************************************************************/
void tegra_fc_ccplex_pgexit_unlock(void)
{
/* clear lock bits, clear pending interrupts */
tegra_fc_write_32(FLOWCTRL_FC_SEQ_INTERCEPT, INTERCEPT_IRQ_PENDING);
(void)tegra_fc_read_32(FLOWCTRL_FC_SEQ_INTERCEPT);
}
/*******************************************************************************
* Powerdn the current CPU
******************************************************************************/
void tegra_fc_cpu_powerdn(uint32_t mpidr)
{
int cpu = mpidr & MPIDR_CPU_MASK;
VERBOSE("CPU%d powering down...\n", cpu);
tegra_fc_prepare_suspend(cpu, 0);
}
/*******************************************************************************
* Suspend the current CPU cluster
******************************************************************************/
void tegra_fc_cluster_idle(uint32_t mpidr)
{
int cpu = mpidr & MPIDR_CPU_MASK;
uint32_t val;
VERBOSE("Entering cluster idle state...\n");
tegra_fc_cc4_ctrl(cpu, 0);
/* hardware L2 flush is faster for A53 only */
tegra_fc_write_32(FLOWCTRL_L2_FLUSH_CONTROL,
!!MPIDR_AFFLVL1_VAL(mpidr));
/* suspend the CPU cluster */
val = FLOWCTRL_PG_CPU_NONCPU << FLOWCTRL_ENABLE_EXT;
tegra_fc_prepare_suspend(cpu, val);
}
/*******************************************************************************
* Power down the current CPU cluster
******************************************************************************/
void tegra_fc_cluster_powerdn(uint32_t mpidr)
{
int cpu = mpidr & MPIDR_CPU_MASK;
uint32_t val;
VERBOSE("Entering cluster powerdn state...\n");
tegra_fc_cc4_ctrl(cpu, 0);
/* hardware L2 flush is faster for A53 only */
tegra_fc_write_32(FLOWCTRL_L2_FLUSH_CONTROL,
read_midr() == CORTEX_A53_MIDR);
/* power down the CPU cluster */
val = FLOWCTRL_TURNOFF_CPURAIL << FLOWCTRL_ENABLE_EXT;
tegra_fc_prepare_suspend(cpu, val);
}
/*******************************************************************************
* Check if cluster idle or power down state is allowed from this CPU
******************************************************************************/
bool tegra_fc_is_ccx_allowed(void)
{
unsigned int i, cpu = read_mpidr() & MPIDR_CPU_MASK;
uint32_t val;
bool ccx_allowed = true;
for (i = 0; i < ARRAY_SIZE(flowctrl_offset_cpu_csr); i++) {
/* skip current CPU */
if (i == cpu)
continue;
/* check if all other CPUs are already halted */
val = mmio_read_32(flowctrl_offset_cpu_csr[i]);
if ((val & FLOWCTRL_CSR_HALT_MASK) == 0U) {
ccx_allowed = false;
}
}
return ccx_allowed;
}
/*******************************************************************************
* Suspend the entire SoC
******************************************************************************/
void tegra_fc_soc_powerdn(uint32_t mpidr)
{
int cpu = mpidr & MPIDR_CPU_MASK;
uint32_t val;
VERBOSE("Entering SoC powerdn state...\n");
tegra_fc_cc4_ctrl(cpu, 0);
tegra_fc_write_32(FLOWCTRL_L2_FLUSH_CONTROL, 1);
val = FLOWCTRL_TURNOFF_CPURAIL << FLOWCTRL_ENABLE_EXT;
tegra_fc_prepare_suspend(cpu, val);
/* overwrite HALT register */
tegra_fc_halt_cpu(cpu, FLOWCTRL_WAITEVENT);
}
/*******************************************************************************
* Power up the CPU
******************************************************************************/
void tegra_fc_cpu_on(int cpu)
{
tegra_fc_cpu_csr(cpu, FLOWCTRL_CSR_ENABLE);
tegra_fc_halt_cpu(cpu, FLOWCTRL_WAITEVENT | FLOWCTRL_HALT_SCLK);
}
/*******************************************************************************
* Power down the CPU
******************************************************************************/
void tegra_fc_cpu_off(int cpu)
{
uint32_t val;
/*
* Flow controller powers down the CPU during wfi. The CPU would be
* powered on when it receives any interrupt.
*/
val = FLOWCTRL_CSR_INTR_FLAG | FLOWCTRL_CSR_EVENT_FLAG |
FLOWCTRL_CSR_ENABLE | (FLOWCTRL_WAIT_WFI_BITMAP << cpu);
tegra_fc_cpu_csr(cpu, val);
tegra_fc_halt_cpu(cpu, FLOWCTRL_WAITEVENT);
tegra_fc_cc4_ctrl(cpu, 0);
}
/*******************************************************************************
* Inform the BPMP that we have completed the cluster power up
******************************************************************************/
void tegra_fc_lock_active_cluster(void)
{
uint32_t val;
val = tegra_fc_read_32(FLOWCTRL_BPMP_CLUSTER_CONTROL);
val |= FLOWCTRL_BPMP_CLUSTER_PWRON_LOCK;
tegra_fc_write_32(FLOWCTRL_BPMP_CLUSTER_CONTROL, val);
val = tegra_fc_read_32(FLOWCTRL_BPMP_CLUSTER_CONTROL);
}
/*******************************************************************************
* Power ON BPMP processor
******************************************************************************/
void tegra_fc_bpmp_on(uint32_t entrypoint)
{
/* halt BPMP */
tegra_fc_write_32(FLOWCTRL_HALT_BPMP_EVENTS, FLOWCTRL_WAITEVENT);
/* Assert BPMP reset */
mmio_write_32(TEGRA_CAR_RESET_BASE + CLK_RST_DEV_L_SET, CLK_BPMP_RST);
/* Set reset address (stored in PMC_SCRATCH39) */
mmio_write_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR, entrypoint);
while (entrypoint != mmio_read_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR))
; /* wait till value reaches EVP_BPMP_RESET_VECTOR */
/* Wait for 2us before de-asserting the reset signal. */
udelay(2);
/* De-assert BPMP reset */
mmio_write_32(TEGRA_CAR_RESET_BASE + CLK_RST_DEV_L_CLR, CLK_BPMP_RST);
/* Un-halt BPMP */
tegra_fc_write_32(FLOWCTRL_HALT_BPMP_EVENTS, 0);
}
/*******************************************************************************
* Power OFF BPMP processor
******************************************************************************/
void tegra_fc_bpmp_off(void)
{
/* halt BPMP */
tegra_fc_write_32(FLOWCTRL_HALT_BPMP_EVENTS, FLOWCTRL_WAITEVENT);
/* Assert BPMP reset */
mmio_write_32(TEGRA_CAR_RESET_BASE + CLK_RST_DEV_L_SET, CLK_BPMP_RST);
/* Clear reset address */
mmio_write_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR, 0);
while (0 != mmio_read_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR))
; /* wait till value reaches EVP_BPMP_RESET_VECTOR */
}
/*******************************************************************************
* Route legacy FIQ to the GICD
******************************************************************************/
void tegra_fc_enable_fiq_to_ccplex_routing(void)
{
uint32_t val = tegra_fc_read_32(FLOW_CTLR_FLOW_DBG_QUAL);
/* set the bit to pass FIQs to the GICD */
tegra_fc_write_32(FLOW_CTLR_FLOW_DBG_QUAL, val | FLOWCTRL_FIQ2CCPLEX_ENABLE);
}
/*******************************************************************************
* Disable routing legacy FIQ to the GICD
******************************************************************************/
void tegra_fc_disable_fiq_to_ccplex_routing(void)
{
uint32_t val = tegra_fc_read_32(FLOW_CTLR_FLOW_DBG_QUAL);
/* clear the bit to pass FIQs to the GICD */
tegra_fc_write_32(FLOW_CTLR_FLOW_DBG_QUAL, val & ~FLOWCTRL_FIQ2CCPLEX_ENABLE);
}
@@ -0,0 +1,188 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <errno.h>
#include <gpcdma.h>
#include <lib/mmio.h>
#include <lib/utils_def.h>
#include <platform_def.h>
#include <stdbool.h>
#include <tegra_def.h>
/* DMA channel registers */
#define DMA_CH_CSR U(0x0)
#define DMA_CH_CSR_WEIGHT_SHIFT U(10)
#define DMA_CH_CSR_XFER_MODE_SHIFT U(21)
#define DMA_CH_CSR_DMA_MODE_MEM2MEM U(4)
#define DMA_CH_CSR_DMA_MODE_FIXEDPATTERN U(6)
#define DMA_CH_CSR_IRQ_MASK_ENABLE (U(1) << 15)
#define DMA_CH_CSR_RUN_ONCE (U(1) << 27)
#define DMA_CH_CSR_ENABLE (U(1) << 31)
#define DMA_CH_STAT U(0x4)
#define DMA_CH_STAT_BUSY (U(1) << 31)
#define DMA_CH_SRC_PTR U(0xC)
#define DMA_CH_DST_PTR U(0x10)
#define DMA_CH_HI_ADR_PTR U(0x14)
#define DMA_CH_HI_ADR_PTR_SRC_MASK U(0xFF)
#define DMA_CH_HI_ADR_PTR_DST_SHIFT U(16)
#define DMA_CH_HI_ADR_PTR_DST_MASK U(0xFF)
#define DMA_CH_MC_SEQ U(0x18)
#define DMA_CH_MC_SEQ_REQ_CNT_SHIFT U(25)
#define DMA_CH_MC_SEQ_REQ_CNT_VAL U(0x10)
#define DMA_CH_MC_SEQ_BURST_SHIFT U(23)
#define DMA_CH_MC_SEQ_BURST_16_WORDS U(0x3)
#define DMA_CH_WORD_COUNT U(0x20)
#define DMA_CH_FIXED_PATTERN U(0x34)
#define DMA_CH_TZ U(0x38)
#define DMA_CH_TZ_ACCESS_ENABLE U(0)
#define DMA_CH_TZ_ACCESS_DISABLE U(3)
#define MAX_TRANSFER_SIZE (1U*1024U*1024U*1024U) /* 1GB */
#define GPCDMA_TIMEOUT_MS U(100)
#define GPCDMA_RESET_BIT (U(1) << 1)
static bool init_done;
static void tegra_gpcdma_write32(uint32_t offset, uint32_t val)
{
mmio_write_32(TEGRA_GPCDMA_BASE + offset, val);
}
static uint32_t tegra_gpcdma_read32(uint32_t offset)
{
return mmio_read_32(TEGRA_GPCDMA_BASE + offset);
}
static void tegra_gpcdma_init(void)
{
/* assert reset for DMA engine */
mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_GPCDMA_RST_SET_REG_OFFSET,
GPCDMA_RESET_BIT);
udelay(2);
/* de-assert reset for DMA engine */
mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_GPCDMA_RST_CLR_REG_OFFSET,
GPCDMA_RESET_BIT);
}
static void tegra_gpcdma_memcpy_priv(uint64_t dst_addr, uint64_t src_addr,
uint32_t num_bytes, uint32_t mode)
{
uint32_t val, timeout = 0;
int32_t ret = 0;
/* sanity check byte count */
if ((num_bytes > MAX_TRANSFER_SIZE) || ((num_bytes & 0x3U) != U(0))) {
ret = -EINVAL;
}
/* initialise GPCDMA block */
if (!init_done) {
tegra_gpcdma_init();
init_done = true;
}
/* make sure channel isn't busy */
val = tegra_gpcdma_read32(DMA_CH_STAT);
if ((val & DMA_CH_STAT_BUSY) == DMA_CH_STAT_BUSY) {
ERROR("DMA channel is busy\n");
ret = -EBUSY;
}
if (ret == 0) {
/* disable any DMA transfers */
tegra_gpcdma_write32(DMA_CH_CSR, 0);
/* enable DMA access to TZDRAM */
tegra_gpcdma_write32(DMA_CH_TZ, DMA_CH_TZ_ACCESS_ENABLE);
/* configure MC sequencer */
val = (DMA_CH_MC_SEQ_REQ_CNT_VAL << DMA_CH_MC_SEQ_REQ_CNT_SHIFT) |
(DMA_CH_MC_SEQ_BURST_16_WORDS << DMA_CH_MC_SEQ_BURST_SHIFT);
tegra_gpcdma_write32(DMA_CH_MC_SEQ, val);
/* reset fixed pattern */
tegra_gpcdma_write32(DMA_CH_FIXED_PATTERN, 0);
/* populate src and dst address registers */
tegra_gpcdma_write32(DMA_CH_SRC_PTR, (uint32_t)src_addr);
tegra_gpcdma_write32(DMA_CH_DST_PTR, (uint32_t)dst_addr);
val = (uint32_t)((src_addr >> 32) & DMA_CH_HI_ADR_PTR_SRC_MASK);
val |= (uint32_t)(((dst_addr >> 32) & DMA_CH_HI_ADR_PTR_DST_MASK) <<
DMA_CH_HI_ADR_PTR_DST_SHIFT);
tegra_gpcdma_write32(DMA_CH_HI_ADR_PTR, val);
/* transfer size (in words) */
tegra_gpcdma_write32(DMA_CH_WORD_COUNT, ((num_bytes >> 2) - 1U));
/* populate value for CSR */
val = (mode << DMA_CH_CSR_XFER_MODE_SHIFT) |
DMA_CH_CSR_RUN_ONCE | (U(1) << DMA_CH_CSR_WEIGHT_SHIFT) |
DMA_CH_CSR_IRQ_MASK_ENABLE;
tegra_gpcdma_write32(DMA_CH_CSR, val);
/* enable transfer */
val = tegra_gpcdma_read32(DMA_CH_CSR);
val |= DMA_CH_CSR_ENABLE;
tegra_gpcdma_write32(DMA_CH_CSR, val);
/* wait till transfer completes */
do {
/* read the status */
val = tegra_gpcdma_read32(DMA_CH_STAT);
if ((val & DMA_CH_STAT_BUSY) != DMA_CH_STAT_BUSY) {
break;
}
mdelay(1);
timeout++;
} while (timeout < GPCDMA_TIMEOUT_MS);
/* flag timeout error */
if (timeout == GPCDMA_TIMEOUT_MS) {
ERROR("DMA transfer timed out\n");
}
dsbsy();
/* disable DMA access to TZDRAM */
tegra_gpcdma_write32(DMA_CH_TZ, DMA_CH_TZ_ACCESS_DISABLE);
isb();
}
}
/*******************************************************************************
* Memcpy using GPCDMA block (Mem2Mem copy)
******************************************************************************/
void tegra_gpcdma_memcpy(uint64_t dst_addr, uint64_t src_addr,
uint32_t num_bytes)
{
tegra_gpcdma_memcpy_priv(dst_addr, src_addr, num_bytes,
DMA_CH_CSR_DMA_MODE_MEM2MEM);
}
/*******************************************************************************
* Memset using GPCDMA block (Fixed pattern write)
******************************************************************************/
void tegra_gpcdma_zeromem(uint64_t dst_addr, uint32_t num_bytes)
{
tegra_gpcdma_memcpy_priv(dst_addr, 0, num_bytes,
DMA_CH_CSR_DMA_MODE_FIXEDPATTERN);
}
@@ -0,0 +1,212 @@
/*
* Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2020, NVIDIA Corporation. 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/mmio.h>
#include <lib/utils.h>
#include <lib/xlat_tables/xlat_tables_v2.h>
#include <memctrl.h>
#include <memctrl_v1.h>
#include <tegra_def.h>
/* Video Memory base and size (live values) */
static uint64_t video_mem_base;
static uint64_t video_mem_size;
/*
* Init SMMU.
*/
void tegra_memctrl_setup(void)
{
/*
* Setup the Memory controller to allow only secure accesses to
* the TZDRAM carveout
*/
INFO("Tegra Memory Controller (v1)\n");
/* allow translations for all MC engines */
tegra_mc_write_32(MC_SMMU_TRANSLATION_ENABLE_0_0,
(unsigned int)MC_SMMU_TRANSLATION_ENABLE);
tegra_mc_write_32(MC_SMMU_TRANSLATION_ENABLE_1_0,
(unsigned int)MC_SMMU_TRANSLATION_ENABLE);
tegra_mc_write_32(MC_SMMU_TRANSLATION_ENABLE_2_0,
(unsigned int)MC_SMMU_TRANSLATION_ENABLE);
tegra_mc_write_32(MC_SMMU_TRANSLATION_ENABLE_3_0,
(unsigned int)MC_SMMU_TRANSLATION_ENABLE);
tegra_mc_write_32(MC_SMMU_TRANSLATION_ENABLE_4_0,
(unsigned int)MC_SMMU_TRANSLATION_ENABLE);
tegra_mc_write_32(MC_SMMU_ASID_SECURITY_0, MC_SMMU_ASID_SECURITY);
tegra_mc_write_32(MC_SMMU_TLB_CONFIG_0, MC_SMMU_TLB_CONFIG_0_RESET_VAL);
tegra_mc_write_32(MC_SMMU_PTC_CONFIG_0, MC_SMMU_PTC_CONFIG_0_RESET_VAL);
/* flush PTC and TLB */
tegra_mc_write_32(MC_SMMU_PTC_FLUSH_0, MC_SMMU_PTC_FLUSH_ALL);
(void)tegra_mc_read_32(MC_SMMU_CONFIG_0); /* read to flush writes */
tegra_mc_write_32(MC_SMMU_TLB_FLUSH_0, MC_SMMU_TLB_FLUSH_ALL);
/* enable SMMU */
tegra_mc_write_32(MC_SMMU_CONFIG_0,
MC_SMMU_CONFIG_0_SMMU_ENABLE_ENABLE);
(void)tegra_mc_read_32(MC_SMMU_CONFIG_0); /* read to flush writes */
/* video memory carveout */
tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_HI,
(uint32_t)(video_mem_base >> 32));
tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_LO, (uint32_t)video_mem_base);
tegra_mc_write_32(MC_VIDEO_PROTECT_SIZE_MB, video_mem_size);
}
/*
* Restore Memory Controller settings after "System Suspend"
*/
void tegra_memctrl_restore_settings(void)
{
tegra_memctrl_setup();
}
/*
* Secure the BL31 DRAM aperture.
*
* phys_base = physical base of TZDRAM aperture
* size_in_bytes = size of aperture in bytes
*/
void tegra_memctrl_tzdram_setup(uint64_t phys_base, uint32_t size_in_bytes)
{
/*
* Setup the Memory controller to allow only secure accesses to
* the TZDRAM carveout
*/
INFO("Configuring TrustZone DRAM Memory Carveout\n");
tegra_mc_write_32(MC_SECURITY_CFG0_0, phys_base);
tegra_mc_write_32(MC_SECURITY_CFG1_0, size_in_bytes >> 20);
}
static void tegra_clear_videomem(uintptr_t non_overlap_area_start,
unsigned long long non_overlap_area_size)
{
int ret;
/*
* Map the NS memory first, clean it and then unmap it.
*/
ret = mmap_add_dynamic_region(non_overlap_area_start, /* PA */
non_overlap_area_start, /* VA */
non_overlap_area_size, /* size */
MT_NS | MT_RW | MT_EXECUTE_NEVER |
MT_NON_CACHEABLE); /* attrs */
assert(ret == 0);
zeromem((void *)non_overlap_area_start, non_overlap_area_size);
flush_dcache_range(non_overlap_area_start, non_overlap_area_size);
mmap_remove_dynamic_region(non_overlap_area_start,
non_overlap_area_size);
}
/*
* Program the Video Memory carveout region
*
* phys_base = physical base of aperture
* size_in_bytes = size of aperture in bytes
*/
void tegra_memctrl_videomem_setup(uint64_t phys_base, uint32_t size_in_bytes)
{
uintptr_t vmem_end_old = video_mem_base + (video_mem_size << 20);
uintptr_t vmem_end_new = phys_base + size_in_bytes;
unsigned long long non_overlap_area_size;
/*
* Setup the Memory controller to restrict CPU accesses to the Video
* Memory region
*/
INFO("Configuring Video Memory Carveout\n");
/*
* Configure Memory Controller directly for the first time.
*/
if (video_mem_base == 0)
goto done;
/*
* Clear the old regions now being exposed. The following cases
* can occur -
*
* 1. clear whole old region (no overlap with new region)
* 2. clear old sub-region below new base
* 3. clear old sub-region above new end
*/
INFO("Cleaning previous Video Memory Carveout\n");
if (phys_base > vmem_end_old || video_mem_base > vmem_end_new) {
tegra_clear_videomem(video_mem_base, video_mem_size << 20);
} else {
if (video_mem_base < phys_base) {
non_overlap_area_size = phys_base - video_mem_base;
tegra_clear_videomem(video_mem_base, non_overlap_area_size);
}
if (vmem_end_old > vmem_end_new) {
non_overlap_area_size = vmem_end_old - vmem_end_new;
tegra_clear_videomem(vmem_end_new, non_overlap_area_size);
}
}
done:
tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_HI, (uint32_t)(phys_base >> 32));
tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_LO, (uint32_t)phys_base);
tegra_mc_write_32(MC_VIDEO_PROTECT_SIZE_MB, size_in_bytes >> 20);
/* store new values */
video_mem_base = phys_base;
video_mem_size = size_in_bytes >> 20;
}
/*
* During boot, USB3 and flash media (SDMMC/SATA) devices need access to
* IRAM. Because these clients connect to the MC and do not have a direct
* path to the IRAM, the MC implements AHB redirection during boot to allow
* path to IRAM. In this mode, accesses to a programmed memory address aperture
* are directed to the AHB bus, allowing access to the IRAM. The AHB aperture
* is defined by the IRAM_BASE_LO and IRAM_BASE_HI registers, which are
* initialized to disable this aperture.
*
* Once bootup is complete, we must program IRAM base to 0xffffffff and
* IRAM top to 0x00000000, thus disabling access to IRAM. DRAM is then
* potentially accessible in this address range. These aperture registers
* also have an access_control/lock bit. After disabling the aperture, the
* access_control register should be programmed to lock the registers.
*/
void tegra_memctrl_disable_ahb_redirection(void)
{
/* program the aperture registers */
tegra_mc_write_32(MC_IRAM_BASE_LO, 0xFFFFFFFF);
tegra_mc_write_32(MC_IRAM_TOP_LO, 0);
tegra_mc_write_32(MC_IRAM_BASE_TOP_HI, 0);
/* lock the aperture registers */
tegra_mc_write_32(MC_IRAM_REG_CTRL, MC_DISABLE_IRAM_CFG_WRITES);
}
void tegra_memctrl_clear_pending_interrupts(void)
{
uint32_t mcerr;
/* check if there are any pending interrupts */
mcerr = mmio_read_32(TEGRA_MC_BASE + MC_INTSTATUS);
if (mcerr != (uint32_t)0U) { /* should not see error here */
WARN("MC_INTSTATUS = 0x%x (should be zero)\n", mcerr);
mmio_write_32((TEGRA_MC_BASE + MC_INTSTATUS), mcerr);
}
}
@@ -0,0 +1,354 @@
/*
* Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2019-2020, NVIDIA Corporation. 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 <lib/mmio.h>
#include <lib/utils.h>
#include <lib/xlat_tables/xlat_tables_v2.h>
#include <mce.h>
#include <memctrl.h>
#include <memctrl_v2.h>
#include <smmu.h>
#include <tegra_def.h>
#include <tegra_platform.h>
#include <tegra_private.h>
/* Video Memory base and size (live values) */
static uint64_t video_mem_base;
static uint64_t video_mem_size_mb;
/*
* Init Memory controller during boot.
*/
void tegra_memctrl_setup(void)
{
INFO("Tegra Memory Controller (v2)\n");
/* Initialize the System memory management unit */
tegra_smmu_init();
/* allow platforms to program custom memory controller settings */
plat_memctrl_setup();
/*
* All requests at boot time, and certain requests during
* normal run time, are physically addressed and must bypass
* the SMMU. The client hub logic implements a hardware bypass
* path around the Translation Buffer Units (TBU). During
* boot-time, the SMMU_BYPASS_CTRL register (which defaults to
* TBU_BYPASS mode) will be used to steer all requests around
* the uninitialized TBUs. During normal operation, this register
* is locked into TBU_BYPASS_SID config, which routes requests
* with special StreamID 0x7f on the bypass path and all others
* through the selected TBU. This is done to disable SMMU Bypass
* mode, as it could be used to circumvent SMMU security checks.
*/
tegra_mc_write_32(MC_SMMU_BYPASS_CONFIG,
MC_SMMU_BYPASS_CONFIG_SETTINGS);
}
/*
* Restore Memory Controller settings after "System Suspend"
*/
void tegra_memctrl_restore_settings(void)
{
/* restore platform's memory controller settings */
plat_memctrl_restore();
/* video memory carveout region */
if (video_mem_base != 0ULL) {
tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_LO,
(uint32_t)video_mem_base);
assert(tegra_mc_read_32(MC_VIDEO_PROTECT_BASE_LO)
== (uint32_t)video_mem_base);
tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_HI,
(uint32_t)(video_mem_base >> 32));
assert(tegra_mc_read_32(MC_VIDEO_PROTECT_BASE_HI)
== (uint32_t)(video_mem_base >> 32));
tegra_mc_write_32(MC_VIDEO_PROTECT_SIZE_MB,
(uint32_t)video_mem_size_mb);
assert(tegra_mc_read_32(MC_VIDEO_PROTECT_SIZE_MB)
== (uint32_t)video_mem_size_mb);
/*
* MCE propagates the VideoMem configuration values across the
* CCPLEX.
*/
mce_update_gsc_videomem();
}
}
/*
* Secure the BL31 DRAM aperture.
*
* phys_base = physical base of TZDRAM aperture
* size_in_bytes = size of aperture in bytes
*/
void tegra_memctrl_tzdram_setup(uint64_t phys_base, uint32_t size_in_bytes)
{
/*
* Perform platform specific steps.
*/
plat_memctrl_tzdram_setup(phys_base, size_in_bytes);
}
/*
* Secure the BL31 TZRAM aperture.
*
* phys_base = physical base of TZRAM aperture
* size_in_bytes = size of aperture in bytes
*/
void tegra_memctrl_tzram_setup(uint64_t phys_base, uint32_t size_in_bytes)
{
; /* do nothing */
}
/*
* Save MC settings before "System Suspend" to TZDRAM
*/
void tegra_mc_save_context(uint64_t mc_ctx_addr)
{
uint32_t i, num_entries = 0;
mc_regs_t *mc_ctx_regs;
const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
uint64_t tzdram_base = params_from_bl2->tzdram_base;
uint64_t tzdram_end = tzdram_base + params_from_bl2->tzdram_size;
assert((mc_ctx_addr >= tzdram_base) && (mc_ctx_addr <= tzdram_end));
/* get MC context table */
mc_ctx_regs = plat_memctrl_get_sys_suspend_ctx();
assert(mc_ctx_regs != NULL);
/*
* mc_ctx_regs[0].val contains the size of the context table minus
* the last entry. Sanity check the table size before we start with
* the context save operation.
*/
while (mc_ctx_regs[num_entries].reg != 0xFFFFFFFFU) {
num_entries++;
}
/* panic if the sizes do not match */
if (num_entries != mc_ctx_regs[0].val) {
ERROR("MC context size mismatch!");
panic();
}
/* save MC register values */
for (i = 1U; i < num_entries; i++) {
mc_ctx_regs[i].val = mmio_read_32(mc_ctx_regs[i].reg);
}
/* increment by 1 to take care of the last entry */
num_entries++;
/* Save MC config settings */
(void)memcpy((void *)mc_ctx_addr, mc_ctx_regs,
sizeof(mc_regs_t) * num_entries);
/* save the MC table address */
mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_MC_TABLE_ADDR_LO,
(uint32_t)mc_ctx_addr);
assert(mmio_read_32(TEGRA_SCRATCH_BASE + SCRATCH_MC_TABLE_ADDR_LO)
== (uint32_t)mc_ctx_addr);
mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_MC_TABLE_ADDR_HI,
(uint32_t)(mc_ctx_addr >> 32));
assert(mmio_read_32(TEGRA_SCRATCH_BASE + SCRATCH_MC_TABLE_ADDR_HI)
== (uint32_t)(mc_ctx_addr >> 32));
}
static void tegra_lock_videomem_nonoverlap(uint64_t phys_base,
uint64_t size_in_bytes)
{
uint32_t index;
uint64_t total_128kb_blocks = size_in_bytes >> 17;
uint64_t residual_4kb_blocks = (size_in_bytes & (uint32_t)0x1FFFF) >> 12;
uint64_t val;
/*
* Reset the access configuration registers to restrict access to
* old Videomem aperture
*/
for (index = MC_VIDEO_PROTECT_CLEAR_ACCESS_CFG0;
index < ((uint32_t)MC_VIDEO_PROTECT_CLEAR_ACCESS_CFG0 + (uint32_t)MC_GSC_CONFIG_REGS_SIZE);
index += 4U) {
tegra_mc_write_32(index, 0);
}
/*
* Set the base. It must be 4k aligned, at least.
*/
assert((phys_base & (uint64_t)0xFFF) == 0U);
tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_BASE_LO, (uint32_t)phys_base);
tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_BASE_HI,
(uint32_t)(phys_base >> 32) & (uint32_t)MC_GSC_BASE_HI_MASK);
/*
* Set the aperture size
*
* total size = (number of 128KB blocks) + (number of remaining 4KB
* blocks)
*
*/
val = (uint32_t)((residual_4kb_blocks << MC_GSC_SIZE_RANGE_4KB_SHIFT) |
total_128kb_blocks);
tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_SIZE, (uint32_t)val);
/*
* Lock the configuration settings by enabling TZ-only lock and
* locking the configuration against any future changes from NS
* world.
*/
tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_CFG,
(uint32_t)MC_GSC_ENABLE_TZ_LOCK_BIT);
/*
* MCE propagates the GSC configuration values across the
* CCPLEX.
*/
}
static void tegra_unlock_videomem_nonoverlap(void)
{
/* Clear the base */
tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_BASE_LO, 0);
tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_BASE_HI, 0);
/* Clear the size */
tegra_mc_write_32(MC_VIDEO_PROTECT_CLEAR_SIZE, 0);
}
static void tegra_clear_videomem(uintptr_t non_overlap_area_start,
unsigned long long non_overlap_area_size)
{
int ret;
INFO("Cleaning previous Video Memory Carveout\n");
/*
* Map the NS memory first, clean it and then unmap it.
*/
ret = mmap_add_dynamic_region(non_overlap_area_start, /* PA */
non_overlap_area_start, /* VA */
non_overlap_area_size, /* size */
MT_DEVICE | MT_RW | MT_NS); /* attrs */
assert(ret == 0);
zeromem((void *)non_overlap_area_start, non_overlap_area_size);
flush_dcache_range(non_overlap_area_start, non_overlap_area_size);
ret = mmap_remove_dynamic_region(non_overlap_area_start,
non_overlap_area_size);
assert(ret == 0);
}
static void tegra_clear_videomem_nonoverlap(uintptr_t phys_base,
unsigned long size_in_bytes)
{
uintptr_t vmem_end_old = video_mem_base + (video_mem_size_mb << 20);
uintptr_t vmem_end_new = phys_base + size_in_bytes;
unsigned long long non_overlap_area_size;
/*
* Clear the old regions now being exposed. The following cases
* can occur -
*
* 1. clear whole old region (no overlap with new region)
* 2. clear old sub-region below new base
* 3. clear old sub-region above new end
*/
if ((phys_base > vmem_end_old) || (video_mem_base > vmem_end_new)) {
tegra_clear_videomem(video_mem_base,
video_mem_size_mb << 20U);
} else {
if (video_mem_base < phys_base) {
non_overlap_area_size = phys_base - video_mem_base;
tegra_clear_videomem(video_mem_base, non_overlap_area_size);
}
if (vmem_end_old > vmem_end_new) {
non_overlap_area_size = vmem_end_old - vmem_end_new;
tegra_clear_videomem(vmem_end_new, non_overlap_area_size);
}
}
}
/*
* Program the Video Memory carveout region
*
* phys_base = physical base of aperture
* size_in_bytes = size of aperture in bytes
*/
void tegra_memctrl_videomem_setup(uint64_t phys_base, uint32_t size_in_bytes)
{
/*
* Setup the Memory controller to restrict CPU accesses to the Video
* Memory region
*/
INFO("Configuring Video Memory Carveout\n");
if (video_mem_base != 0U) {
/*
* Lock the non overlapping memory being cleared so that
* other masters do not accidently write to it. The memory
* would be unlocked once the non overlapping region is
* cleared and the new memory settings take effect.
*/
tegra_lock_videomem_nonoverlap(video_mem_base,
video_mem_size_mb << 20);
}
/* program the Videomem aperture */
tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_LO, (uint32_t)phys_base);
tegra_mc_write_32(MC_VIDEO_PROTECT_BASE_HI,
(uint32_t)(phys_base >> 32));
tegra_mc_write_32(MC_VIDEO_PROTECT_SIZE_MB, size_in_bytes >> 20);
/* Redundancy check for Video Protect setting */
assert(tegra_mc_read_32(MC_VIDEO_PROTECT_BASE_LO)
== (uint32_t)phys_base);
assert(tegra_mc_read_32(MC_VIDEO_PROTECT_BASE_HI)
== (uint32_t)(phys_base >> 32));
assert(tegra_mc_read_32(MC_VIDEO_PROTECT_SIZE_MB)
== (size_in_bytes >> 20));
/*
* MCE propagates the VideoMem configuration values across the
* CCPLEX.
*/
(void)mce_update_gsc_videomem();
/* Clear the non-overlapping memory */
if (video_mem_base != 0U) {
tegra_clear_videomem_nonoverlap(phys_base, size_in_bytes);
tegra_unlock_videomem_nonoverlap();
}
/* store new values */
video_mem_base = phys_base;
video_mem_size_mb = (uint64_t)size_in_bytes >> 20;
}
/*
* This feature exists only for v1 of the Tegra Memory Controller.
*/
void tegra_memctrl_disable_ahb_redirection(void)
{
; /* do nothing */
}
void tegra_memctrl_clear_pending_interrupts(void)
{
; /* do nothing */
}
@@ -0,0 +1,153 @@
/*
* Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <arch_helpers.h>
#include <common/debug.h>
#include <lib/mmio.h>
#include <pmc.h>
#include <tegra_def.h>
#define RESET_ENABLE 0x10U
/* Module IDs used during power ungate procedure */
static const uint32_t pmc_cpu_powergate_id[4] = {
14, /* CPU 0 */
9, /* CPU 1 */
10, /* CPU 2 */
11 /* CPU 3 */
};
/*******************************************************************************
* Power ungate CPU to start the boot process. CPU reset vectors must be
* populated before calling this function.
******************************************************************************/
void tegra_pmc_cpu_on(int32_t cpu)
{
uint32_t val;
/*
* Check if CPU is already power ungated
*/
val = tegra_pmc_read_32(PMC_PWRGATE_STATUS);
if ((val & (1U << pmc_cpu_powergate_id[cpu])) == 0U) {
/*
* The PMC deasserts the START bit when it starts the power
* ungate process. Loop till no power toggle is in progress.
*/
do {
val = tegra_pmc_read_32(PMC_PWRGATE_TOGGLE);
} while ((val & PMC_TOGGLE_START) != 0U);
/*
* Start the power ungate procedure
*/
val = pmc_cpu_powergate_id[cpu] | PMC_TOGGLE_START;
tegra_pmc_write_32(PMC_PWRGATE_TOGGLE, val);
/*
* The PMC deasserts the START bit when it starts the power
* ungate process. Loop till powergate START bit is asserted.
*/
do {
val = tegra_pmc_read_32(PMC_PWRGATE_TOGGLE);
} while ((val & (1U << 8)) != 0U);
/* loop till the CPU is power ungated */
do {
val = tegra_pmc_read_32(PMC_PWRGATE_STATUS);
} while ((val & (1U << pmc_cpu_powergate_id[cpu])) == 0U);
}
}
/*******************************************************************************
* Setup CPU vectors for resume from deep sleep
******************************************************************************/
void tegra_pmc_cpu_setup(uint64_t reset_addr)
{
uint32_t val;
tegra_pmc_write_32(PMC_SECURE_SCRATCH34,
((uint32_t)reset_addr & 0xFFFFFFFFU) | 1U);
val = (uint32_t)(reset_addr >> 32U);
tegra_pmc_write_32(PMC_SECURE_SCRATCH35, val & 0x7FFU);
}
/*******************************************************************************
* Lock CPU vectors to restrict further writes
******************************************************************************/
void tegra_pmc_lock_cpu_vectors(void)
{
uint32_t val;
/* lock PMC_SECURE_SCRATCH22 */
val = tegra_pmc_read_32(PMC_SECURE_DISABLE2);
val |= PMC_SECURE_DISABLE2_WRITE22_ON;
tegra_pmc_write_32(PMC_SECURE_DISABLE2, val);
/* lock PMC_SECURE_SCRATCH34/35 */
val = tegra_pmc_read_32(PMC_SECURE_DISABLE3);
val |= (PMC_SECURE_DISABLE3_WRITE34_ON |
PMC_SECURE_DISABLE3_WRITE35_ON);
tegra_pmc_write_32(PMC_SECURE_DISABLE3, val);
}
/*******************************************************************************
* Find out if this is the last standing CPU
******************************************************************************/
bool tegra_pmc_is_last_on_cpu(void)
{
int i, cpu = read_mpidr() & MPIDR_CPU_MASK;
uint32_t val = tegra_pmc_read_32(PMC_PWRGATE_STATUS);;
bool status = true;
/* check if this is the last standing CPU */
for (i = 0; i < PLATFORM_MAX_CPUS_PER_CLUSTER; i++) {
/* skip the current CPU */
if (i == cpu)
continue;
/* are other CPUs already power gated? */
if ((val & ((uint32_t)1 << pmc_cpu_powergate_id[i])) != 0U) {
status = false;
}
}
return status;
}
/*******************************************************************************
* Handler to be called on exiting System suspend. Right now only DPD registers
* are cleared.
******************************************************************************/
void tegra_pmc_resume(void)
{
/* Clear DPD sample */
mmio_write_32((TEGRA_PMC_BASE + PMC_IO_DPD_SAMPLE), 0x0);
/* Clear DPD Enable */
mmio_write_32((TEGRA_PMC_BASE + PMC_DPD_ENABLE_0), 0x0);
}
/*******************************************************************************
* Restart the system
******************************************************************************/
__dead2 void tegra_pmc_system_reset(void)
{
uint32_t reg;
reg = tegra_pmc_read_32(PMC_CONFIG);
reg |= RESET_ENABLE; /* restart */
tegra_pmc_write_32(PMC_CONFIG, reg);
wfi();
ERROR("Tegra System Reset: operation not handled.\n");
panic();
}
@@ -0,0 +1,121 @@
/*
* Copyright (c) 2016-2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <string.h>
#include <platform_def.h>
#include <common/bl_common.h>
#include <common/debug.h>
#include <smmu.h>
#include <tegra_platform.h>
#include <tegra_private.h>
extern void memcpy16(void *dest, const void *src, unsigned int length);
#define SMMU_NUM_CONTEXTS 64U
#define SMMU_CONTEXT_BANK_MAX_IDX 64U
#define MISMATCH_DETECTED 0x55AA55AAU
/*
* Init SMMU during boot or "System Suspend" exit
*/
void tegra_smmu_init(void)
{
uint32_t val, cb_idx, smmu_id, ctx_base;
uint32_t num_smmu_devices = plat_get_num_smmu_devices();
for (smmu_id = 0U; smmu_id < num_smmu_devices; smmu_id++) {
/* Program the SMMU pagesize and reset CACHE_LOCK bit */
val = tegra_smmu_read_32(smmu_id, SMMU_GSR0_SECURE_ACR);
val |= SMMU_GSR0_PGSIZE_64K;
val &= (uint32_t)~SMMU_ACR_CACHE_LOCK_ENABLE_BIT;
tegra_smmu_write_32(smmu_id, SMMU_GSR0_SECURE_ACR, val);
/* reset CACHE LOCK bit for NS Aux. Config. Register */
val = tegra_smmu_read_32(smmu_id, SMMU_GNSR_ACR);
val &= (uint32_t)~SMMU_ACR_CACHE_LOCK_ENABLE_BIT;
tegra_smmu_write_32(smmu_id, SMMU_GNSR_ACR, val);
/* disable TCU prefetch for all contexts */
ctx_base = (SMMU_GSR0_PGSIZE_64K * SMMU_NUM_CONTEXTS)
+ SMMU_CBn_ACTLR;
for (cb_idx = 0U; cb_idx < SMMU_CONTEXT_BANK_MAX_IDX; cb_idx++) {
val = tegra_smmu_read_32(smmu_id,
ctx_base + (SMMU_GSR0_PGSIZE_64K * cb_idx));
val &= (uint32_t)~SMMU_CBn_ACTLR_CPRE_BIT;
tegra_smmu_write_32(smmu_id, ctx_base +
(SMMU_GSR0_PGSIZE_64K * cb_idx), val);
}
/* set CACHE LOCK bit for NS Aux. Config. Register */
val = tegra_smmu_read_32(smmu_id, SMMU_GNSR_ACR);
val |= (uint32_t)SMMU_ACR_CACHE_LOCK_ENABLE_BIT;
tegra_smmu_write_32(smmu_id, SMMU_GNSR_ACR, val);
/* set CACHE LOCK bit for S Aux. Config. Register */
val = tegra_smmu_read_32(smmu_id, SMMU_GSR0_SECURE_ACR);
val |= (uint32_t)SMMU_ACR_CACHE_LOCK_ENABLE_BIT;
tegra_smmu_write_32(smmu_id, SMMU_GSR0_SECURE_ACR, val);
}
}
/*
* Verify SMMU settings have not been altered during boot
*/
void tegra_smmu_verify(void)
{
uint32_t cb_idx, ctx_base, smmu_id, val;
uint32_t num_smmu_devices = plat_get_num_smmu_devices();
uint32_t mismatch = 0U;
for (smmu_id = 0U; smmu_id < num_smmu_devices; smmu_id++) {
/* check PGSIZE_64K bit inr S Aux. Config. Register */
val = tegra_smmu_read_32(smmu_id, SMMU_GSR0_SECURE_ACR);
if (0U == (val & SMMU_GSR0_PGSIZE_64K)) {
ERROR("%s: PGSIZE_64K Mismatch - smmu_id=%d, GSR0_SECURE_ACR=%x\n",
__func__, smmu_id, val);
mismatch = MISMATCH_DETECTED;
}
/* check CACHE LOCK bit in S Aux. Config. Register */
if (0U == (val & SMMU_ACR_CACHE_LOCK_ENABLE_BIT)) {
ERROR("%s: CACHE_LOCK Mismatch - smmu_id=%d, GSR0_SECURE_ACR=%x\n",
__func__, smmu_id, val);
mismatch = MISMATCH_DETECTED;
}
/* check CACHE LOCK bit in NS Aux. Config. Register */
val = tegra_smmu_read_32(smmu_id, SMMU_GNSR_ACR);
if (0U == (val & SMMU_ACR_CACHE_LOCK_ENABLE_BIT)) {
ERROR("%s: Mismatch - smmu_id=%d, GNSR_ACR=%x\n",
__func__, smmu_id, val);
mismatch = MISMATCH_DETECTED;
}
/* verify TCU prefetch for all contexts is disabled */
ctx_base = (SMMU_GSR0_PGSIZE_64K * SMMU_NUM_CONTEXTS) +
SMMU_CBn_ACTLR;
for (cb_idx = 0U; cb_idx < SMMU_CONTEXT_BANK_MAX_IDX; cb_idx++) {
val = tegra_smmu_read_32(smmu_id,
ctx_base + (SMMU_GSR0_PGSIZE_64K * cb_idx));
if (0U != (val & SMMU_CBn_ACTLR_CPRE_BIT)) {
ERROR("%s: Mismatch - smmu_id=%d, cb_idx=%d, GSR0_PGSIZE_64K=%x\n",
__func__, smmu_id, cb_idx, val);
mismatch = MISMATCH_DETECTED;
}
}
}
/* Treat configuration mismatch as fatal */
if ((mismatch == MISMATCH_DETECTED) && tegra_platform_is_silicon()) {
panic();
}
}
@@ -0,0 +1,187 @@
/*
* Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <asm_macros.S>
#include <assert_macros.S>
#include <console_macros.S>
#define CONSOLE_NUM_BYTES_SHIFT 24
#define CONSOLE_FLUSH_DATA_TO_PORT (1 << 26)
#define CONSOLE_RING_DOORBELL (1 << 31)
#define CONSOLE_IS_BUSY (1 << 31)
#define CONSOLE_TIMEOUT 0xC000 /* 50 ms */
/*
* This file contains a driver implementation to make use of the
* real console implementation provided by the SPE firmware running
* SoCs after Tegra186.
*
* This console is shared by multiple components and the SPE firmware
* finally displays everything on the UART port.
*/
.globl console_spe_core_init
.globl console_spe_core_putc
.globl console_spe_core_getc
.globl console_spe_core_flush
.globl console_spe_putc
.globl console_spe_getc
.globl console_spe_flush
.globl console_spe_register
.macro check_if_console_is_ready base, tmp1, tmp2, label
/* wait until spe is ready or timeout expires */
mrs \tmp2, cntps_tval_el1
1: ldr \tmp1, [\base]
and \tmp1, \tmp1, #CONSOLE_IS_BUSY
cbz \tmp1, 2f
mrs \tmp1, cntps_tval_el1
sub \tmp1, \tmp2, \tmp1
cmp \tmp1, #CONSOLE_TIMEOUT
b.lt 1b
b \label
2:
.endm
/* -------------------------------------------------
* int console_spe_register(uintptr_t baseaddr,
* uint32_t clock, uint32_t baud,
* console_t *console);
* Function to initialize and register a new spe
* console. Storage passed in for the console struct
* *must* be persistent (i.e. not from the stack).
* In: x0 - UART register base address
* w1 - UART clock in Hz
* w2 - Baud rate
* x3 - pointer to empty console_t struct
* Out: return 1 on success, 0 on error
* Clobber list : x0, x1, x2, x6, x7, x14
* -------------------------------------------------
*/
func console_spe_register
/* Check the input base address */
cbz x0, register_fail
/* Dont use clock or baud rate, so ok to overwrite them */
check_if_console_is_ready x0, x1, x2, register_fail
cbz x3, register_fail
str x0, [x3, #CONSOLE_T_BASE]
mov x0, x3
finish_console_register spe putc=1, getc=1, flush=1
register_fail:
mov w0, wzr
ret
endfunc console_spe_register
/* --------------------------------------------------------
* int console_spe_core_putc(int c, uintptr_t base_addr)
* Function to output a character over the console. It
* returns the character printed on success or -1 on error.
* In : w0 - character to be printed
* x1 - console base address
* Out : return -1 on error else return character.
* Clobber list : x2, x3
* --------------------------------------------------------
*/
func console_spe_core_putc
/* Check the input parameter */
cbz x1, putc_error
/* Prepend '\r' to '\n' */
cmp w0, #0xA
b.ne not_eol
check_if_console_is_ready x1, x2, x3, putc_error
/* spe is ready */
mov w2, #0xD /* '\r' */
and w2, w2, #0xFF
mov w3, #(CONSOLE_RING_DOORBELL | (1 << CONSOLE_NUM_BYTES_SHIFT))
orr w2, w2, w3
str w2, [x1]
not_eol:
check_if_console_is_ready x1, x2, x3, putc_error
/* spe is ready */
mov w2, w0
and w2, w2, #0xFF
mov w3, #(CONSOLE_RING_DOORBELL | (1 << CONSOLE_NUM_BYTES_SHIFT))
orr w2, w2, w3
str w2, [x1]
ret
putc_error:
mov w0, #-1
ret
endfunc console_spe_core_putc
/* --------------------------------------------------------
* int console_spe_putc(int c, console_t *console)
* Function to output a character over the console. It
* returns the character printed on success or -1 on error.
* In : w0 - character to be printed
* x1 - pointer to console_t structure
* Out : return -1 on error else return character.
* Clobber list : x2
* --------------------------------------------------------
*/
func console_spe_putc
ldr x1, [x1, #CONSOLE_T_BASE]
b console_spe_core_putc
endfunc console_spe_putc
/* ---------------------------------------------
* int console_spe_getc(console_t *console)
* Function to get a character from the console.
* It returns the character grabbed on success
* or -1 if no character is available.
* In : x0 - pointer to console_t structure
* Out: w0 - character if available, else -1
* Clobber list : x0, x1
* ---------------------------------------------
*/
func console_spe_getc
mov w0, #-1
ret
endfunc console_spe_getc
/* -------------------------------------------------
* void console_spe_core_flush(uintptr_t base_addr)
* Function to force a write of all buffered
* data that hasn't been output.
* In : x0 - console base address
* Out : void.
* Clobber list : x0, x1
* -------------------------------------------------
*/
func console_spe_core_flush
#if ENABLE_ASSERTIONS
cmp x0, #0
ASM_ASSERT(ne)
#endif /* ENABLE_ASSERTIONS */
/* flush console */
mov w1, #(CONSOLE_RING_DOORBELL | CONSOLE_FLUSH_DATA_TO_PORT)
str w1, [x0]
ret
endfunc console_spe_core_flush
/* ---------------------------------------------
* void console_spe_flush(console_t *console)
* Function to force a write of all buffered
* data that hasn't been output.
* In : x0 - pointer to console_t structure
* Out : void.
* Clobber list : x0, x1
* ---------------------------------------------
*/
func console_spe_flush
ldr x0, [x0, #CONSOLE_T_BASE]
b console_spe_core_flush
endfunc console_spe_flush
@@ -0,0 +1,127 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef BPMP_H
#define BPMP_H
#include <stdint.h>
/* macro to enable clock to the Atomics block */
#define CAR_ENABLE_ATOMICS (1U << 16)
/* command to get the channel base addresses from bpmp */
#define ATOMIC_CMD_GET 4U
/* Hardware IRQ # used to signal bpmp of an incoming command */
#define INT_SHR_SEM_OUTBOX_FULL 6U
/* macros to decode the bpmp's state */
#define CH_MASK(ch) ((uint32_t)0x3 << ((ch) * 2U))
#define MA_FREE(ch) ((uint32_t)0x2 << ((ch) * 2U))
#define MA_ACKD(ch) ((uint32_t)0x3 << ((ch) * 2U))
/* response from bpmp to indicate it has powered up */
#define SIGN_OF_LIFE 0xAAAAAAAAU
/* flags to indicate bpmp driver's state */
#define BPMP_NOT_PRESENT 0xF00DBEEFU
#define BPMP_INIT_COMPLETE 0xBEEFF00DU
#define BPMP_INIT_PENDING 0xDEADBEEFU
#define BPMP_SUSPEND_ENTRY 0xF00DCAFEU
/* requests serviced by the bpmp */
#define MRQ_PING 0
#define MRQ_QUERY_TAG 1
#define MRQ_DO_IDLE 2
#define MRQ_TOLERATE_IDLE 3
#define MRQ_MODULE_LOAD 4
#define MRQ_MODULE_UNLOAD 5
#define MRQ_SWITCH_CLUSTER 6
#define MRQ_TRACE_MODIFY 7
#define MRQ_WRITE_TRACE 8
#define MRQ_THREADED_PING 9
#define MRQ_CPUIDLE_USAGE 10
#define MRQ_MODULE_MAIL 11
#define MRQ_SCX_ENABLE 12
#define MRQ_BPMPIDLE_USAGE 14
#define MRQ_HEAP_USAGE 15
#define MRQ_SCLK_SKIP_SET_RATE 16
#define MRQ_ENABLE_SUSPEND 17
#define MRQ_PASR_MASK 18
#define MRQ_DEBUGFS 19
#define MRQ_THERMAL 27
/* Tegra PM states as known to BPMP */
#define TEGRA_PM_CC1 9
#define TEGRA_PM_CC4 12
#define TEGRA_PM_CC6 14
#define TEGRA_PM_CC7 15
#define TEGRA_PM_SC1 17
#define TEGRA_PM_SC2 18
#define TEGRA_PM_SC3 19
#define TEGRA_PM_SC4 20
#define TEGRA_PM_SC7 23
/* flag to indicate if entry into a CCx power state is allowed */
#define BPMP_CCx_ALLOWED 0U
/* number of communication channels to interact with the bpmp */
#define NR_CHANNELS 4U
/* flag to ask bpmp to acknowledge command packet */
#define NO_ACK (0U << 0U)
#define DO_ACK (1U << 0U)
/* size of the command/response data */
#define MSG_DATA_MAX_SZ 120U
/**
* command/response packet to/from the bpmp
*
* command
* -------
* code: MRQ_* command
* flags: DO_ACK or NO_ACK
* data:
* [0] = cpu #
* [1] = cluster power state (TEGRA_PM_CCx)
* [2] = system power state (TEGRA_PM_SCx)
*
* response
* ---------
* code: error code
* flags: not used
* data:
* [0-3] = response value
*/
typedef struct mb_data {
int32_t code;
uint32_t flags;
uint8_t data[MSG_DATA_MAX_SZ];
} mb_data_t;
/**
* Function to initialise the interface with the bpmp
*/
int tegra_bpmp_init(void);
/**
* Function to suspend the interface with the bpmp
*/
void tegra_bpmp_suspend(void);
/**
* Function to resume the interface with the bpmp
*/
void tegra_bpmp_resume(void);
/**
* Handler to send a MRQ_* command to the bpmp
*/
int32_t tegra_bpmp_send_receive_atomic(int mrq, const void *ob_data, int ob_sz,
void *ib_data, int ib_sz);
#endif /* BPMP_H */
@@ -0,0 +1,43 @@
/*
* Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef BPMP_IPC_H
#define BPMP_IPC_H
#include <lib/utils_def.h>
#include <stdbool.h>
#include <stdint.h>
/**
* Currently supported reset identifiers
*/
#define TEGRA_RESET_ID_XUSB_PADCTL U(114)
#define TEGRA_RESET_ID_GPCDMA U(70)
/**
* Function to initialise the IPC with the bpmp
*/
int32_t tegra_bpmp_ipc_init(void);
/**
* Handler to reset a module
*/
int32_t tegra_bpmp_ipc_reset_module(uint32_t rst_id);
/**
* Handler to enable clock to a module. Only SE device is
* supported for now.
*/
int tegra_bpmp_ipc_enable_clock(uint32_t clk_id);
/**
* Handler to disable clock to a module. Only SE device is
* supported for now.
*/
int tegra_bpmp_ipc_disable_clock(uint32_t clk_id);
#endif /* BPMP_IPC_H */
@@ -0,0 +1,98 @@
/*
* Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef FLOWCTRL_H
#define FLOWCTRL_H
#include <lib/mmio.h>
#include <stdbool.h>
#include <tegra_def.h>
#define FLOWCTRL_HALT_CPU0_EVENTS (0x0U)
#define FLOWCTRL_WAITEVENT (2U << 29)
#define FLOWCTRL_WAIT_FOR_INTERRUPT (4U << 29)
#define FLOWCTRL_JTAG_RESUME (1U << 28)
#define FLOWCTRL_HALT_SCLK (1U << 27)
#define FLOWCTRL_HALT_LIC_IRQ (1U << 11)
#define FLOWCTRL_HALT_LIC_FIQ (1U << 10)
#define FLOWCTRL_HALT_GIC_IRQ (1U << 9)
#define FLOWCTRL_HALT_GIC_FIQ (1U << 8)
#define FLOWCTRL_HALT_BPMP_EVENTS (0x4U)
#define FLOWCTRL_CPU0_CSR (0x8U)
#define FLOWCTRL_CSR_HALT_MASK (1U << 22)
#define FLOWCTRL_CSR_PWR_OFF_STS (1U << 16)
#define FLOWCTRL_CSR_INTR_FLAG (1U << 15)
#define FLOWCTRL_CSR_EVENT_FLAG (1U << 14)
#define FLOWCTRL_CSR_IMMEDIATE_WAKE (1U << 3)
#define FLOWCTRL_CSR_ENABLE (1U << 0)
#define FLOWCTRL_HALT_CPU1_EVENTS (0x14U)
#define FLOWCTRL_CPU1_CSR (0x18U)
#define FLOW_CTLR_FLOW_DBG_QUAL (0x50U)
#define FLOWCTRL_FIQ2CCPLEX_ENABLE (1U << 28)
#define FLOWCTRL_FC_SEQ_INTERCEPT (0x5cU)
#define INTERCEPT_IRQ_PENDING (0xffU)
#define INTERCEPT_HVC (U(1) << 21)
#define INTERCEPT_ENTRY_CC4 (U(1) << 20)
#define INTERCEPT_ENTRY_PG_NONCPU (U(1) << 19)
#define INTERCEPT_EXIT_PG_NONCPU (U(1) << 18)
#define INTERCEPT_ENTRY_RG_CPU (U(1) << 17)
#define INTERCEPT_EXIT_RG_CPU (U(1) << 16)
#define INTERCEPT_ENTRY_PG_CORE0 (U(1) << 15)
#define INTERCEPT_EXIT_PG_CORE0 (U(1) << 14)
#define INTERCEPT_ENTRY_PG_CORE1 (U(1) << 13)
#define INTERCEPT_EXIT_PG_CORE1 (U(1) << 12)
#define INTERCEPT_ENTRY_PG_CORE2 (U(1) << 11)
#define INTERCEPT_EXIT_PG_CORE2 (U(1) << 10)
#define INTERCEPT_ENTRY_PG_CORE3 (U(1) << 9)
#define INTERCEPT_EXIT_PG_CORE3 (U(1) << 8)
#define INTERRUPT_PENDING_NONCPU (U(1) << 7)
#define INTERRUPT_PENDING_CRAIL (U(1) << 6)
#define INTERRUPT_PENDING_CORE0 (U(1) << 5)
#define INTERRUPT_PENDING_CORE1 (U(1) << 4)
#define INTERRUPT_PENDING_CORE2 (U(1) << 3)
#define INTERRUPT_PENDING_CORE3 (U(1) << 2)
#define CC4_INTERRUPT_PENDING (U(1) << 1)
#define HVC_INTERRUPT_PENDING (U(1) << 0)
#define FLOWCTRL_CC4_CORE0_CTRL (0x6cU)
#define FLOWCTRL_WAIT_WFI_BITMAP (0x100U)
#define FLOWCTRL_L2_FLUSH_CONTROL (0x94U)
#define FLOWCTRL_BPMP_CLUSTER_CONTROL (0x98U)
#define FLOWCTRL_BPMP_CLUSTER_PWRON_LOCK (1U << 2)
#define FLOWCTRL_ENABLE_EXT 12U
#define FLOWCTRL_ENABLE_EXT_MASK 3U
#define FLOWCTRL_PG_CPU_NONCPU 0x1U
#define FLOWCTRL_TURNOFF_CPURAIL 0x2U
static inline uint32_t tegra_fc_read_32(uint32_t off)
{
return mmio_read_32(TEGRA_FLOWCTRL_BASE + off);
}
static inline void tegra_fc_write_32(uint32_t off, uint32_t val)
{
mmio_write_32(TEGRA_FLOWCTRL_BASE + off, val);
}
void tegra_fc_bpmp_on(uint32_t entrypoint);
void tegra_fc_bpmp_off(void);
void tegra_fc_ccplex_pgexit_lock(void);
void tegra_fc_ccplex_pgexit_unlock(void);
void tegra_fc_cluster_idle(uint32_t midr);
void tegra_fc_cpu_powerdn(uint32_t mpidr);
void tegra_fc_cluster_powerdn(uint32_t midr);
void tegra_fc_cpu_on(int cpu);
void tegra_fc_cpu_off(int cpu);
void tegra_fc_disable_fiq_to_ccplex_routing(void);
void tegra_fc_enable_fiq_to_ccplex_routing(void);
bool tegra_fc_is_ccx_allowed(void);
void tegra_fc_lock_active_cluster(void);
void tegra_fc_soc_powerdn(uint32_t midr);
#endif /* FLOWCTRL_H */
@@ -0,0 +1,17 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef GPCDMA_H
#define GPCDMA_H
#include <stdint.h>
void tegra_gpcdma_memcpy(uint64_t dst_addr, uint64_t src_addr,
uint32_t num_bytes);
void tegra_gpcdma_zeromem(uint64_t dst_addr, uint32_t num_bytes);
#endif /* GPCDMA_H */
@@ -0,0 +1,76 @@
/*
* Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MCE_H
#define MCE_H
#include <lib/mmio.h>
#include <tegra_def.h>
/*******************************************************************************
* MCE commands
******************************************************************************/
typedef enum mce_cmd {
MCE_CMD_ENTER_CSTATE = 0U,
MCE_CMD_UPDATE_CSTATE_INFO = 1U,
MCE_CMD_UPDATE_CROSSOVER_TIME = 2U,
MCE_CMD_READ_CSTATE_STATS = 3U,
MCE_CMD_WRITE_CSTATE_STATS = 4U,
MCE_CMD_IS_SC7_ALLOWED = 5U,
MCE_CMD_ONLINE_CORE = 6U,
MCE_CMD_CC3_CTRL = 7U,
MCE_CMD_ECHO_DATA = 8U,
MCE_CMD_READ_VERSIONS = 9U,
MCE_CMD_ENUM_FEATURES = 10U,
MCE_CMD_ROC_FLUSH_CACHE_TRBITS = 11U,
MCE_CMD_ENUM_READ_MCA = 12U,
MCE_CMD_ENUM_WRITE_MCA = 13U,
MCE_CMD_ROC_FLUSH_CACHE = 14U,
MCE_CMD_ROC_CLEAN_CACHE = 15U,
MCE_CMD_ENABLE_LATIC = 16U,
MCE_CMD_UNCORE_PERFMON_REQ = 17U,
MCE_CMD_MISC_CCPLEX = 18U,
MCE_CMD_IS_CCX_ALLOWED = 0xFEU,
MCE_CMD_MAX = 0xFFU,
} mce_cmd_t;
#define MCE_CMD_MASK 0xFFU
/*******************************************************************************
* Timeout value used to powerdown a core
******************************************************************************/
#define MCE_CORE_SLEEP_TIME_INFINITE 0xFFFFFFFFU
/*******************************************************************************
* Struct to prepare UPDATE_CSTATE_INFO request
******************************************************************************/
typedef struct mce_cstate_info {
/* cluster cstate value */
uint32_t cluster;
/* ccplex cstate value */
uint32_t ccplex;
/* system cstate value */
uint32_t system;
/* force system state? */
uint8_t system_state_force;
/* wake mask value */
uint32_t wake_mask;
/* update the wake mask? */
uint8_t update_wake_mask;
} mce_cstate_info_t;
/* public interfaces */
int mce_command_handler(uint64_t cmd, uint64_t arg0, uint64_t arg1,
uint64_t arg2);
int mce_update_reset_vector(void);
int mce_update_gsc_videomem(void);
int mce_update_gsc_tzdram(void);
__dead2 void mce_enter_ccplex_state(uint32_t state_idx);
void mce_update_cstate_info(const mce_cstate_info_t *cstate);
void mce_verify_firmware_version(void);
#endif /* MCE_H */
@@ -0,0 +1,18 @@
/*
* Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MEMCTRL_H
#define MEMCTRL_H
void tegra_memctrl_setup(void);
void tegra_memctrl_restore_settings(void);
void tegra_memctrl_tzdram_setup(uint64_t phys_base, uint32_t size_in_bytes);
void tegra_memctrl_videomem_setup(uint64_t phys_base, uint32_t size_in_bytes);
void tegra_memctrl_disable_ahb_redirection(void);
void tegra_memctrl_clear_pending_interrupts(void);
#endif /* MEMCTRL_H */
@@ -0,0 +1,57 @@
/*
* Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MEMCTRL_V1_H
#define MEMCTRL_V1_H
#include <lib/mmio.h>
#include <tegra_def.h>
/* SMMU registers */
#define MC_SMMU_CONFIG_0 0x10U
#define MC_SMMU_CONFIG_0_SMMU_ENABLE_DISABLE 0U
#define MC_SMMU_CONFIG_0_SMMU_ENABLE_ENABLE 1U
#define MC_SMMU_TLB_CONFIG_0 0x14U
#define MC_SMMU_TLB_CONFIG_0_RESET_VAL 0x20000010U
#define MC_SMMU_PTC_CONFIG_0 0x18U
#define MC_SMMU_PTC_CONFIG_0_RESET_VAL 0x2000003fU
#define MC_SMMU_TLB_FLUSH_0 0x30U
#define TLB_FLUSH_VA_MATCH_ALL 0U
#define TLB_FLUSH_ASID_MATCH_DISABLE 0U
#define TLB_FLUSH_ASID_MATCH_SHIFT 31U
#define MC_SMMU_TLB_FLUSH_ALL \
(TLB_FLUSH_VA_MATCH_ALL | \
(TLB_FLUSH_ASID_MATCH_DISABLE << TLB_FLUSH_ASID_MATCH_SHIFT))
#define MC_SMMU_PTC_FLUSH_0 0x34U
#define MC_SMMU_PTC_FLUSH_ALL 0U
#define MC_SMMU_ASID_SECURITY_0 0x38U
#define MC_SMMU_ASID_SECURITY 0U
#define MC_SMMU_TRANSLATION_ENABLE_0_0 0x228U
#define MC_SMMU_TRANSLATION_ENABLE_1_0 0x22cU
#define MC_SMMU_TRANSLATION_ENABLE_2_0 0x230U
#define MC_SMMU_TRANSLATION_ENABLE_3_0 0x234U
#define MC_SMMU_TRANSLATION_ENABLE_4_0 0xb98U
#define MC_SMMU_TRANSLATION_ENABLE (~0)
/* MC IRAM aperture registers */
#define MC_IRAM_BASE_LO 0x65CU
#define MC_IRAM_TOP_LO 0x660U
#define MC_IRAM_BASE_TOP_HI 0x980U
#define MC_IRAM_REG_CTRL 0x964U
#define MC_DISABLE_IRAM_CFG_WRITES 1U
static inline uint32_t tegra_mc_read_32(uint32_t off)
{
return mmio_read_32(TEGRA_MC_BASE + off);
}
static inline void tegra_mc_write_32(uint32_t off, uint32_t val)
{
mmio_write_32(TEGRA_MC_BASE + off, val);
}
#endif /* MEMCTRL_V1_H */
@@ -0,0 +1,107 @@
/*
* Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MEMCTRL_V2_H
#define MEMCTRL_V2_H
#include <arch.h>
#include <tegra_def.h>
/*******************************************************************************
* Memory Controller SMMU Bypass config register
******************************************************************************/
#define MC_SMMU_BYPASS_CONFIG 0x1820U
#define MC_SMMU_BYPASS_CTRL_MASK 0x3U
#define MC_SMMU_BYPASS_CTRL_SHIFT 0U
#define MC_SMMU_CTRL_TBU_BYPASS_ALL (0U << MC_SMMU_BYPASS_CTRL_SHIFT)
#define MC_SMMU_CTRL_TBU_RSVD (1U << MC_SMMU_BYPASS_CTRL_SHIFT)
#define MC_SMMU_CTRL_TBU_BYPASS_SPL_STREAMID (2U << MC_SMMU_BYPASS_CTRL_SHIFT)
#define MC_SMMU_CTRL_TBU_BYPASS_NONE (3U << MC_SMMU_BYPASS_CTRL_SHIFT)
#define MC_SMMU_BYPASS_CONFIG_WRITE_ACCESS_BIT (1U << 31)
#define MC_SMMU_BYPASS_CONFIG_SETTINGS (MC_SMMU_BYPASS_CONFIG_WRITE_ACCESS_BIT | \
MC_SMMU_CTRL_TBU_BYPASS_SPL_STREAMID)
#ifndef __ASSEMBLER__
#include <assert.h>
typedef struct mc_regs {
uint32_t reg;
uint32_t val;
} mc_regs_t;
#define mc_smmu_bypass_cfg \
{ \
.reg = TEGRA_MC_BASE + MC_SMMU_BYPASS_CONFIG, \
.val = 0x00000000U, \
}
#define _START_OF_TABLE_ \
{ \
.reg = 0xCAFE05C7U, \
.val = 0x00000000U, \
}
#define _END_OF_TABLE_ \
{ \
.reg = 0xFFFFFFFFU, \
.val = 0xFFFFFFFFU, \
}
#endif /* __ASSEMBLER__ */
#ifndef __ASSEMBLER__
#include <lib/mmio.h>
static inline uint32_t tegra_mc_read_32(uint32_t off)
{
return mmio_read_32(TEGRA_MC_BASE + off);
}
static inline void tegra_mc_write_32(uint32_t off, uint32_t val)
{
mmio_write_32(TEGRA_MC_BASE + off, val);
}
#if defined(TEGRA_MC_STREAMID_BASE)
static inline uint32_t tegra_mc_streamid_read_32(uint32_t off)
{
return mmio_read_32(TEGRA_MC_STREAMID_BASE + off);
}
static inline void tegra_mc_streamid_write_32(uint32_t off, uint32_t val)
{
mmio_write_32(TEGRA_MC_STREAMID_BASE + off, val);
assert(mmio_read_32(TEGRA_MC_STREAMID_BASE + off) == val);
}
#endif
void plat_memctrl_setup(void);
void plat_memctrl_restore(void);
mc_regs_t *plat_memctrl_get_sys_suspend_ctx(void);
/*******************************************************************************
* Handler to save MC settings before "System Suspend" to TZDRAM
*
* Implemented by Tegra common memctrl_v2 driver under common/drivers/memctrl
******************************************************************************/
void tegra_mc_save_context(uint64_t mc_ctx_addr);
/*******************************************************************************
* Handler to program the scratch registers with TZDRAM settings for the
* resume firmware.
*
* Implemented by SoCs under tegra/soc/txxx
******************************************************************************/
void plat_memctrl_tzdram_setup(uint64_t phys_base, uint64_t size_in_bytes);
#endif /* __ASSEMBLER__ */
#endif /* MEMCTRL_V2_H */
@@ -0,0 +1,72 @@
/*
* Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef PMC_H
#define PMC_H
#include <lib/mmio.h>
#include <lib/utils_def.h>
#include <stdbool.h>
#include <tegra_def.h>
#define PMC_CONFIG U(0x0)
#define PMC_IO_DPD_SAMPLE U(0x20)
#define PMC_DPD_ENABLE_0 U(0x24)
#define PMC_PWRGATE_STATUS U(0x38)
#define PMC_PWRGATE_TOGGLE U(0x30)
#define PMC_SCRATCH1 U(0x54)
#define PMC_CRYPTO_OP_0 U(0xf4)
#define PMC_TOGGLE_START U(0x100)
#define PMC_SCRATCH31 U(0x118)
#define PMC_SCRATCH32 U(0x11C)
#define PMC_SCRATCH33 U(0x120)
#define PMC_SCRATCH39 U(0x138)
#define PMC_SCRATCH40 U(0x13C)
#define PMC_SCRATCH41 U(0x140)
#define PMC_SCRATCH42 U(0x144)
#define PMC_SCRATCH43 U(0x22C)
#define PMC_SCRATCH44 U(0x230)
#define PMC_SCRATCH45 U(0x234)
#define PMC_SCRATCH46 U(0x238)
#define PMC_SCRATCH47 U(0x23C)
#define PMC_SCRATCH48 U(0x240)
#define PMC_SCRATCH50 U(0x248)
#define PMC_SCRATCH51 U(0x24C)
#define PMC_TSC_MULT_0 U(0x2B4)
#define PMC_STICKY_BIT U(0x2C0)
#define PMC_SECURE_DISABLE2 U(0x2C4)
#define PMC_SECURE_DISABLE2_WRITE22_ON (U(1) << 28)
#define PMC_FUSE_CONTROL_0 U(0x450)
#define PMC_SECURE_DISABLE3 U(0x2D8)
#define PMC_SECURE_DISABLE3_WRITE34_ON (U(1) << 20)
#define PMC_SECURE_DISABLE3_WRITE35_ON (U(1) << 22)
#define PMC_SECURE_SCRATCH22 U(0x338)
#define PMC_SECURE_SCRATCH34 U(0x368)
#define PMC_SECURE_SCRATCH35 U(0x36c)
#define PMC_SCRATCH56 U(0x600)
#define PMC_SCRATCH57 U(0x604)
#define PMC_SCRATCH201 U(0x844)
static inline uint32_t tegra_pmc_read_32(uint32_t off)
{
return mmio_read_32(TEGRA_PMC_BASE + off);
}
static inline void tegra_pmc_write_32(uint32_t off, uint32_t val)
{
mmio_write_32(TEGRA_PMC_BASE + off, val);
}
void tegra_pmc_cpu_on(int32_t cpu);
void tegra_pmc_cpu_setup(uint64_t reset_addr);
bool tegra_pmc_is_last_on_cpu(void);
void tegra_pmc_lock_cpu_vectors(void);
void tegra_pmc_resume(void);
__dead2 void tegra_pmc_system_reset(void);
#endif /* PMC_H */
@@ -0,0 +1,60 @@
/*
* Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef SECURITY_ENGINE_H
#define SECURITY_ENGINE_H
/*******************************************************************************
* Structure definition
******************************************************************************/
/* Security Engine Linked List */
struct tegra_se_ll {
/* DMA buffer address */
uint32_t addr;
/* Data length in DMA buffer */
uint32_t data_len;
};
#define SE_LL_MAX_BUFFER_NUM 4
typedef struct tegra_se_io_lst {
volatile uint32_t last_buff_num;
volatile struct tegra_se_ll buffer[SE_LL_MAX_BUFFER_NUM];
} tegra_se_io_lst_t __attribute__((aligned(4)));
/* SE device structure */
typedef struct tegra_se_dev {
/* Security Engine ID */
const int se_num;
/* SE base address */
const uint64_t se_base;
/* SE context size in AES blocks */
const uint32_t ctx_size_blks;
/* pointer to source linked list buffer */
tegra_se_io_lst_t *src_ll_buf;
/* pointer to destination linked list buffer */
tegra_se_io_lst_t *dst_ll_buf;
/* LP context buffer pointer */
uint32_t *ctx_save_buf;
} tegra_se_dev_t;
/* PKA1 device structure */
typedef struct tegra_pka_dev {
/* PKA1 base address */
uint64_t pka_base;
} tegra_pka_dev_t;
/*******************************************************************************
* Public interface
******************************************************************************/
void tegra_se_init(void);
int tegra_se_suspend(void);
void tegra_se_resume(void);
int tegra_se_save_tzram(void);
int32_t tegra_se_save_sha256_hash(uint64_t bl31_base, uint32_t src_len_inbyte);
#endif /* SECURITY_ENGINE_H */
@@ -0,0 +1,92 @@
/*
* Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef SMMU_H
#define SMMU_H
#include <lib/mmio.h>
#include <memctrl_v2.h>
#include <tegra_def.h>
#define SMMU_CBn_ACTLR (0x4U)
/*******************************************************************************
* SMMU Global Secure Aux. Configuration Register
******************************************************************************/
#define SMMU_GSR0_SECURE_ACR 0x10U
#define SMMU_GNSR_ACR (SMMU_GSR0_SECURE_ACR + 0x400U)
#define SMMU_GSR0_PGSIZE_SHIFT 16U
#define SMMU_GSR0_PGSIZE_4K (0U << SMMU_GSR0_PGSIZE_SHIFT)
#define SMMU_GSR0_PGSIZE_64K (1U << SMMU_GSR0_PGSIZE_SHIFT)
#define SMMU_ACR_CACHE_LOCK_ENABLE_BIT (1ULL << 26U)
#define SMMU_GSR0_PER (0x20200U)
/*******************************************************************************
* SMMU Global Aux. Control Register
******************************************************************************/
#define SMMU_CBn_ACTLR_CPRE_BIT (1ULL << 1U)
/* SMMU IDs currently supported by the driver */
enum {
TEGRA_SMMU0 = 0U,
TEGRA_SMMU1 = 1U,
TEGRA_SMMU2 = 2U
};
static inline uint32_t tegra_smmu_read_32(uint32_t smmu_id, uint32_t off)
{
uint32_t ret = 0U;
#if defined(TEGRA_SMMU0_BASE)
if (smmu_id == TEGRA_SMMU0) {
ret = mmio_read_32(TEGRA_SMMU0_BASE + (uint64_t)off);
}
#endif
#if defined(TEGRA_SMMU1_BASE)
if (smmu_id == TEGRA_SMMU1) {
ret = mmio_read_32(TEGRA_SMMU1_BASE + (uint64_t)off);
}
#endif
#if defined(TEGRA_SMMU2_BASE)
if (smmu_id == TEGRA_SMMU2) {
ret = mmio_read_32(TEGRA_SMMU2_BASE + (uint64_t)off);
}
#endif
return ret;
}
static inline void tegra_smmu_write_32(uint32_t smmu_id,
uint32_t off, uint32_t val)
{
#if defined(TEGRA_SMMU0_BASE)
if (smmu_id == TEGRA_SMMU0) {
mmio_write_32(TEGRA_SMMU0_BASE + (uint64_t)off, val);
}
#endif
#if defined(TEGRA_SMMU1_BASE)
if (smmu_id == TEGRA_SMMU1) {
mmio_write_32(TEGRA_SMMU1_BASE + (uint64_t)off, val);
}
#endif
#if defined(TEGRA_SMMU2_BASE)
if (smmu_id == TEGRA_SMMU2) {
mmio_write_32(TEGRA_SMMU2_BASE + (uint64_t)off, val);
}
#endif
}
void tegra_smmu_init(void);
void tegra_smmu_verify(void);
uint32_t plat_get_num_smmu_devices(void);
#endif /* SMMU_H */
@@ -0,0 +1,23 @@
/*
* Copyright (c) 2019, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef SPE_H
#define SPE_H
#include <stdint.h>
#include <drivers/console.h>
/*
* Initialize a new spe console instance and register it with the console
* framework. The |console| pointer must point to storage that will be valid
* for the lifetime of the console, such as a global or static local variable.
* Its contents will be reinitialized from scratch.
*/
int console_spe_register(uintptr_t baseaddr, uint32_t clock, uint32_t baud,
console_t *console);
#endif /* SPE_H */
@@ -0,0 +1,30 @@
/*
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef TEGRA_GIC_H
#define TEGRA_GIC_H
#include <common/interrupt_props.h>
/*******************************************************************************
* Per-CPU struct describing FIQ state to be stored
******************************************************************************/
typedef struct pcpu_fiq_state {
uint64_t elr_el3;
uint64_t spsr_el3;
} pcpu_fiq_state_t;
/*******************************************************************************
* Fucntion declarations
******************************************************************************/
void tegra_gic_cpuif_deactivate(void);
void tegra_gic_init(void);
void tegra_gic_pcpu_init(void);
void tegra_gic_setup(const interrupt_prop_t *interrupt_props,
unsigned int interrupt_props_num);
#endif /* TEGRA_GIC_H */
@@ -0,0 +1,20 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef PROFILER_H
#define PROFILER_H
/*******************************************************************************
* Number of bytes of memory used by the profiler on Tegra
******************************************************************************/
#define PROFILER_SIZE_BYTES U(0x1000)
void boot_profiler_init(uint64_t shmem_base, uint32_t tmr_base);
void boot_profiler_add_record(const char *str);
void boot_profiler_deinit(void);
#endif /* PROFILER_H */
@@ -0,0 +1,63 @@
/*
* Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2015-2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef PLAT_MACROS_S
#define PLAT_MACROS_S
#include <drivers/arm/gicv2.h>
#include <tegra_def.h>
.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 macro prints out relevant GIC
* registers whenever an unhandled exception is
* taken in BL31.
* ---------------------------------------------
*/
.macro plat_crash_print_regs
#ifdef TEGRA_GICC_BASE
mov_imm x16, TEGRA_GICC_BASE
/* gicc base address is now in x16 */
adr x6, gicc_regs /* Load the gicc reg list to x6 */
/* Load the gicc regs to gp regs used by str_in_crash_buf_print */
ldr w8, [x16, #GICC_HPPIR]
ldr w9, [x16, #GICC_AHPPIR]
ldr w10, [x16, #GICC_CTLR]
/* Store to the crash buf and print to cosole */
bl str_in_crash_buf_print
#endif
/* Print the GICD_ISPENDR regs */
mov_imm x16, TEGRA_GICD_BASE
add x7, x16, #GICD_ISPENDR
adr x4, gicd_pend_reg
bl asm_print_str
2:
sub x4, x7, x16
cmp x4, #0x280
b.eq 1f
bl asm_print_hex
adr x4, spacer
bl asm_print_str
ldr w4, [x7], #4
bl asm_print_hex
adr x4, newline
bl asm_print_str
b 2b
1:
.endm
#endif /* PLAT_MACROS_S */
@@ -0,0 +1,132 @@
/*
* Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef PLATFORM_DEF_H
#define PLATFORM_DEF_H
#include <arch.h>
#include <lib/utils_def.h>
#include <tegra_def.h>
/*******************************************************************************
* Check and error if SEPARATE_CODE_AND_RODATA is not set to 1
******************************************************************************/
#if !SEPARATE_CODE_AND_RODATA
#error "SEPARATE_CODE_AND_RODATA should be set to 1"
#endif
/*
* Platform binary types for linking
*/
#define PLATFORM_LINKER_FORMAT "elf64-littleaarch64"
#define PLATFORM_LINKER_ARCH aarch64
/*
* Platform binary types for linking
*/
#define PLATFORM_LINKER_FORMAT "elf64-littleaarch64"
#define PLATFORM_LINKER_ARCH aarch64
/*******************************************************************************
* Generic platform constants
******************************************************************************/
/* Size of cacheable stacks */
#ifdef IMAGE_BL31
#define PLATFORM_STACK_SIZE U(0x400)
#endif
#define TEGRA_PRIMARY_CPU U(0x0)
#define PLAT_MAX_PWR_LVL MPIDR_AFFLVL2
#define PLATFORM_CORE_COUNT (PLATFORM_CLUSTER_COUNT * \
PLATFORM_MAX_CPUS_PER_CLUSTER)
#define PLAT_NUM_PWR_DOMAINS (PLATFORM_CORE_COUNT + \
PLATFORM_CLUSTER_COUNT + U(1))
/*******************************************************************************
* Platform console related constants
******************************************************************************/
#define TEGRA_CONSOLE_BAUDRATE U(115200)
#define TEGRA_BOOT_UART_CLK_13_MHZ U(13000000)
#define TEGRA_BOOT_UART_CLK_408_MHZ U(408000000)
/*******************************************************************************
* Platform memory map related constants
******************************************************************************/
/* Size of trusted dram */
#define TZDRAM_SIZE U(0x00400000)
#define TZDRAM_END (TZDRAM_BASE + TZDRAM_SIZE)
/*******************************************************************************
* BL31 specific defines.
******************************************************************************/
#define BL31_BASE TZDRAM_BASE
#define BL31_LIMIT (TZDRAM_BASE + BL31_SIZE - 1)
#define BL32_BASE (TZDRAM_BASE + BL31_SIZE)
#define BL32_LIMIT TZDRAM_END
/*******************************************************************************
* 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_SHIFT 6
#define CACHE_WRITEBACK_GRANULE (0x40) /* (U(1) << CACHE_WRITEBACK_SHIFT) */
/*******************************************************************************
* Dummy macros to compile io_storage support
******************************************************************************/
#define MAX_IO_DEVICES U(0)
#define MAX_IO_HANDLES U(0)
/*******************************************************************************
* Platforms macros to support SDEI
******************************************************************************/
#define TEGRA_SDEI_SGI_PRIVATE U(8)
/*******************************************************************************
* Platform macros to support exception handling framework
******************************************************************************/
#define PLAT_PRI_BITS U(3)
#define PLAT_RAS_PRI U(0x10)
#define PLAT_SDEI_CRITICAL_PRI U(0x20)
#define PLAT_SDEI_NORMAL_PRI U(0x30)
#define PLAT_TEGRA_WDT_PRIO U(0x40)
#define PLAT_EHF_DESC EHF_PRI_DESC(PLAT_PRI_BITS,\
PLAT_TEGRA_WDT_PRIO)
/*******************************************************************************
* SDEI events
******************************************************************************/
/* SDEI dynamic private event numbers */
#define TEGRA_SDEI_DP_EVENT_0 U(100)
#define TEGRA_SDEI_DP_EVENT_1 U(101)
#define TEGRA_SDEI_DP_EVENT_2 U(102)
/* SDEI dynamic shared event numbers */
#define TEGRA_SDEI_DS_EVENT_0 U(200)
#define TEGRA_SDEI_DS_EVENT_1 U(201)
#define TEGRA_SDEI_DS_EVENT_2 U(202)
/* SDEI explicit events */
#define TEGRA_SDEI_EP_EVENT_0 U(300)
#define TEGRA_SDEI_EP_EVENT_1 U(301)
#define TEGRA_SDEI_EP_EVENT_2 U(302)
#define TEGRA_SDEI_EP_EVENT_3 U(303)
#define TEGRA_SDEI_EP_EVENT_4 U(304)
#define TEGRA_SDEI_EP_EVENT_5 U(305)
#define TEGRA_SDEI_EP_EVENT_6 U(306)
#define TEGRA_SDEI_EP_EVENT_7 U(307)
#define TEGRA_SDEI_EP_EVENT_8 U(308)
#define TEGRA_SDEI_EP_EVENT_9 U(309)
#define TEGRA_SDEI_EP_EVENT_10 U(310)
#define TEGRA_SDEI_EP_EVENT_11 U(311)
#endif /* PLATFORM_DEF_H */
@@ -0,0 +1,12 @@
/*
* Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef TEGRA186_PRIVATE_H
#define TEGRA186_PRIVATE_H
uint64_t tegra186_get_mc_ctx_size(void);
#endif /* TEGRA186_PRIVATE_H */
@@ -0,0 +1,327 @@
/*
* Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef TEGRA_DEF_H
#define TEGRA_DEF_H
#include <lib/utils_def.h>
/*******************************************************************************
* Platform BL31 specific defines.
******************************************************************************/
#define BL31_SIZE U(0x40000)
/*******************************************************************************
* MCE apertures used by the ARI interface
*
* Aperture 0 - Cpu0 (ARM Cortex A-57)
* Aperture 1 - Cpu1 (ARM Cortex A-57)
* Aperture 2 - Cpu2 (ARM Cortex A-57)
* Aperture 3 - Cpu3 (ARM Cortex A-57)
* Aperture 4 - Cpu4 (Denver15)
* Aperture 5 - Cpu5 (Denver15)
******************************************************************************/
#define MCE_ARI_APERTURE_0_OFFSET U(0x0)
#define MCE_ARI_APERTURE_1_OFFSET U(0x10000)
#define MCE_ARI_APERTURE_2_OFFSET U(0x20000)
#define MCE_ARI_APERTURE_3_OFFSET U(0x30000)
#define MCE_ARI_APERTURE_4_OFFSET U(0x40000)
#define MCE_ARI_APERTURE_5_OFFSET U(0x50000)
#define MCE_ARI_APERTURE_OFFSET_MAX MCE_APERTURE_5_OFFSET
/* number of apertures */
#define MCE_ARI_APERTURES_MAX U(6)
/* each ARI aperture is 64KB */
#define MCE_ARI_APERTURE_SIZE U(0x10000)
/*******************************************************************************
* CPU core id macros for the MCE_ONLINE_CORE ARI
******************************************************************************/
#define MCE_CORE_ID_MAX U(8)
#define MCE_CORE_ID_MASK U(0x7)
/*******************************************************************************
* These values are used by the PSCI implementation during the `CPU_SUSPEND`
* and `SYSTEM_SUSPEND` calls as the `state-id` field in the 'power state'
* parameter.
******************************************************************************/
#define PSTATE_ID_CORE_IDLE U(6)
#define PSTATE_ID_CORE_POWERDN U(7)
#define PSTATE_ID_SOC_POWERDN U(2)
/*******************************************************************************
* Platform power states (used by PSCI framework)
*
* - PLAT_MAX_RET_STATE should be less than lowest PSTATE_ID
* - PLAT_MAX_OFF_STATE should be greater than the highest PSTATE_ID
******************************************************************************/
#define PLAT_MAX_RET_STATE U(1)
#define PLAT_MAX_OFF_STATE U(8)
/*******************************************************************************
* Chip specific page table and MMU setup constants
******************************************************************************/
#define PLAT_PHY_ADDR_SPACE_SIZE (ULL(1) << 35)
#define PLAT_VIRT_ADDR_SPACE_SIZE (ULL(1) << 35)
/*******************************************************************************
* Secure IRQ definitions
******************************************************************************/
#define TEGRA186_TOP_WDT_IRQ U(49)
#define TEGRA186_AON_WDT_IRQ U(50)
#define TEGRA186_SEC_IRQ_TARGET_MASK U(0xF3) /* 4 A57 - 2 Denver */
/*******************************************************************************
* Clock identifier for the SE device
******************************************************************************/
#define TEGRA186_CLK_SE U(103)
#define TEGRA_CLK_SE TEGRA186_CLK_SE
/*******************************************************************************
* Tegra Miscellanous register constants
******************************************************************************/
#define TEGRA_MISC_BASE U(0x00100000)
#define HARDWARE_REVISION_OFFSET U(0x4)
#define MISCREG_PFCFG U(0x200C)
/*******************************************************************************
* Tegra TSA Controller constants
******************************************************************************/
#define TEGRA_TSA_BASE U(0x02400000)
/*******************************************************************************
* TSA configuration registers
******************************************************************************/
#define TSA_CONFIG_STATIC0_CSW_SESWR U(0x4010)
#define TSA_CONFIG_STATIC0_CSW_SESWR_RESET U(0x1100)
#define TSA_CONFIG_STATIC0_CSW_ETRW U(0x4038)
#define TSA_CONFIG_STATIC0_CSW_ETRW_RESET U(0x1100)
#define TSA_CONFIG_STATIC0_CSW_SDMMCWAB U(0x5010)
#define TSA_CONFIG_STATIC0_CSW_SDMMCWAB_RESET U(0x1100)
#define TSA_CONFIG_STATIC0_CSW_AXISW U(0x7008)
#define TSA_CONFIG_STATIC0_CSW_AXISW_RESET U(0x1100)
#define TSA_CONFIG_STATIC0_CSW_HDAW U(0xA008)
#define TSA_CONFIG_STATIC0_CSW_HDAW_RESET U(0x100)
#define TSA_CONFIG_STATIC0_CSW_AONDMAW U(0xB018)
#define TSA_CONFIG_STATIC0_CSW_AONDMAW_RESET U(0x1100)
#define TSA_CONFIG_STATIC0_CSW_SCEDMAW U(0xD018)
#define TSA_CONFIG_STATIC0_CSW_SCEDMAW_RESET U(0x1100)
#define TSA_CONFIG_STATIC0_CSW_BPMPDMAW U(0xD028)
#define TSA_CONFIG_STATIC0_CSW_BPMPDMAW_RESET U(0x1100)
#define TSA_CONFIG_STATIC0_CSW_APEDMAW U(0x12018)
#define TSA_CONFIG_STATIC0_CSW_APEDMAW_RESET U(0x1100)
#define TSA_CONFIG_STATIC0_CSW_UFSHCW U(0x13008)
#define TSA_CONFIG_STATIC0_CSW_UFSHCW_RESET U(0x1100)
#define TSA_CONFIG_STATIC0_CSW_AFIW U(0x13018)
#define TSA_CONFIG_STATIC0_CSW_AFIW_RESET U(0x1100)
#define TSA_CONFIG_STATIC0_CSW_SATAW U(0x13028)
#define TSA_CONFIG_STATIC0_CSW_SATAW_RESET U(0x1100)
#define TSA_CONFIG_STATIC0_CSW_EQOSW U(0x13038)
#define TSA_CONFIG_STATIC0_CSW_EQOSW_RESET U(0x1100)
#define TSA_CONFIG_STATIC0_CSW_XUSB_DEVW U(0x15008)
#define TSA_CONFIG_STATIC0_CSW_XUSB_DEVW_RESET U(0x1100)
#define TSA_CONFIG_STATIC0_CSW_XUSB_HOSTW U(0x15018)
#define TSA_CONFIG_STATIC0_CSW_XUSB_HOSTW_RESET U(0x1100)
#define TSA_CONFIG_CSW_MEMTYPE_OVERRIDE_MASK (ULL(0x3) << 11)
#define TSA_CONFIG_CSW_MEMTYPE_OVERRIDE_PASTHRU (ULL(0) << 11)
/*******************************************************************************
* Tegra General Purpose Centralised DMA constants
******************************************************************************/
#define TEGRA_GPCDMA_BASE ULL(0x2610000)
/*******************************************************************************
* Tegra Memory Controller constants
******************************************************************************/
#define TEGRA_MC_STREAMID_BASE U(0x02C00000)
#define TEGRA_MC_BASE U(0x02C10000)
/* General Security Carveout register macros */
#define MC_GSC_CONFIG_REGS_SIZE U(0x40)
#define MC_GSC_LOCK_CFG_SETTINGS_BIT (U(1) << 1)
#define MC_GSC_ENABLE_TZ_LOCK_BIT (ULL(1) << 0)
#define MC_GSC_SIZE_RANGE_4KB_SHIFT U(27)
#define MC_GSC_BASE_LO_SHIFT U(12)
#define MC_GSC_BASE_LO_MASK U(0xFFFFF)
#define MC_GSC_BASE_HI_SHIFT U(0)
#define MC_GSC_BASE_HI_MASK U(3)
#define MC_GSC_ENABLE_CPU_SECURE_BIT (U(1) << 31)
/* TZDRAM carveout configuration registers */
#define MC_SECURITY_CFG0_0 U(0x70)
#define MC_SECURITY_CFG1_0 U(0x74)
#define MC_SECURITY_CFG3_0 U(0x9BC)
#define MC_SECURITY_BOM_MASK (U(0xFFF) << 20)
#define MC_SECURITY_SIZE_MB_MASK (U(0x1FFF) << 0)
#define MC_SECURITY_BOM_HI_MASK (U(0x3) << 0)
/* Video Memory carveout configuration registers */
#define MC_VIDEO_PROTECT_BASE_HI U(0x978)
#define MC_VIDEO_PROTECT_BASE_LO U(0x648)
#define MC_VIDEO_PROTECT_SIZE_MB U(0x64C)
#define MC_VIDEO_PROTECT_REG_CTRL U(0x650)
#define MC_VIDEO_PROTECT_WRITE_ACCESS_ENABLED U(3)
/*
* Carveout (MC_SECURITY_CARVEOUT24) registers used to clear the
* non-overlapping Video memory region
*/
#define MC_VIDEO_PROTECT_CLEAR_CFG U(0x25A0)
#define MC_VIDEO_PROTECT_CLEAR_BASE_LO U(0x25A4)
#define MC_VIDEO_PROTECT_CLEAR_BASE_HI U(0x25A8)
#define MC_VIDEO_PROTECT_CLEAR_SIZE U(0x25AC)
#define MC_VIDEO_PROTECT_CLEAR_ACCESS_CFG0 U(0x25B0)
/* TZRAM carveout (MC_SECURITY_CARVEOUT11) configuration registers */
#define MC_TZRAM_CARVEOUT_CFG U(0x2190)
#define MC_TZRAM_BASE_LO U(0x2194)
#define MC_TZRAM_BASE_HI U(0x2198)
#define MC_TZRAM_SIZE U(0x219C)
#define MC_TZRAM_CLIENT_ACCESS0_CFG0 U(0x21A0)
#define MC_TZRAM_CLIENT_ACCESS1_CFG0 U(0x21A4)
#define TZRAM_ALLOW_MPCORER (U(1) << 7)
#define TZRAM_ALLOW_MPCOREW (U(1) << 25)
/*******************************************************************************
* Tegra UART Controller constants
******************************************************************************/
#define TEGRA_UARTA_BASE U(0x03100000)
#define TEGRA_UARTB_BASE U(0x03110000)
#define TEGRA_UARTC_BASE U(0x0C280000)
#define TEGRA_UARTD_BASE U(0x03130000)
#define TEGRA_UARTE_BASE U(0x03140000)
#define TEGRA_UARTF_BASE U(0x03150000)
#define TEGRA_UARTG_BASE U(0x0C290000)
/*******************************************************************************
* Tegra Fuse Controller related constants
******************************************************************************/
#define TEGRA_FUSE_BASE U(0x03820000)
#define OPT_SUBREVISION U(0x248)
#define SUBREVISION_MASK U(0xFF)
/*******************************************************************************
* GICv2 & interrupt handling related constants
******************************************************************************/
#define TEGRA_GICD_BASE U(0x03881000)
#define TEGRA_GICC_BASE U(0x03882000)
/*******************************************************************************
* Security Engine related constants
******************************************************************************/
#define TEGRA_SE0_BASE U(0x03AC0000)
#define SE_MUTEX_WATCHDOG_NS_LIMIT U(0x6C)
#define TEGRA_PKA1_BASE U(0x03AD0000)
#define PKA_MUTEX_WATCHDOG_NS_LIMIT U(0x8144)
#define TEGRA_RNG1_BASE U(0x03AE0000)
#define RNG_MUTEX_WATCHDOG_NS_LIMIT U(0xFE0)
/*******************************************************************************
* Tegra HSP doorbell #0 constants
******************************************************************************/
#define TEGRA_HSP_DBELL_BASE U(0x03C90000)
#define HSP_DBELL_1_ENABLE U(0x104)
#define HSP_DBELL_3_TRIGGER U(0x300)
#define HSP_DBELL_3_ENABLE U(0x304)
/*******************************************************************************
* Tegra Clock and Reset Controller constants
******************************************************************************/
#define TEGRA_CAR_RESET_BASE U(0x05000000)
#define TEGRA_GPU_RESET_REG_OFFSET U(0x30)
#define TEGRA_GPU_RESET_GPU_SET_OFFSET U(0x34)
#define GPU_RESET_BIT (U(1) << 0)
#define GPU_SET_BIT (U(1) << 0)
#define TEGRA_GPCDMA_RST_SET_REG_OFFSET U(0x6A0004)
#define TEGRA_GPCDMA_RST_CLR_REG_OFFSET U(0x6A0008)
/*******************************************************************************
* Tegra micro-seconds timer constants
******************************************************************************/
#define TEGRA_TMRUS_BASE U(0x0C2E0000)
#define TEGRA_TMRUS_SIZE U(0x1000)
/*******************************************************************************
* Tegra Power Mgmt Controller constants
******************************************************************************/
#define TEGRA_PMC_BASE U(0x0C360000)
/*******************************************************************************
* Tegra scratch registers constants
******************************************************************************/
#define TEGRA_SCRATCH_BASE U(0x0C390000)
#define SECURE_SCRATCH_RSV0_HI U(0x654)
#define SECURE_SCRATCH_RSV1_LO U(0x658)
#define SECURE_SCRATCH_RSV1_HI U(0x65C)
#define SECURE_SCRATCH_RSV6 U(0x680)
#define SECURE_SCRATCH_RSV11_LO U(0x6A8)
#define SECURE_SCRATCH_RSV11_HI U(0x6AC)
#define SECURE_SCRATCH_RSV53_LO U(0x7F8)
#define SECURE_SCRATCH_RSV53_HI U(0x7FC)
#define SECURE_SCRATCH_RSV55_LO U(0x808)
#define SECURE_SCRATCH_RSV55_HI U(0x80C)
#define SECURE_SCRATCH_RSV63_LO U(0x848)
#define SECURE_SCRATCH_RSV63_HI U(0x84C)
#define SECURE_SCRATCH_RSV64_LO U(0x850)
#define SECURE_SCRATCH_RSV64_HI U(0x854)
#define SECURE_SCRATCH_RSV65_LO U(0x858)
#define SECURE_SCRATCH_RSV65_HI U(0x85c)
#define SECURE_SCRATCH_RSV66_LO U(0x860)
#define SECURE_SCRATCH_RSV66_HI U(0x864)
#define SECURE_SCRATCH_RSV68_LO U(0x870)
#define SCRATCH_RESET_VECTOR_LO SECURE_SCRATCH_RSV1_LO
#define SCRATCH_RESET_VECTOR_HI SECURE_SCRATCH_RSV1_HI
#define SCRATCH_SECURE_BOOTP_FCFG SECURE_SCRATCH_RSV6
#define SCRATCH_MC_TABLE_ADDR_LO SECURE_SCRATCH_RSV11_LO
#define SCRATCH_MC_TABLE_ADDR_HI SECURE_SCRATCH_RSV11_HI
#define SCRATCH_BL31_PARAMS_ADDR SECURE_SCRATCH_RSV53_LO
#define SCRATCH_BL31_PLAT_PARAMS_ADDR SECURE_SCRATCH_RSV53_HI
#define SCRATCH_TZDRAM_ADDR_LO SECURE_SCRATCH_RSV55_LO
#define SCRATCH_TZDRAM_ADDR_HI SECURE_SCRATCH_RSV55_HI
/*******************************************************************************
* Tegra Memory Mapped Control Register Access constants
******************************************************************************/
#define TEGRA_MMCRAB_BASE U(0x0E000000)
/*******************************************************************************
* Tegra Memory Mapped Activity Monitor Register Access constants
******************************************************************************/
#define TEGRA_ARM_ACTMON_CTR_BASE U(0x0E060000)
#define TEGRA_DENVER_ACTMON_CTR_BASE U(0x0E070000)
/*******************************************************************************
* Tegra SMMU Controller constants
******************************************************************************/
#define TEGRA_SMMU0_BASE U(0x12000000)
/*******************************************************************************
* Tegra TZRAM constants
******************************************************************************/
#define TEGRA_TZRAM_BASE U(0x30000000)
#define TEGRA_TZRAM_SIZE U(0x40000)
/*******************************************************************************
* Tegra CCPLEX-BPMP IPC constants
******************************************************************************/
#define TEGRA_BPMP_IPC_TX_PHYS_BASE U(0x3004C000)
#define TEGRA_BPMP_IPC_RX_PHYS_BASE U(0x3004D000)
#define TEGRA_BPMP_IPC_CH_MAP_SIZE U(0x1000) /* 4KB */
/*******************************************************************************
* Tegra DRAM memory base address
******************************************************************************/
#define TEGRA_DRAM_BASE ULL(0x80000000)
#define TEGRA_DRAM_END ULL(0x27FFFFFFF)
#endif /* TEGRA_DEF_H */
@@ -0,0 +1,398 @@
/*
* Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef TEGRA_MC_DEF_H
#define TEGRA_MC_DEF_H
/*******************************************************************************
* Memory Controller's PCFIFO client configuration registers
******************************************************************************/
#define MC_PCFIFO_CLIENT_CONFIG0 0xdd0U
#define MC_PCFIFO_CLIENT_CONFIG1 0xdd4U
#define MC_PCFIFO_CLIENT_CONFIG1_RESET_VAL 0x20000U
#define MC_PCFIFO_CLIENT_CONFIG1_PCFIFO_AFIW_UNORDERED (0U << 17)
#define MC_PCFIFO_CLIENT_CONFIG1_PCFIFO_AFIW_MASK (1U << 17)
#define MC_PCFIFO_CLIENT_CONFIG1_PCFIFO_HDAW_UNORDERED (0U << 21)
#define MC_PCFIFO_CLIENT_CONFIG1_PCFIFO_HDAW_MASK (1U << 21)
#define MC_PCFIFO_CLIENT_CONFIG1_PCFIFO_SATAW_UNORDERED (0U << 29)
#define MC_PCFIFO_CLIENT_CONFIG1_PCFIFO_SATAW_MASK (1U << 29)
#define MC_PCFIFO_CLIENT_CONFIG2 0xdd8U
#define MC_PCFIFO_CLIENT_CONFIG2_RESET_VAL 0x20000U
#define MC_PCFIFO_CLIENT_CONFIG2_PCFIFO_XUSB_HOSTW_UNORDERED (0U << 11)
#define MC_PCFIFO_CLIENT_CONFIG2_PCFIFO_XUSB_HOSTW_MASK (1U << 11)
#define MC_PCFIFO_CLIENT_CONFIG2_PCFIFO_XUSB_DEVW_UNORDERED (0U << 13)
#define MC_PCFIFO_CLIENT_CONFIG2_PCFIFO_XUSB_DEVW_MASK (1U << 13)
#define MC_PCFIFO_CLIENT_CONFIG3 0xddcU
#define MC_PCFIFO_CLIENT_CONFIG3_RESET_VAL 0U
#define MC_PCFIFO_CLIENT_CONFIG3_PCFIFO_SDMMCWAB_UNORDERED (0U << 7)
#define MC_PCFIFO_CLIENT_CONFIG3_PCFIFO_SDMMCWAB_MASK (1U << 7)
#define MC_PCFIFO_CLIENT_CONFIG4 0xde0U
#define MC_PCFIFO_CLIENT_CONFIG4_RESET_VAL 0U
#define MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_SESWR_UNORDERED (0U << 1)
#define MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_SESWR_MASK (1U << 1)
#define MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_ETRW_UNORDERED (0U << 5)
#define MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_ETRW_MASK (1U << 5)
#define MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_AXISW_UNORDERED (0U << 13)
#define MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_AXISW_MASK (1U << 13)
#define MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_EQOSW_UNORDERED (0U << 15)
#define MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_EQOSW_ORDERED (1U << 15)
#define MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_EQOSW_MASK (1U << 15)
#define MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_UFSHCW_UNORDERED (0U << 17)
#define MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_UFSHCW_MASK (1U << 17)
#define MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_BPMPDMAW_UNORDERED (0U << 22)
#define MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_BPMPDMAW_MASK (1U << 22)
#define MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_AONDMAW_UNORDERED (0U << 26)
#define MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_AONDMAW_MASK (1U << 26)
#define MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_SCEDMAW_UNORDERED (0U << 30)
#define MC_PCFIFO_CLIENT_CONFIG4_PCFIFO_SCEDMAW_MASK (1U << 30)
#define MC_PCFIFO_CLIENT_CONFIG5 0xbf4U
#define MC_PCFIFO_CLIENT_CONFIG5_RESET_VAL 0U
#define MC_PCFIFO_CLIENT_CONFIG5_PCFIFO_APEDMAW_UNORDERED (0U << 0)
#define MC_PCFIFO_CLIENT_CONFIG5_PCFIFO_APEDMAW_MASK (1U << 0)
/*******************************************************************************
* Stream ID Override Config registers
******************************************************************************/
#define MC_STREAMID_OVERRIDE_CFG_PTCR 0x000U
#define MC_STREAMID_OVERRIDE_CFG_AFIR 0x070U
#define MC_STREAMID_OVERRIDE_CFG_HDAR 0x0A8U
#define MC_STREAMID_OVERRIDE_CFG_HOST1XDMAR 0x0B0U
#define MC_STREAMID_OVERRIDE_CFG_NVENCSRD 0x0E0U
#define MC_STREAMID_OVERRIDE_CFG_SATAR 0x0F8U
#define MC_STREAMID_OVERRIDE_CFG_MPCORER 0x138U
#define MC_STREAMID_OVERRIDE_CFG_NVENCSWR 0x158U
#define MC_STREAMID_OVERRIDE_CFG_AFIW 0x188U
#define MC_STREAMID_OVERRIDE_CFG_HDAW 0x1A8U
#define MC_STREAMID_OVERRIDE_CFG_MPCOREW 0x1C8U
#define MC_STREAMID_OVERRIDE_CFG_SATAW 0x1E8U
#define MC_STREAMID_OVERRIDE_CFG_ISPRA 0x220U
#define MC_STREAMID_OVERRIDE_CFG_ISPWA 0x230U
#define MC_STREAMID_OVERRIDE_CFG_ISPWB 0x238U
#define MC_STREAMID_OVERRIDE_CFG_XUSB_HOSTR 0x250U
#define MC_STREAMID_OVERRIDE_CFG_XUSB_HOSTW 0x258U
#define MC_STREAMID_OVERRIDE_CFG_XUSB_DEVR 0x260U
#define MC_STREAMID_OVERRIDE_CFG_XUSB_DEVW 0x268U
#define MC_STREAMID_OVERRIDE_CFG_TSECSRD 0x2A0U
#define MC_STREAMID_OVERRIDE_CFG_TSECSWR 0x2A8U
#define MC_STREAMID_OVERRIDE_CFG_GPUSRD 0x2C0U
#define MC_STREAMID_OVERRIDE_CFG_GPUSWR 0x2C8U
#define MC_STREAMID_OVERRIDE_CFG_SDMMCRA 0x300U
#define MC_STREAMID_OVERRIDE_CFG_SDMMCRAA 0x308U
#define MC_STREAMID_OVERRIDE_CFG_SDMMCR 0x310U
#define MC_STREAMID_OVERRIDE_CFG_SDMMCRAB 0x318U
#define MC_STREAMID_OVERRIDE_CFG_SDMMCWA 0x320U
#define MC_STREAMID_OVERRIDE_CFG_SDMMCWAA 0x328U
#define MC_STREAMID_OVERRIDE_CFG_SDMMCW 0x330U
#define MC_STREAMID_OVERRIDE_CFG_SDMMCWAB 0x338U
#define MC_STREAMID_OVERRIDE_CFG_VICSRD 0x360U
#define MC_STREAMID_OVERRIDE_CFG_VICSWR 0x368U
#define MC_STREAMID_OVERRIDE_CFG_VIW 0x390U
#define MC_STREAMID_OVERRIDE_CFG_NVDECSRD 0x3C0U
#define MC_STREAMID_OVERRIDE_CFG_NVDECSWR 0x3C8U
#define MC_STREAMID_OVERRIDE_CFG_APER 0x3D0U
#define MC_STREAMID_OVERRIDE_CFG_APEW 0x3D8U
#define MC_STREAMID_OVERRIDE_CFG_NVJPGSRD 0x3F0U
#define MC_STREAMID_OVERRIDE_CFG_NVJPGSWR 0x3F8U
#define MC_STREAMID_OVERRIDE_CFG_SESRD 0x400U
#define MC_STREAMID_OVERRIDE_CFG_SESWR 0x408U
#define MC_STREAMID_OVERRIDE_CFG_ETRR 0x420U
#define MC_STREAMID_OVERRIDE_CFG_ETRW 0x428U
#define MC_STREAMID_OVERRIDE_CFG_TSECSRDB 0x430U
#define MC_STREAMID_OVERRIDE_CFG_TSECSWRB 0x438U
#define MC_STREAMID_OVERRIDE_CFG_GPUSRD2 0x440U
#define MC_STREAMID_OVERRIDE_CFG_GPUSWR2 0x448U
#define MC_STREAMID_OVERRIDE_CFG_AXISR 0x460U
#define MC_STREAMID_OVERRIDE_CFG_AXISW 0x468U
#define MC_STREAMID_OVERRIDE_CFG_EQOSR 0x470U
#define MC_STREAMID_OVERRIDE_CFG_EQOSW 0x478U
#define MC_STREAMID_OVERRIDE_CFG_UFSHCR 0x480U
#define MC_STREAMID_OVERRIDE_CFG_UFSHCW 0x488U
#define MC_STREAMID_OVERRIDE_CFG_NVDISPLAYR 0x490U
#define MC_STREAMID_OVERRIDE_CFG_BPMPR 0x498U
#define MC_STREAMID_OVERRIDE_CFG_BPMPW 0x4A0U
#define MC_STREAMID_OVERRIDE_CFG_BPMPDMAR 0x4A8U
#define MC_STREAMID_OVERRIDE_CFG_BPMPDMAW 0x4B0U
#define MC_STREAMID_OVERRIDE_CFG_AONR 0x4B8U
#define MC_STREAMID_OVERRIDE_CFG_AONW 0x4C0U
#define MC_STREAMID_OVERRIDE_CFG_AONDMAR 0x4C8U
#define MC_STREAMID_OVERRIDE_CFG_AONDMAW 0x4D0U
#define MC_STREAMID_OVERRIDE_CFG_SCER 0x4D8U
#define MC_STREAMID_OVERRIDE_CFG_SCEW 0x4E0U
#define MC_STREAMID_OVERRIDE_CFG_SCEDMAR 0x4E8U
#define MC_STREAMID_OVERRIDE_CFG_SCEDMAW 0x4F0U
#define MC_STREAMID_OVERRIDE_CFG_APEDMAR 0x4F8U
#define MC_STREAMID_OVERRIDE_CFG_APEDMAW 0x500U
#define MC_STREAMID_OVERRIDE_CFG_NVDISPLAYR1 0x508U
#define MC_STREAMID_OVERRIDE_CFG_VICSRD1 0x510U
#define MC_STREAMID_OVERRIDE_CFG_NVDECSRD1 0x518U
/*******************************************************************************
* Macro to calculate Security cfg register addr from StreamID Override register
******************************************************************************/
#define MC_STREAMID_OVERRIDE_TO_SECURITY_CFG(addr) ((addr) + (uint32_t)sizeof(uint32_t))
#define MC_TXN_OVERRIDE_CONFIG_COH_PATH_NO_OVERRIDE_SO_DEV (0U << 4)
#define MC_TXN_OVERRIDE_CONFIG_COH_PATH_FORCE_NON_COHERENT_SO_DEV (1U << 4)
#define MC_TXN_OVERRIDE_CONFIG_COH_PATH_FORCE_COHERENT_SO_DEV (2U << 4)
#define MC_TXN_OVERRIDE_CONFIG_COH_PATH_FORCE_COHERENT_SNOOP_SO_DEV (3U << 4)
#define MC_TXN_OVERRIDE_CONFIG_COH_PATH_NO_OVERRIDE_NORMAL (0U << 8)
#define MC_TXN_OVERRIDE_CONFIG_COH_PATH_FORCE_NON_COHERENT_NORMAL (1U << 8)
#define MC_TXN_OVERRIDE_CONFIG_COH_PATH_FORCE_COHERENT_NORMAL (2U << 8)
#define MC_TXN_OVERRIDE_CONFIG_COH_PATH_FORCE_COHERENT_SNOOP_NORMAL (3U << 8)
#define MC_TXN_OVERRIDE_CONFIG_CGID_SO_DEV_ZERO (0U << 12)
#define MC_TXN_OVERRIDE_CONFIG_CGID_SO_DEV_CLIENT_AXI_ID (1U << 12)
/*******************************************************************************
* Memory Controller transaction override config registers
******************************************************************************/
#define MC_TXN_OVERRIDE_CONFIG_HDAR 0x10a8U
#define MC_TXN_OVERRIDE_CONFIG_BPMPW 0x14a0U
#define MC_TXN_OVERRIDE_CONFIG_PTCR 0x1000U
#define MC_TXN_OVERRIDE_CONFIG_NVDISPLAYR 0x1490U
#define MC_TXN_OVERRIDE_CONFIG_EQOSW 0x1478U
#define MC_TXN_OVERRIDE_CONFIG_NVJPGSWR 0x13f8U
#define MC_TXN_OVERRIDE_CONFIG_ISPRA 0x1220U
#define MC_TXN_OVERRIDE_CONFIG_SDMMCWAA 0x1328U
#define MC_TXN_OVERRIDE_CONFIG_VICSRD 0x1360U
#define MC_TXN_OVERRIDE_CONFIG_MPCOREW 0x11c8U
#define MC_TXN_OVERRIDE_CONFIG_GPUSRD 0x12c0U
#define MC_TXN_OVERRIDE_CONFIG_AXISR 0x1460U
#define MC_TXN_OVERRIDE_CONFIG_SCEDMAW 0x14f0U
#define MC_TXN_OVERRIDE_CONFIG_SDMMCW 0x1330U
#define MC_TXN_OVERRIDE_CONFIG_EQOSR 0x1470U
#define MC_TXN_OVERRIDE_CONFIG_APEDMAR 0x14f8U
#define MC_TXN_OVERRIDE_CONFIG_NVENCSRD 0x10e0U
#define MC_TXN_OVERRIDE_CONFIG_SDMMCRAB 0x1318U
#define MC_TXN_OVERRIDE_CONFIG_VICSRD1 0x1510U
#define MC_TXN_OVERRIDE_CONFIG_BPMPDMAR 0x14a8U
#define MC_TXN_OVERRIDE_CONFIG_VIW 0x1390U
#define MC_TXN_OVERRIDE_CONFIG_SDMMCRAA 0x1308U
#define MC_TXN_OVERRIDE_CONFIG_AXISW 0x1468U
#define MC_TXN_OVERRIDE_CONFIG_XUSB_DEVR 0x1260U
#define MC_TXN_OVERRIDE_CONFIG_UFSHCR 0x1480U
#define MC_TXN_OVERRIDE_CONFIG_TSECSWR 0x12a8U
#define MC_TXN_OVERRIDE_CONFIG_GPUSWR 0x12c8U
#define MC_TXN_OVERRIDE_CONFIG_SATAR 0x10f8U
#define MC_TXN_OVERRIDE_CONFIG_XUSB_HOSTW 0x1258U
#define MC_TXN_OVERRIDE_CONFIG_TSECSWRB 0x1438U
#define MC_TXN_OVERRIDE_CONFIG_GPUSRD2 0x1440U
#define MC_TXN_OVERRIDE_CONFIG_SCEDMAR 0x14e8U
#define MC_TXN_OVERRIDE_CONFIG_GPUSWR2 0x1448U
#define MC_TXN_OVERRIDE_CONFIG_AONDMAW 0x14d0U
#define MC_TXN_OVERRIDE_CONFIG_APEDMAW 0x1500U
#define MC_TXN_OVERRIDE_CONFIG_AONW 0x14c0U
#define MC_TXN_OVERRIDE_CONFIG_HOST1XDMAR 0x10b0U
#define MC_TXN_OVERRIDE_CONFIG_ETRR 0x1420U
#define MC_TXN_OVERRIDE_CONFIG_SESWR 0x1408U
#define MC_TXN_OVERRIDE_CONFIG_NVJPGSRD 0x13f0U
#define MC_TXN_OVERRIDE_CONFIG_NVDECSRD 0x13c0U
#define MC_TXN_OVERRIDE_CONFIG_TSECSRDB 0x1430U
#define MC_TXN_OVERRIDE_CONFIG_BPMPDMAW 0x14b0U
#define MC_TXN_OVERRIDE_CONFIG_APER 0x13d0U
#define MC_TXN_OVERRIDE_CONFIG_NVDECSRD1 0x1518U
#define MC_TXN_OVERRIDE_CONFIG_XUSB_HOSTR 0x1250U
#define MC_TXN_OVERRIDE_CONFIG_ISPWA 0x1230U
#define MC_TXN_OVERRIDE_CONFIG_SESRD 0x1400U
#define MC_TXN_OVERRIDE_CONFIG_SCER 0x14d8U
#define MC_TXN_OVERRIDE_CONFIG_AONR 0x14b8U
#define MC_TXN_OVERRIDE_CONFIG_MPCORER 0x1138U
#define MC_TXN_OVERRIDE_CONFIG_SDMMCWA 0x1320U
#define MC_TXN_OVERRIDE_CONFIG_HDAW 0x11a8U
#define MC_TXN_OVERRIDE_CONFIG_NVDECSWR 0x13c8U
#define MC_TXN_OVERRIDE_CONFIG_UFSHCW 0x1488U
#define MC_TXN_OVERRIDE_CONFIG_AONDMAR 0x14c8U
#define MC_TXN_OVERRIDE_CONFIG_SATAW 0x11e8U
#define MC_TXN_OVERRIDE_CONFIG_ETRW 0x1428U
#define MC_TXN_OVERRIDE_CONFIG_VICSWR 0x1368U
#define MC_TXN_OVERRIDE_CONFIG_NVENCSWR 0x1158U
#define MC_TXN_OVERRIDE_CONFIG_AFIR 0x1070U
#define MC_TXN_OVERRIDE_CONFIG_SDMMCWAB 0x1338U
#define MC_TXN_OVERRIDE_CONFIG_SDMMCRA 0x1300U
#define MC_TXN_OVERRIDE_CONFIG_NVDISPLAYR1 0x1508U
#define MC_TXN_OVERRIDE_CONFIG_ISPWB 0x1238U
#define MC_TXN_OVERRIDE_CONFIG_BPMPR 0x1498U
#define MC_TXN_OVERRIDE_CONFIG_APEW 0x13d8U
#define MC_TXN_OVERRIDE_CONFIG_SDMMCR 0x1310U
#define MC_TXN_OVERRIDE_CONFIG_XUSB_DEVW 0x1268U
#define MC_TXN_OVERRIDE_CONFIG_TSECSRD 0x12a0U
#define MC_TXN_OVERRIDE_CONFIG_AFIW 0x1188U
#define MC_TXN_OVERRIDE_CONFIG_SCEW 0x14e0U
#define MC_TXN_OVERRIDE_CONFIG_AXID_OVERRIDE_CGID (1U << 0)
#define MC_TXN_OVERRIDE_CONFIG_COH_PATH_OVERRIDE_SO_DEV (2U << 4)
#define MC_TXN_OVERRIDE_CONFIG_AXID_OVERRIDE_SO_DEV_CGID_SO_DEV_CLIENT (1U << 12)
/*******************************************************************************
* Non-SO_DEV transactions override values for CGID_TAG bitfield for the
* MC_TXN_OVERRIDE_CONFIG_{module} registers
******************************************************************************/
#define MC_TXN_OVERRIDE_CGID_TAG_DEFAULT 0U
#define MC_TXN_OVERRIDE_CGID_TAG_CLIENT_AXI_ID 1U
#define MC_TXN_OVERRIDE_CGID_TAG_ZERO 2U
#define MC_TXN_OVERRIDE_CGID_TAG_ADR 3U
#define MC_TXN_OVERRIDE_CGID_TAG_MASK 3ULL
/*******************************************************************************
* Memory Controller Reset Control registers
******************************************************************************/
#define MC_CLIENT_HOTRESET_CTRL0 0x200U
#define MC_CLIENT_HOTRESET_CTRL0_RESET_VAL 0U
#define MC_CLIENT_HOTRESET_CTRL0_AFI_FLUSH_ENB (1U << 0)
#define MC_CLIENT_HOTRESET_CTRL0_HC_FLUSH_ENB (1U << 6)
#define MC_CLIENT_HOTRESET_CTRL0_HDA_FLUSH_ENB (1U << 7)
#define MC_CLIENT_HOTRESET_CTRL0_ISP2_FLUSH_ENB (1U << 8)
#define MC_CLIENT_HOTRESET_CTRL0_MPCORE_FLUSH_ENB (1U << 9)
#define MC_CLIENT_HOTRESET_CTRL0_NVENC_FLUSH_ENB (1U << 11)
#define MC_CLIENT_HOTRESET_CTRL0_SATA_FLUSH_ENB (1U << 15)
#define MC_CLIENT_HOTRESET_CTRL0_VI_FLUSH_ENB (1U << 17)
#define MC_CLIENT_HOTRESET_CTRL0_VIC_FLUSH_ENB (1U << 18)
#define MC_CLIENT_HOTRESET_CTRL0_XUSB_HOST_FLUSH_ENB (1U << 19)
#define MC_CLIENT_HOTRESET_CTRL0_XUSB_DEV_FLUSH_ENB (1U << 20)
#define MC_CLIENT_HOTRESET_CTRL0_TSEC_FLUSH_ENB (1U << 22)
#define MC_CLIENT_HOTRESET_CTRL0_SDMMC1A_FLUSH_ENB (1U << 29)
#define MC_CLIENT_HOTRESET_CTRL0_SDMMC2A_FLUSH_ENB (1U << 30)
#define MC_CLIENT_HOTRESET_CTRL0_SDMMC3A_FLUSH_ENB (1U << 31)
#define MC_CLIENT_HOTRESET_STATUS0 0x204U
#define MC_CLIENT_HOTRESET_CTRL1 0x970U
#define MC_CLIENT_HOTRESET_CTRL1_RESET_VAL 0U
#define MC_CLIENT_HOTRESET_CTRL1_SDMMC4A_FLUSH_ENB (1U << 0)
#define MC_CLIENT_HOTRESET_CTRL1_GPU_FLUSH_ENB (1U << 2)
#define MC_CLIENT_HOTRESET_CTRL1_NVDEC_FLUSH_ENB (1U << 5)
#define MC_CLIENT_HOTRESET_CTRL1_APE_FLUSH_ENB (1U << 6)
#define MC_CLIENT_HOTRESET_CTRL1_SE_FLUSH_ENB (1U << 7)
#define MC_CLIENT_HOTRESET_CTRL1_NVJPG_FLUSH_ENB (1U << 8)
#define MC_CLIENT_HOTRESET_CTRL1_ETR_FLUSH_ENB (1U << 12)
#define MC_CLIENT_HOTRESET_CTRL1_TSECB_FLUSH_ENB (1U << 13)
#define MC_CLIENT_HOTRESET_CTRL1_AXIS_FLUSH_ENB (1U << 18)
#define MC_CLIENT_HOTRESET_CTRL1_EQOS_FLUSH_ENB (1U << 19)
#define MC_CLIENT_HOTRESET_CTRL1_UFSHC_FLUSH_ENB (1U << 20)
#define MC_CLIENT_HOTRESET_CTRL1_NVDISPLAY_FLUSH_ENB (1U << 21)
#define MC_CLIENT_HOTRESET_CTRL1_BPMP_FLUSH_ENB (1U << 22)
#define MC_CLIENT_HOTRESET_CTRL1_AON_FLUSH_ENB (1U << 23)
#define MC_CLIENT_HOTRESET_CTRL1_SCE_FLUSH_ENB (1U << 24)
#define MC_CLIENT_HOTRESET_STATUS1 0x974U
#ifndef __ASSEMBLER__
/*******************************************************************************
* Structure to hold the transaction override settings to use to override
* client inputs
******************************************************************************/
typedef struct mc_txn_override_cfg {
uint32_t offset;
uint8_t cgid_tag;
} mc_txn_override_cfg_t;
#define mc_make_txn_override_cfg(off, val) \
{ \
.offset = MC_TXN_OVERRIDE_CONFIG_ ## off, \
.cgid_tag = MC_TXN_OVERRIDE_ ## val \
}
/*******************************************************************************
* Structure to hold the Stream ID to use to override client inputs
******************************************************************************/
typedef struct mc_streamid_override_cfg {
uint32_t offset;
uint8_t stream_id;
} mc_streamid_override_cfg_t;
/*******************************************************************************
* Structure to hold the Stream ID Security Configuration settings
******************************************************************************/
typedef struct mc_streamid_security_cfg {
char *name;
uint32_t offset;
uint32_t override_enable;
uint32_t override_client_inputs;
uint32_t override_client_ns_flag;
} mc_streamid_security_cfg_t;
#define OVERRIDE_DISABLE 1U
#define OVERRIDE_ENABLE 0U
#define CLIENT_FLAG_SECURE 0U
#define CLIENT_FLAG_NON_SECURE 1U
#define CLIENT_INPUTS_OVERRIDE 1U
#define CLIENT_INPUTS_NO_OVERRIDE 0U
/*******************************************************************************
* StreamID to indicate no SMMU translations (requests to be steered on the
* SMMU bypass path)
******************************************************************************/
#define MC_STREAM_ID_MAX 0x7FU
#define mc_make_sec_cfg(off, ns, ovrrd, access) \
{ \
.name = # off, \
.offset = MC_STREAMID_OVERRIDE_TO_SECURITY_CFG( \
MC_STREAMID_OVERRIDE_CFG_ ## off), \
.override_client_ns_flag = CLIENT_FLAG_ ## ns, \
.override_client_inputs = CLIENT_INPUTS_ ## ovrrd, \
.override_enable = OVERRIDE_ ## access \
}
#define mc_make_sid_override_cfg(name) \
{ \
.reg = TEGRA_MC_STREAMID_BASE + MC_STREAMID_OVERRIDE_CFG_ ## name, \
.val = 0x00000000U, \
}
#define mc_make_sid_security_cfg(name) \
{ \
.reg = TEGRA_MC_STREAMID_BASE + MC_STREAMID_OVERRIDE_TO_SECURITY_CFG(MC_STREAMID_OVERRIDE_CFG_ ## name), \
.val = 0x00000000U, \
}
#define mc_set_pcfifo_unordered_boot_so_mss(id, client) \
((uint32_t)~MC_PCFIFO_CLIENT_CONFIG##id##_PCFIFO_##client##_MASK | \
MC_PCFIFO_CLIENT_CONFIG##id##_PCFIFO_##client##_UNORDERED)
#define mc_set_pcfifo_ordered_boot_so_mss(id, client) \
MC_PCFIFO_CLIENT_CONFIG##id##_PCFIFO_##client##_ORDERED
#define mc_set_tsa_passthrough(client) \
do { \
mmio_write_32(TEGRA_TSA_BASE + TSA_CONFIG_STATIC0_CSW_##client, \
(TSA_CONFIG_STATIC0_CSW_##client##_RESET & \
(uint32_t)~TSA_CONFIG_CSW_MEMTYPE_OVERRIDE_MASK) | \
(uint32_t)TSA_CONFIG_CSW_MEMTYPE_OVERRIDE_PASTHRU); \
} while (0)
#define mc_set_tsa_w_passthrough(client) \
do { \
mmio_write_32(TEGRA_TSA_BASE + TSA_CONFIG_STATIC0_CSW_##client, \
(TSA_CONFIG_STATIC0_CSW_RESET_W & \
(uint32_t)~TSA_CONFIG_CSW_MEMTYPE_OVERRIDE_MASK) | \
(uint32_t)TSA_CONFIG_CSW_MEMTYPE_OVERRIDE_PASTHRU); \
} while (0)
#define mc_set_tsa_r_passthrough(client) \
{ \
mmio_write_32(TEGRA_TSA_BASE + TSA_CONFIG_STATIC0_CSR_##client, \
(TSA_CONFIG_STATIC0_CSR_RESET_R & \
(uint32_t)~TSA_CONFIG_CSW_MEMTYPE_OVERRIDE_MASK) | \
(uint32_t)TSA_CONFIG_CSW_MEMTYPE_OVERRIDE_PASTHRU); \
} while (0)
#define mc_set_txn_override(client, normal_axi_id, so_dev_axi_id, normal_override, so_dev_override) \
do { \
tegra_mc_write_32(MC_TXN_OVERRIDE_CONFIG_##client, \
MC_TXN_OVERRIDE_##normal_axi_id | \
MC_TXN_OVERRIDE_CONFIG_COH_PATH_##so_dev_override##_SO_DEV | \
MC_TXN_OVERRIDE_CONFIG_COH_PATH_##normal_override##_NORMAL | \
MC_TXN_OVERRIDE_CONFIG_CGID_##so_dev_axi_id); \
} while (0)
#endif /* __ASSEMBLER__ */
#endif /* TEGRA_MC_DEF_H */
@@ -0,0 +1,16 @@
/*
* Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef TEGRA194_PRIVATE_H
#define TEGRA194_PRIVATE_H
void tegra194_cpu_reset_handler(void);
uint64_t tegra194_get_cpu_reset_handler_base(void);
uint64_t tegra194_get_cpu_reset_handler_size(void);
uint64_t tegra194_get_mc_ctx_offset(void);
void tegra194_set_system_suspend_entry(void);
#endif /* TEGRA194_PRIVATE_H */
@@ -0,0 +1,263 @@
/*
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef TEGRA194_RAS_PRIVATE
#define TEGRA194_RAS_PRIVATE
#include <stdint.h>
/* Implementation defined RAS error and corresponding error message */
struct ras_error {
const char *error_msg;
/* IERR(bits[15:8]) from ERR<n>STATUS */
uint8_t error_code;
};
/* RAS error node-specific auxiliary data */
struct ras_aux_data {
/* name for current RAS node. */
const char *name;
/* point to null-terminated ras_error array to convert error code to msg. */
const struct ras_error *error_records;
/*
* function to return an value which needs to be programmed into ERXCTLR_EL1
* to enable all specified RAS errors for current node.
*/
uint64_t (*err_ctrl)(void);
};
/* IFU Uncorrectable RAS ERROR */
#define IFU_UNCORR_RAS_ERROR_LIST(X)
/* JSR_RET Uncorrectable RAS ERROR */
#define JSR_RET_UNCORR_RAS_ERROR_LIST(X) \
/* Name, ERR_CTRL, IERR, ISA Desc */ \
X(JSR_RET, 35, 0x13, "Floating Point Register File Parity Error") \
X(JSR_RET, 34, 0x12, "Integer Register File Parity Error") \
X(JSR_RET, 33, 0x11, "Garbage Bundle") \
X(JSR_RET, 32, 0x10, "Bundle Completion Timeout")
/* JSR_MTS Uncorrectable RAS ERROR */
#define JSR_MTS_UNCORR_RAS_ERROR_LIST(X) \
/* Name, ERR_CTRL, IERR, ISA Desc */ \
X(JSR_MTS, 40, 0x28, "CoreSight Access Error") \
X(JSR_MTS, 39, 0x27, "Dual Execution Uncorrectable Error") \
X(JSR_MTS, 37, 0x25, "CTU MMIO Region") \
X(JSR_MTS, 36, 0x24, "MTS MMCRAB Region Access") \
X(JSR_MTS, 35, 0x23, "MTS_CARVEOUT Access from ARM SW") \
X(JSR_MTS, 34, 0x22, "NAFLL PLL Failure to Lock") \
X(JSR_MTS, 32, 0x20, "Internal Uncorrectable MTS Error")
/* LSD_STQ Uncorrectable RAS ERROR */
#define LSD_STQ_UNCORR_RAS_ERROR_LIST(X) \
/* Name, ERR_CTRL, IERR, ISA Desc */ \
X(LSD_STQ, 41, 0x39, "Coherent Cache Data Store Multi-Line ECC Error") \
X(LSD_STQ, 40, 0x38, "Coherent Cache Data Store Uncorrectable ECC Error") \
X(LSD_STQ, 38, 0x36, "Coherent Cache Data Load Uncorrectable ECC Error") \
X(LSD_STQ, 33, 0x31, "Coherent Cache Tag Store Parity Error") \
X(LSD_STQ, 32, 0x30, "Coherent Cache Tag Load Parity Error")
/* LSD_DCC Uncorrectable RAS ERROR */
#define LSD_DCC_UNCORR_RAS_ERROR_LIST(X) \
/* Name, ERR_CTRL, IERR, ISA Desc */ \
X(LSD_DCC, 41, 0x49, "BTU Copy Mini-Cache PPN Multi-Hit Error") \
X(LSD_DCC, 39, 0x47, "Coherent Cache Data Uncorrectable ECC Error") \
X(LSD_DCC, 37, 0x45, "Version Cache Byte-Enable Parity Error") \
X(LSD_DCC, 36, 0x44, "Version Cache Data Uncorrectable ECC Error") \
X(LSD_DCC, 33, 0x41, "BTU Copy Coherent Cache PPN Parity Error") \
X(LSD_DCC, 32, 0x40, "BTU Copy Coherent Cache VPN Parity Error")
/* LSD_L1HPF Uncorrectable RAS ERROR */
#define LSD_L1HPF_UNCORR_RAS_ERROR_LIST(X)
/* L2 Uncorrectable RAS ERROR */
#define L2_UNCORR_RAS_ERROR_LIST(X) \
/* Name, ERR_CTRL, IERR, ISA Desc */ \
X(L2, 56, 0x68, "URT Timeout") \
X(L2, 55, 0x67, "L2 Protocol Violation") \
X(L2, 54, 0x66, "SCF to L2 Slave Error Read") \
X(L2, 53, 0x65, "SCF to L2 Slave Error Write") \
X(L2, 52, 0x64, "SCF to L2 Decode Error Read") \
X(L2, 51, 0x63, "SCF to L2 Decode Error Write") \
X(L2, 50, 0x62, "SCF to L2 Request Response Interface Parity Errors") \
X(L2, 49, 0x61, "SCF to L2 Advance notice interface parity errors") \
X(L2, 48, 0x60, "SCF to L2 Filldata Parity Errors") \
X(L2, 47, 0x5F, "SCF to L2 UnCorrectable ECC Data Error on interface") \
X(L2, 45, 0x5D, "Core 1 to L2 Parity Error") \
X(L2, 44, 0x5C, "Core 0 to L2 Parity Error") \
X(L2, 43, 0x5B, "L2 Multi-Hit") \
X(L2, 42, 0x5A, "L2 URT Tag Parity Error") \
X(L2, 41, 0x59, "L2 NTT Tag Parity Error") \
X(L2, 40, 0x58, "L2 MLT Tag Parity Error") \
X(L2, 39, 0x57, "L2 URD Data") \
X(L2, 38, 0x56, "L2 NTP Data") \
X(L2, 36, 0x54, "L2 MLC Uncorrectable Clean") \
X(L2, 35, 0x53, "L2 URD Uncorrectable Dirty") \
X(L2, 34, 0x52, "L2 MLC Uncorrectable Dirty")
/* CLUSTER_CLOCKS Uncorrectable RAS ERROR */
#define CLUSTER_CLOCKS_UNCORR_RAS_ERROR_LIST(X) \
/* Name, ERR_CTRL, IERR, ISA Desc */ \
X(CLUSTER_CLOCKS, 32, 0xE4, "Frequency Monitor Error")
/* MMU Uncorrectable RAS ERROR */
#define MMU_UNCORR_RAS_ERROR_LIST(X)
/* L3 Uncorrectable RAS ERROR */
#define L3_UNCORR_RAS_ERROR_LIST(X) \
/* Name, ERR_CTRL, IERR, ISA Desc */ \
X(L3, 43, 0x7B, "SNOC Interface Parity Error") \
X(L3, 42, 0x7A, "MCF Interface Parity Error") \
X(L3, 41, 0x79, "L3 Tag Parity Error") \
X(L3, 40, 0x78, "L3 Dir Parity Error") \
X(L3, 39, 0x77, "L3 Uncorrectable ECC Error") \
X(L3, 37, 0x75, "Multi-Hit CAM Error") \
X(L3, 36, 0x74, "Multi-Hit Tag Error") \
X(L3, 35, 0x73, "Unrecognized Command Error") \
X(L3, 34, 0x72, "L3 Protocol Error")
/* CCPMU Uncorrectable RAS ERROR */
#define CCPMU_UNCORR_RAS_ERROR_LIST(X) \
/* Name, ERR_CTRL, IERR, ISA Desc */ \
X(CCPMU, 40, 0x87, "CoreSight Access Error") \
X(CCPMU, 36, 0x84, "MCE Ucode Error") \
X(CCPMU, 35, 0x83, "MCE IL1 Parity Error") \
X(CCPMU, 34, 0x82, "MCE Timeout Error") \
X(CCPMU, 33, 0x81, "CRAB Access Error") \
X(CCPMU, 32, 0x80, "MCE Memory Access Error")
/* SCF_IOB Uncorrectable RAS ERROR */
#define SCF_IOB_UNCORR_RAS_ERROR_LIST(X) \
/* Name, ERR_CTRL, IERR, ISA Desc */ \
X(SCF_IOB, 41, 0x99, "Request parity error") \
X(SCF_IOB, 40, 0x98, "Putdata parity error") \
X(SCF_IOB, 39, 0x97, "Uncorrectable ECC on Putdata") \
X(SCF_IOB, 38, 0x96, "CBB Interface Error") \
X(SCF_IOB, 37, 0x95, "MMCRAB Error") \
X(SCF_IOB, 36, 0x94, "IHI Interface Error") \
X(SCF_IOB, 35, 0x93, "CRI Error") \
X(SCF_IOB, 34, 0x92, "TBX Interface Error") \
X(SCF_IOB, 33, 0x91, "EVP Interface Error")
/* SCF_SNOC Uncorrectable RAS ERROR */
#define SCF_SNOC_UNCORR_RAS_ERROR_LIST(X) \
/* Name, ERR_CTRL, IERR, ISA Desc */ \
X(SCF_SNOC, 42, 0xAA, "Misc Client Parity Error") \
X(SCF_SNOC, 41, 0xA9, "Misc Filldata Parity Error") \
X(SCF_SNOC, 40, 0xA8, "Uncorrectable ECC Misc Client") \
X(SCF_SNOC, 39, 0xA7, "DVMU Interface Parity Error") \
X(SCF_SNOC, 38, 0xA6, "DVMU Interface Timeout Error") \
X(SCF_SNOC, 37, 0xA5, "CPE Request Error") \
X(SCF_SNOC, 36, 0xA4, "CPE Response Error") \
X(SCF_SNOC, 35, 0xA3, "CPE Timeout Error") \
X(SCF_SNOC, 34, 0xA2, "Uncorrectable Carveout Error")
/* SCF_CTU Uncorrectable RAS ERROR */
#define SCF_CTU_UNCORR_RAS_ERROR_LIST(X) \
/* Name, ERR_CTRL, IERR, ISA Desc */ \
X(SCF_CTU, 39, 0xB7, "Timeout error for TRC_DMA request") \
X(SCF_CTU, 38, 0xB6, "Timeout error for CTU Snp") \
X(SCF_CTU, 37, 0xB5, "Parity error in CTU TAG RAM") \
X(SCF_CTU, 36, 0xB3, "Parity error in CTU DATA RAM") \
X(SCF_CTU, 35, 0xB4, "Parity error for Cluster Rsp") \
X(SCF_CTU, 34, 0xB2, "Parity error for TRL requests from 9 agents") \
X(SCF_CTU, 33, 0xB1, "Parity error for MCF request") \
X(SCF_CTU, 32, 0xB0, "TRC DMA fillsnoop parity error")
/* CMU_CLOCKS Uncorrectable RAS ERROR */
#define CMU_CLOCKS_UNCORR_RAS_ERROR_LIST(X) \
/* Name, ERR_CTRL, IERR, ISA Desc */ \
X(CMU_CLOCKS, 39, 0xC7, "Cluster 3 frequency monitor error") \
X(CMU_CLOCKS, 38, 0xC6, "Cluster 2 frequency monitor error") \
X(CMU_CLOCKS, 37, 0xC5, "Cluster 1 frequency monitor error") \
X(CMU_CLOCKS, 36, 0xC3, "Cluster 0 frequency monitor error") \
X(CMU_CLOCKS, 35, 0xC4, "Voltage error on ADC1 Monitored Logic") \
X(CMU_CLOCKS, 34, 0xC2, "Voltage error on ADC0 Monitored Logic") \
X(CMU_CLOCKS, 33, 0xC1, "Lookup Table 1 Parity Error") \
X(CMU_CLOCKS, 32, 0xC0, "Lookup Table 0 Parity Error")
/*
* Define one ras_error entry.
*
* This macro wille be used to to generate ras_error records for each node
* defined by <NODE_NAME>_UNCORR_RAS_ERROR_LIST macro.
*/
#define DEFINE_ONE_RAS_ERROR_MSG(unit, ras_bit, ierr, msg) \
{ \
.error_msg = (msg), \
.error_code = (ierr) \
},
/*
* Set one implementation defined bit in ERR<n>CTLR
*
* This macro will be used to collect all defined ERR_CTRL bits for each node
* defined by <NODE_NAME>_UNCORR_RAS_ERROR_LIST macro.
*/
#define DEFINE_ENABLE_RAS_BIT(unit, ras_bit, ierr, msg) \
do { \
val |= (1ULL << ras_bit##U); \
} while (0);
/* Represent one RAS node with 0 or more error bits (ERR_CTLR) enabled */
#define DEFINE_ONE_RAS_NODE(node) \
static const struct ras_error node##_uncorr_ras_errors[] = { \
node##_UNCORR_RAS_ERROR_LIST(DEFINE_ONE_RAS_ERROR_MSG) \
{ \
NULL, \
0U \
}, \
}; \
static inline uint64_t node##_err_ctrl(void) \
{ \
uint64_t val = 0ULL; \
node##_UNCORR_RAS_ERROR_LIST(DEFINE_ENABLE_RAS_BIT) \
return val; \
}
#define DEFINE_ONE_RAS_AUX_DATA(node) \
{ \
.name = #node, \
.error_records = node##_uncorr_ras_errors, \
.err_ctrl = &node##_err_ctrl \
},
#define PER_CORE_RAS_NODE_LIST(X) \
X(IFU) \
X(JSR_RET) \
X(JSR_MTS) \
X(LSD_STQ) \
X(LSD_DCC) \
X(LSD_L1HPF)
#define PER_CORE_RAS_GROUP_NODES PER_CORE_RAS_NODE_LIST(DEFINE_ONE_RAS_AUX_DATA)
#define PER_CLUSTER_RAS_NODE_LIST(X) \
X(L2) \
X(CLUSTER_CLOCKS) \
X(MMU)
#define PER_CLUSTER_RAS_GROUP_NODES PER_CLUSTER_RAS_NODE_LIST(DEFINE_ONE_RAS_AUX_DATA)
#define SCF_L3_BANK_RAS_NODE_LIST(X) X(L3)
/* we have 4 SCF_L3 nodes:3*256 + L3_Bank_ID(0-3) */
#define SCF_L3_BANK_RAS_GROUP_NODES \
SCF_L3_BANK_RAS_NODE_LIST(DEFINE_ONE_RAS_AUX_DATA) \
SCF_L3_BANK_RAS_NODE_LIST(DEFINE_ONE_RAS_AUX_DATA) \
SCF_L3_BANK_RAS_NODE_LIST(DEFINE_ONE_RAS_AUX_DATA) \
SCF_L3_BANK_RAS_NODE_LIST(DEFINE_ONE_RAS_AUX_DATA)
#define CCPLEX_RAS_NODE_LIST(X) \
X(CCPMU) \
X(SCF_IOB) \
X(SCF_SNOC) \
X(SCF_CTU) \
X(CMU_CLOCKS)
#define CCPLEX_RAS_GROUP_NODES CCPLEX_RAS_NODE_LIST(DEFINE_ONE_RAS_AUX_DATA)
#endif /* TEGRA194_RAS_PRIVATE */
@@ -0,0 +1,326 @@
/*
* Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef TEGRA_DEF_H
#define TEGRA_DEF_H
#include <lib/utils_def.h>
/*******************************************************************************
* Platform BL31 specific defines.
******************************************************************************/
#define BL31_SIZE U(0x40000)
/*******************************************************************************
* Chip specific cluster and cpu numbers
******************************************************************************/
#define PLATFORM_CLUSTER_COUNT U(4)
#define PLATFORM_MAX_CPUS_PER_CLUSTER U(2)
/*******************************************************************************
* Chip specific page table and MMU setup constants
******************************************************************************/
#define PLAT_PHY_ADDR_SPACE_SIZE (ULL(1) << 40)
#define PLAT_VIRT_ADDR_SPACE_SIZE (ULL(1) << 40)
/*******************************************************************************
* These values are used by the PSCI implementation during the `CPU_SUSPEND`
* and `SYSTEM_SUSPEND` calls as the `state-id` field in the 'power state'
* parameter.
******************************************************************************/
#define PSTATE_ID_CORE_IDLE U(6)
#define PSTATE_ID_CORE_POWERDN U(7)
#define PSTATE_ID_SOC_POWERDN U(2)
/*******************************************************************************
* Platform power states (used by PSCI framework)
*
* - PLAT_MAX_RET_STATE should be less than lowest PSTATE_ID
* - PLAT_MAX_OFF_STATE should be greater than the highest PSTATE_ID
******************************************************************************/
#define PLAT_MAX_RET_STATE U(1)
#define PLAT_MAX_OFF_STATE U(8)
/*******************************************************************************
* Secure IRQ definitions
******************************************************************************/
#define TEGRA194_MAX_SEC_IRQS U(2)
#define TEGRA194_TOP_WDT_IRQ U(49)
#define TEGRA194_AON_WDT_IRQ U(50)
#define TEGRA194_SEC_IRQ_TARGET_MASK U(0xFF) /* 8 Carmel */
/*******************************************************************************
* Clock identifier for the SE device
******************************************************************************/
#define TEGRA194_CLK_SE U(124)
#define TEGRA_CLK_SE TEGRA194_CLK_SE
/*******************************************************************************
* Tegra Miscellanous register constants
******************************************************************************/
#define TEGRA_MISC_BASE U(0x00100000)
#define HARDWARE_REVISION_OFFSET U(0x4)
#define MISCREG_EMU_REVID U(0x3160)
#define BOARD_MASK_BITS U(0xFF)
#define BOARD_SHIFT_BITS U(24)
#define MISCREG_PFCFG U(0x200C)
/*******************************************************************************
* Tegra General Purpose Centralised DMA constants
******************************************************************************/
#define TEGRA_GPCDMA_BASE U(0x02610000)
/*******************************************************************************
* Tegra Memory Controller constants
******************************************************************************/
#define TEGRA_MC_STREAMID_BASE U(0x02C00000)
#define TEGRA_MC_BASE U(0x02C10000)
/* General Security Carveout register macros */
#define MC_GSC_CONFIG_REGS_SIZE U(0x40)
#define MC_GSC_LOCK_CFG_SETTINGS_BIT (U(1) << 1)
#define MC_GSC_ENABLE_TZ_LOCK_BIT (U(1) << 0)
#define MC_GSC_SIZE_RANGE_4KB_SHIFT U(27)
#define MC_GSC_BASE_LO_SHIFT U(12)
#define MC_GSC_BASE_LO_MASK U(0xFFFFF)
#define MC_GSC_BASE_HI_SHIFT U(0)
#define MC_GSC_BASE_HI_MASK U(3)
#define MC_GSC_ENABLE_CPU_SECURE_BIT (U(1) << 31)
/* TZDRAM carveout configuration registers */
#define MC_SECURITY_CFG0_0 U(0x70)
#define MC_SECURITY_CFG1_0 U(0x74)
#define MC_SECURITY_CFG3_0 U(0x9BC)
#define MC_SECURITY_BOM_MASK (U(0xFFF) << 20)
#define MC_SECURITY_SIZE_MB_MASK (U(0x1FFF) << 0)
#define MC_SECURITY_BOM_HI_MASK (U(0x3) << 0)
#define MC_SECURITY_CFG_REG_CTRL_0 U(0x154)
#define SECURITY_CFG_WRITE_ACCESS_BIT (U(0x1) << 0)
#define SECURITY_CFG_WRITE_ACCESS_ENABLE U(0x0)
#define SECURITY_CFG_WRITE_ACCESS_DISABLE U(0x1)
/* Video Memory carveout configuration registers */
#define MC_VIDEO_PROTECT_BASE_HI U(0x978)
#define MC_VIDEO_PROTECT_BASE_LO U(0x648)
#define MC_VIDEO_PROTECT_SIZE_MB U(0x64c)
#define MC_VIDEO_PROTECT_REG_CTRL U(0x650)
#define MC_VIDEO_PROTECT_WRITE_ACCESS_ENABLED U(3)
/*
* Carveout (MC_SECURITY_CARVEOUT24) registers used to clear the
* non-overlapping Video memory region
*/
#define MC_VIDEO_PROTECT_CLEAR_CFG U(0x25A0)
#define MC_VIDEO_PROTECT_CLEAR_BASE_LO U(0x25A4)
#define MC_VIDEO_PROTECT_CLEAR_BASE_HI U(0x25A8)
#define MC_VIDEO_PROTECT_CLEAR_SIZE U(0x25AC)
#define MC_VIDEO_PROTECT_CLEAR_ACCESS_CFG0 U(0x25B0)
/* TZRAM carveout (MC_SECURITY_CARVEOUT11) configuration registers */
#define MC_TZRAM_CARVEOUT_CFG U(0x2190)
#define MC_TZRAM_BASE_LO U(0x2194)
#define MC_TZRAM_BASE_HI U(0x2198)
#define MC_TZRAM_SIZE U(0x219C)
#define MC_TZRAM_CLIENT_ACCESS0_CFG0 U(0x21A0)
#define MC_TZRAM_CLIENT_ACCESS1_CFG0 U(0x21A4)
#define TZRAM_ALLOW_MPCORER (U(1) << 7)
#define TZRAM_ALLOW_MPCOREW (U(1) << 25)
/* Memory Controller Reset Control registers */
#define MC_CLIENT_HOTRESET_CTRL1_DLAA_FLUSH_ENB (U(1) << 28)
#define MC_CLIENT_HOTRESET_CTRL1_DLA1A_FLUSH_ENB (U(1) << 29)
#define MC_CLIENT_HOTRESET_CTRL1_PVA0A_FLUSH_ENB (U(1) << 30)
#define MC_CLIENT_HOTRESET_CTRL1_PVA1A_FLUSH_ENB (U(1) << 31)
/*******************************************************************************
* Tegra UART Controller constants
******************************************************************************/
#define TEGRA_UARTA_BASE U(0x03100000)
#define TEGRA_UARTB_BASE U(0x03110000)
#define TEGRA_UARTC_BASE U(0x0C280000)
#define TEGRA_UARTD_BASE U(0x03130000)
#define TEGRA_UARTE_BASE U(0x03140000)
#define TEGRA_UARTF_BASE U(0x03150000)
#define TEGRA_UARTG_BASE U(0x0C290000)
/*******************************************************************************
* XUSB PADCTL
******************************************************************************/
#define TEGRA_XUSB_PADCTL_BASE U(0x03520000)
#define TEGRA_XUSB_PADCTL_SIZE U(0x10000)
#define XUSB_PADCTL_HOST_AXI_STREAMID_PF_0 U(0x136c)
#define XUSB_PADCTL_HOST_AXI_STREAMID_VF_0 U(0x1370)
#define XUSB_PADCTL_HOST_AXI_STREAMID_VF_1 U(0x1374)
#define XUSB_PADCTL_HOST_AXI_STREAMID_VF_2 U(0x1378)
#define XUSB_PADCTL_HOST_AXI_STREAMID_VF_3 U(0x137c)
#define XUSB_PADCTL_DEV_AXI_STREAMID_PF_0 U(0x139c)
/*******************************************************************************
* Tegra Fuse Controller related constants
******************************************************************************/
#define TEGRA_FUSE_BASE U(0x03820000)
#define OPT_SUBREVISION U(0x248)
#define SUBREVISION_MASK U(0xF)
/*******************************************************************************
* GICv2 & interrupt handling related constants
******************************************************************************/
#define TEGRA_GICD_BASE U(0x03881000)
#define TEGRA_GICC_BASE U(0x03882000)
/*******************************************************************************
* Security Engine related constants
******************************************************************************/
#define TEGRA_SE0_BASE U(0x03AC0000)
#define SE0_MUTEX_WATCHDOG_NS_LIMIT U(0x6C)
#define SE0_AES0_ENTROPY_SRC_AGE_CTRL U(0x2FC)
#define TEGRA_PKA1_BASE U(0x03AD0000)
#define SE_PKA1_CTRL_SE_MUTEX_TMOUT_DFTVAL U(0x144)
#define PKA1_MUTEX_WATCHDOG_NS_LIMIT SE_PKA1_CTRL_SE_MUTEX_TMOUT_DFTVAL
#define TEGRA_RNG1_BASE U(0x03AE0000)
#define RNG1_MUTEX_WATCHDOG_NS_LIMIT U(0xFE0)
/*******************************************************************************
* Tegra HSP doorbell #0 constants
******************************************************************************/
#define TEGRA_HSP_DBELL_BASE U(0x03C90000)
#define HSP_DBELL_1_ENABLE U(0x104)
#define HSP_DBELL_3_TRIGGER U(0x300)
#define HSP_DBELL_3_ENABLE U(0x304)
/*******************************************************************************
* Tegra hardware synchronization primitives for the SPE engine
******************************************************************************/
#define TEGRA_AON_HSP_SM_6_7_BASE U(0x0c190000)
#define TEGRA_CONSOLE_SPE_BASE (TEGRA_AON_HSP_SM_6_7_BASE + U(0x8000))
/*******************************************************************************
* Tegra micro-seconds timer constants
******************************************************************************/
#define TEGRA_TMRUS_BASE U(0x0C2E0000)
#define TEGRA_TMRUS_SIZE U(0x10000)
/*******************************************************************************
* Tegra Power Mgmt Controller constants
******************************************************************************/
#define TEGRA_PMC_BASE U(0x0C360000)
/*******************************************************************************
* Tegra scratch registers constants
******************************************************************************/
#define TEGRA_SCRATCH_BASE U(0x0C390000)
#define SECURE_SCRATCH_RSV68_LO U(0x284)
#define SECURE_SCRATCH_RSV68_HI U(0x288)
#define SECURE_SCRATCH_RSV69_LO U(0x28C)
#define SECURE_SCRATCH_RSV69_HI U(0x290)
#define SECURE_SCRATCH_RSV70_LO U(0x294)
#define SECURE_SCRATCH_RSV70_HI U(0x298)
#define SECURE_SCRATCH_RSV71_LO U(0x29C)
#define SECURE_SCRATCH_RSV71_HI U(0x2A0)
#define SECURE_SCRATCH_RSV72_LO U(0x2A4)
#define SECURE_SCRATCH_RSV72_HI U(0x2A8)
#define SECURE_SCRATCH_RSV75 U(0x2BC)
#define SECURE_SCRATCH_RSV81_LO U(0x2EC)
#define SECURE_SCRATCH_RSV81_HI U(0x2F0)
#define SECURE_SCRATCH_RSV97 U(0x36C)
#define SECURE_SCRATCH_RSV99_LO U(0x37C)
#define SECURE_SCRATCH_RSV99_HI U(0x380)
#define SECURE_SCRATCH_RSV109_LO U(0x3CC)
#define SECURE_SCRATCH_RSV109_HI U(0x3D0)
#define SCRATCH_BL31_PARAMS_HI_ADDR SECURE_SCRATCH_RSV75
#define SCRATCH_BL31_PARAMS_HI_ADDR_MASK U(0xFFFF)
#define SCRATCH_BL31_PARAMS_HI_ADDR_SHIFT U(0)
#define SCRATCH_BL31_PARAMS_LO_ADDR SECURE_SCRATCH_RSV81_LO
#define SCRATCH_BL31_PLAT_PARAMS_HI_ADDR SECURE_SCRATCH_RSV75
#define SCRATCH_BL31_PLAT_PARAMS_HI_ADDR_MASK U(0xFFFF0000)
#define SCRATCH_BL31_PLAT_PARAMS_HI_ADDR_SHIFT U(16)
#define SCRATCH_BL31_PLAT_PARAMS_LO_ADDR SECURE_SCRATCH_RSV81_HI
#define SCRATCH_SECURE_BOOTP_FCFG SECURE_SCRATCH_RSV97
#define SCRATCH_MC_TABLE_ADDR_LO SECURE_SCRATCH_RSV99_LO
#define SCRATCH_MC_TABLE_ADDR_HI SECURE_SCRATCH_RSV99_HI
#define SCRATCH_RESET_VECTOR_LO SECURE_SCRATCH_RSV109_LO
#define SCRATCH_RESET_VECTOR_HI SECURE_SCRATCH_RSV109_HI
/*******************************************************************************
* Tegra Memory Mapped Control Register Access Bus constants
******************************************************************************/
#define TEGRA_MMCRAB_BASE U(0x0E000000)
/*******************************************************************************
* Tegra SMMU Controller constants
******************************************************************************/
#define TEGRA_SMMU0_BASE U(0x12000000)
#define TEGRA_SMMU1_BASE U(0x11000000)
#define TEGRA_SMMU2_BASE U(0x10000000)
/*******************************************************************************
* Tegra TZRAM constants
******************************************************************************/
#define TEGRA_TZRAM_BASE U(0x40000000)
#define TEGRA_TZRAM_SIZE U(0x40000)
/*******************************************************************************
* Tegra CCPLEX-BPMP IPC constants
******************************************************************************/
#define TEGRA_BPMP_IPC_TX_PHYS_BASE U(0x4004C000)
#define TEGRA_BPMP_IPC_RX_PHYS_BASE U(0x4004D000)
#define TEGRA_BPMP_IPC_CH_MAP_SIZE U(0x1000) /* 4KB */
/*******************************************************************************
* Tegra Clock and Reset Controller constants
******************************************************************************/
#define TEGRA_CAR_RESET_BASE U(0x20000000)
#define TEGRA_GPU_RESET_REG_OFFSET U(0x18)
#define TEGRA_GPU_RESET_GPU_SET_OFFSET U(0x1C)
#define GPU_RESET_BIT (U(1) << 0)
#define GPU_SET_BIT (U(1) << 0)
#define TEGRA_GPCDMA_RST_SET_REG_OFFSET U(0x6A0004)
#define TEGRA_GPCDMA_RST_CLR_REG_OFFSET U(0x6A0008)
/*******************************************************************************
* Tegra DRAM memory base address
******************************************************************************/
#define TEGRA_DRAM_BASE ULL(0x80000000)
#define TEGRA_DRAM_END ULL(0xFFFFFFFFF)
/*******************************************************************************
* XUSB STREAMIDs
******************************************************************************/
#define TEGRA_SID_XUSB_HOST U(0x1b)
#define TEGRA_SID_XUSB_DEV U(0x1c)
#define TEGRA_SID_XUSB_VF0 U(0x5d)
#define TEGRA_SID_XUSB_VF1 U(0x5e)
#define TEGRA_SID_XUSB_VF2 U(0x5f)
#define TEGRA_SID_XUSB_VF3 U(0x60)
/*******************************************************************************
* SCR addresses and expected settings
******************************************************************************/
#define SCRATCH_RSV68_SCR U(0x0C398110)
#define SCRATCH_RSV68_SCR_VAL U(0x38000101)
#define SCRATCH_RSV71_SCR U(0x0C39811C)
#define SCRATCH_RSV71_SCR_VAL U(0x38000101)
#define SCRATCH_RSV72_SCR U(0x0C398120)
#define SCRATCH_RSV72_SCR_VAL U(0x38000101)
#define SCRATCH_RSV75_SCR U(0x0C39812C)
#define SCRATCH_RSV75_SCR_VAL U(0x3A000005)
#define SCRATCH_RSV81_SCR U(0x0C398144)
#define SCRATCH_RSV81_SCR_VAL U(0x3A000105)
#define SCRATCH_RSV97_SCR U(0x0C398184)
#define SCRATCH_RSV97_SCR_VAL U(0x38000101)
#define SCRATCH_RSV99_SCR U(0x0C39818C)
#define SCRATCH_RSV99_SCR_VAL U(0x38000101)
#define SCRATCH_RSV109_SCR U(0x0C3981B4)
#define SCRATCH_RSV109_SCR_VAL U(0x38000101)
#define MISCREG_SCR_SCRTZWELCK U(0x00109000)
#define MISCREG_SCR_SCRTZWELCK_VAL U(0x30000100)
#endif /* TEGRA_DEF_H */
@@ -0,0 +1,293 @@
/*
* Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef TEGRA_DEF_H
#define TEGRA_DEF_H
#include <lib/utils_def.h>
/*******************************************************************************
* Platform BL31 specific defines.
******************************************************************************/
#define BL31_SIZE U(0x40000)
/*******************************************************************************
* Power down state IDs
******************************************************************************/
#define PSTATE_ID_CORE_POWERDN U(7)
#define PSTATE_ID_CLUSTER_IDLE U(16)
#define PSTATE_ID_SOC_POWERDN U(27)
/*******************************************************************************
* This value is used by the PSCI implementation during the `SYSTEM_SUSPEND`
* call as the `state-id` field in the 'power state' parameter.
******************************************************************************/
#define PLAT_SYS_SUSPEND_STATE_ID PSTATE_ID_SOC_POWERDN
/*******************************************************************************
* Platform power states (used by PSCI framework)
*
* - PLAT_MAX_RET_STATE should be less than lowest PSTATE_ID
* - PLAT_MAX_OFF_STATE should be greater than the highest PSTATE_ID
******************************************************************************/
#define PLAT_MAX_RET_STATE U(1)
#define PLAT_MAX_OFF_STATE (PSTATE_ID_SOC_POWERDN + U(1))
/*******************************************************************************
* Chip specific page table and MMU setup constants
******************************************************************************/
#define PLAT_PHY_ADDR_SPACE_SIZE (ULL(1) << 35)
#define PLAT_VIRT_ADDR_SPACE_SIZE (ULL(1) << 35)
/*******************************************************************************
* SC7 entry firmware's header size
******************************************************************************/
#define SC7ENTRY_FW_HEADER_SIZE_BYTES U(0x400)
/*******************************************************************************
* Counter-timer physical secure timer PPI
******************************************************************************/
#define TEGRA210_TIMER1_IRQ 32
/*******************************************************************************
* iRAM memory constants
******************************************************************************/
#define TEGRA_IRAM_BASE U(0x40000000)
#define TEGRA_IRAM_A_SIZE U(0x10000) /* 64KB */
#define TEGRA_IRAM_SIZE U(40000) /* 256KB */
/*******************************************************************************
* GIC memory map
******************************************************************************/
#define TEGRA_GICD_BASE U(0x50041000)
#define TEGRA_GICC_BASE U(0x50042000)
/*******************************************************************************
* Secure IRQ definitions
******************************************************************************/
#define TEGRA210_WDT_CPU_LEGACY_FIQ U(28)
/*******************************************************************************
* Tegra Memory Select Switch Controller constants
******************************************************************************/
#define TEGRA_MSELECT_BASE U(0x50060000)
#define MSELECT_CONFIG U(0x0)
#define ENABLE_WRAP_INCR_MASTER2_BIT (U(1) << U(29))
#define ENABLE_WRAP_INCR_MASTER1_BIT (U(1) << U(28))
#define ENABLE_WRAP_INCR_MASTER0_BIT (U(1) << U(27))
#define UNSUPPORTED_TX_ERR_MASTER2_BIT (U(1) << U(25))
#define UNSUPPORTED_TX_ERR_MASTER1_BIT (U(1) << U(24))
#define ENABLE_UNSUP_TX_ERRORS (UNSUPPORTED_TX_ERR_MASTER2_BIT | \
UNSUPPORTED_TX_ERR_MASTER1_BIT)
#define ENABLE_WRAP_TO_INCR_BURSTS (ENABLE_WRAP_INCR_MASTER2_BIT | \
ENABLE_WRAP_INCR_MASTER1_BIT | \
ENABLE_WRAP_INCR_MASTER0_BIT)
/*******************************************************************************
* Tegra Resource Semaphore constants
******************************************************************************/
#define TEGRA_RES_SEMA_BASE 0x60001000UL
#define STA_OFFSET 0UL
#define SET_OFFSET 4UL
#define CLR_OFFSET 8UL
/*******************************************************************************
* Tegra Primary Interrupt Controller constants
******************************************************************************/
#define TEGRA_PRI_ICTLR_BASE 0x60004000UL
#define CPU_IEP_FIR_SET 0x18UL
/*******************************************************************************
* Tegra micro-seconds timer constants
******************************************************************************/
#define TEGRA_TMRUS_BASE U(0x60005010)
#define TEGRA_TMRUS_SIZE U(0x1000)
/*******************************************************************************
* Tegra Clock and Reset Controller constants
******************************************************************************/
#define TEGRA_CAR_RESET_BASE U(0x60006000)
#define TEGRA_BOND_OUT_H U(0x74)
#define APB_DMA_LOCK_BIT (U(1) << 2)
#define AHB_DMA_LOCK_BIT (U(1) << 1)
#define TEGRA_BOND_OUT_U U(0x78)
#define IRAM_D_LOCK_BIT (U(1) << 23)
#define IRAM_C_LOCK_BIT (U(1) << 22)
#define IRAM_B_LOCK_BIT (U(1) << 21)
#define TEGRA_GPU_RESET_REG_OFFSET U(0x28C)
#define TEGRA_GPU_RESET_GPU_SET_OFFSET U(0x290)
#define GPU_RESET_BIT (U(1) << 24)
#define GPU_SET_BIT (U(1) << 24)
#define TEGRA_RST_DEV_SET_Y U(0x2a8)
#define NVENC_RESET_BIT (U(1) << 27)
#define TSECB_RESET_BIT (U(1) << 14)
#define APE_RESET_BIT (U(1) << 6)
#define NVJPG_RESET_BIT (U(1) << 3)
#define NVDEC_RESET_BIT (U(1) << 2)
#define TEGRA_RST_DEV_SET_L U(0x300)
#define HOST1X_RESET_BIT (U(1) << 28)
#define ISP_RESET_BIT (U(1) << 23)
#define USBD_RESET_BIT (U(1) << 22)
#define VI_RESET_BIT (U(1) << 20)
#define SDMMC4_RESET_BIT (U(1) << 15)
#define SDMMC1_RESET_BIT (U(1) << 14)
#define SDMMC2_RESET_BIT (U(1) << 9)
#define TEGRA_RST_DEV_SET_H U(0x308)
#define USB2_RESET_BIT (U(1) << 26)
#define APBDMA_RESET_BIT (U(1) << 2)
#define AHBDMA_RESET_BIT (U(1) << 1)
#define TEGRA_RST_DEV_SET_U U(0x310)
#define XUSB_DEV_RESET_BIT (U(1) << 31)
#define XUSB_HOST_RESET_BIT (U(1) << 25)
#define TSEC_RESET_BIT (U(1) << 19)
#define PCIE_RESET_BIT (U(1) << 6)
#define SDMMC3_RESET_BIT (U(1) << 5)
#define TEGRA_RST_DEVICES_V U(0x358)
#define TEGRA_RST_DEVICES_W U(0x35C)
#define ENTROPY_CLK_ENB_BIT (U(1) << 21)
#define TEGRA_CLK_OUT_ENB_V U(0x360)
#define SE_CLK_ENB_BIT (U(1) << 31)
#define TEGRA_CLK_OUT_ENB_W U(0x364)
#define ENTROPY_RESET_BIT (U(1) << 21)
#define TEGRA_CLK_RST_CTL_CLK_SRC_SE U(0x42C)
#define SE_CLK_SRC_MASK (U(7) << 29)
#define SE_CLK_SRC_CLK_M (U(6) << 29)
#define TEGRA_RST_DEV_SET_V U(0x430)
#define SE_RESET_BIT (U(1) << 31)
#define HDA_RESET_BIT (U(1) << 29)
#define SATA_RESET_BIT (U(1) << 28)
#define TEGRA_RST_DEV_CLR_V U(0x434)
#define TEGRA_CLK_ENB_V U(0x440)
/*******************************************************************************
* Tegra Flow Controller constants
******************************************************************************/
#define TEGRA_FLOWCTRL_BASE U(0x60007000)
/*******************************************************************************
* Tegra AHB arbitration controller
******************************************************************************/
#define TEGRA_AHB_ARB_BASE 0x6000C000UL
/*******************************************************************************
* Tegra Secure Boot Controller constants
******************************************************************************/
#define TEGRA_SB_BASE U(0x6000C200)
/*******************************************************************************
* Tegra Exception Vectors constants
******************************************************************************/
#define TEGRA_EVP_BASE U(0x6000F000)
/*******************************************************************************
* Tegra Miscellaneous register constants
******************************************************************************/
#define TEGRA_MISC_BASE U(0x70000000)
#define HARDWARE_REVISION_OFFSET U(0x804)
#define APB_SLAVE_SECURITY_ENABLE U(0xC00)
#define PMC_SECURITY_EN_BIT (U(1) << 13)
#define PINMUX_AUX_DVFS_PWM U(0x3184)
#define PINMUX_PWM_TRISTATE (U(1) << 4)
/*******************************************************************************
* Tegra UART controller base addresses
******************************************************************************/
#define TEGRA_UARTA_BASE U(0x70006000)
#define TEGRA_UARTB_BASE U(0x70006040)
#define TEGRA_UARTC_BASE U(0x70006200)
#define TEGRA_UARTD_BASE U(0x70006300)
#define TEGRA_UARTE_BASE U(0x70006400)
/*******************************************************************************
* Tegra Fuse Controller related constants
******************************************************************************/
#define TEGRA_FUSE_BASE 0x7000F800UL
#define FUSE_BOOT_SECURITY_INFO 0x268UL
#define FUSE_ATOMIC_SAVE_CARVEOUT_EN (0x1U << 7)
#define FUSE_JTAG_SECUREID_VALID (0x104UL)
#define ECID_VALID (0x1UL)
/*******************************************************************************
* Tegra Power Mgmt Controller constants
******************************************************************************/
#define TEGRA_PMC_BASE U(0x7000E400)
#define TEGRA_PMC_SIZE U(0xC00) /* 3k */
/*******************************************************************************
* Tegra Atomics constants
******************************************************************************/
#define TEGRA_ATOMICS_BASE 0x70016000UL
#define TRIGGER0_REG_OFFSET 0UL
#define TRIGGER_WIDTH_SHIFT 4UL
#define TRIGGER_ID_SHIFT 16UL
#define RESULT0_REG_OFFSET 0xC00UL
/*******************************************************************************
* Tegra Memory Controller constants
******************************************************************************/
#define TEGRA_MC_BASE U(0x70019000)
/* Memory Controller Interrupt Status */
#define MC_INTSTATUS 0x00U
/* TZDRAM carveout configuration registers */
#define MC_SECURITY_CFG0_0 U(0x70)
#define MC_SECURITY_CFG1_0 U(0x74)
#define MC_SECURITY_CFG3_0 U(0x9BC)
/* Video Memory carveout configuration registers */
#define MC_VIDEO_PROTECT_BASE_HI U(0x978)
#define MC_VIDEO_PROTECT_BASE_LO U(0x648)
#define MC_VIDEO_PROTECT_SIZE_MB U(0x64c)
#define MC_VIDEO_PROTECT_REG_CTRL U(0x650)
#define MC_VIDEO_PROTECT_WRITE_ACCESS_ENABLED U(3)
/* SMMU configuration registers*/
#define MC_SMMU_PPCS_ASID_0 0x270U
#define PPCS_SMMU_ENABLE (0x1U << 31)
/*******************************************************************************
* Tegra CLDVFS constants
******************************************************************************/
#define TEGRA_CL_DVFS_BASE U(0x70110000)
#define DVFS_DFLL_CTRL U(0x00)
#define ENABLE_OPEN_LOOP U(1)
#define ENABLE_CLOSED_LOOP U(2)
#define DVFS_DFLL_OUTPUT_CFG U(0x20)
#define DFLL_OUTPUT_CFG_I2C_EN_BIT (U(1) << 30)
#define DFLL_OUTPUT_CFG_CLK_EN_BIT (U(1) << 6)
/*******************************************************************************
* Tegra SE constants
******************************************************************************/
#define TEGRA_SE1_BASE U(0x70012000)
#define TEGRA_SE2_BASE U(0x70412000)
#define TEGRA_PKA1_BASE U(0x70420000)
#define TEGRA_SE2_RANGE_SIZE U(0x2000)
#define SE_TZRAM_SECURITY U(0x4)
/*******************************************************************************
* Tegra TZRAM constants
******************************************************************************/
#define TEGRA_TZRAM_BASE U(0x7C010000)
#define TEGRA_TZRAM_SIZE U(0x10000)
/*******************************************************************************
* Tegra TZRAM carveout constants
******************************************************************************/
#define TEGRA_TZRAM_CARVEOUT_BASE U(0x7C04C000)
#define TEGRA_TZRAM_CARVEOUT_SIZE U(0x4000)
/*******************************************************************************
* Tegra DRAM memory base address
******************************************************************************/
#define TEGRA_DRAM_BASE ULL(0x80000000)
#define TEGRA_DRAM_END ULL(0x27FFFFFFF)
#endif /* TEGRA_DEF_H */
@@ -0,0 +1,70 @@
/*
* Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2020-2021, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef TEGRA_PLATFORM_H
#define TEGRA_PLATFORM_H
#include <cdefs.h>
#include <lib/utils_def.h>
#include <stdbool.h>
/*******************************************************************************
* Tegra major, minor version helper macros
******************************************************************************/
#define MAJOR_VERSION_SHIFT U(0x4)
#define MAJOR_VERSION_MASK U(0xF)
#define MINOR_VERSION_SHIFT U(0x10)
#define MINOR_VERSION_MASK U(0xF)
#define CHIP_ID_SHIFT U(8)
#define CHIP_ID_MASK U(0xFF)
#define PRE_SI_PLATFORM_SHIFT U(0x14)
#define PRE_SI_PLATFORM_MASK U(0xF)
/*******************************************************************************
* Tegra chip ID values
******************************************************************************/
#define TEGRA_CHIPID_TEGRA13 U(0x13)
#define TEGRA_CHIPID_TEGRA21 U(0x21)
#define TEGRA_CHIPID_TEGRA18 U(0x18)
#define TEGRA_CHIPID_TEGRA19 U(0x19)
/*******************************************************************************
* JEDEC Standard Manufacturer's Identification Code and Bank ID
******************************************************************************/
#define JEDEC_NVIDIA_MFID U(0x6B)
#define JEDEC_NVIDIA_BKID U(3)
#ifndef __ASSEMBLER__
/*
* Tegra chip ID major/minor identifiers
*/
uint32_t tegra_get_chipid_major(void);
uint32_t tegra_get_chipid_minor(void);
/*
* Tegra chip ID identifiers
*/
bool tegra_chipid_is_t186(void);
bool tegra_chipid_is_t210(void);
bool tegra_chipid_is_t210_b01(void);
bool tegra_chipid_is_t194(void);
/*
* Tegra platform identifiers
*/
bool tegra_platform_is_silicon(void);
bool tegra_platform_is_qt(void);
bool tegra_platform_is_emulation(void);
bool tegra_platform_is_linsim(void);
bool tegra_platform_is_fpga(void);
bool tegra_platform_is_unit_fpga(void);
bool tegra_platform_is_virt_dev_kit(void);
#endif /* __ASSEMBLER__ */
#endif /* TEGRA_PLATFORM_H */
@@ -0,0 +1,158 @@
/*
* Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef TEGRA_PRIVATE_H
#define TEGRA_PRIVATE_H
#include <platform_def.h>
#include <stdbool.h>
#include <arch.h>
#include <arch_helpers.h>
#include <drivers/ti/uart/uart_16550.h>
#include <lib/psci/psci.h>
#include <lib/xlat_tables/xlat_tables_v2.h>
#include <tegra_gic.h>
/*******************************************************************************
* Implementation defined ACTLR_EL1 bit definitions
******************************************************************************/
#define ACTLR_EL1_PMSTATE_MASK (ULL(0xF) << 0)
/*******************************************************************************
* Implementation defined ACTLR_EL2 bit definitions
******************************************************************************/
#define ACTLR_EL2_PMSTATE_MASK (ULL(0xF) << 0)
/*******************************************************************************
* Struct for parameters received from BL2
******************************************************************************/
typedef struct plat_params_from_bl2 {
/* TZ memory size */
uint64_t tzdram_size;
/* TZ memory base */
uint64_t tzdram_base;
/* UART port ID */
int32_t uart_id;
/* L2 ECC parity protection disable flag */
int32_t l2_ecc_parity_prot_dis;
/* SHMEM base address for storing the boot logs */
uint64_t boot_profiler_shmem_base;
/* System Suspend Entry Firmware size */
uint64_t sc7entry_fw_size;
/* System Suspend Entry Firmware base address */
uint64_t sc7entry_fw_base;
/* Enable dual execution */
uint8_t enable_ccplex_lock_step;
} plat_params_from_bl2_t;
/*******************************************************************************
* Helper function to access l2ctlr_el1 register on Cortex-A57 CPUs
******************************************************************************/
DEFINE_RENAME_SYSREG_RW_FUNCS(l2ctlr_el1, CORTEX_A57_L2CTLR_EL1)
/*******************************************************************************
* Struct describing parameters passed to bl31
******************************************************************************/
struct tegra_bl31_params {
param_header_t h;
image_info_t *bl31_image_info;
entry_point_info_t *bl32_ep_info;
image_info_t *bl32_image_info;
entry_point_info_t *bl33_ep_info;
image_info_t *bl33_image_info;
};
/*******************************************************************************
* To suppress Coverity MISRA C-2012 Rule 2.2 violations
*******************************************************************************/
#define UNUSED_FUNC_NOP() asm("nop")
/* Declarations for plat_psci_handlers.c */
int32_t tegra_soc_validate_power_state(uint32_t power_state,
psci_power_state_t *req_state);
/* Declarations for plat_setup.c */
const mmap_region_t *plat_get_mmio_map(void);
void plat_enable_console(int32_t id);
void plat_gic_setup(void);
struct tegra_bl31_params *plat_get_bl31_params(void);
plat_params_from_bl2_t *plat_get_bl31_plat_params(void);
void plat_early_platform_setup(void);
void plat_late_platform_setup(void);
void plat_relocate_bl32_image(const image_info_t *bl32_img_info);
bool plat_supports_system_suspend(void);
void plat_runtime_setup(void);
/* Declarations for plat_secondary.c */
void plat_secondary_setup(void);
int32_t plat_lock_cpu_vectors(void);
/* Declarations for tegra_fiq_glue.c */
void tegra_fiq_handler_setup(void);
int32_t tegra_fiq_get_intr_context(void);
void tegra_fiq_set_ns_entrypoint(uint64_t entrypoint);
/* Declarations for tegra_security.c */
void tegra_security_setup(void);
void tegra_security_setup_videomem(uintptr_t base, uint64_t size);
/* Declarations for tegra_pm.c */
void tegra_pm_system_suspend_entry(void);
void tegra_pm_system_suspend_exit(void);
int32_t tegra_system_suspended(void);
int32_t tegra_soc_cpu_standby(plat_local_state_t cpu_state);
int32_t tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state);
int32_t tegra_soc_pwr_domain_on(u_register_t mpidr);
int32_t tegra_soc_pwr_domain_off(const psci_power_state_t *target_state);
int32_t tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state);
int32_t tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state);
int32_t tegra_soc_pwr_domain_suspend_pwrdown_early(const psci_power_state_t *target_state);
int32_t tegra_soc_prepare_system_reset(void);
__dead2 void tegra_soc_prepare_system_off(void);
plat_local_state_t tegra_soc_get_target_pwr_state(uint32_t lvl,
const plat_local_state_t *states,
uint32_t ncpu);
/* Declarations for tegraXXX_pm.c */
int tegra_prepare_cpu_suspend(unsigned int id, unsigned int afflvl);
int tegra_prepare_cpu_on_finish(unsigned long mpidr);
/* Declarations for tegra_bl31_setup.c */
plat_params_from_bl2_t *bl31_get_plat_params(void);
int32_t bl31_check_ns_address(uint64_t base, uint64_t size_in_bytes);
/* Declarations for tegra_delay_timer.c */
void tegra_delay_timer_init(void);
void tegra_secure_entrypoint(void);
/* Declarations for tegra_sip_calls.c */
uintptr_t tegra_sip_handler(uint32_t smc_fid,
u_register_t x1,
u_register_t x2,
u_register_t x3,
u_register_t x4,
void *cookie,
void *handle,
u_register_t flags);
int plat_sip_handler(uint32_t smc_fid,
uint64_t x1,
uint64_t x2,
uint64_t x3,
uint64_t x4,
const void *cookie,
void *handle,
uint64_t flags);
#if RAS_EXTENSION
void tegra194_ras_enable(void);
void tegra194_ras_corrected_err_clear(uint64_t *cookie);
#endif
#endif /* TEGRA_PRIVATE_H */
@@ -0,0 +1,144 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
/*******************************************************************************
* The profiler stores the timestamps captured during cold boot to the shared
* memory for the non-secure world. The non-secure world driver parses the
* shared memory block and writes the contents to a file on the device, which
* can be later extracted for analysis.
*
* Profiler memory map
*
* TOP --------------------------- ---
* Trusted OS timestamps 3KB
* --------------------------- ---
* Trusted Firmware timestamps 1KB
* BASE --------------------------- ---
*
******************************************************************************/
#include <arch.h>
#include <arch_helpers.h>
#include <assert.h>
#include <lib/mmio.h>
#include <lib/utils_def.h>
#include <lib/xlat_tables/xlat_tables_v2.h>
#include <profiler.h>
#include <stdbool.h>
#include <string.h>
static uint64_t shmem_base_addr;
#define MAX_PROFILER_RECORDS U(16)
#define TAG_LEN_BYTES U(56)
/*******************************************************************************
* Profiler entry format
******************************************************************************/
typedef struct {
/* text explaining the timestamp location in code */
uint8_t tag[TAG_LEN_BYTES];
/* timestamp value */
uint64_t timestamp;
} profiler_rec_t;
static profiler_rec_t *head, *cur, *tail;
static uint32_t tmr;
static bool is_shmem_buf_mapped;
/*******************************************************************************
* Initialise the profiling library
******************************************************************************/
void boot_profiler_init(uint64_t shmem_base, uint32_t tmr_base)
{
uint64_t shmem_end_base;
assert(shmem_base != ULL(0));
assert(tmr_base != U(0));
/* store the buffer address */
shmem_base_addr = shmem_base;
/* calculate the base address of the last record */
shmem_end_base = shmem_base + (sizeof(profiler_rec_t) *
(MAX_PROFILER_RECORDS - U(1)));
/* calculate the head, tail and cur values */
head = (profiler_rec_t *)shmem_base;
tail = (profiler_rec_t *)shmem_end_base;
cur = head;
/* timer used to get the current timestamp */
tmr = tmr_base;
}
/*******************************************************************************
* Add tag and timestamp to profiler
******************************************************************************/
void boot_profiler_add_record(const char *str)
{
unsigned int len;
/* calculate the length of the tag */
if (((unsigned int)strlen(str) + U(1)) > TAG_LEN_BYTES) {
len = TAG_LEN_BYTES;
} else {
len = (unsigned int)strlen(str) + U(1);
}
if (head != NULL) {
/*
* The profiler runs with/without MMU enabled. Check
* if MMU is enabled and memmap the shmem buffer, in
* case it is.
*/
if ((!is_shmem_buf_mapped) &&
((read_sctlr_el3() & SCTLR_M_BIT) != U(0))) {
(void)mmap_add_dynamic_region(shmem_base_addr,
shmem_base_addr,
PROFILER_SIZE_BYTES,
(MT_NS | MT_RW | MT_EXECUTE_NEVER));
is_shmem_buf_mapped = true;
}
/* write the tag and timestamp to buffer */
(void)snprintf((char *)cur->tag, len, "%s", str);
cur->timestamp = mmio_read_32(tmr);
/* start from head if we reached the end */
if (cur == tail) {
cur = head;
} else {
cur++;
}
}
}
/*******************************************************************************
* Deinint the profiler
******************************************************************************/
void boot_profiler_deinit(void)
{
if (shmem_base_addr != ULL(0)) {
/* clean up resources */
cur = NULL;
head = NULL;
tail = NULL;
/* flush the shmem for it to be visible to the NS world */
flush_dcache_range(shmem_base_addr, PROFILER_SIZE_BYTES);
/* unmap the shmem buffer */
if (is_shmem_buf_mapped) {
(void)mmap_remove_dynamic_region(shmem_base_addr,
PROFILER_SIZE_BYTES);
}
}
}
@@ -0,0 +1,97 @@
#
# Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
# Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
SOC_DIR := plat/nvidia/tegra/soc/${TARGET_SOC}
# dump the state on crash console
CRASH_REPORTING := 1
$(eval $(call add_define,CRASH_REPORTING))
# enable assert() for release/debug builds
ENABLE_ASSERTIONS := 1
PLAT_LOG_LEVEL_ASSERT := 50
$(eval $(call add_define,PLAT_LOG_LEVEL_ASSERT))
# enable dynamic memory mapping
PLAT_XLAT_TABLES_DYNAMIC := 1
$(eval $(call add_define,PLAT_XLAT_TABLES_DYNAMIC))
# Enable exception handling at EL3
EL3_EXCEPTION_HANDLING := 1
GICV2_G0_FOR_EL3 := 1
# Enable PSCI v1.0 extended state ID format
PSCI_EXTENDED_STATE_ID := 1
# code and read-only data should be put on separate memory pages
SEPARATE_CODE_AND_RODATA := 1
# do not use coherent memory
USE_COHERENT_MEM := 0
# enable D-cache early during CPU warmboot
WARMBOOT_ENABLE_DCACHE_EARLY := 1
# remove the standard libc
OVERRIDE_LIBC := 1
# Flag to enable WDT FIQ interrupt handling for Tegra SoCs
# prior to Tegra186
ENABLE_TEGRA_WDT_LEGACY_FIQ_HANDLING ?= 0
# Flag to allow relocation of BL32 image to TZDRAM during boot
RELOCATE_BL32_IMAGE ?= 0
# Enable stack protection
ENABLE_STACK_PROTECTOR := strong
# Enable SDEI
SDEI_SUPPORT := 1
# modify BUILD_PLAT to point to SoC specific build directory
BUILD_PLAT := ${BUILD_BASE}/${PLAT}/${TARGET_SOC}/${BUILD_TYPE}
include plat/nvidia/tegra/common/tegra_common.mk
include ${SOC_DIR}/platform_${TARGET_SOC}.mk
$(eval $(call add_define,ENABLE_TEGRA_WDT_LEGACY_FIQ_HANDLING))
$(eval $(call add_define,RELOCATE_BL32_IMAGE))
# platform cflags (enable signed comparisons, disable stdlib)
TF_CFLAGS += -nostdlib
# override with necessary libc files for the Tegra platform
override LIBC_SRCS := $(addprefix lib/libc/, \
aarch64/setjmp.S \
assert.c \
memchr.c \
memcmp.c \
memcpy.c \
memmove.c \
memset.c \
printf.c \
putchar.c \
strrchr.c \
strlen.c \
snprintf.c)
INCLUDES += -Iinclude/lib/libc \
-Iinclude/lib/libc/$(ARCH) \
ifneq ($(findstring armlink,$(notdir $(LD))),)
# o suppress warnings for section mismatches, undefined symbols
# o use only those libraries that are specified in the input file
# list to resolve references
# o create a static callgraph of functions
# o resolve undefined symbols to el3_panic
# o include only required sections
TF_LDFLAGS += --diag_suppress=L6314,L6332 --no_scanlib --callgraph
TF_LDFLAGS += --keep="*(__pubsub*)" --keep="*(rt_svc_descs*)" --keep="*(*cpu_ops)"
ifeq (${ENABLE_PMF},1)
TF_LDFLAGS += --keep="*(*pmf_svc_descs*)"
endif
endif
@@ -0,0 +1,284 @@
#! armclang -E -x c
/*
* Copyright (c) 2019, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <platform_def.h>
#define PAGE_SIZE (1024 * 4)
LR_START BL31_BASE
{
__BL31_START__ +0 FIXED EMPTY 0
{
/* placeholder */
}
/* BL31_BASE address must be aligned on a page boundary. */
ScatterAssert((ImageBase(__BL31_START__) AND 0xFFF) == 0)
}
LR_TEXT BL31_BASE
{
__TEXT__ +0 FIXED
{
*(:gdef:bl31_entrypoint, +FIRST)
*(.text*)
*(.vectors)
.ANY1(+RO-CODE)
}
__TEXT_EPILOGUE__ AlignExpr(+0, PAGE_SIZE) FIXED EMPTY 0
{
/* section delimiter */
}
}
LR_RO_DATA +0
{
__RODATA__ AlignExpr(ImageLimit(LR_TEXT), 0) FIXED
{
*(.rodata*)
.ANY2(+RO-DATA)
}
/* Ensure 8-byte alignment for descriptors and ensure inclusion */
__RT_SVC_DESCS__ AlignExpr(ImageLimit(__RODATA__), 8) FIXED
{
*(rt_svc_descs)
}
#if ENABLE_PMF
/* Ensure 8-byte alignment for descriptors and ensure inclusion */
__PMF_SVC_DESCS__ AlignExpr(ImageLimit(__RT_SVC_DESCS__), 8) FIXED
{
*(pmf_svc_descs)
}
#endif /* ENABLE_PMF */
/*
* Ensure 8-byte alignment for cpu_ops so that its fields are also
* aligned.
*/
__CPU_OPS__ AlignExpr(+0, 8) FIXED
{
*(cpu_ops)
}
/*
* Keep the .got section in the RO section as it is patched
* prior to enabling the MMU and having the .got in RO is better for
* security. GOT is a table of addresses so ensure 8-byte alignment.
*/
__GOT__ AlignExpr(ImageLimit(__CPU_OPS__), 8) FIXED
{
*(.got)
}
/* Place pubsub sections for events */
__PUBSUB_EVENTS__ AlignExpr(+0, 8) EMPTY 0
{
/* placeholder */
}
#include <lib/el3_runtime/pubsub_events.h>
__RODATA_EPILOGUE__ AlignExpr(+0, PAGE_SIZE) FIXED EMPTY 0
{
/* section delimiter */
}
}
/* cpu_ops must always be defined */
ScatterAssert(ImageLength(__CPU_OPS__) > 0)
#if SPM_MM
LR_SPM +0
{
/*
* Exception vectors of the SPM shim layer. They must be aligned to a 2K
* address, but we need to place them in a separate page so that we can set
* individual permissions to them, so the actual alignment needed is 4K.
*
* There's no need to include this into the RO section of BL31 because it
* doesn't need to be accessed by BL31.
*/
__SPM_SHIM_EXCEPTIONS__ AlignExpr(ImageLimit(LR_RO_DATA), PAGE_SIZE) FIXED
{
*(.spm_shim_exceptions)
}
__SPM_SHIM_EXCEPTIONS_EPILOGUE__ AlignExpr(ImageLimit(__SPM_SHIM_EXCEPTIONS__), PAGE_SIZE) FIXED
{
/* placeholder */
}
}
#endif
LR_RW_DATA +0
{
__DATA__ AlignExpr(+0, 16) FIXED
{
*(.data*)
*(.constdata)
*(locale$$data)
}
}
LR_RELA +0
{
/*
* .rela.dyn needs to come after .data for the read-elf utility to parse
* this section correctly. Ensure 8-byte alignment so that the fields of
* RELA data structure are aligned.
*/
__RELA__ AlignExpr(ImageLimit(LR_RW_DATA), 8) FIXED
{
*(.rela.dyn)
}
}
#ifdef BL31_PROGBITS_LIMIT
/* BL31 progbits has exceeded its limit. */
ScatterAssert(ImageLimit(LR_RELA) <= BL31_PROGBITS_LIMIT)
#endif
LR_STACKS +0
{
__STACKS__ AlignExpr(+0, 64) FIXED
{
*(tzfw_normal_stacks)
}
}
#define __BAKERY_LOCK_SIZE__ (ImageLimit(__BAKERY_LOCKS_EPILOGUE__) - \
ImageBase(__BAKERY_LOCKS__))
#define BAKERY_LOCK_SIZE (__BAKERY_LOCK_SIZE__ * (PLATFORM_CORE_COUNT - 1))
#define __PMF_TIMESTAMP_SIZE__ (ImageLimit(__PMF_TIMESTAMP__) - \
ImageBase(__PMF_TIMESTAMP__))
#define PER_CPU_TIMESTAMP_SIZE (__PMF_TIMESTAMP_SIZE__ * (PLATFORM_CORE_COUNT - 1))
LR_BSS +0
{
__BSS__ AlignExpr(ImageLimit(LR_STACKS), 256) FIXED
{
*(.bss*)
*(COMDAT)
}
#if !USE_COHERENT_MEM
/*
* Bakery locks are stored in normal .bss memory
*
* Each lock's data is spread across multiple cache lines, one per CPU,
* but multiple locks can share the same cache line.
* The compiler will allocate enough memory for one CPU's bakery locks,
* the remaining cache lines are allocated by the linker script
*/
__BAKERY_LOCKS__ AlignExpr(ImageLimit(__BSS__), CACHE_WRITEBACK_GRANULE) FIXED
{
*(bakery_lock)
}
__BAKERY_LOCKS_EPILOGUE__ AlignExpr(ImageLimit(__BAKERY_LOCKS__), CACHE_WRITEBACK_GRANULE) FIXED EMPTY 0
{
/* section delimiter */
}
__PER_CPU_BAKERY_LOCKS__ ImageLimit(__BAKERY_LOCKS_EPILOGUE__) FIXED FILL 0 BAKERY_LOCK_SIZE
{
/* padded memory section to store per cpu bakery locks */
}
#ifdef PLAT_PERCPU_BAKERY_LOCK_SIZE
/* PLAT_PERCPU_BAKERY_LOCK_SIZE does not match bakery lock requirements */
ScatterAssert(__PER_CPU_BAKERY_LOCK_SIZE__ == PLAT_PERCPU_BAKERY_LOCK_SIZE)
#endif
#endif
#if ENABLE_PMF
/*
* Time-stamps are stored in normal .bss memory
*
* The compiler will allocate enough memory for one CPU's time-stamps,
* the remaining memory for other CPU's is allocated by the
* linker script
*/
__PMF_TIMESTAMP__ AlignExpr(+0, CACHE_WRITEBACK_GRANULE) FIXED EMPTY CACHE_WRITEBACK_GRANULE
{
/* store timestamps in this carved out memory */
}
__PMF_TIMESTAMP_EPILOGUE__ AlignExpr(ImageLimit(__PMF_TIMESTAMP__), CACHE_WRITEBACK_GRANULE) FIXED EMPTY 0
{
/*
* placeholder to make __PMF_TIMESTAMP_START__ end on a
* CACHE_WRITEBACK_GRANULE boundary
*/
}
__PER_CPU_TIMESTAMPS__ +0 FIXED FILL 0 PER_CPU_TIMESTAMP_SIZE
{
/* padded memory section to store per cpu timestamps */
}
#endif /* ENABLE_PMF */
}
LR_XLAT_TABLE +0
{
xlat_table +0 FIXED
{
*(xlat_table)
}
}
#if USE_COHERENT_MEM
LR_COHERENT_RAM +0
{
/*
* The base address of the coherent memory section must be page-aligned (4K)
* to guarantee that the coherent data are stored on their own pages and
* are not mixed with normal data. This is required to set up the correct
* memory attributes for the coherent data page tables.
*/
__COHERENT_RAM__ AlignExpr(+0, PAGE_SIZE) FIXED
{
/*
* Bakery locks are stored in coherent memory
*
* Each lock's data is contiguous and fully allocated by the compiler
*/
*(bakery_lock)
*(tzfw_coherent_mem)
}
__COHERENT_RAM_EPILOGUE_UNALIGNED__ +0 FIXED EMPTY 0
{
/* section delimiter */
}
/*
* Memory page(s) mapped to this section will be marked
* as device memory. No other unexpected data must creep in.
* Ensure the rest of the current memory page is unused.
*/
__COHERENT_RAM_EPILOGUE__ AlignExpr(ImageLimit(__COHERENT_RAM_START__), PAGE_SIZE) FIXED EMPTY 0
{
/* section delimiter */
}
}
#endif
LR_END +0
{
__BL31_END__ +0 FIXED EMPTY 0
{
/* placeholder */
}
/* BL31 image has exceeded its limit. */
ScatterAssert(ImageLimit(__BL31_END__) <= BL31_LIMIT)
}
@@ -0,0 +1,260 @@
/*
* Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MCE_PRIVATE_H
#define MCE_PRIVATE_H
#include <lib/mmio.h>
#include <tegra_def.h>
/*******************************************************************************
* Macros to prepare CSTATE info request
******************************************************************************/
/* Description of the parameters for UPDATE_CSTATE_INFO request */
#define CLUSTER_CSTATE_MASK ULL(0x7)
#define CLUSTER_CSTATE_SHIFT U(0)
#define CLUSTER_CSTATE_UPDATE_BIT (ULL(1) << 7)
#define CCPLEX_CSTATE_MASK ULL(0x3)
#define CCPLEX_CSTATE_SHIFT ULL(8)
#define CCPLEX_CSTATE_UPDATE_BIT (ULL(1) << 15)
#define SYSTEM_CSTATE_MASK ULL(0xF)
#define SYSTEM_CSTATE_SHIFT ULL(16)
#define SYSTEM_CSTATE_FORCE_UPDATE_SHIFT ULL(22)
#define SYSTEM_CSTATE_FORCE_UPDATE_BIT (ULL(1) << 22)
#define SYSTEM_CSTATE_UPDATE_BIT (ULL(1) << 23)
#define CSTATE_WAKE_MASK_UPDATE_BIT (ULL(1) << 31)
#define CSTATE_WAKE_MASK_SHIFT ULL(32)
#define CSTATE_WAKE_MASK_CLEAR U(0xFFFFFFFF)
/*******************************************************************************
* Auto-CC3 control macros
******************************************************************************/
#define MCE_AUTO_CC3_FREQ_MASK U(0x1FF)
#define MCE_AUTO_CC3_FREQ_SHIFT U(0)
#define MCE_AUTO_CC3_VTG_MASK U(0x7F)
#define MCE_AUTO_CC3_VTG_SHIFT U(16)
#define MCE_AUTO_CC3_ENABLE_BIT (U(1) << 31)
/*******************************************************************************
* Macros for the 'IS_SC7_ALLOWED' command
******************************************************************************/
#define MCE_SC7_ALLOWED_MASK U(0x7)
#define MCE_SC7_WAKE_TIME_SHIFT U(32)
/*******************************************************************************
* Macros for 'read/write ctats' commands
******************************************************************************/
#define MCE_CSTATE_STATS_TYPE_SHIFT ULL(32)
#define MCE_CSTATE_WRITE_DATA_LO_MASK U(0xF)
/*******************************************************************************
* Macros for 'update crossover threshold' command
******************************************************************************/
#define MCE_CROSSOVER_THRESHOLD_TIME_SHIFT U(32)
/*******************************************************************************
* MCA argument macros
******************************************************************************/
#define MCA_ARG_ERROR_MASK U(0xFF)
#define MCA_ARG_FINISH_SHIFT U(24)
#define MCA_ARG_FINISH_MASK U(0xFF)
/*******************************************************************************
* Uncore PERFMON ARI macros
******************************************************************************/
#define UNCORE_PERFMON_CMD_READ U(0)
#define UNCORE_PERFMON_CMD_WRITE U(1)
#define UNCORE_PERFMON_CMD_MASK U(0xFF)
#define UNCORE_PERFMON_UNIT_GRP_MASK U(0xF)
#define UNCORE_PERFMON_SELECTOR_MASK U(0xF)
#define UNCORE_PERFMON_REG_MASK U(0xFF)
#define UNCORE_PERFMON_CTR_MASK U(0xFF)
#define UNCORE_PERFMON_RESP_STATUS_MASK U(0xFF)
/*******************************************************************************
* Structure populated by arch specific code to export routines which perform
* common low level MCE functions
******************************************************************************/
typedef struct arch_mce_ops {
/*
* This ARI request sets up the MCE to start execution on assertion
* of STANDBYWFI, update the core power state and expected wake time,
* then determine the proper power state to enter.
*/
int32_t (*enter_cstate)(uint32_t ari_base, uint32_t state,
uint32_t wake_time);
/*
* This ARI request allows updating of the CLUSTER_CSTATE,
* CCPLEX_CSTATE, and SYSTEM_CSTATE register values.
*/
int32_t (*update_cstate_info)(uint32_t ari_base,
uint32_t cluster,
uint32_t ccplex,
uint32_t system,
uint8_t sys_state_force,
uint32_t wake_mask,
uint8_t update_wake_mask);
/*
* This ARI request allows updating of power state crossover
* threshold times. An index value specifies which crossover
* state is being updated.
*/
int32_t (*update_crossover_time)(uint32_t ari_base,
uint32_t type,
uint32_t time);
/*
* This ARI request allows read access to statistical information
* related to power states.
*/
uint64_t (*read_cstate_stats)(uint32_t ari_base,
uint32_t state);
/*
* This ARI request allows write access to statistical information
* related to power states.
*/
int32_t (*write_cstate_stats)(uint32_t ari_base,
uint32_t state,
uint32_t stats);
/*
* This ARI request allows the CPU to understand the features
* supported by the MCE firmware.
*/
uint64_t (*call_enum_misc)(uint32_t ari_base, uint32_t cmd,
uint32_t data);
/*
* This ARI request allows querying the CCPLEX to determine if
* the CCx state is allowed given a target core C-state and wake
* time. If the CCx state is allowed, the response indicates CCx
* must be entered. If the CCx state is not allowed, the response
* indicates CC6/CC7 can't be entered
*/
int32_t (*is_ccx_allowed)(uint32_t ari_base, uint32_t state,
uint32_t wake_time);
/*
* This ARI request allows querying the CCPLEX to determine if
* the SC7 state is allowed given a target core C-state and wake
* time. If the SC7 state is allowed, all cores but the associated
* core are offlined (WAKE_EVENTS are set to 0) and the response
* indicates SC7 must be entered. If the SC7 state is not allowed,
* the response indicates SC7 can't be entered
*/
int32_t (*is_sc7_allowed)(uint32_t ari_base, uint32_t state,
uint32_t wake_time);
/*
* This ARI request allows a core to bring another offlined core
* back online to the C0 state. Note that a core is offlined by
* entering a C-state where the WAKE_MASK is all 0.
*/
int32_t (*online_core)(uint32_t ari_base, uint32_t cpuid);
/*
* This ARI request allows the CPU to enable/disable Auto-CC3 idle
* state.
*/
int32_t (*cc3_ctrl)(uint32_t ari_base,
uint32_t freq,
uint32_t volt,
uint8_t enable);
/*
* This ARI request allows updating the reset vector register for
* D15 and A57 CPUs.
*/
int32_t (*update_reset_vector)(uint32_t ari_base);
/*
* This ARI request instructs the ROC to flush A57 data caches in
* order to maintain coherency with the Denver cluster.
*/
int32_t (*roc_flush_cache)(uint32_t ari_base);
/*
* This ARI request instructs the ROC to flush A57 data caches along
* with the caches covering ARM code in order to maintain coherency
* with the Denver cluster.
*/
int32_t (*roc_flush_cache_trbits)(uint32_t ari_base);
/*
* This ARI request instructs the ROC to clean A57 data caches along
* with the caches covering ARM code in order to maintain coherency
* with the Denver cluster.
*/
int32_t (*roc_clean_cache)(uint32_t ari_base);
/*
* This ARI request reads/writes the Machine Check Arch. (MCA)
* registers.
*/
uint64_t (*read_write_mca)(uint32_t ari_base,
uint64_t cmd,
uint64_t *data);
/*
* Some MC GSC (General Security Carveout) register values are
* expected to be changed by TrustZone secure ARM code after boot.
* Since there is no hardware mechanism for the CCPLEX to know
* that an MC GSC register has changed to allow it to update its
* own internal GSC register, there needs to be a mechanism that
* can be used by ARM code to cause the CCPLEX to update its GSC
* register value. This ARI request allows updating the GSC register
* value for a certain carveout in the CCPLEX.
*/
int32_t (*update_ccplex_gsc)(uint32_t ari_base, uint32_t gsc_idx);
/*
* This ARI request instructs the CCPLEX to either shutdown or
* reset the entire system
*/
void (*enter_ccplex_state)(uint32_t ari_base, uint32_t state_idx);
/*
* This ARI request reads/writes data from/to Uncore PERFMON
* registers
*/
int32_t (*read_write_uncore_perfmon)(uint32_t ari_base,
uint64_t req, uint64_t *data);
/*
* This ARI implements ARI_MISC_CCPLEX commands. This can be
* used to enable/disable coresight clock gating.
*/
void (*misc_ccplex)(uint32_t ari_base, uint32_t index,
uint32_t value);
} arch_mce_ops_t;
/* declarations for ARI/NVG handler functions */
int32_t ari_enter_cstate(uint32_t ari_base, uint32_t state, uint32_t wake_time);
int32_t ari_update_cstate_info(uint32_t ari_base, uint32_t cluster, uint32_t ccplex,
uint32_t system, uint8_t sys_state_force, uint32_t wake_mask,
uint8_t update_wake_mask);
int32_t ari_update_crossover_time(uint32_t ari_base, uint32_t type, uint32_t time);
uint64_t ari_read_cstate_stats(uint32_t ari_base, uint32_t state);
int32_t ari_write_cstate_stats(uint32_t ari_base, uint32_t state, uint32_t stats);
uint64_t ari_enumeration_misc(uint32_t ari_base, uint32_t cmd, uint32_t data);
int32_t ari_is_ccx_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time);
int32_t ari_is_sc7_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time);
int32_t ari_online_core(uint32_t ari_base, uint32_t core);
int32_t ari_cc3_ctrl(uint32_t ari_base, uint32_t freq, uint32_t volt, uint8_t enable);
int32_t ari_reset_vector_update(uint32_t ari_base);
int32_t ari_roc_flush_cache_trbits(uint32_t ari_base);
int32_t ari_roc_flush_cache(uint32_t ari_base);
int32_t ari_roc_clean_cache(uint32_t ari_base);
uint64_t ari_read_write_mca(uint32_t ari_base, uint64_t cmd, uint64_t *data);
int32_t ari_update_ccplex_gsc(uint32_t ari_base, uint32_t gsc_idx);
void ari_enter_ccplex_state(uint32_t ari_base, uint32_t state_idx);
int32_t ari_read_write_uncore_perfmon(uint32_t ari_base,
uint64_t req, uint64_t *data);
void ari_misc_ccplex(uint32_t ari_base, uint32_t index, uint32_t value);
int32_t nvg_enter_cstate(uint32_t ari_base, uint32_t state, uint32_t wake_time);
int32_t nvg_update_cstate_info(uint32_t ari_base, uint32_t cluster, uint32_t ccplex,
uint32_t system, uint8_t sys_state_force, uint32_t wake_mask,
uint8_t update_wake_mask);
int32_t nvg_update_crossover_time(uint32_t ari_base, uint32_t type, uint32_t time);
uint64_t nvg_read_cstate_stats(uint32_t ari_base, uint32_t state);
int32_t nvg_write_cstate_stats(uint32_t ari_base, uint32_t state, uint32_t stats);
int32_t nvg_is_ccx_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time);
int32_t nvg_is_sc7_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time);
int32_t nvg_online_core(uint32_t ari_base, uint32_t core);
int32_t nvg_cc3_ctrl(uint32_t ari_base, uint32_t freq, uint32_t volt, uint8_t enable);
extern void nvg_set_request_data(uint64_t req, uint64_t data);
extern void nvg_set_request(uint64_t req);
extern uint64_t nvg_get_result(void);
#endif /* MCE_PRIVATE_H */
@@ -0,0 +1,437 @@
/*
* Copyright (c) 2016-2017, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef T18X_ARI_H
#define T18X_ARI_H
/*
* ----------------------------------------------------------------------------
* t18x_ari.h
*
* Global ARI definitions.
* ----------------------------------------------------------------------------
*/
enum {
TEGRA_ARI_VERSION_MAJOR = 3U,
TEGRA_ARI_VERSION_MINOR = 1U,
};
typedef enum {
/* indexes below get the core lock */
TEGRA_ARI_MISC = 0U,
/* index 1 is deprecated */
/* index 2 is deprecated */
/* index 3 is deprecated */
TEGRA_ARI_ONLINE_CORE = 4U,
/* indexes below need cluster lock */
TEGRA_ARI_MISC_CLUSTER = 41U,
TEGRA_ARI_IS_CCX_ALLOWED = 42U,
TEGRA_ARI_CC3_CTRL = 43U,
/* indexes below need ccplex lock */
TEGRA_ARI_ENTER_CSTATE = 80U,
TEGRA_ARI_UPDATE_CSTATE_INFO = 81U,
TEGRA_ARI_IS_SC7_ALLOWED = 82U,
/* index 83 is deprecated */
TEGRA_ARI_PERFMON = 84U,
TEGRA_ARI_UPDATE_CCPLEX_GSC = 85U,
/* index 86 is depracated */
/* index 87 is deprecated */
TEGRA_ARI_ROC_FLUSH_CACHE_ONLY = 88U,
TEGRA_ARI_ROC_FLUSH_CACHE_TRBITS = 89U,
TEGRA_ARI_MISC_CCPLEX = 90U,
TEGRA_ARI_MCA = 91U,
TEGRA_ARI_UPDATE_CROSSOVER = 92U,
TEGRA_ARI_CSTATE_STATS = 93U,
TEGRA_ARI_WRITE_CSTATE_STATS = 94U,
TEGRA_ARI_COPY_MISCREG_AA64_RST = 95U,
TEGRA_ARI_ROC_CLEAN_CACHE_ONLY = 96U,
} tegra_ari_req_id_t;
typedef enum {
TEGRA_ARI_MISC_ECHO = 0U,
TEGRA_ARI_MISC_VERSION = 1U,
TEGRA_ARI_MISC_FEATURE_LEAF_0 = 2U,
} tegra_ari_misc_index_t;
typedef enum {
TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_POWER_OFF = 0U,
TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_REBOOT = 1U,
TEGRA_ARI_MISC_CCPLEX_CORESIGHT_CG_CTRL = 2U,
TEGRA_ARI_MISC_CCPLEX_EDBGREQ = 3U,
} tegra_ari_misc_ccplex_index_t;
typedef enum {
TEGRA_ARI_CORE_C0 = 0U,
TEGRA_ARI_CORE_C1 = 1U,
TEGRA_ARI_CORE_C6 = 6U,
TEGRA_ARI_CORE_C7 = 7U,
TEGRA_ARI_CORE_WARMRSTREQ = 8U,
} tegra_ari_core_sleep_state_t;
typedef enum {
TEGRA_ARI_CLUSTER_CC0 = 0U,
TEGRA_ARI_CLUSTER_CC1 = 1U,
TEGRA_ARI_CLUSTER_CC6 = 6U,
TEGRA_ARI_CLUSTER_CC7 = 7U,
} tegra_ari_cluster_sleep_state_t;
typedef enum {
TEGRA_ARI_CCPLEX_CCP0 = 0U,
TEGRA_ARI_CCPLEX_CCP1 = 1U,
TEGRA_ARI_CCPLEX_CCP3 = 3U, /* obsoleted */
} tegra_ari_ccplex_sleep_state_t;
typedef enum {
TEGRA_ARI_SYSTEM_SC0 = 0U,
TEGRA_ARI_SYSTEM_SC1 = 1U, /* obsoleted */
TEGRA_ARI_SYSTEM_SC2 = 2U, /* obsoleted */
TEGRA_ARI_SYSTEM_SC3 = 3U, /* obsoleted */
TEGRA_ARI_SYSTEM_SC4 = 4U, /* obsoleted */
TEGRA_ARI_SYSTEM_SC7 = 7U,
TEGRA_ARI_SYSTEM_SC8 = 8U,
} tegra_ari_system_sleep_state_t;
typedef enum {
TEGRA_ARI_CROSSOVER_C1_C6 = 0U,
TEGRA_ARI_CROSSOVER_CC1_CC6 = 1U,
TEGRA_ARI_CROSSOVER_CC1_CC7 = 2U,
TEGRA_ARI_CROSSOVER_CCP1_CCP3 = 3U, /* obsoleted */
TEGRA_ARI_CROSSOVER_CCP3_SC2 = 4U, /* obsoleted */
TEGRA_ARI_CROSSOVER_CCP3_SC3 = 5U, /* obsoleted */
TEGRA_ARI_CROSSOVER_CCP3_SC4 = 6U, /* obsoleted */
TEGRA_ARI_CROSSOVER_CCP3_SC7 = 7U, /* obsoleted */
TEGRA_ARI_CROSSOVER_SC0_SC7 = 7U,
TEGRA_ARI_CROSSOVER_CCP3_SC1 = 8U, /* obsoleted */
} tegra_ari_crossover_index_t;
typedef enum {
TEGRA_ARI_CSTATE_STATS_CLEAR = 0U,
TEGRA_ARI_CSTATE_STATS_SC7_ENTRIES = 1U,
TEGRA_ARI_CSTATE_STATS_SC4_ENTRIES, /* obsoleted */
TEGRA_ARI_CSTATE_STATS_SC3_ENTRIES, /* obsoleted */
TEGRA_ARI_CSTATE_STATS_SC2_ENTRIES, /* obsoleted */
TEGRA_ARI_CSTATE_STATS_CCP3_ENTRIES, /* obsoleted */
TEGRA_ARI_CSTATE_STATS_A57_CC6_ENTRIES,
TEGRA_ARI_CSTATE_STATS_A57_CC7_ENTRIES,
TEGRA_ARI_CSTATE_STATS_D15_CC6_ENTRIES,
TEGRA_ARI_CSTATE_STATS_D15_CC7_ENTRIES,
TEGRA_ARI_CSTATE_STATS_D15_0_C6_ENTRIES,
TEGRA_ARI_CSTATE_STATS_D15_1_C6_ENTRIES,
TEGRA_ARI_CSTATE_STATS_D15_0_C7_ENTRIES = 14U,
TEGRA_ARI_CSTATE_STATS_D15_1_C7_ENTRIES,
TEGRA_ARI_CSTATE_STATS_A57_0_C7_ENTRIES = 18U,
TEGRA_ARI_CSTATE_STATS_A57_1_C7_ENTRIES,
TEGRA_ARI_CSTATE_STATS_A57_2_C7_ENTRIES,
TEGRA_ARI_CSTATE_STATS_A57_3_C7_ENTRIES,
TEGRA_ARI_CSTATE_STATS_LAST_CSTATE_ENTRY_D15_0,
TEGRA_ARI_CSTATE_STATS_LAST_CSTATE_ENTRY_D15_1,
TEGRA_ARI_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_0 = 26U,
TEGRA_ARI_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_1,
TEGRA_ARI_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_2,
TEGRA_ARI_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_3,
} tegra_ari_cstate_stats_index_t;
typedef enum {
TEGRA_ARI_GSC_ALL = 0U,
TEGRA_ARI_GSC_BPMP = 6U,
TEGRA_ARI_GSC_APE = 7U,
TEGRA_ARI_GSC_SPE = 8U,
TEGRA_ARI_GSC_SCE = 9U,
TEGRA_ARI_GSC_APR = 10U,
TEGRA_ARI_GSC_TZRAM = 11U,
TEGRA_ARI_GSC_SE = 12U,
TEGRA_ARI_GSC_BPMP_TO_SPE = 16U,
TEGRA_ARI_GSC_SPE_TO_BPMP = 17U,
TEGRA_ARI_GSC_CPU_TZ_TO_BPMP = 18U,
TEGRA_ARI_GSC_BPMP_TO_CPU_TZ = 19U,
TEGRA_ARI_GSC_CPU_NS_TO_BPMP = 20U,
TEGRA_ARI_GSC_BPMP_TO_CPU_NS = 21U,
TEGRA_ARI_GSC_IPC_SE_SPE_SCE_BPMP = 22U,
TEGRA_ARI_GSC_SC7_RESUME_FW = 23U,
TEGRA_ARI_GSC_TZ_DRAM_IDX = 34U,
TEGRA_ARI_GSC_VPR_IDX = 35U,
} tegra_ari_gsc_index_t;
/* This macro will produce enums for __name##_LSB, __name##_MSB and __name##_MSK */
#define TEGRA_ARI_ENUM_MASK_LSB_MSB(__name, __lsb, __msb) __name##_LSB = __lsb, __name##_MSB = __msb
typedef enum {
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__CLUSTER_CSTATE, 0U, 2U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__CLUSTER_CSTATE_PRESENT, 7U, 7U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__CCPLEX_CSTATE, 8U, 9U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__CCPLEX_CSTATE_PRESENT, 15U, 15U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__SYSTEM_CSTATE, 16U, 19U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__IGNORE_CROSSOVERS, 22U, 22U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__SYSTEM_CSTATE_PRESENT, 23U, 23U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_UPDATE_CSTATE_INFO__WAKE_MASK_PRESENT, 31U, 31U),
} tegra_ari_update_cstate_info_bitmasks_t;
typedef enum {
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MISC_CCPLEX_CORESIGHT_CG_CTRL__EN, 0U, 0U),
} tegra_ari_misc_ccplex_bitmasks_t;
typedef enum {
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_CC3_CTRL__IDLE_FREQ, 0U, 8U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_CC3_CTRL__IDLE_VOLT, 16U, 23U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_CC3_CTRL__ENABLE, 31U, 31U),
} tegra_ari_cc3_ctrl_bitmasks_t;
typedef enum {
TEGRA_ARI_MCA_NOP = 0U,
TEGRA_ARI_MCA_READ_SERR = 1U,
TEGRA_ARI_MCA_WRITE_SERR = 2U,
TEGRA_ARI_MCA_CLEAR_SERR = 4U,
TEGRA_ARI_MCA_REPORT_SERR = 5U,
TEGRA_ARI_MCA_READ_INTSTS = 6U,
TEGRA_ARI_MCA_WRITE_INTSTS = 7U,
TEGRA_ARI_MCA_READ_PREBOOT_SERR = 8U,
} tegra_ari_mca_commands_t;
typedef enum {
TEGRA_ARI_MCA_RD_WR_DPMU = 0U,
TEGRA_ARI_MCA_RD_WR_IOB = 1U,
TEGRA_ARI_MCA_RD_WR_MCB = 2U,
TEGRA_ARI_MCA_RD_WR_CCE = 3U,
TEGRA_ARI_MCA_RD_WR_CQX = 4U,
TEGRA_ARI_MCA_RD_WR_CTU = 5U,
TEGRA_ARI_MCA_RD_WR_JSR_MTS = 7U,
TEGRA_ARI_MCA_RD_BANK_INFO = 0x0fU,
TEGRA_ARI_MCA_RD_BANK_TEMPLATE = 0x10U,
TEGRA_ARI_MCA_RD_WR_SECURE_ACCESS_REGISTER = 0x11U,
TEGRA_ARI_MCA_RD_WR_GLOBAL_CONFIG_REGISTER = 0x12U,
} tegra_ari_mca_rd_wr_indexes_t;
typedef enum {
TEGRA_ARI_MCA_RD_WR_ASERRX_CTRL = 0U,
TEGRA_ARI_MCA_RD_WR_ASERRX_STATUS = 1U,
TEGRA_ARI_MCA_RD_WR_ASERRX_ADDR = 2U,
TEGRA_ARI_MCA_RD_WR_ASERRX_MISC1 = 3U,
TEGRA_ARI_MCA_RD_WR_ASERRX_MISC2 = 4U,
} tegra_ari_mca_read_asserx_subindexes_t;
typedef enum {
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SECURE_REGISTER_SETTING_ENABLES_NS_PERMITTED, 0U, 0U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SECURE_REGISTER_READING_STATUS_NS_PERMITTED, 1U, 1U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SECURE_REGISTER_PENDING_MCA_ERRORS_NS_PERMITTED, 2U, 2U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SECURE_REGISTER_CLEARING_MCA_INTERRUPTS_NS_PERMITTED, 3U, 3U),
} tegra_ari_mca_secure_register_bitmasks_t;
typedef enum {
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_SERR_ERR_CODE, 0U, 15U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_PWM_ERR, 16U, 16U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_CRAB_ERR, 17U, 17U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_RD_WR_N, 18U, 18U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_UCODE_ERR, 19U, 19U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_PWM, 20U, 23U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_AV, 58U, 58U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_MV, 59U, 59U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_EN, 60U, 60U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_UC, 61U, 61U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_OVF, 62U, 62U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_STAT_VAL, 63U, 63U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_ADDR_ADDR, 0U, 41U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_ADDR_UCODE_ERRCD, 42U, 52U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_CTRL_EN_PWM_ERR, 0U, 0U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_CTRL_EN_CRAB_ERR, 1U, 1U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR0_CTRL_EN_UCODE_ERR, 3U, 3U),
} tegra_ari_mca_aserr0_bitmasks_t;
typedef enum {
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_SERR_ERR_CODE, 0U, 15U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_MSI_ERR, 16U, 16U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_IHI_ERR, 17U, 17U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_CRI_ERR, 18U, 18U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_MMCRAB_ERR, 19U, 19U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_CSI_ERR, 20U, 20U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_RD_WR_N, 21U, 21U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_REQ_ERRT, 22U, 23U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_RESP_ERRT, 24U, 25U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_AV, 58U, 58U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_MV, 59U, 59U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_EN, 60U, 60U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_UC, 61U, 61U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_OVF, 62U, 62U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_VAL, 63U, 63U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_AXI_ID, 0U, 7U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_CQX_ID, 8U, 27U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_CQX_CID, 28U, 31U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_STAT_CQX_CMD, 32U, 35U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_CTRL_EN_MSI_ERR, 0U, 0U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_CTRL_EN_IHI_ERR, 1U, 1U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_CTRL_EN_CRI_ERR, 2U, 2U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_CTRL_EN_MMCRAB_ERR, 3U, 3U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_CTRL_EN_CSI_ERR, 4U, 4U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR1_MISC_ADDR, 0U, 41U),
} tegra_ari_mca_aserr1_bitmasks_t;
typedef enum {
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_SERR_ERR_CODE, 0U, 15U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_MC_ERR, 16U, 16U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_SYSRAM_ERR, 17U, 17U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_CLIENT_ID, 18U, 19U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_AV, 58U, 58U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_MV, 59U, 59U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_EN, 60U, 60U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_UC, 61U, 61U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_OVF, 62U, 62U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_STAT_VAL, 63U, 63U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_ADDR_ID, 0U, 17U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_ADDR_CMD, 18U, 21U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_ADDR_ADDR, 22U, 53U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR2_CTRL_EN_MC_ERR, 0U, 0U),
} tegra_ari_mca_aserr2_bitmasks_t;
typedef enum {
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_SERR_ERR_CODE, 0U, 15U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_TO_ERR, 16U, 16U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_STAT_ERR, 17U, 17U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_DST_ERR, 18U, 18U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_UNC_ERR, 19U, 19U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_MH_ERR, 20U, 20U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_PERR, 21U, 21U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_PSN_ERR, 22U, 22U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_AV, 58U, 58U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_MV, 59U, 59U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_EN, 60U, 60U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_UC, 61U, 61U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_OVF, 62U, 62U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_STAT_VAL, 63U, 63U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_ADDR_CMD, 0U, 5U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_ADDR_ADDR, 6U, 47U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC1_TO, 0U, 0U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC1_DIV4, 1U, 1U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC1_TLIMIT, 2U, 11U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC1_PSN_ERR_CORR_MSK, 12U, 25U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC2_MORE_INFO, 0U, 17U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC2_TO_INFO, 18U, 43U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC2_SRC, 44U, 45U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_MISC2_TID, 46U, 52U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_CTRL_EN_TO_ERR, 0U, 0U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_CTRL_EN_STAT_ERR, 1U, 1U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_CTRL_EN_DST_ERR, 2U, 2U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_CTRL_EN_UNC_ERR, 3U, 3U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_CTRL_EN_MH_ERR, 4U, 4U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_CTRL_EN_PERR, 5U, 5U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR3_CTRL_EN_PSN_ERR, 6U, 19U),
} tegra_ari_mca_aserr3_bitmasks_t;
typedef enum {
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_SERR_ERR_CODE, 0U, 15U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_SRC_ERR, 16U, 16U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_DST_ERR, 17U, 17U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_REQ_ERR, 18U, 18U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_RSP_ERR, 19U, 19U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_AV, 58U, 58U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_MV, 59U, 59U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_EN, 60U, 60U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_UC, 61U, 61U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_OVF, 62U, 62U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_STAT_VAL, 63U, 63U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR4_CTRL_EN_CPE_ERR, 0U, 0U),
} tegra_ari_mca_aserr4_bitmasks_t;
typedef enum {
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_SERR_ERR_CODE, 0U, 15U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_CTUPAR, 16U, 16U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_MULTI, 17U, 17U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_AV, 58U, 58U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_MV, 59U, 59U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_EN, 60U, 60U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_UC, 61U, 61U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_OVF, 62U, 62U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_STAT_VAL, 63U, 63U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_ADDR_SRC, 0U, 7U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_ADDR_ID, 8U, 15U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_ADDR_DATA, 16U, 26U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_ADDR_CMD, 32U, 35U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_ADDR_ADDR, 36U, 45U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_ASERR5_CTRL_EN_CTUPAR, 0U, 0U),
} tegra_ari_mca_aserr5_bitmasks_t;
typedef enum {
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SERR1_STAT_SERR_ERR_CODE, 0U, 15U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SERR1_STAT_AV, 58U, 58U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SERR1_STAT_MV, 59U, 59U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SERR1_STAT_EN, 60U, 60U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SERR1_STAT_UC, 61U, 61U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SERR1_STAT_OVF, 62U, 62U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SERR1_STAT_VAL, 63U, 63U),
TEGRA_ARI_ENUM_MASK_LSB_MSB(TEGRA_ARI_MCA_SERR1_ADDR_TBD_INFO, 0U, 63U),
} tegra_ari_mca_serr1_bitmasks_t;
#undef TEGRA_ARI_ENUM_MASK_LSB_MSB
typedef enum {
TEGRA_NVG_CHANNEL_PMIC = 0U,
TEGRA_NVG_CHANNEL_POWER_PERF = 1U,
TEGRA_NVG_CHANNEL_POWER_MODES = 2U,
TEGRA_NVG_CHANNEL_WAKE_TIME = 3U,
TEGRA_NVG_CHANNEL_CSTATE_INFO = 4U,
TEGRA_NVG_CHANNEL_CROSSOVER_C1_C6 = 5U,
TEGRA_NVG_CHANNEL_CROSSOVER_CC1_CC6 = 6U,
TEGRA_NVG_CHANNEL_CROSSOVER_CC1_CC7 = 7U,
TEGRA_NVG_CHANNEL_CROSSOVER_CCP1_CCP3 = 8U, /* obsoleted */
TEGRA_NVG_CHANNEL_CROSSOVER_CCP3_SC2 = 9U, /* obsoleted */
TEGRA_NVG_CHANNEL_CROSSOVER_CCP3_SC3 = 10U, /* obsoleted */
TEGRA_NVG_CHANNEL_CROSSOVER_CCP3_SC4 = 11U, /* obsoleted */
TEGRA_NVG_CHANNEL_CROSSOVER_CCP3_SC7 = 12U, /* obsoleted */
TEGRA_NVG_CHANNEL_CROSSOVER_SC0_SC7 = 12U,
TEGRA_NVG_CHANNEL_CSTATE_STATS_CLEAR = 13U,
TEGRA_NVG_CHANNEL_CSTATE_STATS_SC7_ENTRIES = 14U,
TEGRA_NVG_CHANNEL_CSTATE_STATS_SC4_ENTRIES = 15U, /* obsoleted */
TEGRA_NVG_CHANNEL_CSTATE_STATS_SC3_ENTRIES = 16U, /* obsoleted */
TEGRA_NVG_CHANNEL_CSTATE_STATS_SC2_ENTRIES = 17U, /* obsoleted */
TEGRA_NVG_CHANNEL_CSTATE_STATS_CCP3_ENTRIES = 18U, /* obsoleted */
TEGRA_NVG_CHANNEL_CSTATE_STATS_A57_CC6_ENTRIES = 19U,
TEGRA_NVG_CHANNEL_CSTATE_STATS_A57_CC7_ENTRIES = 20U,
TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_CC6_ENTRIES = 21U,
TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_CC7_ENTRIES = 22U,
TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_0_C6_ENTRIES = 23U,
TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_1_C6_ENTRIES = 24U,
TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_2_C6_ENTRIES = 25U, /* Reserved (for Denver15 core 2) */
TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_3_C6_ENTRIES = 26U, /* Reserved (for Denver15 core 3) */
TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_0_C7_ENTRIES = 27U,
TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_1_C7_ENTRIES = 28U,
TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_2_C7_ENTRIES = 29U, /* Reserved (for Denver15 core 2) */
TEGRA_NVG_CHANNEL_CSTATE_STATS_D15_3_C7_ENTRIES = 30U, /* Reserved (for Denver15 core 3) */
TEGRA_NVG_CHANNEL_CSTATE_STATS_A57_0_C7_ENTRIES = 31U,
TEGRA_NVG_CHANNEL_CSTATE_STATS_A57_1_C7_ENTRIES = 32U,
TEGRA_NVG_CHANNEL_CSTATE_STATS_A57_2_C7_ENTRIES = 33U,
TEGRA_NVG_CHANNEL_CSTATE_STATS_A57_3_C7_ENTRIES = 34U,
TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_D15_0 = 35U,
TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_D15_1 = 36U,
TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_D15_2 = 37U, /* Reserved (for Denver15 core 2) */
TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_D15_3 = 38U, /* Reserved (for Denver15 core 3) */
TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_0 = 39U,
TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_1 = 40U,
TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_2 = 41U,
TEGRA_NVG_CHANNEL_CSTATE_STATS_LAST_CSTATE_ENTRY_A57_3 = 42U,
TEGRA_NVG_CHANNEL_IS_SC7_ALLOWED = 43U,
TEGRA_NVG_CHANNEL_ONLINE_CORE = 44U,
TEGRA_NVG_CHANNEL_CC3_CTRL = 45U,
TEGRA_NVG_CHANNEL_CROSSOVER_CCP3_SC1 = 46U, /* obsoleted */
TEGRA_NVG_CHANNEL_LAST_INDEX,
} tegra_nvg_channel_id_t;
#endif /* T18X_ARI_H */
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
.globl nvg_set_request_data
.globl nvg_set_request
.globl nvg_get_result
/* void nvg_set_request_data(uint64_t req, uint64_t data) */
func nvg_set_request_data
msr s3_0_c15_c1_2, x0
msr s3_0_c15_c1_3, x1
ret
endfunc nvg_set_request_data
/* void nvg_set_request(uint64_t req) */
func nvg_set_request
msr s3_0_c15_c1_2, x0
ret
endfunc nvg_set_request
/* uint64_t nvg_get_result(void) */
func nvg_get_result
mrs x0, s3_0_c15_c1_3
ret
endfunc nvg_get_result
@@ -0,0 +1,564 @@
/*
* Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
*
* 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/delay_timer.h>
#include <denver.h>
#include <lib/mmio.h>
#include <plat/common/platform.h>
#include <mce_private.h>
#include <t18x_ari.h>
/*******************************************************************************
* Register offsets for ARI request/results
******************************************************************************/
#define ARI_REQUEST 0x0U
#define ARI_REQUEST_EVENT_MASK 0x4U
#define ARI_STATUS 0x8U
#define ARI_REQUEST_DATA_LO 0xCU
#define ARI_REQUEST_DATA_HI 0x10U
#define ARI_RESPONSE_DATA_LO 0x14U
#define ARI_RESPONSE_DATA_HI 0x18U
/* Status values for the current request */
#define ARI_REQ_PENDING 1U
#define ARI_REQ_ONGOING 3U
#define ARI_REQUEST_VALID_BIT (1U << 8)
#define ARI_EVT_MASK_STANDBYWFI_BIT (1U << 7)
/* default timeout (us) to wait for ARI completion */
#define ARI_MAX_RETRY_COUNT U(2000000)
/*******************************************************************************
* ARI helper functions
******************************************************************************/
static inline uint32_t ari_read_32(uint32_t ari_base, uint32_t reg)
{
return mmio_read_32((uint64_t)ari_base + (uint64_t)reg);
}
static inline void ari_write_32(uint32_t ari_base, uint32_t val, uint32_t reg)
{
mmio_write_32((uint64_t)ari_base + (uint64_t)reg, val);
}
static inline uint32_t ari_get_request_low(uint32_t ari_base)
{
return ari_read_32(ari_base, ARI_REQUEST_DATA_LO);
}
static inline uint32_t ari_get_request_high(uint32_t ari_base)
{
return ari_read_32(ari_base, ARI_REQUEST_DATA_HI);
}
static inline uint32_t ari_get_response_low(uint32_t ari_base)
{
return ari_read_32(ari_base, ARI_RESPONSE_DATA_LO);
}
static inline uint32_t ari_get_response_high(uint32_t ari_base)
{
return ari_read_32(ari_base, ARI_RESPONSE_DATA_HI);
}
static inline void ari_clobber_response(uint32_t ari_base)
{
ari_write_32(ari_base, 0, ARI_RESPONSE_DATA_LO);
ari_write_32(ari_base, 0, ARI_RESPONSE_DATA_HI);
}
static int32_t ari_request_wait(uint32_t ari_base, uint32_t evt_mask, uint32_t req,
uint32_t lo, uint32_t hi)
{
uint32_t retries = (uint32_t)ARI_MAX_RETRY_COUNT;
uint32_t status;
int32_t ret = 0;
/* program the request, event_mask, hi and lo registers */
ari_write_32(ari_base, lo, ARI_REQUEST_DATA_LO);
ari_write_32(ari_base, hi, ARI_REQUEST_DATA_HI);
ari_write_32(ari_base, evt_mask, ARI_REQUEST_EVENT_MASK);
ari_write_32(ari_base, req | ARI_REQUEST_VALID_BIT, ARI_REQUEST);
/*
* For commands that have an event trigger, we should bypass
* ARI_STATUS polling, since MCE is waiting for SW to trigger
* the event.
*/
if (evt_mask != 0U) {
ret = 0;
} else {
/* For shutdown/reboot commands, we dont have to check for timeouts */
if ((req == TEGRA_ARI_MISC_CCPLEX) &&
((lo == TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_POWER_OFF) ||
(lo == TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_REBOOT))) {
ret = 0;
} else {
/*
* Wait for the command response for not more than the timeout
*/
while (retries != 0U) {
/* read the command status */
status = ari_read_32(ari_base, ARI_STATUS);
if ((status & (ARI_REQ_ONGOING | ARI_REQ_PENDING)) == 0U) {
break;
}
/* delay 1 us */
udelay(1);
/* decrement the retry count */
retries--;
}
/* assert if the command timed out */
if (retries == 0U) {
ERROR("ARI request timed out: req %d on CPU %d\n",
req, plat_my_core_pos());
assert(retries != 0U);
}
}
}
return ret;
}
int32_t ari_enter_cstate(uint32_t ari_base, uint32_t state, uint32_t wake_time)
{
int32_t ret = 0;
/* check for allowed power state */
if ((state != TEGRA_ARI_CORE_C0) &&
(state != TEGRA_ARI_CORE_C1) &&
(state != TEGRA_ARI_CORE_C6) &&
(state != TEGRA_ARI_CORE_C7)) {
ERROR("%s: unknown cstate (%d)\n", __func__, state);
ret = EINVAL;
} else {
/* clean the previous response state */
ari_clobber_response(ari_base);
/* Enter the cstate, to be woken up after wake_time (TSC ticks) */
ret = ari_request_wait(ari_base, ARI_EVT_MASK_STANDBYWFI_BIT,
(uint32_t)TEGRA_ARI_ENTER_CSTATE, state, wake_time);
}
return ret;
}
int32_t ari_update_cstate_info(uint32_t ari_base, uint32_t cluster, uint32_t ccplex,
uint32_t system, uint8_t sys_state_force, uint32_t wake_mask,
uint8_t update_wake_mask)
{
uint64_t val = 0U;
/* clean the previous response state */
ari_clobber_response(ari_base);
/* update CLUSTER_CSTATE? */
if (cluster != 0U) {
val |= (cluster & CLUSTER_CSTATE_MASK) |
CLUSTER_CSTATE_UPDATE_BIT;
}
/* update CCPLEX_CSTATE? */
if (ccplex != 0U) {
val |= ((ccplex & CCPLEX_CSTATE_MASK) << CCPLEX_CSTATE_SHIFT) |
CCPLEX_CSTATE_UPDATE_BIT;
}
/* update SYSTEM_CSTATE? */
if (system != 0U) {
val |= ((system & SYSTEM_CSTATE_MASK) << SYSTEM_CSTATE_SHIFT) |
(((uint64_t)sys_state_force << SYSTEM_CSTATE_FORCE_UPDATE_SHIFT) |
SYSTEM_CSTATE_UPDATE_BIT);
}
/* update wake mask value? */
if (update_wake_mask != 0U) {
val |= CSTATE_WAKE_MASK_UPDATE_BIT;
}
/* set the updated cstate info */
return ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_UPDATE_CSTATE_INFO,
(uint32_t)val, wake_mask);
}
int32_t ari_update_crossover_time(uint32_t ari_base, uint32_t type, uint32_t time)
{
int32_t ret = 0;
/* sanity check crossover type */
if ((type == TEGRA_ARI_CROSSOVER_C1_C6) ||
(type > TEGRA_ARI_CROSSOVER_CCP3_SC1)) {
ret = EINVAL;
} else {
/* clean the previous response state */
ari_clobber_response(ari_base);
/* update crossover threshold time */
ret = ari_request_wait(ari_base, 0U,
(uint32_t)TEGRA_ARI_UPDATE_CROSSOVER, type, time);
}
return ret;
}
uint64_t ari_read_cstate_stats(uint32_t ari_base, uint32_t state)
{
int32_t ret;
uint64_t result;
/* sanity check crossover type */
if (state == 0U) {
result = EINVAL;
} else {
/* clean the previous response state */
ari_clobber_response(ari_base);
ret = ari_request_wait(ari_base, 0U,
(uint32_t)TEGRA_ARI_CSTATE_STATS, state, 0U);
if (ret != 0) {
result = EINVAL;
} else {
result = (uint64_t)ari_get_response_low(ari_base);
}
}
return result;
}
int32_t ari_write_cstate_stats(uint32_t ari_base, uint32_t state, uint32_t stats)
{
/* clean the previous response state */
ari_clobber_response(ari_base);
/* write the cstate stats */
return ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_WRITE_CSTATE_STATS,
state, stats);
}
uint64_t ari_enumeration_misc(uint32_t ari_base, uint32_t cmd, uint32_t data)
{
uint64_t resp;
int32_t ret;
uint32_t local_data = data;
/* clean the previous response state */
ari_clobber_response(ari_base);
/* ARI_REQUEST_DATA_HI is reserved for commands other than 'ECHO' */
if (cmd != TEGRA_ARI_MISC_ECHO) {
local_data = 0U;
}
ret = ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_MISC, cmd, local_data);
if (ret != 0) {
resp = (uint64_t)ret;
} else {
/* get the command response */
resp = ari_get_response_low(ari_base);
resp |= ((uint64_t)ari_get_response_high(ari_base) << 32);
}
return resp;
}
int32_t ari_is_ccx_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time)
{
int32_t ret;
uint32_t result;
/* clean the previous response state */
ari_clobber_response(ari_base);
ret = ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_IS_CCX_ALLOWED,
state & 0x7U, wake_time);
if (ret != 0) {
ERROR("%s: failed (%d)\n", __func__, ret);
result = 0U;
} else {
result = ari_get_response_low(ari_base) & 0x1U;
}
/* 1 = CCx allowed, 0 = CCx not allowed */
return (int32_t)result;
}
int32_t ari_is_sc7_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time)
{
int32_t ret, result;
/* check for allowed power state */
if ((state != TEGRA_ARI_CORE_C0) && (state != TEGRA_ARI_CORE_C1) &&
(state != TEGRA_ARI_CORE_C6) && (state != TEGRA_ARI_CORE_C7)) {
ERROR("%s: unknown cstate (%d)\n", __func__, state);
result = EINVAL;
} else {
/* clean the previous response state */
ari_clobber_response(ari_base);
ret = ari_request_wait(ari_base, 0U,
(uint32_t)TEGRA_ARI_IS_SC7_ALLOWED, state, wake_time);
if (ret != 0) {
ERROR("%s: failed (%d)\n", __func__, ret);
result = 0;
} else {
/* 1 = SC7 allowed, 0 = SC7 not allowed */
result = (ari_get_response_low(ari_base) != 0U) ? 1 : 0;
}
}
return result;
}
int32_t ari_online_core(uint32_t ari_base, uint32_t core)
{
uint64_t cpu = read_mpidr() & (MPIDR_CPU_MASK);
uint64_t cluster = (read_mpidr() & (MPIDR_CLUSTER_MASK)) >>
(MPIDR_AFFINITY_BITS);
uint64_t impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK;
int32_t ret;
/* construct the current CPU # */
cpu |= (cluster << 2);
/* sanity check target core id */
if ((core >= MCE_CORE_ID_MAX) || (cpu == (uint64_t)core)) {
ERROR("%s: unsupported core id (%d)\n", __func__, core);
ret = EINVAL;
} else {
/*
* The Denver cluster has 2 CPUs only - 0, 1.
*/
if ((impl == DENVER_IMPL) && ((core == 2U) || (core == 3U))) {
ERROR("%s: unknown core id (%d)\n", __func__, core);
ret = EINVAL;
} else {
/* clean the previous response state */
ari_clobber_response(ari_base);
ret = ari_request_wait(ari_base, 0U,
(uint32_t)TEGRA_ARI_ONLINE_CORE, core, 0U);
}
}
return ret;
}
int32_t ari_cc3_ctrl(uint32_t ari_base, uint32_t freq, uint32_t volt, uint8_t enable)
{
uint32_t val;
/* clean the previous response state */
ari_clobber_response(ari_base);
/*
* If the enable bit is cleared, Auto-CC3 will be disabled by setting
* the SW visible voltage/frequency request registers for all non
* floorswept cores valid independent of StandbyWFI and disabling
* the IDLE voltage/frequency request register. If set, Auto-CC3
* will be enabled by setting the ARM SW visible voltage/frequency
* request registers for all non floorswept cores to be enabled by
* StandbyWFI or the equivalent signal, and always keeping the IDLE
* voltage/frequency request register enabled.
*/
val = (((freq & MCE_AUTO_CC3_FREQ_MASK) << MCE_AUTO_CC3_FREQ_SHIFT) |\
((volt & MCE_AUTO_CC3_VTG_MASK) << MCE_AUTO_CC3_VTG_SHIFT) |\
((enable != 0U) ? MCE_AUTO_CC3_ENABLE_BIT : 0U));
return ari_request_wait(ari_base, 0U,
(uint32_t)TEGRA_ARI_CC3_CTRL, val, 0U);
}
int32_t ari_reset_vector_update(uint32_t ari_base)
{
/* clean the previous response state */
ari_clobber_response(ari_base);
/*
* Need to program the CPU reset vector one time during cold boot
* and SC7 exit
*/
(void)ari_request_wait(ari_base, 0U,
(uint32_t)TEGRA_ARI_COPY_MISCREG_AA64_RST, 0U, 0U);
return 0;
}
int32_t ari_roc_flush_cache_trbits(uint32_t ari_base)
{
/* clean the previous response state */
ari_clobber_response(ari_base);
return ari_request_wait(ari_base, 0U,
(uint32_t)TEGRA_ARI_ROC_FLUSH_CACHE_TRBITS, 0U, 0U);
}
int32_t ari_roc_flush_cache(uint32_t ari_base)
{
/* clean the previous response state */
ari_clobber_response(ari_base);
return ari_request_wait(ari_base, 0U,
(uint32_t)TEGRA_ARI_ROC_FLUSH_CACHE_ONLY, 0U, 0U);
}
int32_t ari_roc_clean_cache(uint32_t ari_base)
{
/* clean the previous response state */
ari_clobber_response(ari_base);
return ari_request_wait(ari_base, 0U,
(uint32_t)TEGRA_ARI_ROC_CLEAN_CACHE_ONLY, 0U, 0U);
}
uint64_t ari_read_write_mca(uint32_t ari_base, uint64_t cmd, uint64_t *data)
{
uint64_t mca_arg_data, result = 0;
uint32_t resp_lo, resp_hi;
uint32_t mca_arg_err, mca_arg_finish;
int32_t ret;
/* Set data (write) */
mca_arg_data = (data != NULL) ? *data : 0ULL;
/* Set command */
ari_write_32(ari_base, (uint32_t)cmd, ARI_RESPONSE_DATA_LO);
ari_write_32(ari_base, (uint32_t)(cmd >> 32U), ARI_RESPONSE_DATA_HI);
ret = ari_request_wait(ari_base, 0U, (uint32_t)TEGRA_ARI_MCA,
(uint32_t)mca_arg_data,
(uint32_t)(mca_arg_data >> 32U));
if (ret == 0) {
resp_lo = ari_get_response_low(ari_base);
resp_hi = ari_get_response_high(ari_base);
mca_arg_err = resp_lo & MCA_ARG_ERROR_MASK;
mca_arg_finish = (resp_hi >> MCA_ARG_FINISH_SHIFT) &
MCA_ARG_FINISH_MASK;
if (mca_arg_finish == 0U) {
result = (uint64_t)mca_arg_err;
} else {
if (data != NULL) {
resp_lo = ari_get_request_low(ari_base);
resp_hi = ari_get_request_high(ari_base);
*data = ((uint64_t)resp_hi << 32U) |
(uint64_t)resp_lo;
}
}
}
return result;
}
int32_t ari_update_ccplex_gsc(uint32_t ari_base, uint32_t gsc_idx)
{
int32_t ret = 0;
/* sanity check GSC ID */
if (gsc_idx > TEGRA_ARI_GSC_VPR_IDX) {
ret = EINVAL;
} else {
/* clean the previous response state */
ari_clobber_response(ari_base);
/*
* The MCE code will read the GSC carveout value, corrseponding to
* the ID, from the MC registers and update the internal GSC registers
* of the CCPLEX.
*/
(void)ari_request_wait(ari_base, 0U,
(uint32_t)TEGRA_ARI_UPDATE_CCPLEX_GSC, gsc_idx, 0U);
}
return ret;
}
void ari_enter_ccplex_state(uint32_t ari_base, uint32_t state_idx)
{
/* clean the previous response state */
ari_clobber_response(ari_base);
/*
* The MCE will shutdown or restart the entire system
*/
(void)ari_request_wait(ari_base, 0U,
(uint32_t)TEGRA_ARI_MISC_CCPLEX, state_idx, 0U);
}
int32_t ari_read_write_uncore_perfmon(uint32_t ari_base, uint64_t req,
uint64_t *data)
{
int32_t ret, result;
uint32_t val, req_status;
uint8_t req_cmd;
req_cmd = (uint8_t)(req & UNCORE_PERFMON_CMD_MASK);
/* clean the previous response state */
ari_clobber_response(ari_base);
/* sanity check input parameters */
if ((req_cmd == UNCORE_PERFMON_CMD_READ) && (data == NULL)) {
ERROR("invalid parameters\n");
result = EINVAL;
} else {
/*
* For "write" commands get the value that has to be written
* to the uncore perfmon registers
*/
val = (req_cmd == UNCORE_PERFMON_CMD_WRITE) ?
(uint32_t)*data : 0U;
ret = ari_request_wait(ari_base, 0U,
(uint32_t)TEGRA_ARI_PERFMON, val, (uint32_t)req);
if (ret != 0) {
result = ret;
} else {
/* read the command status value */
req_status = ari_get_response_high(ari_base) &
UNCORE_PERFMON_RESP_STATUS_MASK;
/*
* For "read" commands get the data from the uncore
* perfmon registers
*/
req_status &= UNCORE_PERFMON_RESP_STATUS_MASK;
if ((req_status == 0U) && (req_cmd == UNCORE_PERFMON_CMD_READ)) {
*data = ari_get_response_low(ari_base);
}
result = (int32_t)req_status;
}
}
return result;
}
void ari_misc_ccplex(uint32_t ari_base, uint32_t index, uint32_t value)
{
/*
* This invokes the ARI_MISC_CCPLEX commands. This can be
* used to enable/disable coresight clock gating.
*/
if ((index > TEGRA_ARI_MISC_CCPLEX_EDBGREQ) ||
((index == TEGRA_ARI_MISC_CCPLEX_CORESIGHT_CG_CTRL) &&
(value > 1U))) {
ERROR("%s: invalid parameters \n", __func__);
} else {
/* clean the previous response state */
ari_clobber_response(ari_base);
(void)ari_request_wait(ari_base, 0U,
(uint32_t)TEGRA_ARI_MISC_CCPLEX, index, value);
}
}
@@ -0,0 +1,476 @@
/*
* Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <errno.h>
#include <inttypes.h>
#include <stdint.h>
#include <string.h>
#include <arch.h>
#include <arch_helpers.h>
#include <common/bl_common.h>
#include <common/debug.h>
#include <context.h>
#include <denver.h>
#include <lib/el3_runtime/context_mgmt.h>
#include <lib/mmio.h>
#include <mce.h>
#include <mce_private.h>
#include <t18x_ari.h>
#include <tegra_def.h>
#include <tegra_platform.h>
/* NVG functions handlers */
static arch_mce_ops_t nvg_mce_ops = {
.enter_cstate = nvg_enter_cstate,
.update_cstate_info = nvg_update_cstate_info,
.update_crossover_time = nvg_update_crossover_time,
.read_cstate_stats = nvg_read_cstate_stats,
.write_cstate_stats = nvg_write_cstate_stats,
.call_enum_misc = ari_enumeration_misc,
.is_ccx_allowed = nvg_is_ccx_allowed,
.is_sc7_allowed = nvg_is_sc7_allowed,
.online_core = nvg_online_core,
.cc3_ctrl = nvg_cc3_ctrl,
.update_reset_vector = ari_reset_vector_update,
.roc_flush_cache = ari_roc_flush_cache,
.roc_flush_cache_trbits = ari_roc_flush_cache_trbits,
.roc_clean_cache = ari_roc_clean_cache,
.read_write_mca = ari_read_write_mca,
.update_ccplex_gsc = ari_update_ccplex_gsc,
.enter_ccplex_state = ari_enter_ccplex_state,
.read_write_uncore_perfmon = ari_read_write_uncore_perfmon,
.misc_ccplex = ari_misc_ccplex
};
/* ARI functions handlers */
static arch_mce_ops_t ari_mce_ops = {
.enter_cstate = ari_enter_cstate,
.update_cstate_info = ari_update_cstate_info,
.update_crossover_time = ari_update_crossover_time,
.read_cstate_stats = ari_read_cstate_stats,
.write_cstate_stats = ari_write_cstate_stats,
.call_enum_misc = ari_enumeration_misc,
.is_ccx_allowed = ari_is_ccx_allowed,
.is_sc7_allowed = ari_is_sc7_allowed,
.online_core = ari_online_core,
.cc3_ctrl = ari_cc3_ctrl,
.update_reset_vector = ari_reset_vector_update,
.roc_flush_cache = ari_roc_flush_cache,
.roc_flush_cache_trbits = ari_roc_flush_cache_trbits,
.roc_clean_cache = ari_roc_clean_cache,
.read_write_mca = ari_read_write_mca,
.update_ccplex_gsc = ari_update_ccplex_gsc,
.enter_ccplex_state = ari_enter_ccplex_state,
.read_write_uncore_perfmon = ari_read_write_uncore_perfmon,
.misc_ccplex = ari_misc_ccplex
};
typedef struct {
uint32_t ari_base;
arch_mce_ops_t *ops;
} mce_config_t;
/* Table to hold the per-CPU ARI base address and function handlers */
static mce_config_t mce_cfg_table[MCE_ARI_APERTURES_MAX] = {
{
/* A57 Core 0 */
.ari_base = TEGRA_MMCRAB_BASE + MCE_ARI_APERTURE_0_OFFSET,
.ops = &ari_mce_ops,
},
{
/* A57 Core 1 */
.ari_base = TEGRA_MMCRAB_BASE + MCE_ARI_APERTURE_1_OFFSET,
.ops = &ari_mce_ops,
},
{
/* A57 Core 2 */
.ari_base = TEGRA_MMCRAB_BASE + MCE_ARI_APERTURE_2_OFFSET,
.ops = &ari_mce_ops,
},
{
/* A57 Core 3 */
.ari_base = TEGRA_MMCRAB_BASE + MCE_ARI_APERTURE_3_OFFSET,
.ops = &ari_mce_ops,
},
{
/* D15 Core 0 */
.ari_base = TEGRA_MMCRAB_BASE + MCE_ARI_APERTURE_4_OFFSET,
.ops = &nvg_mce_ops,
},
{
/* D15 Core 1 */
.ari_base = TEGRA_MMCRAB_BASE + MCE_ARI_APERTURE_5_OFFSET,
.ops = &nvg_mce_ops,
}
};
static uint32_t mce_get_curr_cpu_ari_base(void)
{
uint64_t mpidr = read_mpidr();
uint64_t cpuid = mpidr & MPIDR_CPU_MASK;
uint64_t impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK;
/*
* T186 has 2 CPU clusters, one with Denver CPUs and the other with
* ARM CortexA-57 CPUs. Each cluster consists of 4 CPUs and the CPU
* numbers start from 0. In order to get the proper arch_mce_ops_t
* struct, we have to convert the Denver CPU ids to the corresponding
* indices in the mce_ops_table array.
*/
if (impl == DENVER_IMPL) {
cpuid |= 0x4U;
}
return mce_cfg_table[cpuid].ari_base;
}
static arch_mce_ops_t *mce_get_curr_cpu_ops(void)
{
uint64_t mpidr = read_mpidr();
uint64_t cpuid = mpidr & MPIDR_CPU_MASK;
uint64_t impl = (read_midr() >> MIDR_IMPL_SHIFT) &
MIDR_IMPL_MASK;
/*
* T186 has 2 CPU clusters, one with Denver CPUs and the other with
* ARM CortexA-57 CPUs. Each cluster consists of 4 CPUs and the CPU
* numbers start from 0. In order to get the proper arch_mce_ops_t
* struct, we have to convert the Denver CPU ids to the corresponding
* indices in the mce_ops_table array.
*/
if (impl == DENVER_IMPL) {
cpuid |= 0x4U;
}
return mce_cfg_table[cpuid].ops;
}
/*******************************************************************************
* Common handler for all MCE commands
******************************************************************************/
int32_t mce_command_handler(uint64_t cmd, uint64_t arg0, uint64_t arg1,
uint64_t arg2)
{
const arch_mce_ops_t *ops;
gp_regs_t *gp_regs = get_gpregs_ctx(cm_get_context(NON_SECURE));
uint32_t cpu_ari_base;
uint64_t ret64 = 0, arg3, arg4, arg5;
int32_t ret = 0;
assert(gp_regs != NULL);
/* get a pointer to the CPU's arch_mce_ops_t struct */
ops = mce_get_curr_cpu_ops();
/* get the CPU's ARI base address */
cpu_ari_base = mce_get_curr_cpu_ari_base();
switch (cmd) {
case (uint64_t)MCE_CMD_ENTER_CSTATE:
ret = ops->enter_cstate(cpu_ari_base, arg0, arg1);
break;
case (uint64_t)MCE_CMD_UPDATE_CSTATE_INFO:
/*
* get the parameters required for the update cstate info
* command
*/
arg3 = read_ctx_reg(gp_regs, CTX_GPREG_X4);
arg4 = read_ctx_reg(gp_regs, CTX_GPREG_X5);
arg5 = read_ctx_reg(gp_regs, CTX_GPREG_X6);
ret = ops->update_cstate_info(cpu_ari_base, (uint32_t)arg0,
(uint32_t)arg1, (uint32_t)arg2, (uint8_t)arg3,
(uint32_t)arg4, (uint8_t)arg5);
write_ctx_reg(gp_regs, CTX_GPREG_X4, (0ULL));
write_ctx_reg(gp_regs, CTX_GPREG_X5, (0ULL));
write_ctx_reg(gp_regs, CTX_GPREG_X6, (0ULL));
break;
case (uint64_t)MCE_CMD_UPDATE_CROSSOVER_TIME:
ret = ops->update_crossover_time(cpu_ari_base, arg0, arg1);
break;
case (uint64_t)MCE_CMD_READ_CSTATE_STATS:
ret64 = ops->read_cstate_stats(cpu_ari_base, arg0);
/* update context to return cstate stats value */
write_ctx_reg(gp_regs, CTX_GPREG_X1, (ret64));
write_ctx_reg(gp_regs, CTX_GPREG_X2, (ret64));
break;
case (uint64_t)MCE_CMD_WRITE_CSTATE_STATS:
ret = ops->write_cstate_stats(cpu_ari_base, arg0, arg1);
break;
case (uint64_t)MCE_CMD_IS_CCX_ALLOWED:
ret = ops->is_ccx_allowed(cpu_ari_base, arg0, arg1);
/* update context to return CCx status value */
write_ctx_reg(gp_regs, CTX_GPREG_X1, (uint64_t)(ret));
break;
case (uint64_t)MCE_CMD_IS_SC7_ALLOWED:
ret = ops->is_sc7_allowed(cpu_ari_base, arg0, arg1);
/* update context to return SC7 status value */
write_ctx_reg(gp_regs, CTX_GPREG_X1, (uint64_t)(ret));
write_ctx_reg(gp_regs, CTX_GPREG_X3, (uint64_t)(ret));
break;
case (uint64_t)MCE_CMD_ONLINE_CORE:
ret = ops->online_core(cpu_ari_base, arg0);
break;
case (uint64_t)MCE_CMD_CC3_CTRL:
ret = ops->cc3_ctrl(cpu_ari_base, arg0, arg1, arg2);
break;
case (uint64_t)MCE_CMD_ECHO_DATA:
ret64 = ops->call_enum_misc(cpu_ari_base, TEGRA_ARI_MISC_ECHO,
arg0);
/* update context to return if echo'd data matched source */
write_ctx_reg(gp_regs, CTX_GPREG_X1, ((ret64 == arg0) ?
1ULL : 0ULL));
write_ctx_reg(gp_regs, CTX_GPREG_X2, ((ret64 == arg0) ?
1ULL : 0ULL));
break;
case (uint64_t)MCE_CMD_READ_VERSIONS:
ret64 = ops->call_enum_misc(cpu_ari_base, TEGRA_ARI_MISC_VERSION,
arg0);
/*
* version = minor(63:32) | major(31:0). Update context
* to return major and minor version number.
*/
write_ctx_reg(gp_regs, CTX_GPREG_X1, (ret64));
write_ctx_reg(gp_regs, CTX_GPREG_X2, (ret64 >> 32ULL));
break;
case (uint64_t)MCE_CMD_ENUM_FEATURES:
ret64 = ops->call_enum_misc(cpu_ari_base,
TEGRA_ARI_MISC_FEATURE_LEAF_0, arg0);
/* update context to return features value */
write_ctx_reg(gp_regs, CTX_GPREG_X1, (ret64));
break;
case (uint64_t)MCE_CMD_ROC_FLUSH_CACHE_TRBITS:
ret = ops->roc_flush_cache_trbits(cpu_ari_base);
break;
case (uint64_t)MCE_CMD_ROC_FLUSH_CACHE:
ret = ops->roc_flush_cache(cpu_ari_base);
break;
case (uint64_t)MCE_CMD_ROC_CLEAN_CACHE:
ret = ops->roc_clean_cache(cpu_ari_base);
break;
case (uint64_t)MCE_CMD_ENUM_READ_MCA:
ret64 = ops->read_write_mca(cpu_ari_base, arg0, &arg1);
/* update context to return MCA data/error */
write_ctx_reg(gp_regs, CTX_GPREG_X1, (ret64));
write_ctx_reg(gp_regs, CTX_GPREG_X2, (arg1));
write_ctx_reg(gp_regs, CTX_GPREG_X3, (ret64));
break;
case (uint64_t)MCE_CMD_ENUM_WRITE_MCA:
ret64 = ops->read_write_mca(cpu_ari_base, arg0, &arg1);
/* update context to return MCA error */
write_ctx_reg(gp_regs, CTX_GPREG_X1, (ret64));
write_ctx_reg(gp_regs, CTX_GPREG_X3, (ret64));
break;
#if ENABLE_CHIP_VERIFICATION_HARNESS
case (uint64_t)MCE_CMD_ENABLE_LATIC:
/*
* This call is not for production use. The constant value,
* 0xFFFF0000, is specific to allowing for enabling LATIC on
* pre-production parts for the chip verification harness.
*
* Enabling LATIC allows S/W to read the MINI ISPs in the
* CCPLEX. The ISMs are used for various measurements relevant
* to particular locations in the Silicon. They are small
* counters which can be polled to determine how fast a
* particular location in the Silicon is.
*/
ops->enter_ccplex_state(mce_get_curr_cpu_ari_base(),
0xFFFF0000);
break;
#endif
case (uint64_t)MCE_CMD_UNCORE_PERFMON_REQ:
ret = ops->read_write_uncore_perfmon(cpu_ari_base, arg0, &arg1);
/* update context to return data */
write_ctx_reg(gp_regs, CTX_GPREG_X1, (arg1));
break;
case (uint64_t)MCE_CMD_MISC_CCPLEX:
ops->misc_ccplex(cpu_ari_base, arg0, arg1);
break;
default:
ERROR("unknown MCE command (%" PRIu64 ")\n", cmd);
ret = EINVAL;
break;
}
return ret;
}
/*******************************************************************************
* Handler to update the reset vector for CPUs
******************************************************************************/
int32_t mce_update_reset_vector(void)
{
const arch_mce_ops_t *ops = mce_get_curr_cpu_ops();
ops->update_reset_vector(mce_get_curr_cpu_ari_base());
return 0;
}
static int32_t mce_update_ccplex_gsc(tegra_ari_gsc_index_t gsc_idx)
{
const arch_mce_ops_t *ops = mce_get_curr_cpu_ops();
ops->update_ccplex_gsc(mce_get_curr_cpu_ari_base(), gsc_idx);
return 0;
}
/*******************************************************************************
* Handler to update carveout values for Video Memory Carveout region
******************************************************************************/
int32_t mce_update_gsc_videomem(void)
{
return mce_update_ccplex_gsc(TEGRA_ARI_GSC_VPR_IDX);
}
/*******************************************************************************
* Handler to update carveout values for TZDRAM aperture
******************************************************************************/
int32_t mce_update_gsc_tzdram(void)
{
return mce_update_ccplex_gsc(TEGRA_ARI_GSC_TZ_DRAM_IDX);
}
/*******************************************************************************
* Handler to shutdown/reset the entire system
******************************************************************************/
__dead2 void mce_enter_ccplex_state(uint32_t state_idx)
{
const arch_mce_ops_t *ops = mce_get_curr_cpu_ops();
/* sanity check state value */
if ((state_idx != TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_POWER_OFF) &&
(state_idx != TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_REBOOT)) {
panic();
}
ops->enter_ccplex_state(mce_get_curr_cpu_ari_base(), state_idx);
/* wait till the CCPLEX powers down */
for (;;) {
;
}
}
/*******************************************************************************
* Handler to issue the UPDATE_CSTATE_INFO request
******************************************************************************/
void mce_update_cstate_info(const mce_cstate_info_t *cstate)
{
const arch_mce_ops_t *ops = mce_get_curr_cpu_ops();
/* issue the UPDATE_CSTATE_INFO request */
ops->update_cstate_info(mce_get_curr_cpu_ari_base(), cstate->cluster,
cstate->ccplex, cstate->system, cstate->system_state_force,
cstate->wake_mask, cstate->update_wake_mask);
}
/*******************************************************************************
* Handler to read the MCE firmware version and check if it is compatible
* with interface header the BL3-1 was compiled against
******************************************************************************/
void mce_verify_firmware_version(void)
{
const arch_mce_ops_t *ops;
uint32_t cpu_ari_base;
uint64_t version;
uint32_t major, minor;
/*
* MCE firmware is not supported on simulation platforms.
*/
if (tegra_platform_is_emulation()) {
INFO("MCE firmware is not supported\n");
} else {
/* get a pointer to the CPU's arch_mce_ops_t struct */
ops = mce_get_curr_cpu_ops();
/* get the CPU's ARI base address */
cpu_ari_base = mce_get_curr_cpu_ari_base();
/*
* Read the MCE firmware version and extract the major and minor
* version fields
*/
version = ops->call_enum_misc(cpu_ari_base, TEGRA_ARI_MISC_VERSION, 0);
major = (uint32_t)version;
minor = (uint32_t)(version >> 32);
INFO("MCE Version - HW=%d:%d, SW=%d:%d\n", major, minor,
TEGRA_ARI_VERSION_MAJOR, TEGRA_ARI_VERSION_MINOR);
/*
* Verify that the MCE firmware version and the interface header
* match
*/
if (major != TEGRA_ARI_VERSION_MAJOR) {
ERROR("ARI major version mismatch\n");
panic();
}
if (minor < TEGRA_ARI_VERSION_MINOR) {
ERROR("ARI minor version mismatch\n");
panic();
}
}
}
@@ -0,0 +1,256 @@
/*
* Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <errno.h>
#include <arch.h>
#include <arch_helpers.h>
#include <common/debug.h>
#include <denver.h>
#include <lib/mmio.h>
#include <mce_private.h>
#include <t18x_ari.h>
#include <tegra_private.h>
int32_t nvg_enter_cstate(uint32_t ari_base, uint32_t state, uint32_t wake_time)
{
int32_t ret = 0;
uint64_t val = 0ULL;
(void)ari_base;
/* check for allowed power state */
if ((state != TEGRA_ARI_CORE_C0) && (state != TEGRA_ARI_CORE_C1) &&
(state != TEGRA_ARI_CORE_C6) && (state != TEGRA_ARI_CORE_C7)) {
ERROR("%s: unknown cstate (%d)\n", __func__, state);
ret = EINVAL;
} else {
/* time (TSC ticks) until the core is expected to get a wake event */
nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_WAKE_TIME, wake_time);
/* set the core cstate */
val = read_actlr_el1() & ~ACTLR_EL1_PMSTATE_MASK;
write_actlr_el1(val | (uint64_t)state);
}
return ret;
}
/*
* This request allows updating of CLUSTER_CSTATE, CCPLEX_CSTATE and
* SYSTEM_CSTATE values.
*/
int32_t nvg_update_cstate_info(uint32_t ari_base, uint32_t cluster, uint32_t ccplex,
uint32_t system, uint8_t sys_state_force, uint32_t wake_mask,
uint8_t update_wake_mask)
{
uint64_t val = 0ULL;
(void)ari_base;
/* update CLUSTER_CSTATE? */
if (cluster != 0U) {
val |= ((uint64_t)cluster & CLUSTER_CSTATE_MASK) |
CLUSTER_CSTATE_UPDATE_BIT;
}
/* update CCPLEX_CSTATE? */
if (ccplex != 0U) {
val |= (((uint64_t)ccplex & CCPLEX_CSTATE_MASK) << CCPLEX_CSTATE_SHIFT) |
CCPLEX_CSTATE_UPDATE_BIT;
}
/* update SYSTEM_CSTATE? */
if (system != 0U) {
val |= (((uint64_t)system & SYSTEM_CSTATE_MASK) << SYSTEM_CSTATE_SHIFT) |
(((uint64_t)sys_state_force << SYSTEM_CSTATE_FORCE_UPDATE_SHIFT) |
SYSTEM_CSTATE_UPDATE_BIT);
}
/* update wake mask value? */
if (update_wake_mask != 0U) {
val |= CSTATE_WAKE_MASK_UPDATE_BIT;
}
/* set the wake mask */
val &= CSTATE_WAKE_MASK_CLEAR;
val |= ((uint64_t)wake_mask << CSTATE_WAKE_MASK_SHIFT);
/* set the updated cstate info */
nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_CSTATE_INFO, val);
return 0;
}
int32_t nvg_update_crossover_time(uint32_t ari_base, uint32_t type, uint32_t time)
{
int32_t ret = 0;
(void)ari_base;
/* sanity check crossover type */
if (type > TEGRA_ARI_CROSSOVER_CCP3_SC1) {
ret = EINVAL;
} else {
/*
* The crossover threshold limit types start from
* TEGRA_CROSSOVER_TYPE_C1_C6 to TEGRA_CROSSOVER_TYPE_CCP3_SC7.
* The command indices for updating the threshold be generated
* by adding the type to the NVG_SET_THRESHOLD_CROSSOVER_C1_C6
* command index.
*/
nvg_set_request_data((TEGRA_NVG_CHANNEL_CROSSOVER_C1_C6 +
(uint64_t)type), (uint64_t)time);
}
return ret;
}
uint64_t nvg_read_cstate_stats(uint32_t ari_base, uint32_t state)
{
uint64_t ret;
(void)ari_base;
/* sanity check state */
if (state == 0U) {
ret = EINVAL;
} else {
/*
* The cstate types start from NVG_READ_CSTATE_STATS_SC7_ENTRIES
* to NVG_GET_LAST_CSTATE_ENTRY_A57_3. The command indices for
* reading the threshold can be generated by adding the type to
* the NVG_CLEAR_CSTATE_STATS command index.
*/
nvg_set_request((TEGRA_NVG_CHANNEL_CSTATE_STATS_CLEAR +
(uint64_t)state));
ret = nvg_get_result();
}
return ret;
}
int32_t nvg_write_cstate_stats(uint32_t ari_base, uint32_t state, uint32_t stats)
{
uint64_t val;
(void)ari_base;
/*
* The only difference between a CSTATE_STATS_WRITE and
* CSTATE_STATS_READ is the usage of the 63:32 in the request.
* 63:32 are set to '0' for a read, while a write contains the
* actual stats value to be written.
*/
val = ((uint64_t)stats << MCE_CSTATE_STATS_TYPE_SHIFT) | state;
/*
* The cstate types start from NVG_READ_CSTATE_STATS_SC7_ENTRIES
* to NVG_GET_LAST_CSTATE_ENTRY_A57_3. The command indices for
* reading the threshold can be generated by adding the type to
* the NVG_CLEAR_CSTATE_STATS command index.
*/
nvg_set_request_data((TEGRA_NVG_CHANNEL_CSTATE_STATS_CLEAR +
(uint64_t)state), val);
return 0;
}
int32_t nvg_is_ccx_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time)
{
(void)ari_base;
(void)state;
(void)wake_time;
/* This does not apply to the Denver cluster */
return 0;
}
int32_t nvg_is_sc7_allowed(uint32_t ari_base, uint32_t state, uint32_t wake_time)
{
uint64_t val;
int32_t ret;
(void)ari_base;
/* check for allowed power state */
if ((state != TEGRA_ARI_CORE_C0) && (state != TEGRA_ARI_CORE_C1) &&
(state != TEGRA_ARI_CORE_C6) && (state != TEGRA_ARI_CORE_C7)) {
ERROR("%s: unknown cstate (%d)\n", __func__, state);
ret = EINVAL;
} else {
/*
* Request format -
* 63:32 = wake time
* 31:0 = C-state for this core
*/
val = ((uint64_t)wake_time << MCE_SC7_WAKE_TIME_SHIFT) |
((uint64_t)state & MCE_SC7_ALLOWED_MASK);
/* issue command to check if SC7 is allowed */
nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_IS_SC7_ALLOWED, val);
/* 1 = SC7 allowed, 0 = SC7 not allowed */
ret = (nvg_get_result() != 0ULL) ? 1 : 0;
}
return ret;
}
int32_t nvg_online_core(uint32_t ari_base, uint32_t core)
{
uint64_t cpu = read_mpidr() & MPIDR_CPU_MASK;
uint64_t impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK;
int32_t ret = 0;
(void)ari_base;
/* sanity check code id */
if ((core >= MCE_CORE_ID_MAX) || (cpu == core)) {
ERROR("%s: unsupported core id (%d)\n", __func__, core);
ret = EINVAL;
} else {
/*
* The Denver cluster has 2 CPUs only - 0, 1.
*/
if ((impl == DENVER_IMPL) && ((core == 2U) || (core == 3U))) {
ERROR("%s: unknown core id (%d)\n", __func__, core);
ret = EINVAL;
} else {
/* get a core online */
nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_ONLINE_CORE,
((uint64_t)core & MCE_CORE_ID_MASK));
}
}
return ret;
}
int32_t nvg_cc3_ctrl(uint32_t ari_base, uint32_t freq, uint32_t volt, uint8_t enable)
{
uint32_t val;
(void)ari_base;
/*
* If the enable bit is cleared, Auto-CC3 will be disabled by setting
* the SW visible voltage/frequency request registers for all non
* floorswept cores valid independent of StandbyWFI and disabling
* the IDLE voltage/frequency request register. If set, Auto-CC3
* will be enabled by setting the ARM SW visible voltage/frequency
* request registers for all non floorswept cores to be enabled by
* StandbyWFI or the equivalent signal, and always keeping the IDLE
* voltage/frequency request register enabled.
*/
val = (((freq & MCE_AUTO_CC3_FREQ_MASK) << MCE_AUTO_CC3_FREQ_SHIFT) |\
((volt & MCE_AUTO_CC3_VTG_MASK) << MCE_AUTO_CC3_VTG_SHIFT) |\
((enable != 0U) ? MCE_AUTO_CC3_ENABLE_BIT : 0U));
nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_CC3_CTRL, (uint64_t)val);
return 0;
}
@@ -0,0 +1,277 @@
/*
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <drivers/delay_timer.h>
#include <errno.h>
#include <string.h>
#include <bpmp_ipc.h>
#include <pmc.h>
#include <security_engine.h>
#include <tegra_private.h>
#include "se_private.h"
/*******************************************************************************
* Constants and Macros
******************************************************************************/
#define SE0_MAX_BUSY_TIMEOUT_MS U(100) /* 100ms */
#define BYTES_IN_WORD U(4)
#define SHA256_MAX_HASH_RESULT U(7)
#define SHA256_DST_SIZE U(32)
#define SHA_FIRST_OP U(1)
#define MAX_SHA_ENGINE_CHUNK_SIZE U(0xFFFFFF)
#define SHA256_MSG_LENGTH_ONETIME U(0xffff)
/*
* Check that SE operation has completed after kickoff
* This function is invoked after an SE operation has been started,
* and it checks the following conditions:
* 1. SE0_INT_STATUS = SE0_OP_DONE
* 2. SE0_STATUS = IDLE
* 3. SE0_ERR_STATUS is clean.
*/
static int32_t tegra_se_operation_complete(void)
{
uint32_t val = 0U;
/* Read SE0 interrupt register to ensure H/W operation complete */
val = tegra_se_read_32(SE0_INT_STATUS_REG_OFFSET);
if (SE0_INT_OP_DONE(val) == SE0_INT_OP_DONE_CLEAR) {
ERROR("%s: Engine busy state too many times! val = 0x%x\n",
__func__, val);
return -ETIMEDOUT;
}
/* Read SE0 status idle to ensure H/W operation complete */
val = tegra_se_read_32(SE0_SHA_STATUS_0);
if (val != SE0_SHA_STATUS_IDLE) {
ERROR("%s: Idle state timeout! val = 0x%x\n", __func__,
val);
return -ETIMEDOUT;
}
/* Ensure that no errors are thrown during operation */
val = tegra_se_read_32(SE0_ERR_STATUS_REG_OFFSET);
if (val != SE0_ERR_STATUS_CLEAR) {
ERROR("%s: Error during SE operation! val = 0x%x",
__func__, val);
return -ENOTSUP;
}
return 0;
}
/*
* Security engine primitive normal operations
*/
static int32_t tegra_se_start_normal_operation(uint64_t src_addr,
uint32_t nbytes, uint32_t last_buf, uint32_t src_len_inbytes)
{
int32_t ret = 0;
uint32_t val = 0U;
uint32_t src_in_lo;
uint32_t src_in_msb;
uint32_t src_in_hi;
if ((src_addr == 0UL) || (nbytes == 0U))
return -EINVAL;
src_in_lo = (uint32_t)src_addr;
src_in_msb = ((uint32_t)(src_addr >> 32U) & 0xffU);
src_in_hi = ((src_in_msb << SE0_IN_HI_ADDR_HI_0_MSB_SHIFT) |
(nbytes & 0xffffffU));
/* set SRC_IN_ADDR_LO and SRC_IN_ADDR_HI*/
tegra_se_write_32(SE0_IN_ADDR, src_in_lo);
tegra_se_write_32(SE0_IN_HI_ADDR_HI, src_in_hi);
val = tegra_se_read_32(SE0_INT_STATUS_REG_OFFSET);
if (val > 0U) {
tegra_se_write_32(SE0_INT_STATUS_REG_OFFSET, 0x00000U);
}
/* Enable SHA interrupt for SE0 Operation */
tegra_se_write_32(SE0_SHA_INT_ENABLE, 0x1aU);
/* flush to DRAM for SE to use the updated contents */
flush_dcache_range(src_addr, src_len_inbytes);
/* Start SHA256 operation */
if (last_buf == 1U) {
tegra_se_write_32(SE0_OPERATION_REG_OFFSET, SE0_OP_START |
SE0_UNIT_OPERATION_PKT_LASTBUF_FIELD);
} else {
tegra_se_write_32(SE0_OPERATION_REG_OFFSET, SE0_OP_START);
}
/* Wait for SE-operation to finish */
udelay(SE0_MAX_BUSY_TIMEOUT_MS * 100U);
/* Check SE0 operation status */
ret = tegra_se_operation_complete();
if (ret != 0) {
ERROR("SE operation complete Failed! 0x%x", ret);
return ret;
}
return 0;
}
static int32_t tegra_se_calculate_sha256_hash(uint64_t src_addr,
uint32_t src_len_inbyte)
{
uint32_t val, last_buf, i;
int32_t ret = 0;
uint32_t operations;
uint64_t src_len_inbits;
uint32_t len_bits_msb;
uint32_t len_bits_lsb;
uint32_t number_of_operations, max_bytes, bytes_left, remaining_bytes;
if (src_len_inbyte > MAX_SHA_ENGINE_CHUNK_SIZE) {
ERROR("SHA input chunk size too big: 0x%x\n", src_len_inbyte);
return -EINVAL;
}
if (src_addr == 0UL) {
return -EINVAL;
}
/* number of bytes per operation */
max_bytes = SHA256_HASH_SIZE_BYTES * SHA256_MSG_LENGTH_ONETIME;
src_len_inbits = src_len_inbyte * 8U;
len_bits_msb = (uint32_t)(src_len_inbits >> 32U);
len_bits_lsb = (uint32_t)(src_len_inbits & 0xFFFFFFFF);
/* program SE0_CONFIG for SHA256 operation */
val = SE0_CONFIG_ENC_ALG_SHA | SE0_CONFIG_ENC_MODE_SHA256 |
SE0_CONFIG_DEC_ALG_NOP | SE0_CONFIG_DST_HASHREG;
tegra_se_write_32(SE0_SHA_CONFIG, val);
/* set SE0_SHA_MSG_LENGTH registers */
tegra_se_write_32(SE0_SHA_MSG_LENGTH_0, len_bits_lsb);
tegra_se_write_32(SE0_SHA_MSG_LEFT_0, len_bits_lsb);
tegra_se_write_32(SE0_SHA_MSG_LENGTH_1, len_bits_msb);
/* zero out unused SE0_SHA_MSG_LENGTH and SE0_SHA_MSG_LEFT */
tegra_se_write_32(SE0_SHA_MSG_LENGTH_2, 0U);
tegra_se_write_32(SE0_SHA_MSG_LENGTH_3, 0U);
tegra_se_write_32(SE0_SHA_MSG_LEFT_1, 0U);
tegra_se_write_32(SE0_SHA_MSG_LEFT_2, 0U);
tegra_se_write_32(SE0_SHA_MSG_LEFT_3, 0U);
number_of_operations = src_len_inbyte / max_bytes;
remaining_bytes = src_len_inbyte % max_bytes;
if (remaining_bytes > 0U) {
number_of_operations += 1U;
}
/*
* 1. Operations == 1: program SE0_SHA_TASK register to initiate SHA256
* hash generation by setting
* 1(SE0_SHA_CONFIG_HW_INIT_HASH) to SE0_SHA_TASK
* and start SHA256-normal operation.
* 2. 1 < Operations < number_of_operations: program SE0_SHA_TASK to
* 0(SE0_SHA_CONFIG_HW_INIT_HASH_DISABLE) to load
* intermediate SHA256 digest result from
* HASH_RESULT register to continue SHA256
* generation and start SHA256-normal operation.
* 3. Operations == number_of_operations: continue with step 2 and set
* max_bytes to bytes_left to process final
* hash-result generation and
* start SHA256-normal operation.
*/
bytes_left = src_len_inbyte;
for (operations = 1U; operations <= number_of_operations;
operations++) {
if (operations == SHA_FIRST_OP) {
val = SE0_SHA_CONFIG_HW_INIT_HASH;
} else {
/* Load intermediate SHA digest result to
* SHA:HASH_RESULT(0..7) to continue the SHA
* calculation and tell the SHA engine to use it.
*/
for (i = 0U; (i / BYTES_IN_WORD) <=
SHA256_MAX_HASH_RESULT; i += BYTES_IN_WORD) {
val = tegra_se_read_32(SE0_SHA_HASH_RESULT_0 +
i);
tegra_se_write_32(SE0_SHA_HASH_RESULT_0 + i,
val);
}
val = SE0_SHA_CONFIG_HW_INIT_HASH_DISABLE;
if (len_bits_lsb <= (max_bytes * 8U)) {
len_bits_lsb = (remaining_bytes * 8U);
} else {
len_bits_lsb -= (max_bytes * 8U);
}
tegra_se_write_32(SE0_SHA_MSG_LEFT_0, len_bits_lsb);
}
tegra_se_write_32(SE0_SHA_TASK_CONFIG, val);
max_bytes = (SHA256_HASH_SIZE_BYTES *
SHA256_MSG_LENGTH_ONETIME);
if (bytes_left < max_bytes) {
max_bytes = bytes_left;
last_buf = 1U;
} else {
bytes_left = bytes_left - max_bytes;
last_buf = 0U;
}
/* start operation */
ret = tegra_se_start_normal_operation(src_addr, max_bytes,
last_buf, src_len_inbyte);
if (ret != 0) {
ERROR("Error during SE operation! 0x%x", ret);
return -EINVAL;
}
}
return ret;
}
/*
* Handler to generate SHA256 and save SHA256 hash to PMC-Scratch register.
*/
int32_t tegra_se_save_sha256_hash(uint64_t bl31_base, uint32_t src_len_inbyte)
{
int32_t ret = 0;
uint32_t val = 0U, hash_offset = 0U, scratch_offset = 0U, security;
/*
* Set SE_SOFT_SETTINGS=SE_SECURE to prevent NS process to change SE
* registers.
*/
security = tegra_se_read_32(SE0_SECURITY);
tegra_se_write_32(SE0_SECURITY, security | SE0_SECURITY_SE_SOFT_SETTING);
ret = tegra_se_calculate_sha256_hash(bl31_base, src_len_inbyte);
if (ret != 0L) {
ERROR("%s: SHA256 generation failed\n", __func__);
return ret;
}
/*
* Reset SE_SECURE to previous value.
*/
tegra_se_write_32(SE0_SECURITY, security);
/* read SHA256_HASH_RESULT and save to PMC Scratch registers */
scratch_offset = SECURE_SCRATCH_TZDRAM_SHA256_HASH_START;
while (scratch_offset <= SECURE_SCRATCH_TZDRAM_SHA256_HASH_END) {
val = tegra_se_read_32(SE0_SHA_HASH_RESULT_0 + hash_offset);
mmio_write_32(TEGRA_SCRATCH_BASE + scratch_offset, val);
hash_offset += BYTES_IN_WORD;
scratch_offset += BYTES_IN_WORD;
}
return ret;
}
@@ -0,0 +1,100 @@
/*
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef SE_PRIVATE_H
#define SE_PRIVATE_H
#include <lib/utils_def.h>
/* SE0 security register */
#define SE0_SECURITY U(0x18)
#define SE0_SECURITY_SE_SOFT_SETTING (((uint32_t)1) << 16U)
/* SE0 config register */
#define SE0_SHA_CONFIG U(0x104)
#define SE0_SHA_TASK_CONFIG U(0x108)
#define SE0_SHA_CONFIG_HW_INIT_HASH ((1U) << 0U)
#define SE0_SHA_CONFIG_HW_INIT_HASH_DISABLE U(0)
#define SE0_CONFIG_ENC_ALG_SHIFT U(12)
#define SE0_CONFIG_ENC_ALG_SHA \
(((uint32_t)3) << SE0_CONFIG_ENC_ALG_SHIFT)
#define SE0_CONFIG_DEC_ALG_SHIFT U(8)
#define SE0_CONFIG_DEC_ALG_NOP \
(((uint32_t)0) << SE0_CONFIG_DEC_ALG_SHIFT)
#define SE0_CONFIG_DST_SHIFT U(2)
#define SE0_CONFIG_DST_HASHREG \
(((uint32_t)1) << SE0_CONFIG_DST_SHIFT)
#define SHA256_HASH_SIZE_BYTES U(256)
#define SE0_CONFIG_ENC_MODE_SHIFT U(24)
#define SE0_CONFIG_ENC_MODE_SHA256 \
(((uint32_t)5) << SE0_CONFIG_ENC_MODE_SHIFT)
/* SHA input message length */
#define SE0_SHA_MSG_LENGTH_0 U(0x11c)
#define SE0_SHA_MSG_LENGTH_1 U(0x120)
#define SE0_SHA_MSG_LENGTH_2 U(0x124)
#define SE0_SHA_MSG_LENGTH_3 U(0x128)
/* SHA input message left */
#define SE0_SHA_MSG_LEFT_0 U(0x12c)
#define SE0_SHA_MSG_LEFT_1 U(0x130)
#define SE0_SHA_MSG_LEFT_2 U(0x134)
#define SE0_SHA_MSG_LEFT_3 U(0x138)
/* SE Hash Result */
#define SE0_SHA_HASH_RESULT_0 U(0x13c)
/* SE OPERATION */
#define SE0_OPERATION_REG_OFFSET U(0x17c)
#define SE0_UNIT_OPERATION_PKT_LASTBUF_SHIFT U(16)
#define SE0_UNIT_OPERATION_PKT_LASTBUF_FIELD \
(((uint32_t)0x1) << SE0_UNIT_OPERATION_PKT_LASTBUF_SHIFT)
#define SE0_OPERATION_SHIFT U(0)
#define SE0_OP_START \
(((uint32_t)0x1) << SE0_OPERATION_SHIFT)
/* SE Interrupt */
#define SE0_SHA_INT_ENABLE U(0x180)
#define SE0_INT_STATUS_REG_OFFSET U(0x184)
#define SE0_INT_OP_DONE_SHIFT U(4)
#define SE0_INT_OP_DONE_CLEAR \
(((uint32_t)0) << SE0_INT_OP_DONE_SHIFT)
#define SE0_INT_OP_DONE(x) \
((x) & (((uint32_t)0x1) << SE0_INT_OP_DONE_SHIFT))
/* SE SHA status */
#define SE0_SHA_STATUS_0 U(0x188)
#define SE0_SHA_STATUS_IDLE U(0)
/* SE error status */
#define SE0_ERR_STATUS_REG_OFFSET U(0x18c)
#define SE0_ERR_STATUS_CLEAR U(0)
#define SE0_IN_ADDR U(0x10c)
#define SE0_IN_HI_ADDR_HI U(0x110)
#define SE0_IN_HI_ADDR_HI_0_MSB_SHIFT U(24)
/* SE error status */
#define SECURE_SCRATCH_TZDRAM_SHA256_HASH_START SECURE_SCRATCH_RSV63_LO
#define SECURE_SCRATCH_TZDRAM_SHA256_HASH_END SECURE_SCRATCH_RSV66_HI
/*******************************************************************************
* Inline functions definition
******************************************************************************/
static inline uint32_t tegra_se_read_32(uint32_t offset)
{
return mmio_read_32((uint32_t)(TEGRA_SE0_BASE + offset));
}
static inline void tegra_se_write_32(uint32_t offset, uint32_t val)
{
mmio_write_32(((uint32_t)(TEGRA_SE0_BASE + offset)), val);
}
#endif /* SE_PRIVATE_H */
@@ -0,0 +1,700 @@
/*
* Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <common/bl_common.h>
#include <mce.h>
#include <memctrl_v2.h>
#include <tegra186_private.h>
#include <tegra_mc_def.h>
#include <tegra_platform.h>
#include <tegra_private.h>
extern uint64_t tegra_bl31_phys_base;
/*******************************************************************************
* Array to hold stream_id override config register offsets
******************************************************************************/
const static uint32_t tegra186_streamid_override_regs[] = {
MC_STREAMID_OVERRIDE_CFG_SDMMCRA,
MC_STREAMID_OVERRIDE_CFG_SDMMCRAA,
MC_STREAMID_OVERRIDE_CFG_SDMMCR,
MC_STREAMID_OVERRIDE_CFG_SDMMCRAB,
MC_STREAMID_OVERRIDE_CFG_SDMMCWA,
MC_STREAMID_OVERRIDE_CFG_SDMMCWAA,
MC_STREAMID_OVERRIDE_CFG_SDMMCW,
MC_STREAMID_OVERRIDE_CFG_SDMMCWAB,
};
/*******************************************************************************
* Array to hold the security configs for stream IDs
******************************************************************************/
const static mc_streamid_security_cfg_t tegra186_streamid_sec_cfgs[] = {
mc_make_sec_cfg(SCEW, NON_SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(AFIR, NON_SECURE, OVERRIDE, DISABLE),
mc_make_sec_cfg(AFIW, NON_SECURE, OVERRIDE, DISABLE),
mc_make_sec_cfg(NVDISPLAYR1, NON_SECURE, OVERRIDE, DISABLE),
mc_make_sec_cfg(XUSB_DEVR, NON_SECURE, OVERRIDE, ENABLE),
mc_make_sec_cfg(VICSRD1, NON_SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(NVENCSWR, NON_SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(TSECSRDB, NON_SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(AXISW, SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(SDMMCWAB, NON_SECURE, OVERRIDE, DISABLE),
mc_make_sec_cfg(AONDMAW, NON_SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(GPUSWR2, SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(SATAW, NON_SECURE, OVERRIDE, DISABLE),
mc_make_sec_cfg(UFSHCW, NON_SECURE, OVERRIDE, DISABLE),
mc_make_sec_cfg(SDMMCR, NON_SECURE, OVERRIDE, DISABLE),
mc_make_sec_cfg(SCEDMAW, NON_SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(UFSHCR, NON_SECURE, OVERRIDE, DISABLE),
mc_make_sec_cfg(SDMMCWAA, NON_SECURE, OVERRIDE, DISABLE),
mc_make_sec_cfg(SESWR, NON_SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(MPCORER, NON_SECURE, OVERRIDE, DISABLE),
mc_make_sec_cfg(PTCR, NON_SECURE, OVERRIDE, DISABLE),
mc_make_sec_cfg(BPMPW, NON_SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(ETRW, NON_SECURE, OVERRIDE, DISABLE),
mc_make_sec_cfg(GPUSRD, SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(VICSWR, NON_SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(SCEDMAR, NON_SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(HDAW, NON_SECURE, OVERRIDE, DISABLE),
mc_make_sec_cfg(ISPWA, NON_SECURE, OVERRIDE, ENABLE),
mc_make_sec_cfg(EQOSW, NON_SECURE, OVERRIDE, DISABLE),
mc_make_sec_cfg(XUSB_HOSTW, NON_SECURE, OVERRIDE, ENABLE),
mc_make_sec_cfg(TSECSWR, NON_SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(SDMMCRAA, NON_SECURE, OVERRIDE, DISABLE),
mc_make_sec_cfg(VIW, NON_SECURE, OVERRIDE, ENABLE),
mc_make_sec_cfg(AXISR, SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(SDMMCW, NON_SECURE, OVERRIDE, DISABLE),
mc_make_sec_cfg(BPMPDMAW, NON_SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(ISPRA, NON_SECURE, OVERRIDE, ENABLE),
mc_make_sec_cfg(NVDECSWR, NON_SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(XUSB_DEVW, NON_SECURE, OVERRIDE, ENABLE),
mc_make_sec_cfg(NVDECSRD, NON_SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(MPCOREW, NON_SECURE, OVERRIDE, DISABLE),
mc_make_sec_cfg(NVDISPLAYR, NON_SECURE, OVERRIDE, DISABLE),
mc_make_sec_cfg(BPMPDMAR, NON_SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(NVJPGSWR, NON_SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(NVDECSRD1, NON_SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(TSECSRD, NON_SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(NVJPGSRD, NON_SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(SDMMCWA, NON_SECURE, OVERRIDE, DISABLE),
mc_make_sec_cfg(SCER, NON_SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(XUSB_HOSTR, NON_SECURE, OVERRIDE, ENABLE),
mc_make_sec_cfg(VICSRD, NON_SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(AONDMAR, NON_SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(AONW, NON_SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(SDMMCRA, NON_SECURE, OVERRIDE, DISABLE),
mc_make_sec_cfg(HOST1XDMAR, NON_SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(EQOSR, NON_SECURE, OVERRIDE, DISABLE),
mc_make_sec_cfg(SATAR, NON_SECURE, OVERRIDE, DISABLE),
mc_make_sec_cfg(BPMPR, NON_SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(HDAR, NON_SECURE, OVERRIDE, DISABLE),
mc_make_sec_cfg(SDMMCRAB, NON_SECURE, OVERRIDE, DISABLE),
mc_make_sec_cfg(ETRR, NON_SECURE, OVERRIDE, DISABLE),
mc_make_sec_cfg(AONR, NON_SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(SESRD, NON_SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(NVENCSRD, NON_SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(GPUSWR, SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(TSECSWRB, NON_SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(ISPWB, NON_SECURE, OVERRIDE, ENABLE),
mc_make_sec_cfg(GPUSRD2, SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(APEDMAW, NON_SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(APER, NON_SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(APEW, NON_SECURE, NO_OVERRIDE, DISABLE),
mc_make_sec_cfg(APEDMAR, NON_SECURE, NO_OVERRIDE, DISABLE),
};
/*******************************************************************************
* Array to hold the transaction override configs
******************************************************************************/
const static mc_txn_override_cfg_t tegra186_txn_override_cfgs[] = {
mc_make_txn_override_cfg(BPMPW, CGID_TAG_ADR),
mc_make_txn_override_cfg(EQOSW, CGID_TAG_ADR),
mc_make_txn_override_cfg(NVJPGSWR, CGID_TAG_ADR),
mc_make_txn_override_cfg(SDMMCWAA, CGID_TAG_ADR),
mc_make_txn_override_cfg(MPCOREW, CGID_TAG_ADR),
mc_make_txn_override_cfg(SCEDMAW, CGID_TAG_ADR),
mc_make_txn_override_cfg(SDMMCW, CGID_TAG_ADR),
mc_make_txn_override_cfg(AXISW, CGID_TAG_ADR),
mc_make_txn_override_cfg(TSECSWR, CGID_TAG_ADR),
mc_make_txn_override_cfg(GPUSWR, CGID_TAG_ADR),
mc_make_txn_override_cfg(XUSB_HOSTW, CGID_TAG_ADR),
mc_make_txn_override_cfg(TSECSWRB, CGID_TAG_ADR),
mc_make_txn_override_cfg(GPUSWR2, CGID_TAG_ADR),
mc_make_txn_override_cfg(AONDMAW, CGID_TAG_ADR),
mc_make_txn_override_cfg(AONW, CGID_TAG_ADR),
mc_make_txn_override_cfg(SESWR, CGID_TAG_ADR),
mc_make_txn_override_cfg(BPMPDMAW, CGID_TAG_ADR),
mc_make_txn_override_cfg(SDMMCWA, CGID_TAG_ADR),
mc_make_txn_override_cfg(HDAW, CGID_TAG_ADR),
mc_make_txn_override_cfg(NVDECSWR, CGID_TAG_ADR),
mc_make_txn_override_cfg(UFSHCW, CGID_TAG_ADR),
mc_make_txn_override_cfg(SATAW, CGID_TAG_ADR),
mc_make_txn_override_cfg(ETRW, CGID_TAG_ADR),
mc_make_txn_override_cfg(VICSWR, CGID_TAG_ADR),
mc_make_txn_override_cfg(NVENCSWR, CGID_TAG_ADR),
mc_make_txn_override_cfg(SDMMCWAB, CGID_TAG_ADR),
mc_make_txn_override_cfg(ISPWB, CGID_TAG_ADR),
mc_make_txn_override_cfg(APEW, CGID_TAG_ADR),
mc_make_txn_override_cfg(XUSB_DEVW, CGID_TAG_ADR),
mc_make_txn_override_cfg(AFIW, CGID_TAG_ADR),
mc_make_txn_override_cfg(SCEW, CGID_TAG_ADR),
};
static void tegra186_memctrl_reconfig_mss_clients(void)
{
#if ENABLE_ROC_FOR_ORDERING_CLIENT_REQUESTS
uint32_t val, wdata_0, wdata_1;
/*
* Assert Memory Controller's HOTRESET_FLUSH_ENABLE signal for
* boot and strongly ordered MSS clients to flush existing memory
* traffic and stall future requests.
*/
val = tegra_mc_read_32(MC_CLIENT_HOTRESET_CTRL0);
assert(val == MC_CLIENT_HOTRESET_CTRL0_RESET_VAL);
wdata_0 = MC_CLIENT_HOTRESET_CTRL0_HDA_FLUSH_ENB |
MC_CLIENT_HOTRESET_CTRL0_AFI_FLUSH_ENB |
MC_CLIENT_HOTRESET_CTRL0_SATA_FLUSH_ENB |
MC_CLIENT_HOTRESET_CTRL0_XUSB_HOST_FLUSH_ENB |
MC_CLIENT_HOTRESET_CTRL0_XUSB_DEV_FLUSH_ENB;
tegra_mc_write_32(MC_CLIENT_HOTRESET_CTRL0, wdata_0);
/* Wait for HOTRESET STATUS to indicate FLUSH_DONE */
do {
val = tegra_mc_read_32(MC_CLIENT_HOTRESET_STATUS0);
} while ((val & wdata_0) != wdata_0);
/* Wait one more time due to SW WAR for known legacy issue */
do {
val = tegra_mc_read_32(MC_CLIENT_HOTRESET_STATUS0);
} while ((val & wdata_0) != wdata_0);
val = tegra_mc_read_32(MC_CLIENT_HOTRESET_CTRL1);
assert(val == MC_CLIENT_HOTRESET_CTRL1_RESET_VAL);
wdata_1 = MC_CLIENT_HOTRESET_CTRL1_SDMMC4A_FLUSH_ENB |
MC_CLIENT_HOTRESET_CTRL1_APE_FLUSH_ENB |
MC_CLIENT_HOTRESET_CTRL1_SE_FLUSH_ENB |
MC_CLIENT_HOTRESET_CTRL1_ETR_FLUSH_ENB |
MC_CLIENT_HOTRESET_CTRL1_AXIS_FLUSH_ENB |
MC_CLIENT_HOTRESET_CTRL1_EQOS_FLUSH_ENB |
MC_CLIENT_HOTRESET_CTRL1_UFSHC_FLUSH_ENB |
MC_CLIENT_HOTRESET_CTRL1_BPMP_FLUSH_ENB |
MC_CLIENT_HOTRESET_CTRL1_AON_FLUSH_ENB |
MC_CLIENT_HOTRESET_CTRL1_SCE_FLUSH_ENB;
tegra_mc_write_32(MC_CLIENT_HOTRESET_CTRL1, wdata_1);
/* Wait for HOTRESET STATUS to indicate FLUSH_DONE */
do {
val = tegra_mc_read_32(MC_CLIENT_HOTRESET_STATUS1);
} while ((val & wdata_1) != wdata_1);
/* Wait one more time due to SW WAR for known legacy issue */
do {
val = tegra_mc_read_32(MC_CLIENT_HOTRESET_STATUS1);
} while ((val & wdata_1) != wdata_1);
/*
* Change MEMTYPE_OVERRIDE from SO_DEV -> PASSTHRU for boot and
* strongly ordered MSS clients. ROC needs to be single point
* of control on overriding the memory type. So, remove TSA's
* memtype override.
*
* MC clients with default SO_DEV override still enabled at TSA:
* AONW, BPMPW, SCEW, APEW
*/
mc_set_tsa_passthrough(AFIW);
mc_set_tsa_passthrough(HDAW);
mc_set_tsa_passthrough(SATAW);
mc_set_tsa_passthrough(XUSB_HOSTW);
mc_set_tsa_passthrough(XUSB_DEVW);
mc_set_tsa_passthrough(SDMMCWAB);
mc_set_tsa_passthrough(APEDMAW);
mc_set_tsa_passthrough(SESWR);
mc_set_tsa_passthrough(ETRW);
mc_set_tsa_passthrough(AXISW);
mc_set_tsa_passthrough(EQOSW);
mc_set_tsa_passthrough(UFSHCW);
mc_set_tsa_passthrough(BPMPDMAW);
mc_set_tsa_passthrough(AONDMAW);
mc_set_tsa_passthrough(SCEDMAW);
/* Parker has no IO Coherency support and need the following:
* Ordered MC Clients on Parker are AFI, EQOS, SATA, XUSB.
* ISO clients(DISP, VI, EQOS) should never snoop caches and
* don't need ROC/PCFIFO ordering.
* ISO clients(EQOS) that need ordering should use PCFIFO ordering
* and bypass ROC ordering by using FORCE_NON_COHERENT path.
* FORCE_NON_COHERENT/FORCE_COHERENT config take precedence
* over SMMU attributes.
* Force all Normal memory transactions from ISO and non-ISO to be
* non-coherent(bypass ROC, avoid cache snoop to avoid perf hit).
* Force the SO_DEV transactions from ordered ISO clients(EQOS) to
* non-coherent path and enable MC PCFIFO interlock for ordering.
* Force the SO_DEV transactions from ordered non-ISO clients (PCIe,
* XUSB, SATA) to coherent so that the transactions are
* ordered by ROC.
* PCFIFO ensure write ordering.
* Read after Write ordering is maintained/enforced by MC clients.
* Clients that need PCIe type write ordering must
* go through ROC ordering.
* Ordering enable for Read clients is not necessary.
* R5's and A9 would get necessary ordering from AXI and
* don't need ROC ordering enable:
* - MMIO ordering is through dev mapping and MMIO
* accesses bypass SMMU.
* - Normal memory is accessed through SMMU and ordering is
* ensured by client and AXI.
* - Ack point for Normal memory is WCAM in MC.
* - MMIO's can be early acked and AXI ensures dev memory ordering,
* Client ensures read/write direction change ordering.
* - See Bug 200312466 for more details.
*
* CGID_TAG_ADR is only present from T186 A02. As this code is common
* between A01 and A02, tegra_memctrl_set_overrides() programs
* CGID_TAG_ADR for the necessary clients on A02.
*/
mc_set_txn_override(HDAR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(BPMPW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(PTCR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(NVDISPLAYR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(EQOSW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(NVJPGSWR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(ISPRA, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(SDMMCWAA, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(VICSRD, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(MPCOREW, CGID_TAG_DEFAULT, SO_DEV_ZERO, NO_OVERRIDE, NO_OVERRIDE);
mc_set_txn_override(GPUSRD, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(AXISR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(SCEDMAW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(SDMMCW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(EQOSR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
/* See bug 200131110 comment #35*/
mc_set_txn_override(APEDMAR, CGID_TAG_CLIENT_AXI_ID, SO_DEV_CLIENT_AXI_ID, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(NVENCSRD, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(SDMMCRAB, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(VICSRD1, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(BPMPDMAR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(VIW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(SDMMCRAA, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(AXISW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(XUSB_DEVR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(UFSHCR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(TSECSWR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(GPUSWR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(SATAR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(XUSB_HOSTW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_COHERENT);
mc_set_txn_override(TSECSWRB, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(GPUSRD2, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(SCEDMAR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(GPUSWR2, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(AONDMAW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
/* See bug 200131110 comment #35*/
mc_set_txn_override(APEDMAW, CGID_TAG_CLIENT_AXI_ID, SO_DEV_CLIENT_AXI_ID, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(AONW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(HOST1XDMAR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(ETRR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(SESWR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(NVJPGSRD, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(NVDECSRD, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(TSECSRDB, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(BPMPDMAW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(APER, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(NVDECSRD1, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(XUSB_HOSTR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(ISPWA, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(SESRD, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(SCER, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(AONR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(MPCORER, CGID_TAG_DEFAULT, SO_DEV_ZERO, NO_OVERRIDE, NO_OVERRIDE);
mc_set_txn_override(SDMMCWA, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(HDAW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(NVDECSWR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(UFSHCW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(AONDMAR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(SATAW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_COHERENT);
mc_set_txn_override(ETRW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(VICSWR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(NVENCSWR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
/* See bug 200131110 comment #35 */
mc_set_txn_override(AFIR, CGID_TAG_DEFAULT, SO_DEV_CLIENT_AXI_ID, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(SDMMCWAB, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(SDMMCRA, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(NVDISPLAYR1, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(ISPWB, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(BPMPR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(APEW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(SDMMCR, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
mc_set_txn_override(XUSB_DEVW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_COHERENT);
mc_set_txn_override(TSECSRD, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
/*
* See bug 200131110 comment #35 - there are no normal requests
* and AWID for SO/DEV requests is hardcoded in RTL for a
* particular PCIE controller
*/
mc_set_txn_override(AFIW, CGID_TAG_DEFAULT, SO_DEV_CLIENT_AXI_ID, FORCE_NON_COHERENT, FORCE_COHERENT);
mc_set_txn_override(SCEW, CGID_TAG_DEFAULT, SO_DEV_ZERO, FORCE_NON_COHERENT, FORCE_NON_COHERENT);
/*
* At this point, ordering can occur at ROC. So, remove PCFIFO's
* control over ordering requests.
*
* Change PCFIFO_*_ORDERED_CLIENT from ORDERED -> UNORDERED for
* boot and strongly ordered MSS clients
*/
val = MC_PCFIFO_CLIENT_CONFIG1_RESET_VAL &
mc_set_pcfifo_unordered_boot_so_mss(1, AFIW) &
mc_set_pcfifo_unordered_boot_so_mss(1, HDAW) &
mc_set_pcfifo_unordered_boot_so_mss(1, SATAW);
tegra_mc_write_32(MC_PCFIFO_CLIENT_CONFIG1, val);
val = MC_PCFIFO_CLIENT_CONFIG2_RESET_VAL &
mc_set_pcfifo_unordered_boot_so_mss(2, XUSB_HOSTW) &
mc_set_pcfifo_unordered_boot_so_mss(2, XUSB_DEVW);
tegra_mc_write_32(MC_PCFIFO_CLIENT_CONFIG2, val);
val = MC_PCFIFO_CLIENT_CONFIG3_RESET_VAL &
mc_set_pcfifo_unordered_boot_so_mss(3, SDMMCWAB);
tegra_mc_write_32(MC_PCFIFO_CLIENT_CONFIG3, val);
val = MC_PCFIFO_CLIENT_CONFIG4_RESET_VAL &
mc_set_pcfifo_unordered_boot_so_mss(4, SESWR) &
mc_set_pcfifo_unordered_boot_so_mss(4, ETRW) &
mc_set_pcfifo_unordered_boot_so_mss(4, AXISW) &
mc_set_pcfifo_unordered_boot_so_mss(4, UFSHCW) &
mc_set_pcfifo_unordered_boot_so_mss(4, BPMPDMAW) &
mc_set_pcfifo_unordered_boot_so_mss(4, AONDMAW) &
mc_set_pcfifo_unordered_boot_so_mss(4, SCEDMAW);
/* EQOSW is the only client that has PCFIFO order enabled. */
val |= mc_set_pcfifo_ordered_boot_so_mss(4, EQOSW);
tegra_mc_write_32(MC_PCFIFO_CLIENT_CONFIG4, val);
val = MC_PCFIFO_CLIENT_CONFIG5_RESET_VAL &
mc_set_pcfifo_unordered_boot_so_mss(5, APEDMAW);
tegra_mc_write_32(MC_PCFIFO_CLIENT_CONFIG5, val);
/*
* Deassert HOTRESET FLUSH_ENABLE for boot and strongly ordered MSS
* clients to allow memory traffic from all clients to start passing
* through ROC
*/
val = tegra_mc_read_32(MC_CLIENT_HOTRESET_CTRL0);
assert(val == wdata_0);
wdata_0 = MC_CLIENT_HOTRESET_CTRL0_RESET_VAL;
tegra_mc_write_32(MC_CLIENT_HOTRESET_CTRL0, wdata_0);
val = tegra_mc_read_32(MC_CLIENT_HOTRESET_CTRL1);
assert(val == wdata_1);
wdata_1 = MC_CLIENT_HOTRESET_CTRL1_RESET_VAL;
tegra_mc_write_32(MC_CLIENT_HOTRESET_CTRL1, wdata_1);
#endif
}
static void tegra186_memctrl_set_overrides(void)
{
uint32_t i, val;
/*
* Set the MC_TXN_OVERRIDE registers for write clients.
*/
if ((tegra_chipid_is_t186()) &&
(!tegra_platform_is_silicon() ||
(tegra_platform_is_silicon() && (tegra_get_chipid_minor() == 1U)))) {
/*
* GPU and NVENC settings for Tegra186 simulation and
* Silicon rev. A01
*/
val = tegra_mc_read_32(MC_TXN_OVERRIDE_CONFIG_GPUSWR);
val &= (uint32_t)~MC_TXN_OVERRIDE_CGID_TAG_MASK;
tegra_mc_write_32(MC_TXN_OVERRIDE_CONFIG_GPUSWR,
val | MC_TXN_OVERRIDE_CGID_TAG_ZERO);
val = tegra_mc_read_32(MC_TXN_OVERRIDE_CONFIG_GPUSWR2);
val &= (uint32_t)~MC_TXN_OVERRIDE_CGID_TAG_MASK;
tegra_mc_write_32(MC_TXN_OVERRIDE_CONFIG_GPUSWR2,
val | MC_TXN_OVERRIDE_CGID_TAG_ZERO);
val = tegra_mc_read_32(MC_TXN_OVERRIDE_CONFIG_NVENCSWR);
val &= (uint32_t)~MC_TXN_OVERRIDE_CGID_TAG_MASK;
tegra_mc_write_32(MC_TXN_OVERRIDE_CONFIG_NVENCSWR,
val | MC_TXN_OVERRIDE_CGID_TAG_CLIENT_AXI_ID);
} else {
/*
* Settings for Tegra186 silicon rev. A02 and onwards.
*/
for (i = 0; i < ARRAY_SIZE(tegra186_txn_override_cfgs); i++) {
val = tegra_mc_read_32(tegra186_txn_override_cfgs[i].offset);
val &= (uint32_t)~MC_TXN_OVERRIDE_CGID_TAG_MASK;
tegra_mc_write_32(tegra186_txn_override_cfgs[i].offset,
val | tegra186_txn_override_cfgs[i].cgid_tag);
}
}
}
/*******************************************************************************
* Array to hold MC context for Tegra186
******************************************************************************/
static __attribute__((aligned(16))) mc_regs_t tegra186_mc_context[] = {
_START_OF_TABLE_,
mc_make_sid_security_cfg(SCEW),
mc_make_sid_security_cfg(AFIR),
mc_make_sid_security_cfg(NVDISPLAYR1),
mc_make_sid_security_cfg(XUSB_DEVR),
mc_make_sid_security_cfg(VICSRD1),
mc_make_sid_security_cfg(NVENCSWR),
mc_make_sid_security_cfg(TSECSRDB),
mc_make_sid_security_cfg(AXISW),
mc_make_sid_security_cfg(SDMMCWAB),
mc_make_sid_security_cfg(AONDMAW),
mc_make_sid_security_cfg(GPUSWR2),
mc_make_sid_security_cfg(SATAW),
mc_make_sid_security_cfg(UFSHCW),
mc_make_sid_security_cfg(AFIW),
mc_make_sid_security_cfg(SDMMCR),
mc_make_sid_security_cfg(SCEDMAW),
mc_make_sid_security_cfg(UFSHCR),
mc_make_sid_security_cfg(SDMMCWAA),
mc_make_sid_security_cfg(APEDMAW),
mc_make_sid_security_cfg(SESWR),
mc_make_sid_security_cfg(MPCORER),
mc_make_sid_security_cfg(PTCR),
mc_make_sid_security_cfg(BPMPW),
mc_make_sid_security_cfg(ETRW),
mc_make_sid_security_cfg(GPUSRD),
mc_make_sid_security_cfg(VICSWR),
mc_make_sid_security_cfg(SCEDMAR),
mc_make_sid_security_cfg(HDAW),
mc_make_sid_security_cfg(ISPWA),
mc_make_sid_security_cfg(EQOSW),
mc_make_sid_security_cfg(XUSB_HOSTW),
mc_make_sid_security_cfg(TSECSWR),
mc_make_sid_security_cfg(SDMMCRAA),
mc_make_sid_security_cfg(APER),
mc_make_sid_security_cfg(VIW),
mc_make_sid_security_cfg(APEW),
mc_make_sid_security_cfg(AXISR),
mc_make_sid_security_cfg(SDMMCW),
mc_make_sid_security_cfg(BPMPDMAW),
mc_make_sid_security_cfg(ISPRA),
mc_make_sid_security_cfg(NVDECSWR),
mc_make_sid_security_cfg(XUSB_DEVW),
mc_make_sid_security_cfg(NVDECSRD),
mc_make_sid_security_cfg(MPCOREW),
mc_make_sid_security_cfg(NVDISPLAYR),
mc_make_sid_security_cfg(BPMPDMAR),
mc_make_sid_security_cfg(NVJPGSWR),
mc_make_sid_security_cfg(NVDECSRD1),
mc_make_sid_security_cfg(TSECSRD),
mc_make_sid_security_cfg(NVJPGSRD),
mc_make_sid_security_cfg(SDMMCWA),
mc_make_sid_security_cfg(SCER),
mc_make_sid_security_cfg(XUSB_HOSTR),
mc_make_sid_security_cfg(VICSRD),
mc_make_sid_security_cfg(AONDMAR),
mc_make_sid_security_cfg(AONW),
mc_make_sid_security_cfg(SDMMCRA),
mc_make_sid_security_cfg(HOST1XDMAR),
mc_make_sid_security_cfg(EQOSR),
mc_make_sid_security_cfg(SATAR),
mc_make_sid_security_cfg(BPMPR),
mc_make_sid_security_cfg(HDAR),
mc_make_sid_security_cfg(SDMMCRAB),
mc_make_sid_security_cfg(ETRR),
mc_make_sid_security_cfg(AONR),
mc_make_sid_security_cfg(APEDMAR),
mc_make_sid_security_cfg(SESRD),
mc_make_sid_security_cfg(NVENCSRD),
mc_make_sid_security_cfg(GPUSWR),
mc_make_sid_security_cfg(TSECSWRB),
mc_make_sid_security_cfg(ISPWB),
mc_make_sid_security_cfg(GPUSRD2),
mc_make_sid_override_cfg(APER),
mc_make_sid_override_cfg(VICSRD),
mc_make_sid_override_cfg(NVENCSRD),
mc_make_sid_override_cfg(NVJPGSWR),
mc_make_sid_override_cfg(AONW),
mc_make_sid_override_cfg(BPMPR),
mc_make_sid_override_cfg(BPMPW),
mc_make_sid_override_cfg(HDAW),
mc_make_sid_override_cfg(NVDISPLAYR1),
mc_make_sid_override_cfg(APEDMAR),
mc_make_sid_override_cfg(AFIR),
mc_make_sid_override_cfg(AXISR),
mc_make_sid_override_cfg(VICSRD1),
mc_make_sid_override_cfg(TSECSRD),
mc_make_sid_override_cfg(BPMPDMAW),
mc_make_sid_override_cfg(MPCOREW),
mc_make_sid_override_cfg(XUSB_HOSTR),
mc_make_sid_override_cfg(GPUSWR),
mc_make_sid_override_cfg(XUSB_DEVR),
mc_make_sid_override_cfg(UFSHCW),
mc_make_sid_override_cfg(XUSB_HOSTW),
mc_make_sid_override_cfg(SDMMCWAB),
mc_make_sid_override_cfg(SATAW),
mc_make_sid_override_cfg(SCEDMAR),
mc_make_sid_override_cfg(HOST1XDMAR),
mc_make_sid_override_cfg(SDMMCWA),
mc_make_sid_override_cfg(APEDMAW),
mc_make_sid_override_cfg(SESWR),
mc_make_sid_override_cfg(AXISW),
mc_make_sid_override_cfg(AONDMAW),
mc_make_sid_override_cfg(TSECSWRB),
mc_make_sid_override_cfg(MPCORER),
mc_make_sid_override_cfg(ISPWB),
mc_make_sid_override_cfg(AONR),
mc_make_sid_override_cfg(BPMPDMAR),
mc_make_sid_override_cfg(HDAR),
mc_make_sid_override_cfg(SDMMCRA),
mc_make_sid_override_cfg(ETRW),
mc_make_sid_override_cfg(GPUSWR2),
mc_make_sid_override_cfg(EQOSR),
mc_make_sid_override_cfg(TSECSWR),
mc_make_sid_override_cfg(ETRR),
mc_make_sid_override_cfg(NVDECSRD),
mc_make_sid_override_cfg(TSECSRDB),
mc_make_sid_override_cfg(SDMMCRAA),
mc_make_sid_override_cfg(NVDECSRD1),
mc_make_sid_override_cfg(SDMMCR),
mc_make_sid_override_cfg(NVJPGSRD),
mc_make_sid_override_cfg(SCEDMAW),
mc_make_sid_override_cfg(SDMMCWAA),
mc_make_sid_override_cfg(APEW),
mc_make_sid_override_cfg(AONDMAR),
mc_make_sid_override_cfg(PTCR),
mc_make_sid_override_cfg(SCER),
mc_make_sid_override_cfg(ISPRA),
mc_make_sid_override_cfg(ISPWA),
mc_make_sid_override_cfg(VICSWR),
mc_make_sid_override_cfg(SESRD),
mc_make_sid_override_cfg(SDMMCW),
mc_make_sid_override_cfg(SDMMCRAB),
mc_make_sid_override_cfg(EQOSW),
mc_make_sid_override_cfg(GPUSRD2),
mc_make_sid_override_cfg(SCEW),
mc_make_sid_override_cfg(GPUSRD),
mc_make_sid_override_cfg(NVDECSWR),
mc_make_sid_override_cfg(XUSB_DEVW),
mc_make_sid_override_cfg(SATAR),
mc_make_sid_override_cfg(NVDISPLAYR),
mc_make_sid_override_cfg(VIW),
mc_make_sid_override_cfg(UFSHCR),
mc_make_sid_override_cfg(NVENCSWR),
mc_make_sid_override_cfg(AFIW),
mc_smmu_bypass_cfg, /* TBU settings */
_END_OF_TABLE_,
};
/*******************************************************************************
* Handler to return the pointer to the MC's context struct
******************************************************************************/
mc_regs_t *plat_memctrl_get_sys_suspend_ctx(void)
{
/* index of _END_OF_TABLE_ */
tegra186_mc_context[0].val = (uint32_t)(ARRAY_SIZE(tegra186_mc_context)) - 1U;
return tegra186_mc_context;
}
void plat_memctrl_setup(void)
{
uint32_t val;
unsigned int i;
/* Program all the Stream ID overrides */
for (i = 0U; i < ARRAY_SIZE(tegra186_streamid_override_regs); i++) {
tegra_mc_streamid_write_32(tegra186_streamid_override_regs[i],
MC_STREAM_ID_MAX);
}
/* Program the security config settings for all Stream IDs */
for (i = 0U; i < ARRAY_SIZE(tegra186_streamid_sec_cfgs); i++) {
val = (tegra186_streamid_sec_cfgs[i].override_enable << 16) |
(tegra186_streamid_sec_cfgs[i].override_client_inputs << 8) |
(tegra186_streamid_sec_cfgs[i].override_client_ns_flag << 0);
tegra_mc_streamid_write_32(tegra186_streamid_sec_cfgs[i].offset, val);
}
/*
* Re-configure MSS to allow ROC to deal with ordering of the
* Memory Controller traffic. This is needed as the Memory Controller
* boots with MSS having all control, but ROC provides a performance
* boost as compared to MSS.
*/
tegra186_memctrl_reconfig_mss_clients();
/* Program overrides for MC transactions */
tegra186_memctrl_set_overrides();
}
/*******************************************************************************
* Handler to restore platform specific settings to the memory controller
******************************************************************************/
void plat_memctrl_restore(void)
{
/*
* Re-configure MSS to allow ROC to deal with ordering of the
* Memory Controller traffic. This is needed as the Memory Controller
* boots with MSS having all control, but ROC provides a performance
* boost as compared to MSS.
*/
tegra186_memctrl_reconfig_mss_clients();
/* Program overrides for MC transactions */
tegra186_memctrl_set_overrides();
}
/*******************************************************************************
* Handler to program the scratch registers with TZDRAM settings for the
* resume firmware
******************************************************************************/
void plat_memctrl_tzdram_setup(uint64_t phys_base, uint64_t size_in_bytes)
{
uint32_t val;
/*
* Setup the Memory controller to allow only secure accesses to
* the TZDRAM carveout
*/
INFO("Configuring TrustZone DRAM Memory Carveout\n");
tegra_mc_write_32(MC_SECURITY_CFG0_0, (uint32_t)phys_base);
tegra_mc_write_32(MC_SECURITY_CFG3_0, (uint32_t)(phys_base >> 32));
tegra_mc_write_32(MC_SECURITY_CFG1_0, size_in_bytes >> 20);
/*
* When TZ encryption is enabled, we need to setup TZDRAM
* before CPU accesses TZ Carveout, else CPU will fetch
* non-decrypted data. So save TZDRAM setting for SC7 resume
* FW to restore.
*
* Scratch registers map:
* RSV55_0 = CFG1[12:0] | CFG0[31:20]
* RSV55_1 = CFG3[1:0]
*/
val = tegra_mc_read_32(MC_SECURITY_CFG1_0) & MC_SECURITY_SIZE_MB_MASK;
val |= tegra_mc_read_32(MC_SECURITY_CFG0_0) & MC_SECURITY_BOM_MASK;
mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_TZDRAM_ADDR_LO, val);
val = tegra_mc_read_32(MC_SECURITY_CFG3_0) & MC_SECURITY_BOM_HI_MASK;
mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_TZDRAM_ADDR_HI, val);
/*
* MCE propagates the security configuration values across the
* CCPLEX.
*/
(void)mce_update_gsc_tzdram();
}
@@ -0,0 +1,472 @@
/*
* Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <stdbool.h>
#include <string.h>
#include <arch.h>
#include <arch_helpers.h>
#include <common/bl_common.h>
#include <common/debug.h>
#include <context.h>
#include <cortex_a57.h>
#include <denver.h>
#include <lib/el3_runtime/context_mgmt.h>
#include <lib/psci/psci.h>
#include <plat/common/platform.h>
#include <bpmp_ipc.h>
#include <mce.h>
#include <memctrl_v2.h>
#include <security_engine.h>
#include <smmu.h>
#include <t18x_ari.h>
#include <tegra186_private.h>
#include <tegra_private.h>
extern void memcpy16(void *dest, const void *src, unsigned int length);
/* state id mask */
#define TEGRA186_STATE_ID_MASK 0xFU
/* constants to get power state's wake time */
#define TEGRA186_WAKE_TIME_MASK 0x0FFFFFF0U
#define TEGRA186_WAKE_TIME_SHIFT 4U
/* default core wake mask for CPU_SUSPEND */
#define TEGRA186_CORE_WAKE_MASK 0x180cU
/* context size to save during system suspend */
#define TEGRA186_SE_CONTEXT_SIZE 3U
static uint32_t se_regs[TEGRA186_SE_CONTEXT_SIZE];
static struct tegra_psci_percpu_data {
uint32_t wake_time;
} __aligned(CACHE_WRITEBACK_GRANULE) tegra_percpu_data[PLATFORM_CORE_COUNT];
int32_t tegra_soc_validate_power_state(uint32_t power_state,
psci_power_state_t *req_state)
{
uint8_t state_id = (uint8_t)psci_get_pstate_id(power_state) & TEGRA186_STATE_ID_MASK;
uint32_t cpu = plat_my_core_pos();
int32_t ret = PSCI_E_SUCCESS;
/* save the core wake time (in TSC ticks)*/
tegra_percpu_data[cpu].wake_time = (power_state & TEGRA186_WAKE_TIME_MASK)
<< TEGRA186_WAKE_TIME_SHIFT;
/*
* Clean percpu_data[cpu] to DRAM. This needs to be done to ensure that
* the correct value is read in tegra_soc_pwr_domain_suspend(), which
* is called with caches disabled. It is possible to read a stale value
* from DRAM in that function, because the L2 cache is not flushed
* unless the cluster is entering CC6/CC7.
*/
clean_dcache_range((uint64_t)&tegra_percpu_data[cpu],
sizeof(tegra_percpu_data[cpu]));
/* Sanity check the requested state id */
switch (state_id) {
case PSTATE_ID_CORE_IDLE:
case PSTATE_ID_CORE_POWERDN:
if (psci_get_pstate_type(power_state) != PSTATE_TYPE_POWERDOWN) {
ret = PSCI_E_INVALID_PARAMS;
break;
}
/* Core powerdown request */
req_state->pwr_domain_state[MPIDR_AFFLVL0] = state_id;
req_state->pwr_domain_state[MPIDR_AFFLVL1] = state_id;
break;
default:
ERROR("%s: unsupported state id (%d)\n", __func__, state_id);
ret = PSCI_E_INVALID_PARAMS;
break;
}
return ret;
}
int32_t tegra_soc_cpu_standby(plat_local_state_t cpu_state)
{
(void)cpu_state;
return PSCI_E_SUCCESS;
}
int32_t tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
{
const plat_local_state_t *pwr_domain_state;
uint8_t stateid_afflvl0, stateid_afflvl2;
uint32_t cpu = plat_my_core_pos();
const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
mce_cstate_info_t cstate_info = { 0 };
uint64_t mc_ctx_base;
uint32_t val;
/* get the state ID */
pwr_domain_state = target_state->pwr_domain_state;
stateid_afflvl0 = pwr_domain_state[MPIDR_AFFLVL0] &
TEGRA186_STATE_ID_MASK;
stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] &
TEGRA186_STATE_ID_MASK;
if ((stateid_afflvl0 == PSTATE_ID_CORE_IDLE) ||
(stateid_afflvl0 == PSTATE_ID_CORE_POWERDN)) {
/* Enter CPU idle/powerdown */
val = (stateid_afflvl0 == PSTATE_ID_CORE_IDLE) ?
(uint32_t)TEGRA_ARI_CORE_C6 : (uint32_t)TEGRA_ARI_CORE_C7;
(void)mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE, (uint64_t)val,
tegra_percpu_data[cpu].wake_time, 0U);
} else if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
/* save SE registers */
se_regs[0] = mmio_read_32(TEGRA_SE0_BASE +
SE_MUTEX_WATCHDOG_NS_LIMIT);
se_regs[1] = mmio_read_32(TEGRA_RNG1_BASE +
RNG_MUTEX_WATCHDOG_NS_LIMIT);
se_regs[2] = mmio_read_32(TEGRA_PKA1_BASE +
PKA_MUTEX_WATCHDOG_NS_LIMIT);
/* save 'Secure Boot' Processor Feature Config Register */
val = mmio_read_32(TEGRA_MISC_BASE + MISCREG_PFCFG);
mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_SECURE_BOOTP_FCFG, val);
/* save MC context to TZDRAM */
mc_ctx_base = params_from_bl2->tzdram_base;
tegra_mc_save_context((uintptr_t)mc_ctx_base);
/* Prepare for system suspend */
cstate_info.cluster = (uint32_t)TEGRA_ARI_CLUSTER_CC7;
cstate_info.system = (uint32_t)TEGRA_ARI_SYSTEM_SC7;
cstate_info.system_state_force = 1;
cstate_info.update_wake_mask = 1;
mce_update_cstate_info(&cstate_info);
/* Loop until system suspend is allowed */
do {
val = (uint32_t)mce_command_handler(
(uint64_t)MCE_CMD_IS_SC7_ALLOWED,
(uint64_t)TEGRA_ARI_CORE_C7,
MCE_CORE_SLEEP_TIME_INFINITE,
0U);
} while (val == 0U);
/* Instruct the MCE to enter system suspend state */
(void)mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE,
(uint64_t)TEGRA_ARI_CORE_C7, MCE_CORE_SLEEP_TIME_INFINITE, 0U);
} else {
; /* do nothing */
}
return PSCI_E_SUCCESS;
}
/*******************************************************************************
* Helper function to check if this is the last ON CPU in the cluster
******************************************************************************/
static bool tegra_last_cpu_in_cluster(const plat_local_state_t *states,
uint32_t ncpu)
{
plat_local_state_t target;
bool last_on_cpu = true;
uint32_t num_cpus = ncpu, pos = 0;
do {
target = states[pos];
if (target != PLAT_MAX_OFF_STATE) {
last_on_cpu = false;
}
--num_cpus;
pos++;
} while (num_cpus != 0U);
return last_on_cpu;
}
/*******************************************************************************
* Helper function to get target power state for the cluster
******************************************************************************/
static plat_local_state_t tegra_get_afflvl1_pwr_state(const plat_local_state_t *states,
uint32_t ncpu)
{
uint32_t core_pos = (uint32_t)read_mpidr() & (uint32_t)MPIDR_CPU_MASK;
uint32_t cpu = plat_my_core_pos();
int32_t ret;
plat_local_state_t target = states[core_pos];
mce_cstate_info_t cstate_info = { 0 };
/* CPU suspend */
if (target == PSTATE_ID_CORE_POWERDN) {
/* Program default wake mask */
cstate_info.wake_mask = TEGRA186_CORE_WAKE_MASK;
cstate_info.update_wake_mask = 1;
mce_update_cstate_info(&cstate_info);
/* Check if CCx state is allowed. */
ret = mce_command_handler((uint64_t)MCE_CMD_IS_CCX_ALLOWED,
(uint64_t)TEGRA_ARI_CORE_C7,
tegra_percpu_data[cpu].wake_time,
0U);
if (ret == 0) {
target = PSCI_LOCAL_STATE_RUN;
}
}
/* CPU off */
if (target == PLAT_MAX_OFF_STATE) {
/* Enable cluster powerdn from last CPU in the cluster */
if (tegra_last_cpu_in_cluster(states, ncpu)) {
/* Enable CC7 state and turn off wake mask */
cstate_info.cluster = (uint32_t)TEGRA_ARI_CLUSTER_CC7;
cstate_info.update_wake_mask = 1;
mce_update_cstate_info(&cstate_info);
/* Check if CCx state is allowed. */
ret = mce_command_handler((uint64_t)MCE_CMD_IS_CCX_ALLOWED,
(uint64_t)TEGRA_ARI_CORE_C7,
MCE_CORE_SLEEP_TIME_INFINITE,
0U);
if (ret == 0) {
target = PSCI_LOCAL_STATE_RUN;
}
} else {
/* Turn off wake_mask */
cstate_info.update_wake_mask = 1;
mce_update_cstate_info(&cstate_info);
target = PSCI_LOCAL_STATE_RUN;
}
}
return target;
}
/*******************************************************************************
* Platform handler to calculate the proper target power level at the
* specified affinity level
******************************************************************************/
plat_local_state_t tegra_soc_get_target_pwr_state(uint32_t lvl,
const plat_local_state_t *states,
uint32_t ncpu)
{
plat_local_state_t target = PSCI_LOCAL_STATE_RUN;
uint32_t cpu = plat_my_core_pos();
/* System Suspend */
if ((lvl == (uint32_t)MPIDR_AFFLVL2) &&
(states[cpu] == PSTATE_ID_SOC_POWERDN)) {
target = PSTATE_ID_SOC_POWERDN;
}
/* CPU off, CPU suspend */
if (lvl == (uint32_t)MPIDR_AFFLVL1) {
target = tegra_get_afflvl1_pwr_state(states, ncpu);
}
/* target cluster/system state */
return target;
}
int32_t tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state)
{
const plat_local_state_t *pwr_domain_state =
target_state->pwr_domain_state;
const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
uint8_t stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] &
TEGRA186_STATE_ID_MASK;
uint64_t val;
uint64_t src_len_in_bytes = (uint64_t)(((uintptr_t)(&__BL31_END__) -
(uintptr_t)BL31_BASE));
int32_t ret;
if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
val = params_from_bl2->tzdram_base +
tegra186_get_mc_ctx_size();
/* Initialise communication channel with BPMP */
assert(tegra_bpmp_ipc_init() == 0);
/* Enable SE clock */
ret = tegra_bpmp_ipc_enable_clock(TEGRA186_CLK_SE);
if (ret != 0) {
ERROR("Failed to enable clock\n");
return ret;
}
/*
* Generate/save SHA256 of ATF during SC7 entry
*/
if (tegra_se_save_sha256_hash(BL31_BASE,
(uint32_t)src_len_in_bytes) != 0) {
ERROR("Hash calculation failed. Reboot\n");
(void)tegra_soc_prepare_system_reset();
}
/*
* The TZRAM loses power when we enter system suspend. To
* allow graceful exit from system suspend, we need to copy
* BL3-1 over to TZDRAM.
*/
val = params_from_bl2->tzdram_base +
tegra186_get_mc_ctx_size();
memcpy16((void *)(uintptr_t)val, (void *)(uintptr_t)BL31_BASE,
(uintptr_t)BL31_END - (uintptr_t)BL31_BASE);
/*
* Save code base and size; this would be used by SC7-RF to
* verify binary
*/
mmio_write_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV68_LO,
(uint32_t)val);
mmio_write_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV0_HI,
(uint32_t)src_len_in_bytes);
ret = tegra_bpmp_ipc_disable_clock(TEGRA186_CLK_SE);
if (ret != 0) {
ERROR("Failed to disable clock\n");
return ret;
}
}
return PSCI_E_SUCCESS;
}
int32_t tegra_soc_pwr_domain_suspend_pwrdown_early(const psci_power_state_t *target_state)
{
return PSCI_E_NOT_SUPPORTED;
}
int32_t tegra_soc_pwr_domain_on(u_register_t mpidr)
{
int32_t ret = PSCI_E_SUCCESS;
uint64_t target_cpu = mpidr & MPIDR_CPU_MASK;
uint64_t target_cluster = (mpidr & MPIDR_CLUSTER_MASK) >>
MPIDR_AFFINITY_BITS;
if (target_cluster > ((uint32_t)PLATFORM_CLUSTER_COUNT - 1U)) {
ERROR("%s: unsupported CPU (0x%lx)\n", __func__, mpidr);
ret = PSCI_E_NOT_PRESENT;
} else {
/* construct the target CPU # */
target_cpu |= (target_cluster << 2);
(void)mce_command_handler((uint64_t)MCE_CMD_ONLINE_CORE, target_cpu, 0U, 0U);
}
return ret;
}
int32_t tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
{
uint8_t stateid_afflvl2 = target_state->pwr_domain_state[PLAT_MAX_PWR_LVL];
uint8_t stateid_afflvl0 = target_state->pwr_domain_state[MPIDR_AFFLVL0];
mce_cstate_info_t cstate_info = { 0 };
uint64_t impl, val;
const plat_params_from_bl2_t *plat_params = bl31_get_plat_params();
impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK;
/*
* Enable ECC and Parity Protection for Cortex-A57 CPUs (Tegra186
* A02p and beyond).
*/
if ((plat_params->l2_ecc_parity_prot_dis != 1) && (impl != DENVER_IMPL)) {
val = read_l2ctlr_el1();
val |= CORTEX_A57_L2_ECC_PARITY_PROTECTION_BIT;
write_l2ctlr_el1(val);
}
/*
* Reset power state info for CPUs when onlining, we set
* deepest power when offlining a core but that may not be
* requested by non-secure sw which controls idle states. It
* will re-init this info from non-secure software when the
* core come online.
*/
if (stateid_afflvl0 == PLAT_MAX_OFF_STATE) {
cstate_info.cluster = (uint32_t)TEGRA_ARI_CLUSTER_CC1;
cstate_info.update_wake_mask = 1;
mce_update_cstate_info(&cstate_info);
}
/*
* Check if we are exiting from deep sleep and restore SE
* context if we are.
*/
if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
mmio_write_32(TEGRA_SE0_BASE + SE_MUTEX_WATCHDOG_NS_LIMIT,
se_regs[0]);
mmio_write_32(TEGRA_RNG1_BASE + RNG_MUTEX_WATCHDOG_NS_LIMIT,
se_regs[1]);
mmio_write_32(TEGRA_PKA1_BASE + PKA_MUTEX_WATCHDOG_NS_LIMIT,
se_regs[2]);
/* Init SMMU */
tegra_smmu_init();
/*
* Reset power state info for the last core doing SC7
* entry and exit, we set deepest power state as CC7
* and SC7 for SC7 entry which may not be requested by
* non-secure SW which controls idle states.
*/
cstate_info.cluster = (uint32_t)TEGRA_ARI_CLUSTER_CC7;
cstate_info.system = (uint32_t)TEGRA_ARI_SYSTEM_SC1;
cstate_info.update_wake_mask = 1;
mce_update_cstate_info(&cstate_info);
}
return PSCI_E_SUCCESS;
}
int32_t tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
{
uint64_t impl = (read_midr() >> MIDR_IMPL_SHIFT) & (uint64_t)MIDR_IMPL_MASK;
(void)target_state;
/* Disable Denver's DCO operations */
if (impl == DENVER_IMPL) {
denver_disable_dco();
}
/* Turn off CPU */
(void)mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE,
(uint64_t)TEGRA_ARI_CORE_C7, MCE_CORE_SLEEP_TIME_INFINITE, 0U);
return PSCI_E_SUCCESS;
}
__dead2 void tegra_soc_prepare_system_off(void)
{
/* power off the entire system */
mce_enter_ccplex_state((uint32_t)TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_POWER_OFF);
wfi();
/* wait for the system to power down */
for (;;) {
;
}
}
int32_t tegra_soc_prepare_system_reset(void)
{
mce_enter_ccplex_state((uint32_t)TEGRA_ARI_MISC_CCPLEX_SHUTDOWN_REBOOT);
return PSCI_E_SUCCESS;
}
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <string.h>
#include <arch_helpers.h>
#include <common/debug.h>
#include <lib/mmio.h>
#include <mce.h>
#include <tegra_def.h>
#include <tegra_private.h>
#define SCRATCH_SECURE_RSV1_SCRATCH_0 0x658U
#define SCRATCH_SECURE_RSV1_SCRATCH_1 0x65CU
#define CPU_RESET_MODE_AA64 1U
/*******************************************************************************
* Setup secondary CPU vectors
******************************************************************************/
void plat_secondary_setup(void)
{
uint32_t addr_low, addr_high;
INFO("Setting up secondary CPU boot\n");
/* TZDRAM base will be used as the "resume" address */
addr_low = (uintptr_t)&tegra_secure_entrypoint | CPU_RESET_MODE_AA64;
addr_high = (uintptr_t)(((uintptr_t)&tegra_secure_entrypoint >> 32U) & 0x7ffU);
/* save reset vector to be used during SYSTEM_SUSPEND exit */
mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_RESET_VECTOR_LO,
addr_low);
mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_RESET_VECTOR_HI,
addr_high);
}
@@ -0,0 +1,397 @@
/*
* Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <arch_helpers.h>
#include <bl31/bl31.h>
#include <bl31/interrupt_mgmt.h>
#include <common/bl_common.h>
#include <common/debug.h>
#include <common/ep_info.h>
#include <common/interrupt_props.h>
#include <context.h>
#include <cortex_a57.h>
#include <denver.h>
#include <drivers/arm/gic_common.h>
#include <drivers/arm/gicv2.h>
#include <drivers/console.h>
#include <lib/el3_runtime/context_mgmt.h>
#include <lib/utils.h>
#include <lib/xlat_tables/xlat_tables_v2.h>
#include <plat/common/platform.h>
#include <mce.h>
#include <memctrl.h>
#include <smmu.h>
#include <tegra_def.h>
#include <tegra_platform.h>
#include <tegra_private.h>
extern void memcpy16(void *dest, const void *src, unsigned int length);
/*******************************************************************************
* Tegra186 CPU numbers in cluster #0
*******************************************************************************
*/
#define TEGRA186_CLUSTER0_CORE2 2U
#define TEGRA186_CLUSTER0_CORE3 3U
/*******************************************************************************
* The Tegra power domain tree has a single system level power domain i.e. a
* single root node. The first entry in the power domain descriptor specifies
* the number of power domains at the highest power level.
*******************************************************************************
*/
static const uint8_t tegra_power_domain_tree_desc[] = {
/* No of root nodes */
1,
/* No of clusters */
PLATFORM_CLUSTER_COUNT,
/* No of CPU cores - cluster0 */
PLATFORM_MAX_CPUS_PER_CLUSTER,
/* No of CPU cores - cluster1 */
PLATFORM_MAX_CPUS_PER_CLUSTER
};
/*******************************************************************************
* This function returns the Tegra default topology tree information.
******************************************************************************/
const uint8_t *plat_get_power_domain_tree_desc(void)
{
return tegra_power_domain_tree_desc;
}
/*
* Table of regions to map using the MMU.
*/
static const mmap_region_t tegra_mmap[] = {
MAP_REGION_FLAT(TEGRA_MISC_BASE, 0x10000U, /* 64KB */
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(TEGRA_TSA_BASE, 0x20000U, /* 128KB */
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(TEGRA_MC_STREAMID_BASE, 0x10000U, /* 64KB */
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(TEGRA_MC_BASE, 0x10000U, /* 64KB */
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(TEGRA_UARTA_BASE, 0x20000U, /* 128KB - UART A, B*/
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(TEGRA_UARTC_BASE, 0x20000U, /* 128KB - UART C, G */
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(TEGRA_UARTD_BASE, 0x30000U, /* 192KB - UART D, E, F */
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(TEGRA_FUSE_BASE, 0x10000U, /* 64KB */
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(TEGRA_GICD_BASE, 0x20000U, /* 128KB */
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(TEGRA_SE0_BASE, 0x10000U, /* 64KB */
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(TEGRA_PKA1_BASE, 0x10000U, /* 64KB */
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(TEGRA_RNG1_BASE, 0x10000U, /* 64KB */
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(TEGRA_CAR_RESET_BASE, 0x10000U, /* 64KB */
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(TEGRA_PMC_BASE, 0x40000U, /* 256KB */
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(TEGRA_TMRUS_BASE, 0x1000U, /* 4KB */
MT_DEVICE | MT_RO | MT_SECURE),
MAP_REGION_FLAT(TEGRA_SCRATCH_BASE, 0x10000U, /* 64KB */
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(TEGRA_MMCRAB_BASE, 0x60000U, /* 384KB */
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(TEGRA_ARM_ACTMON_CTR_BASE, 0x20000U, /* 128KB - ARM/Denver */
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(TEGRA_SMMU0_BASE, 0x1000000U, /* 64KB */
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(TEGRA_HSP_DBELL_BASE, 0x10000U, /* 64KB */
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(TEGRA_BPMP_IPC_TX_PHYS_BASE, TEGRA_BPMP_IPC_CH_MAP_SIZE, /* 4KB */
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(TEGRA_BPMP_IPC_RX_PHYS_BASE, TEGRA_BPMP_IPC_CH_MAP_SIZE, /* 4KB */
MT_DEVICE | MT_RW | MT_SECURE),
{0}
};
/*******************************************************************************
* Set up the pagetables as per the platform memory map & initialize the MMU
******************************************************************************/
const mmap_region_t *plat_get_mmio_map(void)
{
/* MMIO space */
return tegra_mmap;
}
/*******************************************************************************
* Handler to get the System Counter Frequency
******************************************************************************/
uint32_t plat_get_syscnt_freq2(void)
{
return 31250000;
}
/*******************************************************************************
* Maximum supported UART controllers
******************************************************************************/
#define TEGRA186_MAX_UART_PORTS 7
/*******************************************************************************
* This variable holds the UART port base addresses
******************************************************************************/
static uint32_t tegra186_uart_addresses[TEGRA186_MAX_UART_PORTS + 1] = {
0, /* undefined - treated as an error case */
TEGRA_UARTA_BASE,
TEGRA_UARTB_BASE,
TEGRA_UARTC_BASE,
TEGRA_UARTD_BASE,
TEGRA_UARTE_BASE,
TEGRA_UARTF_BASE,
TEGRA_UARTG_BASE,
};
/*******************************************************************************
* Enable console corresponding to the console ID
******************************************************************************/
void plat_enable_console(int32_t id)
{
static console_t uart_console;
uint32_t console_clock;
if ((id > 0) && (id < TEGRA186_MAX_UART_PORTS)) {
/*
* Reference clock used by the FPGAs is a lot slower.
*/
if (tegra_platform_is_fpga()) {
console_clock = TEGRA_BOOT_UART_CLK_13_MHZ;
} else {
console_clock = TEGRA_BOOT_UART_CLK_408_MHZ;
}
(void)console_16550_register(tegra186_uart_addresses[id],
console_clock,
TEGRA_CONSOLE_BAUDRATE,
&uart_console);
console_set_scope(&uart_console, CONSOLE_FLAG_BOOT |
CONSOLE_FLAG_RUNTIME | CONSOLE_FLAG_CRASH);
}
}
/*******************************************************************************
* Handler for early platform setup
******************************************************************************/
void plat_early_platform_setup(void)
{
uint64_t impl, val;
const plat_params_from_bl2_t *plat_params = bl31_get_plat_params();
const struct tegra_bl31_params *arg_from_bl2 = plat_get_bl31_params();
/* Verify chip id is t186 */
assert(tegra_chipid_is_t186());
/* sanity check MCE firmware compatibility */
mce_verify_firmware_version();
/*
* Do initial security configuration to allow DRAM/device access.
*/
tegra_memctrl_tzdram_setup(plat_params->tzdram_base,
(uint32_t)plat_params->tzdram_size);
impl = (read_midr() >> MIDR_IMPL_SHIFT) & (uint64_t)MIDR_IMPL_MASK;
/*
* Enable ECC and Parity Protection for Cortex-A57 CPUs (Tegra186
* A02p and beyond).
*/
if ((plat_params->l2_ecc_parity_prot_dis != 1) &&
(impl != (uint64_t)DENVER_IMPL)) {
val = read_l2ctlr_el1();
val |= CORTEX_A57_L2_ECC_PARITY_PROTECTION_BIT;
write_l2ctlr_el1(val);
}
/*
* The previous bootloader might not have placed the BL32 image
* inside the TZDRAM. Platform handler to allow relocation of BL32
* image to TZDRAM memory. This behavior might change per platform.
*/
plat_relocate_bl32_image(arg_from_bl2->bl32_image_info);
}
/*******************************************************************************
* Handler for late platform setup
******************************************************************************/
void plat_late_platform_setup(void)
{
; /* do nothing */
}
/* Secure IRQs for Tegra186 */
static const interrupt_prop_t tegra186_interrupt_props[] = {
INTR_PROP_DESC(TEGRA_SDEI_SGI_PRIVATE, PLAT_SDEI_CRITICAL_PRI,
GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE),
INTR_PROP_DESC(TEGRA186_TOP_WDT_IRQ, PLAT_TEGRA_WDT_PRIO,
GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE),
INTR_PROP_DESC(TEGRA186_AON_WDT_IRQ, PLAT_TEGRA_WDT_PRIO,
GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE)
};
/*******************************************************************************
* Initialize the GIC and SGIs
******************************************************************************/
void plat_gic_setup(void)
{
tegra_gic_setup(tegra186_interrupt_props, ARRAY_SIZE(tegra186_interrupt_props));
tegra_gic_init();
/*
* Initialize the FIQ handler only if the platform supports any
* FIQ interrupt sources.
*/
tegra_fiq_handler_setup();
}
/*******************************************************************************
* Return pointer to the BL31 params from previous bootloader
******************************************************************************/
struct tegra_bl31_params *plat_get_bl31_params(void)
{
uint32_t val;
val = mmio_read_32(TEGRA_SCRATCH_BASE + SCRATCH_BL31_PARAMS_ADDR);
return (struct tegra_bl31_params *)(uintptr_t)val;
}
/*******************************************************************************
* Return pointer to the BL31 platform params from previous bootloader
******************************************************************************/
plat_params_from_bl2_t *plat_get_bl31_plat_params(void)
{
uint32_t val;
val = mmio_read_32(TEGRA_SCRATCH_BASE + SCRATCH_BL31_PLAT_PARAMS_ADDR);
return (plat_params_from_bl2_t *)(uintptr_t)val;
}
/*******************************************************************************
* This function implements a part of the critical interface between the psci
* generic layer and the platform that allows the former to query the platform
* to convert an MPIDR to a unique linear index. An error code (-1) is returned
* in case the MPIDR is invalid.
******************************************************************************/
int32_t plat_core_pos_by_mpidr(u_register_t mpidr)
{
u_register_t cluster_id, cpu_id, pos;
int32_t ret;
cluster_id = (mpidr >> (u_register_t)MPIDR_AFF1_SHIFT) & (u_register_t)MPIDR_AFFLVL_MASK;
cpu_id = (mpidr >> (u_register_t)MPIDR_AFF0_SHIFT) & (u_register_t)MPIDR_AFFLVL_MASK;
/*
* Validate cluster_id by checking whether it represents
* one of the two clusters present on the platform.
* Validate cpu_id by checking whether it represents a CPU in
* one of the two clusters present on the platform.
*/
if ((cluster_id >= (u_register_t)PLATFORM_CLUSTER_COUNT) ||
(cpu_id >= (u_register_t)PLATFORM_MAX_CPUS_PER_CLUSTER)) {
ret = PSCI_E_NOT_PRESENT;
} else {
/* calculate the core position */
pos = cpu_id + (cluster_id << 2U);
/* check for non-existent CPUs */
if ((pos == TEGRA186_CLUSTER0_CORE2) || (pos == TEGRA186_CLUSTER0_CORE3)) {
ret = PSCI_E_NOT_PRESENT;
} else {
ret = (int32_t)pos;
}
}
return ret;
}
/*******************************************************************************
* Handler to relocate BL32 image to TZDRAM
******************************************************************************/
void plat_relocate_bl32_image(const image_info_t *bl32_img_info)
{
const plat_params_from_bl2_t *plat_bl31_params = plat_get_bl31_plat_params();
const entry_point_info_t *bl32_ep_info = bl31_plat_get_next_image_ep_info(SECURE);
uint64_t tzdram_start, tzdram_end, bl32_start, bl32_end;
if ((bl32_img_info != NULL) && (bl32_ep_info != NULL)) {
/* Relocate BL32 if it resides outside of the TZDRAM */
tzdram_start = plat_bl31_params->tzdram_base;
tzdram_end = plat_bl31_params->tzdram_base +
plat_bl31_params->tzdram_size;
bl32_start = bl32_img_info->image_base;
bl32_end = bl32_img_info->image_base + bl32_img_info->image_size;
assert(tzdram_end > tzdram_start);
assert(bl32_end > bl32_start);
assert(bl32_ep_info->pc > tzdram_start);
assert(bl32_ep_info->pc < tzdram_end);
/* relocate BL32 */
if ((bl32_start >= tzdram_end) || (bl32_end <= tzdram_start)) {
INFO("Relocate BL32 to TZDRAM\n");
(void)memcpy16((void *)(uintptr_t)bl32_ep_info->pc,
(void *)(uintptr_t)bl32_start,
bl32_img_info->image_size);
/* clean up non-secure intermediate buffer */
zeromem((void *)(uintptr_t)bl32_start,
bl32_img_info->image_size);
}
}
}
/*******************************************************************************
* Handler to indicate support for System Suspend
******************************************************************************/
bool plat_supports_system_suspend(void)
{
return true;
}
/*******************************************************************************
* Platform specific runtime setup.
******************************************************************************/
void plat_runtime_setup(void)
{
/*
* During cold boot, it is observed that the arbitration
* bit is set in the Memory controller leading to false
* error interrupts in the non-secure world. To avoid
* this, clean the interrupt status register before
* booting into the non-secure world
*/
tegra_memctrl_clear_pending_interrupts();
/*
* During boot, USB3 and flash media (SDMMC/SATA) devices need
* access to IRAM. Because these clients connect to the MC and
* do not have a direct path to the IRAM, the MC implements AHB
* redirection during boot to allow path to IRAM. In this mode
* accesses to a programmed memory address aperture are directed
* to the AHB bus, allowing access to the IRAM. This mode must be
* disabled before we jump to the non-secure world.
*/
tegra_memctrl_disable_ahb_redirection();
/*
* Verify the integrity of the previously configured SMMU(s)
* settings
*/
tegra_smmu_verify();
}
@@ -0,0 +1,159 @@
/*
* Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <errno.h>
#include <arch.h>
#include <arch_helpers.h>
#include <common/bl_common.h>
#include <common/debug.h>
#include <common/runtime_svc.h>
#include <denver.h>
#include <lib/el3_runtime/context_mgmt.h>
#include <mce.h>
#include <memctrl.h>
#include <t18x_ari.h>
#include <tegra_private.h>
/*******************************************************************************
* Offset to read the ref_clk counter value
******************************************************************************/
#define REF_CLK_OFFSET 4ULL
/*******************************************************************************
* Tegra186 SiP SMCs
******************************************************************************/
#define TEGRA_SIP_GET_ACTMON_CLK_COUNTERS 0xC2FFFE02
#define TEGRA_SIP_MCE_CMD_ENTER_CSTATE 0xC2FFFF00
#define TEGRA_SIP_MCE_CMD_UPDATE_CSTATE_INFO 0xC2FFFF01
#define TEGRA_SIP_MCE_CMD_UPDATE_CROSSOVER_TIME 0xC2FFFF02
#define TEGRA_SIP_MCE_CMD_READ_CSTATE_STATS 0xC2FFFF03
#define TEGRA_SIP_MCE_CMD_WRITE_CSTATE_STATS 0xC2FFFF04
#define TEGRA_SIP_MCE_CMD_IS_SC7_ALLOWED 0xC2FFFF05
#define TEGRA_SIP_MCE_CMD_CC3_CTRL 0xC2FFFF07
#define TEGRA_SIP_MCE_CMD_ECHO_DATA 0xC2FFFF08
#define TEGRA_SIP_MCE_CMD_READ_VERSIONS 0xC2FFFF09
#define TEGRA_SIP_MCE_CMD_ENUM_FEATURES 0xC2FFFF0A
#define TEGRA_SIP_MCE_CMD_ROC_FLUSH_CACHE_TRBITS 0xC2FFFF0B
#define TEGRA_SIP_MCE_CMD_ENUM_READ_MCA 0xC2FFFF0C
#define TEGRA_SIP_MCE_CMD_ENUM_WRITE_MCA 0xC2FFFF0D
#define TEGRA_SIP_MCE_CMD_ROC_FLUSH_CACHE 0xC2FFFF0E
#define TEGRA_SIP_MCE_CMD_ROC_CLEAN_CACHE 0xC2FFFF0F
#define TEGRA_SIP_MCE_CMD_ENABLE_LATIC 0xC2FFFF10
#define TEGRA_SIP_MCE_CMD_UNCORE_PERFMON_REQ 0xC2FFFF11
#define TEGRA_SIP_MCE_CMD_MISC_CCPLEX 0xC2FFFF12
/*******************************************************************************
* This function is responsible for handling all T186 SiP calls
******************************************************************************/
int32_t plat_sip_handler(uint32_t smc_fid,
uint64_t x1,
uint64_t x2,
uint64_t x3,
uint64_t x4,
const void *cookie,
void *handle,
uint64_t flags)
{
int32_t mce_ret, ret = 0;
uint32_t impl, cpu;
uint32_t base, core_clk_ctr, ref_clk_ctr;
uint32_t local_smc_fid = smc_fid;
uint64_t local_x1 = x1, local_x2 = x2, local_x3 = x3;
(void)x4;
(void)cookie;
(void)flags;
if (((smc_fid >> FUNCID_CC_SHIFT) & FUNCID_CC_MASK) == SMC_32) {
/* 32-bit function, clear top parameter bits */
local_x1 = (uint32_t)x1;
local_x2 = (uint32_t)x2;
local_x3 = (uint32_t)x3;
}
/*
* Convert SMC FID to SMC64, to support SMC32/SMC64 configurations
*/
local_smc_fid |= (SMC_64 << FUNCID_CC_SHIFT);
switch (local_smc_fid) {
/*
* Micro Coded Engine (MCE) commands reside in the 0x82FFFF00 -
* 0x82FFFFFF SiP SMC space
*/
case TEGRA_SIP_MCE_CMD_ENTER_CSTATE:
case TEGRA_SIP_MCE_CMD_UPDATE_CSTATE_INFO:
case TEGRA_SIP_MCE_CMD_UPDATE_CROSSOVER_TIME:
case TEGRA_SIP_MCE_CMD_READ_CSTATE_STATS:
case TEGRA_SIP_MCE_CMD_WRITE_CSTATE_STATS:
case TEGRA_SIP_MCE_CMD_IS_SC7_ALLOWED:
case TEGRA_SIP_MCE_CMD_CC3_CTRL:
case TEGRA_SIP_MCE_CMD_ECHO_DATA:
case TEGRA_SIP_MCE_CMD_READ_VERSIONS:
case TEGRA_SIP_MCE_CMD_ENUM_FEATURES:
case TEGRA_SIP_MCE_CMD_ROC_FLUSH_CACHE_TRBITS:
case TEGRA_SIP_MCE_CMD_ENUM_READ_MCA:
case TEGRA_SIP_MCE_CMD_ENUM_WRITE_MCA:
case TEGRA_SIP_MCE_CMD_ROC_FLUSH_CACHE:
case TEGRA_SIP_MCE_CMD_ROC_CLEAN_CACHE:
case TEGRA_SIP_MCE_CMD_ENABLE_LATIC:
case TEGRA_SIP_MCE_CMD_UNCORE_PERFMON_REQ:
case TEGRA_SIP_MCE_CMD_MISC_CCPLEX:
/* clean up the high bits */
local_smc_fid &= MCE_CMD_MASK;
/* execute the command and store the result */
mce_ret = mce_command_handler(local_smc_fid, local_x1, local_x2, local_x3);
write_ctx_reg(get_gpregs_ctx(handle),
CTX_GPREG_X0, (uint64_t)(mce_ret));
break;
/*
* This function ID reads the Activity monitor's core/ref clock
* counter values for a core/cluster.
*
* x1 = MPIDR of the target core
* x2 = MIDR of the target core
*/
case TEGRA_SIP_GET_ACTMON_CLK_COUNTERS:
cpu = (uint32_t)x1 & MPIDR_CPU_MASK;
impl = ((uint32_t)x2 >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK;
/* sanity check target CPU number */
if (cpu > (uint32_t)PLATFORM_MAX_CPUS_PER_CLUSTER) {
ret = -EINVAL;
} else {
/* get the base address for the current CPU */
base = (impl == DENVER_IMPL) ? TEGRA_DENVER_ACTMON_CTR_BASE :
TEGRA_ARM_ACTMON_CTR_BASE;
/* read the clock counter values */
core_clk_ctr = mmio_read_32(base + (8ULL * cpu));
ref_clk_ctr = mmio_read_32(base + (8ULL * cpu) + REF_CLK_OFFSET);
/* return the counter values as two different parameters */
write_ctx_reg(get_gpregs_ctx(handle),
CTX_GPREG_X1, (core_clk_ctr));
write_ctx_reg(get_gpregs_ctx(handle),
CTX_GPREG_X2, (ref_clk_ctr));
}
break;
default:
ret = -ENOTSUP;
break;
}
return ret;
}
@@ -0,0 +1,22 @@
/*
* Copyright (c) 2017, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/bl_common.h>
#include <smmu.h>
#include <tegra_def.h>
#include <tegra_mc_def.h>
#define MAX_NUM_SMMU_DEVICES U(1)
/*******************************************************************************
* Handler to return the support SMMU devices number
******************************************************************************/
uint32_t plat_get_num_smmu_devices(void)
{
return MAX_NUM_SMMU_DEVICES;
}
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2016-2019, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
#include <common/bl_common.h>
#include <memctrl_v2.h>
#include <plat/common/common_def.h>
#include <tegra_def.h>
#define TEGRA186_MC_CTX_SIZE 0x93
.globl tegra186_get_mc_ctx_size
/*
* Tegra186 reset data (offset 0x0 - 0x420)
*
* 0x000: MC context start
* 0x420: MC context end
*/
.align 4
__tegra186_mc_context:
.rept TEGRA186_MC_CTX_SIZE
.quad 0
.endr
.align 4
__tegra186_mc_context_end:
/* return the size of the MC context */
func tegra186_get_mc_ctx_size
adr x0, __tegra186_mc_context_end
adr x1, __tegra186_mc_context
sub x0, x0, x1
ret
endfunc tegra186_get_mc_ctx_size
@@ -0,0 +1,77 @@
#
# Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
# Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
# platform configs
ENABLE_ROC_FOR_ORDERING_CLIENT_REQUESTS := 1
$(eval $(call add_define,ENABLE_ROC_FOR_ORDERING_CLIENT_REQUESTS))
ENABLE_CHIP_VERIFICATION_HARNESS := 0
$(eval $(call add_define,ENABLE_CHIP_VERIFICATION_HARNESS))
RESET_TO_BL31 := 1
PROGRAMMABLE_RESET_ADDRESS := 0
COLD_BOOT_SINGLE_CPU := 1
RELOCATE_BL32_IMAGE := 1
# platform settings
TZDRAM_BASE := 0x30000000
$(eval $(call add_define,TZDRAM_BASE))
PLATFORM_CLUSTER_COUNT := 2
$(eval $(call add_define,PLATFORM_CLUSTER_COUNT))
PLATFORM_MAX_CPUS_PER_CLUSTER := 4
$(eval $(call add_define,PLATFORM_MAX_CPUS_PER_CLUSTER))
MAX_XLAT_TABLES := 25
$(eval $(call add_define,MAX_XLAT_TABLES))
MAX_MMAP_REGIONS := 30
$(eval $(call add_define,MAX_MMAP_REGIONS))
# platform files
PLAT_INCLUDES += -Iplat/nvidia/tegra/include/t186 \
-I${SOC_DIR}/drivers/include
BL31_SOURCES += ${TEGRA_GICv2_SOURCES} \
drivers/ti/uart/aarch64/16550_console.S \
lib/cpus/aarch64/denver.S \
lib/cpus/aarch64/cortex_a57.S \
${TEGRA_DRIVERS}/bpmp_ipc/intf.c \
${TEGRA_DRIVERS}/bpmp_ipc/ivc.c \
${TEGRA_DRIVERS}/gpcdma/gpcdma.c \
${TEGRA_DRIVERS}/memctrl/memctrl_v2.c \
${TEGRA_DRIVERS}/smmu/smmu.c \
${SOC_DIR}/drivers/mce/mce.c \
${SOC_DIR}/drivers/mce/ari.c \
${SOC_DIR}/drivers/mce/nvg.c \
${SOC_DIR}/drivers/mce/aarch64/nvg_helpers.S \
$(SOC_DIR)/drivers/se/se.c \
${SOC_DIR}/plat_memctrl.c \
${SOC_DIR}/plat_psci_handlers.c \
${SOC_DIR}/plat_setup.c \
${SOC_DIR}/plat_secondary.c \
${SOC_DIR}/plat_sip_calls.c \
${SOC_DIR}/plat_smmu.c \
${SOC_DIR}/plat_trampoline.S
# Enable workarounds for selected Cortex-A57 erratas.
A57_DISABLE_NON_TEMPORAL_HINT := 1
ERRATA_A57_806969 := 1
ERRATA_A57_813419 := 1
ERRATA_A57_813420 := 1
ERRATA_A57_826974 := 1
ERRATA_A57_826977 := 1
ERRATA_A57_828024 := 1
ERRATA_A57_829520 := 1
ERRATA_A57_833471 := 1
# Enable higher performance Non-cacheable load forwarding
A57_ENABLE_NONCACHEABLE_LOAD_FWD := 1
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MCE_PRIVATE_H
#define MCE_PRIVATE_H
#include <stdbool.h>
#include <tegra_def.h>
/*******************************************************************************
* Macros to prepare CSTATE info request
******************************************************************************/
/* Description of the parameters for UPDATE_CSTATE_INFO request */
#define CLUSTER_CSTATE_MASK 0x7U
#define CLUSTER_CSTATE_SHIFT 0X0U
#define CLUSTER_CSTATE_UPDATE_BIT (1U << 7)
#define CCPLEX_CSTATE_MASK 0x7U
#define CCPLEX_CSTATE_SHIFT 8U
#define CCPLEX_CSTATE_UPDATE_BIT (1U << 15)
#define SYSTEM_CSTATE_MASK 0xFU
#define SYSTEM_CSTATE_SHIFT 16U
#define SYSTEM_CSTATE_UPDATE_BIT (1U << 23)
#define CSTATE_WAKE_MASK_UPDATE_BIT (1U << 31)
#define CSTATE_WAKE_MASK_SHIFT 32U
#define CSTATE_WAKE_MASK_CLEAR 0xFFFFFFFFU
/*******************************************************************************
* Core ID mask (bits 3:0 in the online request)
******************************************************************************/
#define MCE_CORE_ID_MASK 0xFU
/*******************************************************************************
* C-state statistics macros
******************************************************************************/
#define MCE_STAT_ID_SHIFT 16U
/*******************************************************************************
* Security config macros
******************************************************************************/
#define STRICT_CHECKING_ENABLED_SET (1UL << 0)
#define STRICT_CHECKING_LOCKED_SET (1UL << 1)
/* declarations for NVG handler functions */
uint64_t nvg_get_version(void);
void nvg_set_wake_time(uint32_t wake_time);
void nvg_update_cstate_info(uint32_t cluster, uint32_t ccplex,
uint32_t system, uint32_t wake_mask, uint8_t update_wake_mask);
int32_t nvg_set_cstate_stat_query_value(uint64_t data);
uint64_t nvg_get_cstate_stat_query_value(void);
int32_t nvg_is_sc7_allowed(void);
int32_t nvg_online_core(uint32_t core);
int32_t nvg_update_ccplex_gsc(uint32_t gsc_idx);
int32_t nvg_enter_cstate(uint32_t state, uint32_t wake_time);
int32_t nvg_roc_clean_cache_trbits(void);
void nvg_enable_strict_checking_mode(void);
void nvg_verify_strict_checking_mode(void);
void nvg_system_shutdown(void);
void nvg_system_reboot(void);
void nvg_clear_hsm_corr_status(void);
/* declarations for assembly functions */
void nvg_set_request_data(uint64_t req, uint64_t data);
void nvg_set_request(uint64_t req);
uint64_t nvg_get_result(void);
uint64_t nvg_cache_clean(void);
uint64_t nvg_cache_clean_inval(void);
uint64_t nvg_cache_inval_all(void);
/* MCE helper functions */
void mce_enable_strict_checking(void);
void mce_verify_strict_checking(void);
void mce_system_shutdown(void);
void mce_system_reboot(void);
void mce_clear_hsm_corr_status(void);
#endif /* MCE_PRIVATE_H */
@@ -0,0 +1,15 @@
/*
* Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef SE_H
#define SE_H
int32_t tegra_se_calculate_save_sha256(uint64_t src_addr,
uint32_t src_len_inbyte);
int32_t tegra_se_suspend(void);
void tegra_se_resume(void);
#endif /* SE_H */
@@ -0,0 +1,429 @@
/*
* Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef T194_NVG_H
#define T194_NVG_H
#include <lib/utils_def.h>
/**
* t194_nvg.h - Header for the NVIDIA Generic interface (NVG).
* Official documentation for this interface is included as part
* of the T194 TRM.
*/
/**
* Current version - Major version increments may break backwards
* compatiblity and binary compatibility. Minor version increments
* occur when there is only new functionality.
*/
enum {
TEGRA_NVG_VERSION_MAJOR = U(6),
TEGRA_NVG_VERSION_MINOR = U(7)
};
typedef enum {
TEGRA_NVG_CHANNEL_VERSION = U(0),
TEGRA_NVG_CHANNEL_POWER_PERF = U(1),
TEGRA_NVG_CHANNEL_POWER_MODES = U(2),
TEGRA_NVG_CHANNEL_WAKE_TIME = U(3),
TEGRA_NVG_CHANNEL_CSTATE_INFO = U(4),
TEGRA_NVG_CHANNEL_CROSSOVER_C6_LOWER_BOUND = U(5),
TEGRA_NVG_CHANNEL_CROSSOVER_CC6_LOWER_BOUND = U(6),
TEGRA_NVG_CHANNEL_CROSSOVER_CG7_LOWER_BOUND = U(8),
TEGRA_NVG_CHANNEL_CSTATE_STAT_QUERY_REQUEST = U(10),
TEGRA_NVG_CHANNEL_CSTATE_STAT_QUERY_VALUE = U(11),
TEGRA_NVG_CHANNEL_NUM_CORES = U(20),
TEGRA_NVG_CHANNEL_UNIQUE_LOGICAL_ID = U(21),
TEGRA_NVG_CHANNEL_LOGICAL_TO_PHYSICAL_MAPPING = U(22),
TEGRA_NVG_CHANNEL_LOGICAL_TO_MPIDR = U(23),
TEGRA_NVG_CHANNEL_SHUTDOWN = U(42),
TEGRA_NVG_CHANNEL_IS_SC7_ALLOWED = U(43),
TEGRA_NVG_CHANNEL_ONLINE_CORE = U(44),
TEGRA_NVG_CHANNEL_CC3_CTRL = U(45),
TEGRA_NVG_CHANNEL_CCPLEX_CACHE_CONTROL = U(49),
TEGRA_NVG_CHANNEL_UPDATE_CCPLEX_GSC = U(50),
TEGRA_NVG_CHANNEL_HSM_ERROR_CTRL = U(53),
TEGRA_NVG_CHANNEL_SECURITY_CONFIG = U(54),
TEGRA_NVG_CHANNEL_DEBUG_CONFIG = U(55),
TEGRA_NVG_CHANNEL_DDA_SNOC_MCF = U(56),
TEGRA_NVG_CHANNEL_DDA_MCF_ORD1 = U(57),
TEGRA_NVG_CHANNEL_DDA_MCF_ORD2 = U(58),
TEGRA_NVG_CHANNEL_DDA_MCF_ORD3 = U(59),
TEGRA_NVG_CHANNEL_DDA_MCF_ISO = U(60),
TEGRA_NVG_CHANNEL_DDA_MCF_SISO = U(61),
TEGRA_NVG_CHANNEL_DDA_MCF_NISO = U(62),
TEGRA_NVG_CHANNEL_DDA_MCF_NISO_REMOTE = U(63),
TEGRA_NVG_CHANNEL_DDA_L3CTRL_ISO = U(64),
TEGRA_NVG_CHANNEL_DDA_L3CTRL_SISO = U(65),
TEGRA_NVG_CHANNEL_DDA_L3CTRL_NISO = U(66),
TEGRA_NVG_CHANNEL_DDA_L3CTRL_NISO_REMOTE = U(67),
TEGRA_NVG_CHANNEL_DDA_L3CTRL_L3FILL = U(68),
TEGRA_NVG_CHANNEL_DDA_L3CTRL_L3WR = U(69),
TEGRA_NVG_CHANNEL_DDA_L3CTRL_RSP_L3RD_DMA = U(70),
TEGRA_NVG_CHANNEL_DDA_L3CTRL_RSP_MCFRD_DMA = U(71),
TEGRA_NVG_CHANNEL_DDA_L3CTRL_GLOBAL = U(72),
TEGRA_NVG_CHANNEL_DDA_L3CTRL_LL = U(73),
TEGRA_NVG_CHANNEL_DDA_L3CTRL_L3D = U(74),
TEGRA_NVG_CHANNEL_DDA_L3CTRL_FCM_RD = U(75),
TEGRA_NVG_CHANNEL_DDA_L3CTRL_FCM_WR = U(76),
TEGRA_NVG_CHANNEL_DDA_SNOC_GLOBAL_CTRL = U(77),
TEGRA_NVG_CHANNEL_DDA_SNOC_CLIENT_REQ_CTRL = U(78),
TEGRA_NVG_CHANNEL_DDA_SNOC_CLIENT_REPLENTISH_CTRL = U(79),
TEGRA_NVG_CHANNEL_RT_SAFE_MASK = U(80),
TEGRA_NVG_CHANNEL_RT_WINDOW_US = U(81),
TEGRA_NVG_CHANNEL_RT_FWD_PROGRESS_US = U(82),
TEGRA_NVG_CHANNEL_LAST_INDEX
} tegra_nvg_channel_id_t;
typedef enum {
NVG_STAT_QUERY_SC7_ENTRIES = U(1),
NVG_STAT_QUERY_CC6_ENTRIES = U(6),
NVG_STAT_QUERY_CG7_ENTRIES = U(7),
NVG_STAT_QUERY_C6_ENTRIES = U(10),
NVG_STAT_QUERY_C7_ENTRIES = U(14),
NVG_STAT_QUERY_SC7_RESIDENCY_SUM = U(32),
NVG_STAT_QUERY_CC6_RESIDENCY_SUM = U(41),
NVG_STAT_QUERY_CG7_RESIDENCY_SUM = U(46),
NVG_STAT_QUERY_C6_RESIDENCY_SUM = U(51),
NVG_STAT_QUERY_C7_RESIDENCY_SUM = U(56),
NVG_STAT_QUERY_SC7_ENTRY_TIME_SUM = U(60),
NVG_STAT_QUERY_CC6_ENTRY_TIME_SUM = U(61),
NVG_STAT_QUERY_CG7_ENTRY_TIME_SUM = U(62),
NVG_STAT_QUERY_C6_ENTRY_TIME_SUM = U(63),
NVG_STAT_QUERY_C7_ENTRY_TIME_SUM = U(64),
NVG_STAT_QUERY_SC7_EXIT_TIME_SUM = U(70),
NVG_STAT_QUERY_CC6_EXIT_TIME_SUM = U(71),
NVG_STAT_QUERY_CG7_EXIT_TIME_SUM = U(72),
NVG_STAT_QUERY_C6_EXIT_TIME_SUM = U(73),
NVG_STAT_QUERY_C7_EXIT_TIME_SUM = U(74),
NVG_STAT_QUERY_SC7_ENTRY_LAST = U(80),
NVG_STAT_QUERY_CC6_ENTRY_LAST = U(81),
NVG_STAT_QUERY_CG7_ENTRY_LAST = U(82),
NVG_STAT_QUERY_C6_ENTRY_LAST = U(83),
NVG_STAT_QUERY_C7_ENTRY_LAST = U(84),
NVG_STAT_QUERY_SC7_EXIT_LAST = U(90),
NVG_STAT_QUERY_CC6_EXIT_LAST = U(91),
NVG_STAT_QUERY_CG7_EXIT_LAST = U(92),
NVG_STAT_QUERY_C6_EXIT_LAST = U(93),
NVG_STAT_QUERY_C7_EXIT_LAST = U(94)
} tegra_nvg_stat_query_t;
typedef enum {
TEGRA_NVG_CORE_C0 = U(0),
TEGRA_NVG_CORE_C1 = U(1),
TEGRA_NVG_CORE_C6 = U(6),
TEGRA_NVG_CORE_C7 = U(7),
TEGRA_NVG_CORE_WARMRSTREQ = U(8)
} tegra_nvg_core_sleep_state_t;
typedef enum {
TEGRA_NVG_SHUTDOWN = U(0),
TEGRA_NVG_REBOOT = U(1)
} tegra_nvg_shutdown_reboot_state_t;
typedef enum {
TEGRA_NVG_CLUSTER_CC0 = U(0),
TEGRA_NVG_CLUSTER_AUTO_CC1 = U(1),
TEGRA_NVG_CLUSTER_CC6 = U(6)
} tegra_nvg_cluster_sleep_state_t;
typedef enum {
TEGRA_NVG_CG_CG0 = U(0),
TEGRA_NVG_CG_CG7 = U(7)
} tegra_nvg_cluster_group_sleep_state_t;
typedef enum {
TEGRA_NVG_SYSTEM_SC0 = U(0),
TEGRA_NVG_SYSTEM_SC7 = U(7),
TEGRA_NVG_SYSTEM_SC8 = U(8)
} tegra_nvg_system_sleep_state_t;
// ---------------------------------------------------------------------------
// NVG Data subformats
// ---------------------------------------------------------------------------
typedef union {
uint64_t flat;
struct nvg_version_channel_t {
uint32_t minor_version : U(32);
uint32_t major_version : U(32);
} bits;
} nvg_version_data_t;
typedef union {
uint64_t flat;
struct {
uint32_t perf_per_watt : U(1);
uint32_t reserved_31_1 : U(31);
uint32_t reserved_63_32 : U(32);
} bits;
} nvg_power_perf_channel_t;
typedef union {
uint64_t flat;
struct {
uint32_t low_battery : U(1);
uint32_t reserved_1_1 : U(1);
uint32_t battery_save : U(1);
uint32_t reserved_31_3 : U(29);
uint32_t reserved_63_32 : U(32);
} bits;
} nvg_power_modes_channel_t;
typedef union nvg_channel_1_data_u {
uint64_t flat;
struct nvg_channel_1_data_s {
uint32_t perf_per_watt_mode : U(1);
uint32_t reserved_31_1 : U(31);
uint32_t reserved_63_32 : U(32);
} bits;
} nvg_channel_1_data_t;
typedef union {
uint64_t flat;
struct {
uint32_t gpu_ways : U(5);
uint32_t reserved_7_5 : U(3);
uint32_t gpu_only_ways : U(5);
uint32_t reserved_31_13 : U(19);
uint32_t reserved_63_32 : U(32);
} bits;
} nvg_ccplex_cache_control_channel_t;
typedef union nvg_channel_2_data_u {
uint64_t flat;
struct nvg_channel_2_data_s {
uint32_t reserved_1_0 : U(2);
uint32_t battery_saver_mode : U(1);
uint32_t reserved_31_3 : U(29);
uint32_t reserved_63_32 : U(32);
} bits;
} nvg_channel_2_data_t;
typedef union {
uint64_t flat;
struct {
uint32_t wake_time : U(32);
uint32_t reserved_63_32 : U(32);
} bits;
} nvg_wake_time_channel_t;
typedef union {
uint64_t flat;
struct {
uint32_t cluster_state : U(3);
uint32_t reserved_6_3 : U(4);
uint32_t update_cluster : U(1);
uint32_t cg_cstate : U(3);
uint32_t reserved_14_11 : U(4);
uint32_t update_cg : U(1);
uint32_t system_cstate : U(4);
uint32_t reserved_22_20 : U(3);
uint32_t update_system : U(1);
uint32_t reserved_30_24 : U(7);
uint32_t update_wake_mask : U(1);
union {
uint32_t flat : U(32);
struct {
uint32_t vfiq : U(1);
uint32_t virq : U(1);
uint32_t fiq : U(1);
uint32_t irq : U(1);
uint32_t serror : U(1);
uint32_t reserved_10_5 : U(6);
uint32_t fiqout : U(1);
uint32_t irqout : U(1);
uint32_t reserved_31_13 : U(19);
} carmel;
} wake_mask;
} bits;
} nvg_cstate_info_channel_t;
typedef union {
uint64_t flat;
struct {
uint32_t crossover_value : U(32);
uint32_t reserved_63_32 : U(32);
} bits;
} nvg_lower_bound_channel_t;
typedef union {
uint64_t flat;
struct {
uint32_t unit_id : U(4);
uint32_t reserved_15_4 : U(12);
uint32_t stat_id : U(16);
uint32_t reserved_63_32 : U(32);
} bits;
} nvg_cstate_stat_query_channel_t;
typedef union {
uint64_t flat;
struct {
uint32_t num_cores : U(4);
uint32_t reserved_31_4 : U(28);
uint32_t reserved_63_32 : U(32);
} bits;
} nvg_num_cores_channel_t;
typedef union {
uint64_t flat;
struct {
uint32_t unique_core_id : U(3);
uint32_t reserved_31_3 : U(29);
uint32_t reserved_63_32 : U(32);
} bits;
} nvg_unique_logical_id_channel_t;
typedef union {
uint64_t flat;
struct {
uint32_t lcore0_pcore_id : U(4);
uint32_t lcore1_pcore_id : U(4);
uint32_t lcore2_pcore_id : U(4);
uint32_t lcore3_pcore_id : U(4);
uint32_t lcore4_pcore_id : U(4);
uint32_t lcore5_pcore_id : U(4);
uint32_t lcore6_pcore_id : U(4);
uint32_t lcore7_pcore_id : U(4);
uint32_t reserved_63_32 : U(32);
} bits;
} nvg_logical_to_physical_mappings_channel_t;
typedef union {
uint64_t flat;
struct nvg_logical_to_mpidr_channel_write_t {
uint32_t lcore_id : U(3);
uint32_t reserved_31_3 : U(29);
uint32_t reserved_63_32 : U(32);
} write;
struct nvg_logical_to_mpidr_channel_read_t {
uint32_t mpidr : U(32);
uint32_t reserved_63_32 : U(32);
} read;
} nvg_logical_to_mpidr_channel_t;
typedef union {
uint64_t flat;
struct {
uint32_t is_sc7_allowed : U(1);
uint32_t reserved_31_1 : U(31);
uint32_t reserved_63_32 : U(32);
} bits;
} nvg_is_sc7_allowed_channel_t;
typedef union {
uint64_t flat;
struct {
uint32_t core_id : U(4);
uint32_t reserved_31_4 : U(28);
uint32_t reserved_63_32 : U(32);
} bits;
} nvg_core_online_channel_t;
typedef union {
uint64_t flat;
struct {
uint32_t freq_req : U(9);
uint32_t reserved_30_9 : U(22);
uint32_t enable : U(1);
uint32_t reserved_63_32 : U(32);
} bits;
} nvg_cc3_control_channel_t;
typedef enum {
TEGRA_NVG_CHANNEL_UPDATE_GSC_ALL = U(0),
TEGRA_NVG_CHANNEL_UPDATE_GSC_NVDEC = U(1),
TEGRA_NVG_CHANNEL_UPDATE_GSC_WPR1 = U(2),
TEGRA_NVG_CHANNEL_UPDATE_GSC_WPR2 = U(3),
TEGRA_NVG_CHANNEL_UPDATE_GSC_TSECA = U(4),
TEGRA_NVG_CHANNEL_UPDATE_GSC_TSECB = U(5),
TEGRA_NVG_CHANNEL_UPDATE_GSC_BPMP = U(6),
TEGRA_NVG_CHANNEL_UPDATE_GSC_APE = U(7),
TEGRA_NVG_CHANNEL_UPDATE_GSC_SPE = U(8),
TEGRA_NVG_CHANNEL_UPDATE_GSC_SCE = U(9),
TEGRA_NVG_CHANNEL_UPDATE_GSC_APR = U(10),
TEGRA_NVG_CHANNEL_UPDATE_GSC_TZRAM = U(11),
TEGRA_NVG_CHANNEL_UPDATE_GSC_IPC_SE_TSEC = U(12),
TEGRA_NVG_CHANNEL_UPDATE_GSC_BPMP_TO_RCE = U(13),
TEGRA_NVG_CHANNEL_UPDATE_GSC_BPMP_TO_MCE = U(14),
TEGRA_NVG_CHANNEL_UPDATE_GSC_SE_SC7 = U(15),
TEGRA_NVG_CHANNEL_UPDATE_GSC_BPMP_TO_SPE = U(16),
TEGRA_NVG_CHANNEL_UPDATE_GSC_RCE = U(17),
TEGRA_NVG_CHANNEL_UPDATE_GSC_CPU_TZ_TO_BPMP = U(18),
TEGRA_NVG_CHANNEL_UPDATE_GSC_VM_ENCR1 = U(19),
TEGRA_NVG_CHANNEL_UPDATE_GSC_CPU_NS_TO_BPMP = U(20),
TEGRA_NVG_CHANNEL_UPDATE_GSC_OEM_SC7 = U(21),
TEGRA_NVG_CHANNEL_UPDATE_GSC_IPC_SE_SPE_SCE_BPMP = U(22),
TEGRA_NVG_CHANNEL_UPDATE_GSC_SC7_RESUME_FW = U(23),
TEGRA_NVG_CHANNEL_UPDATE_GSC_CAMERA_TASKLIST = U(24),
TEGRA_NVG_CHANNEL_UPDATE_GSC_XUSB = U(25),
TEGRA_NVG_CHANNEL_UPDATE_GSC_CV = U(26),
TEGRA_NVG_CHANNEL_UPDATE_GSC_VM_ENCR2 = U(27),
TEGRA_NVG_CHANNEL_UPDATE_GSC_HYPERVISOR_SW = U(28),
TEGRA_NVG_CHANNEL_UPDATE_GSC_SMMU_PAGETABLES = U(29),
TEGRA_NVG_CHANNEL_UPDATE_GSC_30 = U(30),
TEGRA_NVG_CHANNEL_UPDATE_GSC_31 = U(31),
TEGRA_NVG_CHANNEL_UPDATE_GSC_TZ_DRAM = U(32),
TEGRA_NVG_CHANNEL_UPDATE_GSC_NVLINK = U(33),
TEGRA_NVG_CHANNEL_UPDATE_GSC_SBS = U(34),
TEGRA_NVG_CHANNEL_UPDATE_GSC_VPR = U(35),
TEGRA_NVG_CHANNEL_UPDATE_GSC_LAST_INDEX
} tegra_nvg_channel_update_gsc_gsc_enum_t;
typedef union {
uint64_t flat;
struct {
uint32_t gsc_enum : U(16);
uint32_t reserved_31_16 : U(16);
uint32_t reserved_63_32 : U(32);
} bits;
} nvg_update_ccplex_gsc_channel_t;
typedef union {
uint64_t flat;
struct nvg_security_config_channel_t {
uint32_t strict_checking_enabled : U(1);
uint32_t strict_checking_locked : U(1);
uint32_t reserved_31_2 : U(30);
uint32_t reserved_63_32 : U(32);
} bits;
} nvg_security_config_t;
typedef union {
uint64_t flat;
struct nvg_shutdown_channel_t {
uint32_t reboot : U(1);
uint32_t reserved_31_1 : U(31);
uint32_t reserved_63_32 : U(32);
} bits;
} nvg_shutdown_t;
typedef union {
uint64_t flat;
struct nvg_debug_config_channel_t {
uint32_t enter_debug_state_on_mca : U(1);
uint32_t reserved_31_1 : U(31);
uint32_t reserved_63_32 : U(32);
} bits;
} nvg_debug_config_t;
typedef union {
uint64_t flat;
struct {
uint32_t uncorr : U(1);
uint32_t corr : U(1);
uint32_t reserved_31_2 : U(30);
uint32_t reserved_63_32 : U(32);
} bits;
} nvg_hsm_error_ctrl_channel_t;
extern nvg_debug_config_t nvg_debug_config;
#endif /* T194_NVG_H */
@@ -0,0 +1,52 @@
/*
* Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
.globl nvg_set_request_data
.globl nvg_set_request
.globl nvg_get_result
.globl nvg_cache_clean
.globl nvg_cache_clean_inval
.globl nvg_cache_inval_all
/* void nvg_set_request_data(uint64_t req, uint64_t data) */
func nvg_set_request_data
msr s3_0_c15_c1_2, x0
msr s3_0_c15_c1_3, x1
ret
endfunc nvg_set_request_data
/* void nvg_set_request(uint64_t req) */
func nvg_set_request
msr s3_0_c15_c1_2, x0
ret
endfunc nvg_set_request
/* uint64_t nvg_get_result(void) */
func nvg_get_result
mrs x0, s3_0_c15_c1_3
ret
endfunc nvg_get_result
/* uint64_t nvg_cache_clean(void) */
func nvg_cache_clean
mrs x0, s3_0_c15_c3_5
ret
endfunc nvg_cache_clean
/* uint64_t nvg_cache_clean_inval(void) */
func nvg_cache_clean_inval
mrs x0, s3_0_c15_c3_6
ret
endfunc nvg_cache_clean_inval
/* uint64_t nvg_cache_inval_all(void) */
func nvg_cache_inval_all
mrs x0, s3_0_c15_c3_7
ret
endfunc nvg_cache_inval_all
@@ -0,0 +1,255 @@
/*
* Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <arch_helpers.h>
#include <assert.h>
#include <common/bl_common.h>
#include <context.h>
#include <lib/el3_runtime/context_mgmt.h>
#include <common/debug.h>
#include <denver.h>
#include <mce.h>
#include <mce_private.h>
#include <platform_def.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <inttypes.h>
#include <t194_nvg.h>
#include <tegra_def.h>
#include <tegra_platform.h>
#include <tegra_private.h>
/* Handler to check if MCE firmware is supported */
static bool mce_firmware_not_supported(void)
{
bool status;
/* these platforms do not load MCE firmware */
status = tegra_platform_is_linsim() || tegra_platform_is_qt() ||
tegra_platform_is_virt_dev_kit();
return status;
}
/*******************************************************************************
* Common handler for all MCE commands
******************************************************************************/
int32_t mce_command_handler(uint64_t cmd, uint64_t arg0, uint64_t arg1,
uint64_t arg2)
{
int32_t ret = 0;
switch (cmd) {
case (uint64_t)MCE_CMD_ENTER_CSTATE:
ret = nvg_enter_cstate((uint32_t)arg0, (uint32_t)arg1);
if (ret < 0) {
ERROR("%s: enter_cstate failed(%d)\n", __func__, ret);
}
break;
case (uint64_t)MCE_CMD_IS_SC7_ALLOWED:
ret = nvg_is_sc7_allowed();
if (ret < 0) {
ERROR("%s: is_sc7_allowed failed(%d)\n", __func__, ret);
}
break;
case (uint64_t)MCE_CMD_ONLINE_CORE:
ret = nvg_online_core((uint32_t)arg0);
if (ret < 0) {
ERROR("%s: online_core failed(%d)\n", __func__, ret);
}
break;
default:
ERROR("unknown MCE command (%" PRIu64 ")\n", cmd);
ret = -EINVAL;
break;
}
return ret;
}
/*******************************************************************************
* Handler to update carveout values for Video Memory Carveout region
******************************************************************************/
int32_t mce_update_gsc_videomem(void)
{
int32_t ret;
/*
* MCE firmware is not running on simulation platforms.
*/
if (mce_firmware_not_supported()) {
ret = -EINVAL;
} else {
ret = nvg_update_ccplex_gsc((uint32_t)TEGRA_NVG_CHANNEL_UPDATE_GSC_VPR);
}
return ret;
}
/*******************************************************************************
* Handler to update carveout values for TZDRAM aperture
******************************************************************************/
int32_t mce_update_gsc_tzdram(void)
{
int32_t ret;
/*
* MCE firmware is not running on simulation platforms.
*/
if (mce_firmware_not_supported()) {
ret = -EINVAL;
} else {
ret = nvg_update_ccplex_gsc((uint32_t)TEGRA_NVG_CHANNEL_UPDATE_GSC_TZ_DRAM);
}
return ret;
}
/*******************************************************************************
* Handler to issue the UPDATE_CSTATE_INFO request
******************************************************************************/
void mce_update_cstate_info(const mce_cstate_info_t *cstate)
{
/* issue the UPDATE_CSTATE_INFO request */
nvg_update_cstate_info(cstate->cluster, cstate->ccplex, cstate->system,
cstate->wake_mask, cstate->update_wake_mask);
}
/*******************************************************************************
* Handler to read the MCE firmware version and check if it is compatible
* with interface header the BL3-1 was compiled against
******************************************************************************/
void mce_verify_firmware_version(void)
{
uint64_t version;
uint32_t major, minor;
/*
* MCE firmware is not running on simulation platforms.
*/
if (mce_firmware_not_supported()) {
return;
}
/*
* Read the MCE firmware version and extract the major and minor
* version fields
*/
version = nvg_get_version();
minor = (uint32_t)version;
major = (uint32_t)(version >> 32);
INFO("MCE Version - HW=%u:%u, SW=%u:%u\n", major, minor,
TEGRA_NVG_VERSION_MAJOR, TEGRA_NVG_VERSION_MINOR);
/*
* Verify that the MCE firmware version and the interface header
* match
*/
if (major != (uint32_t)TEGRA_NVG_VERSION_MAJOR) {
ERROR("MCE major version mismatch\n");
panic();
}
if (minor < (uint32_t)TEGRA_NVG_VERSION_MINOR) {
ERROR("MCE minor version mismatch\n");
panic();
}
}
#if ENABLE_STRICT_CHECKING_MODE
/*******************************************************************************
* Handler to enable the strict checking mode
******************************************************************************/
void mce_enable_strict_checking(void)
{
uint64_t sctlr = read_sctlr_el3();
int32_t ret = 0;
if (tegra_platform_is_silicon() || tegra_platform_is_fpga()) {
/*
* Step1: TZ-DRAM and TZRAM should be setup before the MMU is
* enabled.
*
* The common code makes sure that TZDRAM/TZRAM are already
* enabled before calling into this handler. If this is not the
* case, the following sequence must be executed before moving
* on to step 2.
*
* tlbialle1is();
* tlbialle3is();
* dsbsy();
* isb();
*
*/
if ((sctlr & (uint64_t)SCTLR_M_BIT) == (uint64_t)SCTLR_M_BIT) {
tlbialle1is();
tlbialle3is();
dsbsy();
isb();
}
/*
* Step2: SCF flush - Clean and invalidate caches and clear the
* TR-bits
*/
ret = nvg_roc_clean_cache_trbits();
if (ret < 0) {
ERROR("%s: flush cache_trbits failed(%d)\n", __func__,
ret);
return;
}
/*
* Step3: Issue the SECURITY_CONFIG request to MCE to enable
* strict checking mode.
*/
nvg_enable_strict_checking_mode();
}
}
void mce_verify_strict_checking(void)
{
bool is_silicon = tegra_platform_is_silicon();
bool is_fpga = tegra_platform_is_fpga();
if (is_silicon || is_fpga) {
nvg_verify_strict_checking_mode();
}
}
#endif
/*******************************************************************************
* Handler to power down the entire system
******************************************************************************/
void mce_system_shutdown(void)
{
nvg_system_shutdown();
}
/*******************************************************************************
* Handler to reboot the entire system
******************************************************************************/
void mce_system_reboot(void)
{
nvg_system_reboot();
}
/*******************************************************************************
* Handler to clear CCPLEX->HSM correctable RAS error signal.
******************************************************************************/
void mce_clear_hsm_corr_status(void)
{
nvg_clear_hsm_corr_status();
}
@@ -0,0 +1,262 @@
/*
* Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <errno.h>
#include <arch.h>
#include <arch_helpers.h>
#include <common/debug.h>
#include <denver.h>
#include <lib/mmio.h>
#include <mce_private.h>
#include <platform_def.h>
#include <t194_nvg.h>
#include <tegra_private.h>
#define ID_AFR0_EL1_CACHE_OPS_SHIFT U(12)
#define ID_AFR0_EL1_CACHE_OPS_MASK U(0xF)
/*
* Reports the major and minor version of this interface.
*
* NVGDATA[0:31]: SW(R) Minor Version
* NVGDATA[32:63]: SW(R) Major Version
*/
uint64_t nvg_get_version(void)
{
nvg_set_request((uint64_t)TEGRA_NVG_CHANNEL_VERSION);
return (uint64_t)nvg_get_result();
}
/*
* Set the expected wake time in TSC ticks for the next low-power state the
* core enters.
*
* NVGDATA[0:31]: SW(RW), WAKE_TIME
*/
void nvg_set_wake_time(uint32_t wake_time)
{
/* time (TSC ticks) until the core is expected to get a wake event */
nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_WAKE_TIME, (uint64_t)wake_time);
}
/*
* This request allows updating of CLUSTER_CSTATE, CCPLEX_CSTATE and
* SYSTEM_CSTATE values.
*
* NVGDATA[0:2]: SW(RW), CLUSTER_CSTATE
* NVGDATA[7]: SW(W), update cluster flag
* NVGDATA[8:10]: SW(RW), CG_CSTATE
* NVGDATA[15]: SW(W), update ccplex flag
* NVGDATA[16:19]: SW(RW), SYSTEM_CSTATE
* NVGDATA[23]: SW(W), update system flag
* NVGDATA[31]: SW(W), update wake mask flag
* NVGDATA[32:63]: SW(RW), WAKE_MASK
*/
void nvg_update_cstate_info(uint32_t cluster, uint32_t ccplex,
uint32_t system, uint32_t wake_mask, uint8_t update_wake_mask)
{
uint64_t val = 0;
/* update CLUSTER_CSTATE? */
if (cluster != 0U) {
val |= ((uint64_t)cluster & CLUSTER_CSTATE_MASK) |
CLUSTER_CSTATE_UPDATE_BIT;
}
/* update CCPLEX_CSTATE? */
if (ccplex != 0U) {
val |= (((uint64_t)ccplex & CCPLEX_CSTATE_MASK) << CCPLEX_CSTATE_SHIFT) |
CCPLEX_CSTATE_UPDATE_BIT;
}
/* update SYSTEM_CSTATE? */
if (system != 0U) {
val |= (((uint64_t)system & SYSTEM_CSTATE_MASK) << SYSTEM_CSTATE_SHIFT) |
SYSTEM_CSTATE_UPDATE_BIT;
}
/* update wake mask value? */
if (update_wake_mask != 0U) {
val |= CSTATE_WAKE_MASK_UPDATE_BIT;
}
/* set the wake mask */
val |= ((uint64_t)wake_mask & CSTATE_WAKE_MASK_CLEAR) << CSTATE_WAKE_MASK_SHIFT;
/* set the updated cstate info */
nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_CSTATE_INFO, val);
}
/*
* Return a non-zero value if the CCPLEX is able to enter SC7
*
* NVGDATA[0]: SW(R), Is allowed result
*/
int32_t nvg_is_sc7_allowed(void)
{
/* issue command to check if SC7 is allowed */
nvg_set_request((uint64_t)TEGRA_NVG_CHANNEL_IS_SC7_ALLOWED);
/* 1 = SC7 allowed, 0 = SC7 not allowed */
return (int32_t)nvg_get_result();
}
/*
* Wake an offlined logical core. Note that a core is offlined by entering
* a C-state where the WAKE_MASK is all 0.
*
* NVGDATA[0:3]: SW(W) logical core to online
*/
int32_t nvg_online_core(uint32_t core)
{
int32_t ret = 0;
/* sanity check the core ID value */
if (core > (uint32_t)PLATFORM_CORE_COUNT) {
ERROR("%s: unknown core id (%d)\n", __func__, core);
ret = -EINVAL;
} else {
/* get a core online */
nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_ONLINE_CORE,
(uint64_t)core & MCE_CORE_ID_MASK);
}
return ret;
}
/*
* MC GSC (General Security Carveout) register values are expected to be
* changed by TrustZone ARM code after boot.
*
* NVGDATA[0:15] SW(R) GSC enun
*/
int32_t nvg_update_ccplex_gsc(uint32_t gsc_idx)
{
int32_t ret = 0;
/* sanity check GSC ID */
if (gsc_idx > (uint32_t)TEGRA_NVG_CHANNEL_UPDATE_GSC_VPR) {
ERROR("%s: unknown gsc_idx (%u)\n", __func__, gsc_idx);
ret = -EINVAL;
} else {
nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_UPDATE_CCPLEX_GSC,
(uint64_t)gsc_idx);
}
return ret;
}
/*
* Cache clean and invalidate, clear TR-bit operation for all CCPLEX caches.
*/
int32_t nvg_roc_clean_cache_trbits(void)
{
int32_t ret = 0;
/* check if cache flush through mts is supported */
if (((read_id_afr0_el1() >> ID_AFR0_EL1_CACHE_OPS_SHIFT) &
ID_AFR0_EL1_CACHE_OPS_MASK) == 1U) {
if (nvg_cache_inval_all() == 0U) {
ERROR("%s: failed\n", __func__);
ret = -ENODEV;
}
} else {
ret = -ENOTSUP;
}
return ret;
}
/*
* Set the power state for a core
*/
int32_t nvg_enter_cstate(uint32_t state, uint32_t wake_time)
{
int32_t ret = 0;
uint64_t val = 0ULL;
/* check for allowed power state */
if ((state != (uint32_t)TEGRA_NVG_CORE_C0) &&
(state != (uint32_t)TEGRA_NVG_CORE_C1) &&
(state != (uint32_t)TEGRA_NVG_CORE_C6) &&
(state != (uint32_t)TEGRA_NVG_CORE_C7))
{
ERROR("%s: unknown cstate (%u)\n", __func__, state);
ret = -EINVAL;
} else {
/* time (TSC ticks) until the core is expected to get a wake event */
nvg_set_wake_time(wake_time);
/* set the core cstate */
val = read_actlr_el1() & ~ACTLR_EL1_PMSTATE_MASK;
write_actlr_el1(val | (uint64_t)state);
}
return ret;
}
#if ENABLE_STRICT_CHECKING_MODE
/*
* Enable strict checking mode
*
* NVGDATA[3] strict_check ON + lock
*/
void nvg_enable_strict_checking_mode(void)
{
uint64_t params = (uint64_t)(STRICT_CHECKING_ENABLED_SET |
STRICT_CHECKING_LOCKED_SET);
nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_SECURITY_CONFIG, params);
}
void nvg_verify_strict_checking_mode(void)
{
uint64_t params = (uint64_t)(STRICT_CHECKING_ENABLED_SET |
STRICT_CHECKING_LOCKED_SET);
nvg_set_request((uint64_t)TEGRA_NVG_CHANNEL_SECURITY_CONFIG);
assert(params == (uint64_t)nvg_get_result());
}
#endif
/*
* Request a reboot
*
* NVGDATA[0]: reboot command
*/
void nvg_system_reboot(void)
{
/* issue command for reboot */
nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_SHUTDOWN,
(uint64_t)TEGRA_NVG_REBOOT);
}
/*
* Request a shutdown
*
* NVGDATA[0]: shutdown command
*/
void nvg_system_shutdown(void)
{
/* issue command for shutdown */
nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_SHUTDOWN,
(uint64_t)TEGRA_NVG_SHUTDOWN);
}
/*
* Request to clear CCPLEX->HSM correctable error signal.
* NVGDATA[1]: A write of 1 clears the CCPLEX->HSM correctable error signal,
* A write of 0 has no effect.
*/
void nvg_clear_hsm_corr_status(void)
{
nvg_hsm_error_ctrl_channel_t status = { .bits = { .corr = 1U, }, };
nvg_set_request_data((uint64_t)TEGRA_NVG_CHANNEL_HSM_ERROR_CTRL, status.flat);
}
@@ -0,0 +1,511 @@
/*
* Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <errno.h>
#include <stdbool.h>
#include <arch_helpers.h>
#include <bpmp_ipc.h>
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <lib/mmio.h>
#include <lib/psci/psci.h>
#include <se.h>
#include <tegra_platform.h>
#include "se_private.h"
/*******************************************************************************
* Constants and Macros
******************************************************************************/
#define ERR_STATUS_SW_CLEAR U(0xFFFFFFFF)
#define INT_STATUS_SW_CLEAR U(0xFFFFFFFF)
#define MAX_TIMEOUT_MS U(1000) /* Max. timeout of 1s */
#define NUM_SE_REGS_TO_SAVE U(4)
#define BYTES_IN_WORD U(4)
#define SHA256_MAX_HASH_RESULT U(7)
#define SHA256_DST_SIZE U(32)
#define SHA_FIRST_OP U(1)
#define MAX_SHA_ENGINE_CHUNK_SIZE U(0xFFFFFF)
#define SHA256_MSG_LENGTH_ONETIME U(0xFFFF)
/*******************************************************************************
* Data structure and global variables
******************************************************************************/
static uint32_t se_regs[NUM_SE_REGS_TO_SAVE];
/*
* Check that SE operation has completed after kickoff.
*
* This function is invoked after an SE operation has been started,
* and it checks the following conditions:
*
* 1. SE_STATUS = IDLE
* 2. AHB bus data transfer is complete.
* 3. SE_ERR_STATUS is clean.
*/
static bool tegra_se_is_operation_complete(void)
{
uint32_t val = 0, timeout = 0, sha_status, aes_status;
int32_t ret = 0;
bool se_is_busy, txn_has_errors, txn_successful;
/*
* Poll the status register to check if the operation
* completed.
*/
do {
val = tegra_se_read_32(CTX_SAVE_AUTO_STATUS);
se_is_busy = ((val & CTX_SAVE_AUTO_SE_BUSY) != 0U);
/* sleep until SE finishes */
if (se_is_busy) {
mdelay(1);
timeout++;
}
} while (se_is_busy && (timeout < MAX_TIMEOUT_MS));
/* any transaction errors? */
txn_has_errors = (tegra_se_read_32(SHA_ERR_STATUS) != 0U) ||
(tegra_se_read_32(AES0_ERR_STATUS) != 0U);
/* transaction successful? */
sha_status = tegra_se_read_32(SHA_INT_STATUS) & SHA_SE_OP_DONE;
aes_status = tegra_se_read_32(AES0_INT_STATUS) & AES0_SE_OP_DONE;
txn_successful = (sha_status == SHA_SE_OP_DONE) &&
(aes_status == AES0_SE_OP_DONE);
if ((timeout == MAX_TIMEOUT_MS) || txn_has_errors || !txn_successful) {
ERROR("%s: Atomic context save operation failed!\n",
__func__);
ret = -ECANCELED;
}
return (ret == 0);
}
/*
* Wait for SE engine to be idle and clear any pending interrupts, before
* starting the next SE operation.
*/
static bool tegra_se_is_ready(void)
{
int32_t ret = 0;
uint32_t val = 0, timeout = 0;
bool se_is_ready;
/* Wait for previous operation to finish */
do {
val = tegra_se_read_32(CTX_SAVE_AUTO_STATUS);
se_is_ready = (val == CTX_SAVE_AUTO_SE_READY);
/* sleep until SE is ready */
if (!se_is_ready) {
mdelay(1);
timeout++;
}
} while (!se_is_ready && (timeout < MAX_TIMEOUT_MS));
if (timeout == MAX_TIMEOUT_MS) {
ERROR("%s: SE is not ready!\n", __func__);
ret = -ETIMEDOUT;
}
/* Clear any pending interrupts from previous operation */
tegra_se_write_32(AES0_INT_STATUS, INT_STATUS_SW_CLEAR);
tegra_se_write_32(AES1_INT_STATUS, INT_STATUS_SW_CLEAR);
tegra_se_write_32(RSA_INT_STATUS, INT_STATUS_SW_CLEAR);
tegra_se_write_32(SHA_INT_STATUS, INT_STATUS_SW_CLEAR);
/* Clear error status for each engine seen from current port */
tegra_se_write_32(AES0_ERR_STATUS, ERR_STATUS_SW_CLEAR);
tegra_se_write_32(AES1_ERR_STATUS, ERR_STATUS_SW_CLEAR);
tegra_se_write_32(RSA_ERR_STATUS, ERR_STATUS_SW_CLEAR);
tegra_se_write_32(SHA_ERR_STATUS, ERR_STATUS_SW_CLEAR);
return (ret == 0);
}
/*
* During System Suspend, this handler triggers the hardware context
* save operation.
*/
static int32_t tegra_se_save_context(void)
{
int32_t ret = -ECANCELED;
/*
* 1. Ensure all SE Driver including RNG1/PKA1 are shut down.
* TSEC/R5s are powergated/idle. All tasks on SE1~SE4, RNG1,
* PKA1 are wrapped up. SE0 is ready for use.
* 2. Clear interrupt/error in SE0 status register.
* 3. Scrub SE0 register to avoid false failure for illegal
* configuration. Probably not needed, dependent on HW
* implementation.
* 4. Check SE is ready for HW CTX_SAVE by polling
* SE_CTX_SAVE_AUTO_STATUS.SE_READY.
*
* Steps 1-4 are executed by tegra_se_is_ready().
*
* 5. Issue context save command.
* 6. Check SE is busy with CTX_SAVE, the command in step5 was not
* dropped for ongoing traffic in any of SE port/engine.
* 7. Poll SE register or wait for SE APB interrupt for task completion
* a. Polling: Read SE_CTX_SAVE_AUTO_STATUS.BUSY till it reports IDLE
* b. Interrupt: After receiving interrupt from SE APB, read
* SE_CTX_SAVE_AUTO_STATUS.BUSY till it reports IDLE.
* 8. Check AES0 and SHA ERR_STATUS to ensure no error case.
* 9. Check AES0 and SHA INT_STATUS to ensure operation has successfully
* completed.
*
* Steps 6-9 are executed by tegra_se_is_operation_complete().
*/
if (tegra_se_is_ready()) {
/* Issue context save command */
tegra_se_write_32(AES0_OPERATION, SE_OP_CTX_SAVE);
/* Wait for operation to finish */
if (tegra_se_is_operation_complete()) {
ret = 0;
}
}
return ret;
}
/*
* Check that SE operation has completed after kickoff
* This function is invoked after an SE operation has been started,
* and it checks the following conditions:
* 1. SE0_INT_STATUS = SE0_OP_DONE
* 2. SE0_STATUS = IDLE
* 3. SE0_ERR_STATUS is clean.
*/
static int32_t tegra_se_sha256_hash_operation_complete(void)
{
uint32_t val = 0U;
/* Poll the SE interrupt register to ensure H/W operation complete */
val = tegra_se_read_32(SE0_INT_STATUS_REG_OFFSET);
while (SE0_INT_OP_DONE(val) == SE0_INT_OP_DONE_CLEAR) {
val = tegra_se_read_32(SE0_INT_STATUS_REG_OFFSET);
if (SE0_INT_OP_DONE(val) != SE0_INT_OP_DONE_CLEAR) {
break;
}
}
/* Poll the SE status idle to ensure H/W operation complete */
val = tegra_se_read_32(SE0_SHA_STATUS_0);
while (val != SE0_SHA_STATUS_IDLE) {
val = tegra_se_read_32(SE0_SHA_STATUS_0);
if (val == SE0_SHA_STATUS_IDLE) {
break;
}
}
/* Ensure that no errors are thrown during operation */
val = tegra_se_read_32(SE0_ERR_STATUS_REG_OFFSET);
if (val != 0U) {
ERROR("%s: error during SE operation! 0x%x", __func__,
val);
return -ENOTSUP;
}
return 0;
}
/*
* Security engine primitive normal operations
*/
static int32_t tegra_se_start_normal_operation(uint64_t src_addr,
uint32_t nbytes, uint32_t last_buf, uint32_t src_len_inbytes)
{
uint32_t val = 0U;
uint32_t src_in_lo;
uint32_t src_in_msb;
uint32_t src_in_hi;
int32_t ret = 0;
if ((src_addr == 0ULL) || (nbytes == 0U))
return -EINVAL;
src_in_lo = (uint32_t)src_addr;
src_in_msb = (uint32_t)((src_addr >> 32U) & 0xFFU);
src_in_hi = ((src_in_msb << SE0_IN_HI_ADDR_HI_0_MSB_SHIFT) |
(nbytes & MAX_SHA_ENGINE_CHUNK_SIZE));
/* set SRC_IN_ADDR_LO and SRC_IN_ADDR_HI*/
tegra_se_write_32(SE0_IN_ADDR, src_in_lo);
tegra_se_write_32(SE0_IN_HI_ADDR_HI, src_in_hi);
val = tegra_se_read_32(SE0_INT_STATUS_REG_OFFSET);
if (val > 0U) {
tegra_se_write_32(SE0_INT_STATUS_REG_OFFSET, 0x0U);
}
/* Enable SHA interrupt for SE0 Operation */
tegra_se_write_32(SE0_SHA_INT_ENABLE, 0x1aU);
/* flush to DRAM for SE to use the updated contents */
flush_dcache_range(src_addr, src_len_inbytes);
/* Start SHA256 operation */
if (last_buf == 1U) {
tegra_se_write_32(SE0_OPERATION_REG_OFFSET, SE0_OP_START |
SE0_UNIT_OPERATION_PKT_LASTBUF_FIELD);
} else {
tegra_se_write_32(SE0_OPERATION_REG_OFFSET, SE0_OP_START);
}
return ret;
}
static int32_t tegra_se_calculate_sha256_hash(uint64_t src_addr,
uint32_t src_len_inbyte)
{
uint32_t val, last_buf, i;
int32_t ret = 0;
uint32_t operations;
uint64_t src_len_inbits;
uint32_t len_bits_msb;
uint32_t len_bits_lsb;
uint32_t number_of_operations, max_bytes, bytes_left, remaining_bytes;
if (src_len_inbyte > MAX_SHA_ENGINE_CHUNK_SIZE) {
ERROR("SHA input chunk size too big: 0x%x\n", src_len_inbyte);
return -EINVAL;
}
if (src_addr == 0ULL) {
return -EINVAL;
}
/* number of bytes per operation */
max_bytes = (SHA256_HASH_SIZE_BYTES * SHA256_MSG_LENGTH_ONETIME);
src_len_inbits = (uint32_t)(src_len_inbyte * 8U);
len_bits_msb = (uint32_t)(src_len_inbits >> 32U);
len_bits_lsb = (uint32_t)src_len_inbits;
/* program SE0_CONFIG for SHA256 operation */
val = (uint32_t)(SE0_CONFIG_ENC_ALG_SHA | SE0_CONFIG_ENC_MODE_SHA256 |
SE0_CONFIG_DEC_ALG_NOP | SE0_CONFIG_DST_HASHREG);
tegra_se_write_32(SE0_SHA_CONFIG, val);
/* set SE0_SHA_MSG_LENGTH registers */
tegra_se_write_32(SE0_SHA_MSG_LENGTH_0, len_bits_lsb);
tegra_se_write_32(SE0_SHA_MSG_LEFT_0, len_bits_lsb);
tegra_se_write_32(SE0_SHA_MSG_LENGTH_1, len_bits_msb);
/* zero out unused SE0_SHA_MSG_LENGTH and SE0_SHA_MSG_LEFT */
tegra_se_write_32(SE0_SHA_MSG_LENGTH_2, 0U);
tegra_se_write_32(SE0_SHA_MSG_LENGTH_3, 0U);
tegra_se_write_32(SE0_SHA_MSG_LEFT_1, 0U);
tegra_se_write_32(SE0_SHA_MSG_LEFT_2, 0U);
tegra_se_write_32(SE0_SHA_MSG_LEFT_3, 0U);
number_of_operations = (src_len_inbyte / max_bytes);
remaining_bytes = (src_len_inbyte % max_bytes);
if (remaining_bytes > 0U) {
number_of_operations += 1U;
}
/*
* 1. Operations == 1: program SE0_SHA_TASK register to initiate SHA256
* hash generation by setting
* 1(SE0_SHA_CONFIG_HW_INIT_HASH) to SE0_SHA_TASK
* and start SHA256-normal operation.
* 2. 1 < Operations < number_of_operations: program SE0_SHA_TASK to
* 0(SE0_SHA_CONFIG_HW_INIT_HASH_DISABLE) to load
* intermediate SHA256 digest result from
* HASH_RESULT register to continue SHA256
* generation and start SHA256-normal operation.
* 3. Operations == number_of_operations: continue with step 2 and set
* max_bytes to bytes_left to process final
* hash-result generation and start SHA256-normal
* operation.
*/
bytes_left = src_len_inbyte;
for (operations = 1U; operations <= number_of_operations;
operations++) {
if (operations == SHA_FIRST_OP) {
val = SE0_SHA_CONFIG_HW_INIT_HASH;
} else {
/* Load intermediate SHA digest result to
* SHA:HASH_RESULT(0..7) to continue the SHA
* calculation and tell the SHA engine to use it.
*/
for (i = 0U; (i / BYTES_IN_WORD) <=
SHA256_MAX_HASH_RESULT; i += BYTES_IN_WORD) {
val = tegra_se_read_32(SE0_SHA_HASH_RESULT_0 +
i);
tegra_se_write_32(SE0_SHA_HASH_RESULT_0 + i,
val);
}
val = SE0_SHA_CONFIG_HW_INIT_HASH_DISABLE;
if (len_bits_lsb <= (max_bytes * 8U)) {
len_bits_lsb = (remaining_bytes * 8U);
} else {
len_bits_lsb -= (max_bytes * 8U);
}
tegra_se_write_32(SE0_SHA_MSG_LEFT_0, len_bits_lsb);
}
tegra_se_write_32(SE0_SHA_TASK_CONFIG, val);
max_bytes = (SHA256_HASH_SIZE_BYTES *
SHA256_MSG_LENGTH_ONETIME);
if (bytes_left < max_bytes) {
max_bytes = bytes_left;
last_buf = 1U;
} else {
bytes_left = bytes_left - max_bytes;
last_buf = 0U;
}
/* start operation */
ret = tegra_se_start_normal_operation(src_addr, max_bytes,
last_buf, src_len_inbyte);
if (ret != 0) {
ERROR("Error during SE operation! 0x%x", ret);
return -EINVAL;
}
}
return ret;
}
static int32_t tegra_se_save_sha256_pmc_scratch(void)
{
uint32_t val = 0U, hash_offset = 0U, scratch_offset = 0U;
int32_t ret;
/* Check SE0 operation status */
ret = tegra_se_sha256_hash_operation_complete();
if (ret != 0) {
ERROR("SE operation complete Failed! 0x%x", ret);
return ret;
}
for (scratch_offset = SECURE_SCRATCH_TZDRAM_SHA256_HASH_START;
scratch_offset <= SECURE_SCRATCH_TZDRAM_SHA256_HASH_END;
scratch_offset += BYTES_IN_WORD) {
val = tegra_se_read_32(SE0_SHA_HASH_RESULT_0 + hash_offset);
mmio_write_32((uint32_t)(TEGRA_SCRATCH_BASE + scratch_offset),
val);
hash_offset += BYTES_IN_WORD;
}
return 0;
}
/*
* Handler to generate SHA256 and save HASH-result to pmc-scratch register
*/
int32_t tegra_se_calculate_save_sha256(uint64_t src_addr,
uint32_t src_len_inbyte)
{
uint32_t security;
int32_t val = 0;
/* Set SE_SOFT_SETTINGS=SE_SECURE to prevent NS process to change SE
* registers.
*/
security = tegra_se_read_32(SE0_SECURITY);
tegra_se_write_32(SE0_SECURITY, security | SE0_SECURITY_SE_SOFT_SETTING);
/* Bootrom enable IN_ID bit in SE0_SHA_GSCID_0 register during SC7-exit, causing
* SE0 ignores SE0 operation, and therefore failure of 2nd iteration of SC7 cycle.
*/
tegra_se_write_32(SE0_SHA_GSCID_0, 0x0U);
/* Calculate SHA256 of BL31 */
val = tegra_se_calculate_sha256_hash(src_addr, src_len_inbyte);
if (val != 0) {
ERROR("%s: SHA256 generation failed\n", __func__);
return val;
}
/*
* Reset SE_SECURE to previous value.
*/
tegra_se_write_32(SE0_SECURITY, security);
/* copy sha256_dst to PMC Scratch register */
val = tegra_se_save_sha256_pmc_scratch();
if (val != 0) {
ERROR("%s: SE0 status Error.\n", __func__);
}
return val;
}
/*
* Handler to power down the SE hardware blocks - SE, RNG1 and PKA1. This
* needs to be called only during System Suspend.
*/
int32_t tegra_se_suspend(void)
{
int32_t ret = 0;
/* initialise communication channel with BPMP */
assert(tegra_bpmp_ipc_init() == 0);
/* Enable SE clock before SE context save */
ret = tegra_bpmp_ipc_enable_clock(TEGRA194_CLK_SE);
assert(ret == 0);
/* save SE registers */
se_regs[0] = mmio_read_32(TEGRA_SE0_BASE + SE0_MUTEX_WATCHDOG_NS_LIMIT);
se_regs[1] = mmio_read_32(TEGRA_SE0_BASE + SE0_AES0_ENTROPY_SRC_AGE_CTRL);
se_regs[2] = mmio_read_32(TEGRA_RNG1_BASE + RNG1_MUTEX_WATCHDOG_NS_LIMIT);
se_regs[3] = mmio_read_32(TEGRA_PKA1_BASE + PKA1_MUTEX_WATCHDOG_NS_LIMIT);
/* Save SE context. The BootROM restores it during System Resume */
ret = tegra_se_save_context();
if (ret != 0) {
ERROR("%s: context save failed (%d)\n", __func__, ret);
}
/* Disable SE clock after SE context save */
ret = tegra_bpmp_ipc_disable_clock(TEGRA194_CLK_SE);
assert(ret == 0);
return ret;
}
/*
* Handler to power up the SE hardware block(s) during System Resume.
*/
void tegra_se_resume(void)
{
int32_t ret = 0;
/* initialise communication channel with BPMP */
assert(tegra_bpmp_ipc_init() == 0);
/* Enable SE clock before SE context restore */
ret = tegra_bpmp_ipc_enable_clock(TEGRA194_CLK_SE);
assert(ret == 0);
/*
* When TZ takes over after System Resume, TZ should first reconfigure
* SE_MUTEX_WATCHDOG_NS_LIMIT, PKA1_MUTEX_WATCHDOG_NS_LIMIT,
* RNG1_MUTEX_WATCHDOG_NS_LIMIT and SE_ENTROPY_SRC_AGE_CTRL before
* other operations.
*/
mmio_write_32(TEGRA_SE0_BASE + SE0_MUTEX_WATCHDOG_NS_LIMIT, se_regs[0]);
mmio_write_32(TEGRA_SE0_BASE + SE0_AES0_ENTROPY_SRC_AGE_CTRL, se_regs[1]);
mmio_write_32(TEGRA_RNG1_BASE + RNG1_MUTEX_WATCHDOG_NS_LIMIT, se_regs[2]);
mmio_write_32(TEGRA_PKA1_BASE + PKA1_MUTEX_WATCHDOG_NS_LIMIT, se_regs[3]);
/* Disable SE clock after SE context restore */
ret = tegra_bpmp_ipc_disable_clock(TEGRA194_CLK_SE);
assert(ret == 0);
}
@@ -0,0 +1,165 @@
/*
* Copyright (c) 2020, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef SE_PRIVATE_H
#define SE_PRIVATE_H
#include <lib/utils_def.h>
#include <tegra_def.h>
/* SE0 security register */
#define SE0_SECURITY U(0x18)
#define SE0_SECURITY_SE_SOFT_SETTING (((uint32_t)1) << 16U)
/* SE0 SHA GSCID register */
#define SE0_SHA_GSCID_0 U(0x100)
/* SE0 config register */
#define SE0_SHA_CONFIG U(0x104)
#define SE0_SHA_TASK_CONFIG U(0x108)
#define SE0_SHA_CONFIG_HW_INIT_HASH (((uint32_t)1) << 0U)
#define SE0_SHA_CONFIG_HW_INIT_HASH_DISABLE U(0)
#define SE0_CONFIG_ENC_ALG_SHIFT U(12)
#define SE0_CONFIG_ENC_ALG_SHA \
(((uint32_t)3) << SE0_CONFIG_ENC_ALG_SHIFT)
#define SE0_CONFIG_DEC_ALG_SHIFT U(8)
#define SE0_CONFIG_DEC_ALG_NOP \
(((uint32_t)0) << SE0_CONFIG_DEC_ALG_SHIFT)
#define SE0_CONFIG_DST_SHIFT U(2)
#define SE0_CONFIG_DST_HASHREG \
(((uint32_t)1) << SE0_CONFIG_DST_SHIFT)
#define SHA256_HASH_SIZE_BYTES U(256)
#define SE0_CONFIG_ENC_MODE_SHIFT U(24)
#define SE0_CONFIG_ENC_MODE_SHA256 \
(((uint32_t)5) << SE0_CONFIG_ENC_MODE_SHIFT)
/* SHA input message length */
#define SE0_IN_ADDR U(0x10c)
#define SE0_IN_HI_ADDR_HI U(0x110)
#define SE0_IN_HI_ADDR_HI_0_MSB_SHIFT U(24)
/* SHA input message length */
#define SE0_SHA_MSG_LENGTH_0 U(0x11c)
#define SE0_SHA_MSG_LENGTH_1 U(0x120)
#define SE0_SHA_MSG_LENGTH_2 U(0x124)
#define SE0_SHA_MSG_LENGTH_3 U(0x128)
/* SHA input message left */
#define SE0_SHA_MSG_LEFT_0 U(0x12c)
#define SE0_SHA_MSG_LEFT_1 U(0x130)
#define SE0_SHA_MSG_LEFT_2 U(0x134)
#define SE0_SHA_MSG_LEFT_3 U(0x138)
/* SE HASH-RESULT */
#define SE0_SHA_HASH_RESULT_0 U(0x13c)
/* SE OPERATION */
#define SE0_OPERATION_REG_OFFSET U(0x17c)
#define SE0_UNIT_OPERATION_PKT_LASTBUF_SHIFT U(16)
#define SE0_UNIT_OPERATION_PKT_LASTBUF_FIELD \
((uint32_t)0x1 << SE0_UNIT_OPERATION_PKT_LASTBUF_SHIFT)
#define SE0_OPERATION_SHIFT U(0)
#define SE0_OP_START \
(((uint32_t)0x1) << SE0_OPERATION_SHIFT)
/* SE Interrupt */
#define SE0_SHA_INT_ENABLE U(0x180)
#define SE0_INT_STATUS_REG_OFFSET U(0x184)
#define SE0_INT_OP_DONE_SHIFT U(4)
#define SE0_INT_OP_DONE_CLEAR \
(((uint32_t)0U) << SE0_INT_OP_DONE_SHIFT)
#define SE0_INT_OP_DONE(x) \
((x) & (((uint32_t)0x1U) << SE0_INT_OP_DONE_SHIFT))
/* SE SHA Status */
#define SE0_SHA_STATUS_0 U(0x188)
#define SE0_SHA_STATUS_IDLE U(0)
/* SE error status */
#define SE0_ERR_STATUS_REG_OFFSET U(0x18c)
#define SE0_ERR_STATUS_CLEAR U(0)
/* SE error status */
#define SECURE_SCRATCH_TZDRAM_SHA256_HASH_START SECURE_SCRATCH_RSV68_LO
#define SECURE_SCRATCH_TZDRAM_SHA256_HASH_END SECURE_SCRATCH_RSV71_HI
/* SE0_INT_ENABLE_0 */
#define SE0_INT_ENABLE U(0x88)
#define SE0_DISABLE_ALL_INT U(0x0)
/* SE0_INT_STATUS_0 */
#define SE0_INT_STATUS U(0x8C)
#define SE0_CLEAR_ALL_INT_STATUS U(0x3F)
/* SE0_SHA_INT_STATUS_0 */
#define SHA_INT_STATUS U(0x184)
#define SHA_SE_OP_DONE (U(1) << 4)
/* SE0_SHA_ERR_STATUS_0 */
#define SHA_ERR_STATUS U(0x18C)
/* SE0_AES0_INT_STATUS_0 */
#define AES0_INT_STATUS U(0x2F0)
#define AES0_SE_OP_DONE (U(1) << 4)
/* SE0_AES0_ERR_STATUS_0 */
#define AES0_ERR_STATUS U(0x2F8)
/* SE0_AES1_INT_STATUS_0 */
#define AES1_INT_STATUS U(0x4F0)
/* SE0_AES1_ERR_STATUS_0 */
#define AES1_ERR_STATUS U(0x4F8)
/* SE0_RSA_INT_STATUS_0 */
#define RSA_INT_STATUS U(0x758)
/* SE0_RSA_ERR_STATUS_0 */
#define RSA_ERR_STATUS U(0x760)
/* SE0_AES0_OPERATION_0 */
#define AES0_OPERATION U(0x238)
#define OP_MASK_BITS U(0x7)
#define SE_OP_CTX_SAVE U(0x3)
/* SE0_AES0_CTX_SAVE_CONFIG_0 */
#define CTX_SAVE_CONFIG U(0x2D4)
/* SE0_AES0_CTX_SAVE_AUTO_STATUS_0 */
#define CTX_SAVE_AUTO_STATUS U(0x300)
#define CTX_SAVE_AUTO_SE_READY U(0xFF)
#define CTX_SAVE_AUTO_SE_BUSY (U(0x1) << 31)
/* SE0_AES0_CTX_SAVE_AUTO_CTRL_0 */
#define CTX_SAVE_AUTO_CTRL U(0x304)
#define SE_CTX_SAVE_AUTO_EN (U(0x1) << 0)
#define SE_CTX_SAVE_AUTO_LOCK_EN (U(0x1) << 1)
/* SE0_AES0_CTX_SAVE_AUTO_START_ADDR_0 */
#define CTX_SAVE_AUTO_START_ADDR U(0x308)
/* SE0_AES0_CTX_SAVE_AUTO_START_ADDR_HI_0 */
#define CTX_SAVE_AUTO_START_ADDR_HI U(0x30C)
/*******************************************************************************
* Inline functions definition
******************************************************************************/
static inline uint32_t tegra_se_read_32(uint32_t offset)
{
return mmio_read_32((uint32_t)(TEGRA_SE0_BASE + offset));
}
static inline void tegra_se_write_32(uint32_t offset, uint32_t val)
{
mmio_write_32((uint32_t)(TEGRA_SE0_BASE + offset), val);
}
#endif /* SE_PRIVATE_H */
@@ -0,0 +1,83 @@
/*
* Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <common/bl_common.h>
#include <mce.h>
#include <memctrl_v2.h>
#include <tegra_platform.h>
#include <tegra_private.h>
/*******************************************************************************
* Array to hold MC context for Tegra194
******************************************************************************/
static __attribute__((aligned(16))) mc_regs_t tegra194_mc_context[] = {
_START_OF_TABLE_,
mc_smmu_bypass_cfg, /* TBU settings */
_END_OF_TABLE_,
};
/*******************************************************************************
* Handler to return the pointer to the MC's context struct
******************************************************************************/
mc_regs_t *plat_memctrl_get_sys_suspend_ctx(void)
{
/* index of _END_OF_TABLE_ */
tegra194_mc_context[0].val = (uint32_t)ARRAY_SIZE(tegra194_mc_context) - 1U;
return tegra194_mc_context;
}
/*******************************************************************************
* Handler to restore platform specific settings to the memory controller
******************************************************************************/
void plat_memctrl_restore(void)
{
UNUSED_FUNC_NOP(); /* do nothing */
}
/*******************************************************************************
* Handler to program platform specific settings to the memory controller
******************************************************************************/
void plat_memctrl_setup(void)
{
UNUSED_FUNC_NOP(); /* do nothing */
}
/*******************************************************************************
* Handler to program the scratch registers with TZDRAM settings for the
* resume firmware
******************************************************************************/
void plat_memctrl_tzdram_setup(uint64_t phys_base, uint64_t size_in_bytes)
{
uint32_t sec_reg_ctrl = tegra_mc_read_32(MC_SECURITY_CFG_REG_CTRL_0);
uint32_t phys_base_lo = (uint32_t)phys_base & 0xFFF00000;
uint32_t phys_base_hi = (uint32_t)(phys_base >> 32);
/*
* Check TZDRAM carveout register access status. Setup TZDRAM fence
* only if access is enabled.
*/
if ((sec_reg_ctrl & SECURITY_CFG_WRITE_ACCESS_BIT) ==
SECURITY_CFG_WRITE_ACCESS_ENABLE) {
/*
* Setup the Memory controller to allow only secure accesses to
* the TZDRAM carveout
*/
INFO("Configuring TrustZone DRAM Memory Carveout\n");
tegra_mc_write_32(MC_SECURITY_CFG0_0, phys_base_lo);
tegra_mc_write_32(MC_SECURITY_CFG3_0, phys_base_hi);
tegra_mc_write_32(MC_SECURITY_CFG1_0, (uint32_t)(size_in_bytes >> 20));
/*
* MCE propagates the security configuration values across the
* CCPLEX.
*/
(void)mce_update_gsc_tzdram();
}
}
@@ -0,0 +1,505 @@
/*
* Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <assert.h>
#include <stdbool.h>
#include <string.h>
#include <arch_helpers.h>
#include <bpmp_ipc.h>
#include <common/bl_common.h>
#include <common/debug.h>
#include <context.h>
#include <drivers/delay_timer.h>
#include <denver.h>
#include <lib/el3_runtime/context_mgmt.h>
#include <lib/psci/psci.h>
#include <mce.h>
#include <mce_private.h>
#include <memctrl_v2.h>
#include <plat/common/platform.h>
#include <se.h>
#include <smmu.h>
#include <t194_nvg.h>
#include <tegra194_private.h>
#include <tegra_platform.h>
#include <tegra_private.h>
extern uint32_t __tegra194_cpu_reset_handler_data,
__tegra194_cpu_reset_handler_end;
/* TZDRAM offset for saving SMMU context */
#define TEGRA194_SMMU_CTX_OFFSET 16U
/* state id mask */
#define TEGRA194_STATE_ID_MASK 0xFU
/* constants to get power state's wake time */
#define TEGRA194_WAKE_TIME_MASK 0x0FFFFFF0U
#define TEGRA194_WAKE_TIME_SHIFT 4U
/* default core wake mask for CPU_SUSPEND */
#define TEGRA194_CORE_WAKE_MASK 0x180cU
static struct t19x_psci_percpu_data {
uint32_t wake_time;
} __aligned(CACHE_WRITEBACK_GRANULE) t19x_percpu_data[PLATFORM_CORE_COUNT];
int32_t tegra_soc_validate_power_state(uint32_t power_state,
psci_power_state_t *req_state)
{
uint8_t state_id = (uint8_t)psci_get_pstate_id(power_state) &
TEGRA194_STATE_ID_MASK;
uint32_t cpu = plat_my_core_pos();
int32_t ret = PSCI_E_SUCCESS;
/* save the core wake time (in TSC ticks)*/
t19x_percpu_data[cpu].wake_time = (power_state & TEGRA194_WAKE_TIME_MASK)
<< TEGRA194_WAKE_TIME_SHIFT;
/*
* Clean t19x_percpu_data[cpu] to DRAM. This needs to be done to ensure
* that the correct value is read in tegra_soc_pwr_domain_suspend(),
* which is called with caches disabled. It is possible to read a stale
* value from DRAM in that function, because the L2 cache is not flushed
* unless the cluster is entering CC6/CC7.
*/
clean_dcache_range((uint64_t)&t19x_percpu_data[cpu],
sizeof(t19x_percpu_data[cpu]));
/* Sanity check the requested state id */
switch (state_id) {
case PSTATE_ID_CORE_IDLE:
if (psci_get_pstate_type(power_state) != PSTATE_TYPE_STANDBY) {
ret = PSCI_E_INVALID_PARAMS;
break;
}
/* Core idle request */
req_state->pwr_domain_state[MPIDR_AFFLVL0] = PLAT_MAX_RET_STATE;
req_state->pwr_domain_state[MPIDR_AFFLVL1] = PSCI_LOCAL_STATE_RUN;
break;
default:
ERROR("%s: unsupported state id (%d)\n", __func__, state_id);
ret = PSCI_E_INVALID_PARAMS;
break;
}
return ret;
}
int32_t tegra_soc_cpu_standby(plat_local_state_t cpu_state)
{
uint32_t cpu = plat_my_core_pos();
mce_cstate_info_t cstate_info = { 0 };
/* Program default wake mask */
cstate_info.wake_mask = TEGRA194_CORE_WAKE_MASK;
cstate_info.update_wake_mask = 1;
mce_update_cstate_info(&cstate_info);
/* Enter CPU idle */
(void)mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE,
(uint64_t)TEGRA_NVG_CORE_C6,
t19x_percpu_data[cpu].wake_time,
0U);
return PSCI_E_SUCCESS;
}
int32_t tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
{
const plat_local_state_t *pwr_domain_state;
uint8_t stateid_afflvl2;
plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
uint64_t mc_ctx_base;
uint32_t val;
mce_cstate_info_t sc7_cstate_info = {
.cluster = (uint32_t)TEGRA_NVG_CLUSTER_CC6,
.ccplex = (uint32_t)TEGRA_NVG_CG_CG7,
.system = (uint32_t)TEGRA_NVG_SYSTEM_SC7,
.system_state_force = 1U,
.update_wake_mask = 1U,
};
int32_t ret = 0;
/* get the state ID */
pwr_domain_state = target_state->pwr_domain_state;
stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] &
TEGRA194_STATE_ID_MASK;
if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
/* save 'Secure Boot' Processor Feature Config Register */
val = mmio_read_32(TEGRA_MISC_BASE + MISCREG_PFCFG);
mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_SECURE_BOOTP_FCFG, val);
/* save MC context */
mc_ctx_base = params_from_bl2->tzdram_base +
tegra194_get_mc_ctx_offset();
tegra_mc_save_context((uintptr_t)mc_ctx_base);
/*
* Suspend SE, RNG1 and PKA1 only on silcon and fpga,
* since VDK does not support atomic se ctx save
*/
if (tegra_platform_is_silicon() || tegra_platform_is_fpga()) {
ret = tegra_se_suspend();
assert(ret == 0);
}
/* Prepare for system suspend */
mce_update_cstate_info(&sc7_cstate_info);
do {
val = (uint32_t)mce_command_handler(
(uint32_t)MCE_CMD_IS_SC7_ALLOWED,
(uint32_t)TEGRA_NVG_CORE_C7,
MCE_CORE_SLEEP_TIME_INFINITE,
0U);
} while (val == 0U);
/* Instruct the MCE to enter system suspend state */
ret = mce_command_handler(
(uint64_t)MCE_CMD_ENTER_CSTATE,
(uint64_t)TEGRA_NVG_CORE_C7,
MCE_CORE_SLEEP_TIME_INFINITE,
0U);
assert(ret == 0);
/* set system suspend state for house-keeping */
tegra194_set_system_suspend_entry();
}
return PSCI_E_SUCCESS;
}
/*******************************************************************************
* Helper function to check if this is the last ON CPU in the cluster
******************************************************************************/
static bool tegra_last_on_cpu_in_cluster(const plat_local_state_t *states,
uint32_t ncpu)
{
plat_local_state_t target;
bool last_on_cpu = true;
uint32_t num_cpus = ncpu, pos = 0;
do {
target = states[pos];
if (target != PLAT_MAX_OFF_STATE) {
last_on_cpu = false;
}
--num_cpus;
pos++;
} while (num_cpus != 0U);
return last_on_cpu;
}
/*******************************************************************************
* Helper function to get target power state for the cluster
******************************************************************************/
static plat_local_state_t tegra_get_afflvl1_pwr_state(const plat_local_state_t *states,
uint32_t ncpu)
{
uint32_t core_pos = (uint32_t)read_mpidr() & (uint32_t)MPIDR_CPU_MASK;
plat_local_state_t target = states[core_pos];
mce_cstate_info_t cstate_info = { 0 };
/* CPU off */
if (target == PLAT_MAX_OFF_STATE) {
/* Enable cluster powerdn from last CPU in the cluster */
if (tegra_last_on_cpu_in_cluster(states, ncpu)) {
/* Enable CC6 state and turn off wake mask */
cstate_info.cluster = (uint32_t)TEGRA_NVG_CLUSTER_CC6;
cstate_info.ccplex = (uint32_t)TEGRA_NVG_CG_CG7;
cstate_info.system_state_force = 1;
cstate_info.update_wake_mask = 1U;
mce_update_cstate_info(&cstate_info);
} else {
/* Turn off wake_mask */
cstate_info.update_wake_mask = 1U;
mce_update_cstate_info(&cstate_info);
target = PSCI_LOCAL_STATE_RUN;
}
}
return target;
}
/*******************************************************************************
* Platform handler to calculate the proper target power level at the
* specified affinity level
******************************************************************************/
plat_local_state_t tegra_soc_get_target_pwr_state(uint32_t lvl,
const plat_local_state_t *states,
uint32_t ncpu)
{
plat_local_state_t target = PSCI_LOCAL_STATE_RUN;
uint32_t cpu = plat_my_core_pos();
/* System Suspend */
if ((lvl == (uint32_t)MPIDR_AFFLVL2) && (states[cpu] == PSTATE_ID_SOC_POWERDN)) {
target = PSTATE_ID_SOC_POWERDN;
}
/* CPU off, CPU suspend */
if (lvl == (uint32_t)MPIDR_AFFLVL1) {
target = tegra_get_afflvl1_pwr_state(states, ncpu);
}
/* target cluster/system state */
return target;
}
int32_t tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state)
{
const plat_local_state_t *pwr_domain_state =
target_state->pwr_domain_state;
plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
uint8_t stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] &
TEGRA194_STATE_ID_MASK;
uint64_t src_len_in_bytes = (uintptr_t)&__BL31_END__ - (uintptr_t)BL31_BASE;
uint64_t val;
int32_t ret = PSCI_E_SUCCESS;
if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
val = params_from_bl2->tzdram_base +
tegra194_get_cpu_reset_handler_size();
/* initialise communication channel with BPMP */
ret = tegra_bpmp_ipc_init();
assert(ret == 0);
/* Enable SE clock before SE context save */
ret = tegra_bpmp_ipc_enable_clock(TEGRA194_CLK_SE);
assert(ret == 0);
/*
* It is very unlikely that the BL31 image would be
* bigger than 2^32 bytes
*/
assert(src_len_in_bytes < UINT32_MAX);
if (tegra_se_calculate_save_sha256(BL31_BASE,
(uint32_t)src_len_in_bytes) != 0) {
ERROR("Hash calculation failed. Reboot\n");
(void)tegra_soc_prepare_system_reset();
}
/*
* The TZRAM loses power when we enter system suspend. To
* allow graceful exit from system suspend, we need to copy
* BL3-1 over to TZDRAM.
*/
val = params_from_bl2->tzdram_base +
tegra194_get_cpu_reset_handler_size();
memcpy((void *)(uintptr_t)val, (void *)(uintptr_t)BL31_BASE,
src_len_in_bytes);
/* Disable SE clock after SE context save */
ret = tegra_bpmp_ipc_disable_clock(TEGRA194_CLK_SE);
assert(ret == 0);
}
return ret;
}
int32_t tegra_soc_pwr_domain_suspend_pwrdown_early(const psci_power_state_t *target_state)
{
return PSCI_E_NOT_SUPPORTED;
}
int32_t tegra_soc_pwr_domain_on(u_register_t mpidr)
{
uint64_t target_cpu = mpidr & MPIDR_CPU_MASK;
uint64_t target_cluster = (mpidr & MPIDR_CLUSTER_MASK) >>
MPIDR_AFFINITY_BITS;
int32_t ret = 0;
if (target_cluster > ((uint32_t)PLATFORM_CLUSTER_COUNT - 1U)) {
ERROR("%s: unsupported CPU (0x%lx)\n", __func__ , mpidr);
return PSCI_E_NOT_PRESENT;
}
/* construct the target CPU # */
target_cpu += (target_cluster << 1U);
ret = mce_command_handler((uint64_t)MCE_CMD_ONLINE_CORE, target_cpu, 0U, 0U);
if (ret < 0) {
return PSCI_E_DENIED;
}
return PSCI_E_SUCCESS;
}
int32_t tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
{
const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
uint8_t enable_ccplex_lock_step = params_from_bl2->enable_ccplex_lock_step;
uint8_t stateid_afflvl2 = target_state->pwr_domain_state[PLAT_MAX_PWR_LVL];
cpu_context_t *ctx = cm_get_context(NON_SECURE);
uint64_t actlr_elx;
/*
* Reset power state info for CPUs when onlining, we set
* deepest power when offlining a core but that may not be
* requested by non-secure sw which controls idle states. It
* will re-init this info from non-secure software when the
* core come online.
*/
actlr_elx = read_ctx_reg((get_el1_sysregs_ctx(ctx)), (CTX_ACTLR_EL1));
actlr_elx &= ~DENVER_CPU_PMSTATE_MASK;
actlr_elx |= DENVER_CPU_PMSTATE_C1;
write_ctx_reg((get_el1_sysregs_ctx(ctx)), (CTX_ACTLR_EL1), (actlr_elx));
/*
* Check if we are exiting from deep sleep and restore SE
* context if we are.
*/
if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
#if ENABLE_STRICT_CHECKING_MODE
/*
* Enable strict checking after programming the GSC for
* enabling TZSRAM and TZDRAM
*/
mce_enable_strict_checking();
#endif
/* Init SMMU */
tegra_smmu_init();
/* Resume SE, RNG1 and PKA1 */
tegra_se_resume();
/*
* Program XUSB STREAMIDs
* ======================
* T19x XUSB has support for XUSB virtualization. It will
* have one physical function (PF) and four Virtual functions
* (VF)
*
* There were below two SIDs for XUSB until T186.
* 1) #define TEGRA_SID_XUSB_HOST 0x1bU
* 2) #define TEGRA_SID_XUSB_DEV 0x1cU
*
* We have below four new SIDs added for VF(s)
* 3) #define TEGRA_SID_XUSB_VF0 0x5dU
* 4) #define TEGRA_SID_XUSB_VF1 0x5eU
* 5) #define TEGRA_SID_XUSB_VF2 0x5fU
* 6) #define TEGRA_SID_XUSB_VF3 0x60U
*
* When virtualization is enabled then we have to disable SID
* override and program above SIDs in below newly added SID
* registers in XUSB PADCTL MMIO space. These registers are
* TZ protected and so need to be done in ATF.
*
* a) #define XUSB_PADCTL_HOST_AXI_STREAMID_PF_0 (0x136cU)
* b) #define XUSB_PADCTL_DEV_AXI_STREAMID_PF_0 (0x139cU)
* c) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_0 (0x1370U)
* d) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_1 (0x1374U)
* e) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_2 (0x1378U)
* f) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_3 (0x137cU)
*
* This change disables SID override and programs XUSB SIDs
* in above registers to support both virtualization and
* non-virtualization platforms
*/
if (tegra_platform_is_silicon() || tegra_platform_is_fpga()) {
mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
XUSB_PADCTL_HOST_AXI_STREAMID_PF_0, TEGRA_SID_XUSB_HOST);
assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE +
XUSB_PADCTL_HOST_AXI_STREAMID_PF_0) == TEGRA_SID_XUSB_HOST);
mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
XUSB_PADCTL_HOST_AXI_STREAMID_VF_0, TEGRA_SID_XUSB_VF0);
assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE +
XUSB_PADCTL_HOST_AXI_STREAMID_VF_0) == TEGRA_SID_XUSB_VF0);
mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
XUSB_PADCTL_HOST_AXI_STREAMID_VF_1, TEGRA_SID_XUSB_VF1);
assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE +
XUSB_PADCTL_HOST_AXI_STREAMID_VF_1) == TEGRA_SID_XUSB_VF1);
mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
XUSB_PADCTL_HOST_AXI_STREAMID_VF_2, TEGRA_SID_XUSB_VF2);
assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE +
XUSB_PADCTL_HOST_AXI_STREAMID_VF_2) == TEGRA_SID_XUSB_VF2);
mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
XUSB_PADCTL_HOST_AXI_STREAMID_VF_3, TEGRA_SID_XUSB_VF3);
assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE +
XUSB_PADCTL_HOST_AXI_STREAMID_VF_3) == TEGRA_SID_XUSB_VF3);
mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
XUSB_PADCTL_DEV_AXI_STREAMID_PF_0, TEGRA_SID_XUSB_DEV);
assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE +
XUSB_PADCTL_DEV_AXI_STREAMID_PF_0) == TEGRA_SID_XUSB_DEV);
}
}
/*
* Enable dual execution optimized translations for all ELx.
*/
if (enable_ccplex_lock_step != 0U) {
actlr_elx = read_actlr_el3();
actlr_elx |= DENVER_CPU_ENABLE_DUAL_EXEC_EL3;
write_actlr_el3(actlr_elx);
actlr_elx = read_actlr_el2();
actlr_elx |= DENVER_CPU_ENABLE_DUAL_EXEC_EL2;
write_actlr_el2(actlr_elx);
actlr_elx = read_actlr_el1();
actlr_elx |= DENVER_CPU_ENABLE_DUAL_EXEC_EL1;
write_actlr_el1(actlr_elx);
}
return PSCI_E_SUCCESS;
}
int32_t tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
{
uint64_t impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK;
int32_t ret = 0;
(void)target_state;
/* Disable Denver's DCO operations */
if (impl == DENVER_IMPL) {
denver_disable_dco();
}
/* Turn off CPU */
ret = mce_command_handler((uint64_t)MCE_CMD_ENTER_CSTATE,
(uint64_t)TEGRA_NVG_CORE_C7, MCE_CORE_SLEEP_TIME_INFINITE, 0U);
assert(ret == 0);
return PSCI_E_SUCCESS;
}
__dead2 void tegra_soc_prepare_system_off(void)
{
/* System power off */
mce_system_shutdown();
wfi();
/* wait for the system to power down */
for (;;) {
;
}
}
int32_t tegra_soc_prepare_system_reset(void)
{
/* System reboot */
mce_system_reboot();
return PSCI_E_SUCCESS;
}
@@ -0,0 +1,493 @@
/*
* Copyright (c) 2020-2021, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <inttypes.h>
#include <stdbool.h>
#include <stdint.h>
#include <common/debug.h>
#include <lib/bakery_lock.h>
#include <lib/cassert.h>
#include <lib/extensions/ras.h>
#include <lib/utils_def.h>
#include <services/sdei.h>
#include <plat/common/platform.h>
#include <platform_def.h>
#include <tegra194_ras_private.h>
#include <tegra_def.h>
#include <tegra_platform.h>
#include <tegra_private.h>
/*
* ERR<n>FR bits[63:32], it indicates supported RAS errors which can be enabled
* by setting corresponding bits in ERR<n>CTLR
*/
#define ERR_FR_EN_BITS_MASK 0xFFFFFFFF00000000ULL
/*
* Number of RAS errors will be cleared per 'tegra194_ras_corrected_err_clear'
* function call.
*/
#define RAS_ERRORS_PER_CALL 8
/*
* the max possible RAS node index value.
*/
#define RAS_NODE_INDEX_MAX 0x1FFFFFFFU
/* bakery lock for platform RAS handler. */
static DEFINE_BAKERY_LOCK(ras_handler_lock);
#define ras_lock() bakery_lock_get(&ras_handler_lock)
#define ras_unlock() bakery_lock_release(&ras_handler_lock)
/*
* Function to handle an External Abort received at EL3.
* This function is invoked by RAS framework.
*/
static void tegra194_ea_handler(unsigned int ea_reason, uint64_t syndrome,
void *cookie, void *handle, uint64_t flags)
{
int32_t ret;
ras_lock();
ERROR("MPIDR 0x%lx: exception reason=%u syndrome=0x%" PRIx64 "\n",
read_mpidr(), ea_reason, syndrome);
/* Call RAS EA handler */
ret = ras_ea_handler(ea_reason, syndrome, cookie, handle, flags);
if (ret != 0) {
ERROR("RAS error handled!\n");
ret = sdei_dispatch_event(TEGRA_SDEI_EP_EVENT_0 +
plat_my_core_pos());
if (ret != 0)
ERROR("sdei_dispatch_event returned %d\n", ret);
} else {
ERROR("Not a RAS error!\n");
}
ras_unlock();
}
/*
* Function to enable all supported RAS error report.
*
* Uncorrected errors are set to report as External abort (SError)
* Corrected errors are set to report as interrupt.
*/
void tegra194_ras_enable(void)
{
VERBOSE("%s\n", __func__);
/* skip RAS enablement if not a silicon platform. */
if (!tegra_platform_is_silicon()) {
return;
}
/*
* Iterate for each group(num_idx ERRSELRs starting from idx_start)
* use normal for loop instead of for_each_err_record_info to get rid
* of MISRA noise..
*/
for (uint32_t i = 0U; i < err_record_mappings.num_err_records; i++) {
const struct err_record_info *info = &err_record_mappings.err_records[i];
uint32_t idx_start = info->sysreg.idx_start;
uint32_t num_idx = info->sysreg.num_idx;
const struct ras_aux_data *aux_data = (const struct ras_aux_data *)info->aux_data;
assert(aux_data != NULL);
for (uint32_t j = 0; j < num_idx; j++) {
/* ERR<n>CTLR register value. */
uint64_t err_ctrl = 0ULL;
/* all supported errors for this node. */
uint64_t err_fr;
/* uncorrectable errors */
uint64_t uncorr_errs;
/* correctable errors */
uint64_t corr_errs;
/*
* Catch error if something wrong with the RAS aux data
* record table.
*/
assert(aux_data[j].err_ctrl != NULL);
/*
* Write to ERRSELR_EL1 to select the RAS error node.
* Always program this at first to select corresponding
* RAS node before any other RAS register r/w.
*/
ser_sys_select_record(idx_start + j);
err_fr = read_erxfr_el1() & ERR_FR_EN_BITS_MASK;
uncorr_errs = aux_data[j].err_ctrl();
corr_errs = ~uncorr_errs & err_fr;
/* enable error reporting */
ERR_CTLR_ENABLE_FIELD(err_ctrl, ED);
/* enable SError reporting for uncorrectable errors */
if ((uncorr_errs & err_fr) != 0ULL) {
ERR_CTLR_ENABLE_FIELD(err_ctrl, UE);
}
/* generate interrupt for corrected errors. */
if (corr_errs != 0ULL) {
ERR_CTLR_ENABLE_FIELD(err_ctrl, CFI);
}
/* enable the supported errors */
err_ctrl |= err_fr;
VERBOSE("errselr_el1:0x%x, erxfr:0x%" PRIx64 ", err_ctrl:0x%" PRIx64 "\n",
idx_start + j, err_fr, err_ctrl);
/* enable specified errors, or set to 0 if no supported error */
write_erxctlr_el1(err_ctrl);
}
}
}
/*
* Function to clear RAS ERR<n>STATUS for corrected RAS error.
*
* This function clears number of 'RAS_ERRORS_PER_CALL' RAS errors at most.
* 'cookie' - in/out cookie parameter to specify/store last visited RAS
* error record index. it is set to '0' to indicate no more RAS
* error record to clear.
*/
void tegra194_ras_corrected_err_clear(uint64_t *cookie)
{
/*
* 'last_node' and 'last_idx' represent last visited RAS node index from
* previous function call. they are set to 0 when first smc call is made
* or all RAS error are visited by followed multipile smc calls.
*/
union prev_record {
struct record {
uint32_t last_node;
uint32_t last_idx;
} rec;
uint64_t value;
} prev;
uint64_t clear_ce_status = 0ULL;
int32_t nerrs_per_call = RAS_ERRORS_PER_CALL;
uint32_t i;
if (cookie == NULL) {
return;
}
prev.value = *cookie;
if ((prev.rec.last_node >= RAS_NODE_INDEX_MAX) ||
(prev.rec.last_idx >= RAS_NODE_INDEX_MAX)) {
return;
}
ERR_STATUS_SET_FIELD(clear_ce_status, AV, 0x1UL);
ERR_STATUS_SET_FIELD(clear_ce_status, V, 0x1UL);
ERR_STATUS_SET_FIELD(clear_ce_status, OF, 0x1UL);
ERR_STATUS_SET_FIELD(clear_ce_status, MV, 0x1UL);
ERR_STATUS_SET_FIELD(clear_ce_status, CE, 0x3UL);
for (i = prev.rec.last_node; i < err_record_mappings.num_err_records; i++) {
const struct err_record_info *info = &err_record_mappings.err_records[i];
uint32_t idx_start = info->sysreg.idx_start;
uint32_t num_idx = info->sysreg.num_idx;
uint32_t j;
j = (i == prev.rec.last_node && prev.value != 0UL) ?
(prev.rec.last_idx + 1U) : 0U;
for (; j < num_idx; j++) {
uint64_t status;
uint32_t err_idx = idx_start + j;
if (err_idx >= RAS_NODE_INDEX_MAX) {
return;
}
write_errselr_el1(err_idx);
status = read_erxstatus_el1();
if (ERR_STATUS_GET_FIELD(status, CE) != 0U) {
write_erxstatus_el1(clear_ce_status);
}
--nerrs_per_call;
/* only clear 'nerrs_per_call' errors each time. */
if (nerrs_per_call <= 0) {
prev.rec.last_idx = j;
prev.rec.last_node = i;
/* save last visited error record index
* into cookie.
*/
*cookie = prev.value;
return;
}
}
}
/*
* finish if all ras error records are checked or provided index is out
* of range.
*/
*cookie = 0ULL;
return;
}
/* Function to probe an error from error record group. */
static int32_t tegra194_ras_record_probe(const struct err_record_info *info,
int *probe_data)
{
/* Skip probing if not a silicon platform */
if (!tegra_platform_is_silicon()) {
return 0;
}
return ser_probe_sysreg(info->sysreg.idx_start, info->sysreg.num_idx, probe_data);
}
/* Function to handle error from one given node */
static int32_t tegra194_ras_node_handler(uint32_t errselr, const char *name,
const struct ras_error *errors, uint64_t status)
{
bool found = false;
uint32_t ierr = (uint32_t)ERR_STATUS_GET_FIELD(status, IERR);
uint32_t serr = (uint32_t)ERR_STATUS_GET_FIELD(status, SERR);
uint64_t val = 0;
/* not a valid error. */
if (ERR_STATUS_GET_FIELD(status, V) == 0U) {
return 0;
}
ERR_STATUS_SET_FIELD(val, V, 1);
/* keep the log print same as linux arm64_ras driver. */
ERROR("**************************************\n");
ERROR("RAS Error in %s, ERRSELR_EL1=0x%x:\n", name, errselr);
ERROR("\tStatus = 0x%" PRIx64 "\n", status);
/* Print uncorrectable errror information. */
if (ERR_STATUS_GET_FIELD(status, UE) != 0U) {
ERR_STATUS_SET_FIELD(val, UE, 1);
ERR_STATUS_SET_FIELD(val, UET, 1);
/* IERR to error message */
for (uint32_t i = 0; errors[i].error_msg != NULL; i++) {
if (ierr == errors[i].error_code) {
ERROR("\tIERR = %s: 0x%x\n",
errors[i].error_msg, ierr);
found = true;
break;
}
}
if (!found) {
ERROR("\tUnknown IERR: 0x%x\n", ierr);
}
ERROR("SERR = %s: 0x%x\n", ras_serr_to_str(serr), serr);
/* Overflow, multiple errors have been detected. */
if (ERR_STATUS_GET_FIELD(status, OF) != 0U) {
ERROR("\tOverflow (there may be more errors) - "
"Uncorrectable\n");
ERR_STATUS_SET_FIELD(val, OF, 1);
}
ERROR("\tUncorrectable (this is fatal)\n");
/* Miscellaneous Register Valid. */
if (ERR_STATUS_GET_FIELD(status, MV) != 0U) {
ERROR("\tMISC0 = 0x%lx\n", read_erxmisc0_el1());
ERROR("\tMISC1 = 0x%lx\n", read_erxmisc1_el1());
ERR_STATUS_SET_FIELD(val, MV, 1);
}
/* Address Valid. */
if (ERR_STATUS_GET_FIELD(status, AV) != 0U) {
ERROR("\tADDR = 0x%lx\n", read_erxaddr_el1());
ERR_STATUS_SET_FIELD(val, AV, 1);
}
/* Deferred error */
if (ERR_STATUS_GET_FIELD(status, DE) != 0U) {
ERROR("\tDeferred error\n");
ERR_STATUS_SET_FIELD(val, DE, 1);
}
} else {
/* For corrected error, simply clear it. */
VERBOSE("corrected RAS error is cleared: ERRSELR_EL1:0x%x, "
"IERR:0x%x, SERR:0x%x\n", errselr, ierr, serr);
ERR_STATUS_SET_FIELD(val, CE, 1);
}
ERROR("**************************************\n");
/* Write to clear reported errors. */
write_erxstatus_el1(val);
/* error handled */
return 0;
}
/* Function to handle one error node from an error record group. */
static int32_t tegra194_ras_record_handler(const struct err_record_info *info,
int probe_data, const struct err_handler_data *const data __unused)
{
uint32_t num_idx = info->sysreg.num_idx;
uint32_t idx_start = info->sysreg.idx_start;
const struct ras_aux_data *aux_data = info->aux_data;
const struct ras_error *errors;
uint32_t offset;
const char *node_name;
uint64_t status = 0ULL;
VERBOSE("%s\n", __func__);
assert(probe_data >= 0);
assert((uint32_t)probe_data < num_idx);
offset = (uint32_t)probe_data;
errors = aux_data[offset].error_records;
node_name = aux_data[offset].name;
assert(errors != NULL);
/* Write to ERRSELR_EL1 to select the error record */
ser_sys_select_record(idx_start + offset);
/* Retrieve status register from the error record */
status = read_erxstatus_el1();
return tegra194_ras_node_handler(idx_start + offset, node_name,
errors, status);
}
/* Instantiate RAS nodes */
PER_CORE_RAS_NODE_LIST(DEFINE_ONE_RAS_NODE)
PER_CLUSTER_RAS_NODE_LIST(DEFINE_ONE_RAS_NODE)
SCF_L3_BANK_RAS_NODE_LIST(DEFINE_ONE_RAS_NODE)
CCPLEX_RAS_NODE_LIST(DEFINE_ONE_RAS_NODE)
/* Instantiate RAS node groups */
static struct ras_aux_data per_core_ras_group[] = {
PER_CORE_RAS_GROUP_NODES
};
CASSERT(ARRAY_SIZE(per_core_ras_group) < RAS_NODE_INDEX_MAX,
assert_max_per_core_ras_group_size);
static struct ras_aux_data per_cluster_ras_group[] = {
PER_CLUSTER_RAS_GROUP_NODES
};
CASSERT(ARRAY_SIZE(per_cluster_ras_group) < RAS_NODE_INDEX_MAX,
assert_max_per_cluster_ras_group_size);
static struct ras_aux_data scf_l3_ras_group[] = {
SCF_L3_BANK_RAS_GROUP_NODES
};
CASSERT(ARRAY_SIZE(scf_l3_ras_group) < RAS_NODE_INDEX_MAX,
assert_max_scf_l3_ras_group_size);
static struct ras_aux_data ccplex_ras_group[] = {
CCPLEX_RAS_GROUP_NODES
};
CASSERT(ARRAY_SIZE(ccplex_ras_group) < RAS_NODE_INDEX_MAX,
assert_max_ccplex_ras_group_size);
/*
* We have same probe and handler for each error record group, use a macro to
* simply the record definition.
*/
#define ADD_ONE_ERR_GROUP(errselr_start, group) \
ERR_RECORD_SYSREG_V1((errselr_start), (uint32_t)ARRAY_SIZE((group)), \
&tegra194_ras_record_probe, \
&tegra194_ras_record_handler, (group))
/* RAS error record group information */
static struct err_record_info carmel_ras_records[] = {
/*
* Per core ras error records
* ERRSELR starts from 0*256 + Logical_CPU_ID*16 + 0 to
* 0*256 + Logical_CPU_ID*16 + 5 for each group.
* 8 cores/groups, 6 * 8 nodes in total.
*/
ADD_ONE_ERR_GROUP(0x000, per_core_ras_group),
ADD_ONE_ERR_GROUP(0x010, per_core_ras_group),
ADD_ONE_ERR_GROUP(0x020, per_core_ras_group),
ADD_ONE_ERR_GROUP(0x030, per_core_ras_group),
ADD_ONE_ERR_GROUP(0x040, per_core_ras_group),
ADD_ONE_ERR_GROUP(0x050, per_core_ras_group),
ADD_ONE_ERR_GROUP(0x060, per_core_ras_group),
ADD_ONE_ERR_GROUP(0x070, per_core_ras_group),
/*
* Per cluster ras error records
* ERRSELR starts from 2*256 + Logical_Cluster_ID*16 + 0 to
* 2*256 + Logical_Cluster_ID*16 + 3.
* 4 clusters/groups, 3 * 4 nodes in total.
*/
ADD_ONE_ERR_GROUP(0x200, per_cluster_ras_group),
ADD_ONE_ERR_GROUP(0x210, per_cluster_ras_group),
ADD_ONE_ERR_GROUP(0x220, per_cluster_ras_group),
ADD_ONE_ERR_GROUP(0x230, per_cluster_ras_group),
/*
* SCF L3_Bank ras error records
* ERRSELR: 3*256 + L3_Bank_ID, L3_Bank_ID: 0-3
* 1 groups, 4 nodes in total.
*/
ADD_ONE_ERR_GROUP(0x300, scf_l3_ras_group),
/*
* CCPLEX ras error records
* ERRSELR: 4*256 + Unit_ID, Unit_ID: 0 - 4
* 1 groups, 5 nodes in total.
*/
ADD_ONE_ERR_GROUP(0x400, ccplex_ras_group),
};
CASSERT(ARRAY_SIZE(carmel_ras_records) < RAS_NODE_INDEX_MAX,
assert_max_carmel_ras_records_size);
REGISTER_ERR_RECORD_INFO(carmel_ras_records);
/* dummy RAS interrupt */
static struct ras_interrupt carmel_ras_interrupts[] = {};
REGISTER_RAS_INTERRUPTS(carmel_ras_interrupts);
/*******************************************************************************
* RAS handler for the platform
******************************************************************************/
void plat_ea_handler(unsigned int ea_reason, uint64_t syndrome, void *cookie,
void *handle, uint64_t flags)
{
#if RAS_EXTENSION
tegra194_ea_handler(ea_reason, syndrome, cookie, handle, flags);
#else
plat_default_ea_handler(ea_reason, syndrome, cookie, handle, flags);
#endif
}
@@ -0,0 +1,75 @@
/*
* Copyright (c) 2019-2020, NVIDIA CORPORATION. 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/mmio.h>
#include <mce.h>
#include <tegra194_private.h>
#include <tegra_def.h>
#include <tegra_private.h>
extern uint64_t tegra_bl31_phys_base;
#define MISCREG_AA64_RST_LOW 0x2004U
#define MISCREG_AA64_RST_HIGH 0x2008U
#define CPU_RESET_MODE_AA64 1U
/*******************************************************************************
* Setup secondary CPU vectors
******************************************************************************/
void plat_secondary_setup(void)
{
uint32_t addr_low, addr_high;
plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
uint64_t cpu_reset_handler_base, cpu_reset_handler_size, tzdram_addr;
uint64_t src_len_bytes = BL_END - tegra_bl31_phys_base;
INFO("Setting up secondary CPU boot\n");
tzdram_addr = params_from_bl2->tzdram_base +
tegra194_get_cpu_reset_handler_size();
/*
* The BL31 code resides in the TZSRAM which loses state
* when we enter System Suspend. Copy the wakeup trampoline
* code to TZDRAM to help us exit from System Suspend.
*/
cpu_reset_handler_base = tegra194_get_cpu_reset_handler_base();
cpu_reset_handler_size = tegra194_get_cpu_reset_handler_size();
memcpy((void *)((uintptr_t)params_from_bl2->tzdram_base),
(void *)((uintptr_t)cpu_reset_handler_base),
cpu_reset_handler_size);
/* TZDRAM base will be used as the "resume" address */
addr_low = (uint32_t)params_from_bl2->tzdram_base | CPU_RESET_MODE_AA64;
addr_high = (uint32_t)((params_from_bl2->tzdram_base >> 32U) & 0x7ffU);
/* write lower 32 bits first, then the upper 11 bits */
mmio_write_32(TEGRA_MISC_BASE + MISCREG_AA64_RST_LOW, addr_low);
assert(mmio_read_32(TEGRA_MISC_BASE + MISCREG_AA64_RST_LOW) == addr_low);
mmio_write_32(TEGRA_MISC_BASE + MISCREG_AA64_RST_HIGH, addr_high);
assert(mmio_read_32(TEGRA_MISC_BASE + MISCREG_AA64_RST_HIGH) == addr_high);
/* save reset vector to be used during SYSTEM_SUSPEND exit */
mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_RESET_VECTOR_LO,
addr_low);
assert(mmio_read_32(TEGRA_SCRATCH_BASE + SCRATCH_RESET_VECTOR_LO) == addr_low);
mmio_write_32(TEGRA_SCRATCH_BASE + SCRATCH_RESET_VECTOR_HI,
addr_high);
assert(mmio_read_32(TEGRA_SCRATCH_BASE + SCRATCH_RESET_VECTOR_HI) == addr_high);
mmio_write_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV72_LO,
(uint32_t)tzdram_addr);
assert(mmio_read_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV72_LO) == (uint32_t)tzdram_addr);
mmio_write_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV72_HI,
(uint32_t)src_len_bytes);
assert(mmio_read_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV72_HI) == (uint32_t)src_len_bytes);
}
@@ -0,0 +1,449 @@
/*
* Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <assert.h>
#include <bl31/bl31.h>
#include <common/bl_common.h>
#include <common/interrupt_props.h>
#include <drivers/console.h>
#include <context.h>
#include <lib/el3_runtime/context_mgmt.h>
#include <cortex_a57.h>
#include <common/debug.h>
#include <denver.h>
#include <drivers/arm/gic_common.h>
#include <drivers/arm/gicv2.h>
#include <bl31/interrupt_mgmt.h>
#include <mce.h>
#include <mce_private.h>
#include <memctrl.h>
#include <plat/common/platform.h>
#include <smmu.h>
#include <spe.h>
#include <tegra_def.h>
#include <tegra_platform.h>
#include <tegra_private.h>
#include <lib/xlat_tables/xlat_tables_v2.h>
/* ID for spe-console */
#define TEGRA_CONSOLE_SPE_ID 0xFE
/*******************************************************************************
* Structure to store the SCR addresses and its expected settings.
*******************************************************************************
*/
typedef struct {
uint32_t scr_addr;
uint32_t scr_val;
} scr_settings_t;
static const scr_settings_t t194_scr_settings[] = {
{ SCRATCH_RSV68_SCR, SCRATCH_RSV68_SCR_VAL },
{ SCRATCH_RSV71_SCR, SCRATCH_RSV71_SCR_VAL },
{ SCRATCH_RSV72_SCR, SCRATCH_RSV72_SCR_VAL },
{ SCRATCH_RSV75_SCR, SCRATCH_RSV75_SCR_VAL },
{ SCRATCH_RSV81_SCR, SCRATCH_RSV81_SCR_VAL },
{ SCRATCH_RSV97_SCR, SCRATCH_RSV97_SCR_VAL },
{ SCRATCH_RSV99_SCR, SCRATCH_RSV99_SCR_VAL },
{ SCRATCH_RSV109_SCR, SCRATCH_RSV109_SCR_VAL },
{ MISCREG_SCR_SCRTZWELCK, MISCREG_SCR_SCRTZWELCK_VAL }
};
/*******************************************************************************
* The Tegra power domain tree has a single system level power domain i.e. a
* single root node. The first entry in the power domain descriptor specifies
* the number of power domains at the highest power level.
*******************************************************************************
*/
static const uint8_t tegra_power_domain_tree_desc[] = {
/* No of root nodes */
1,
/* No of clusters */
PLATFORM_CLUSTER_COUNT,
/* No of CPU cores - cluster0 */
PLATFORM_MAX_CPUS_PER_CLUSTER,
/* No of CPU cores - cluster1 */
PLATFORM_MAX_CPUS_PER_CLUSTER,
/* No of CPU cores - cluster2 */
PLATFORM_MAX_CPUS_PER_CLUSTER,
/* No of CPU cores - cluster3 */
PLATFORM_MAX_CPUS_PER_CLUSTER
};
/*******************************************************************************
* This function returns the Tegra default topology tree information.
******************************************************************************/
const uint8_t *plat_get_power_domain_tree_desc(void)
{
return tegra_power_domain_tree_desc;
}
/*
* Table of regions to map using the MMU.
*/
static const mmap_region_t tegra_mmap[] = {
MAP_REGION_FLAT(TEGRA_MISC_BASE, 0x4000U, /* 16KB */
(uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
MAP_REGION_FLAT(TEGRA_GPCDMA_BASE, 0x10000U, /* 64KB */
(uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
MAP_REGION_FLAT(TEGRA_MC_STREAMID_BASE, 0x8000U, /* 32KB */
(uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
MAP_REGION_FLAT(TEGRA_MC_BASE, 0x8000U, /* 32KB */
(uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
#if !ENABLE_CONSOLE_SPE
MAP_REGION_FLAT(TEGRA_UARTA_BASE, 0x20000U, /* 128KB - UART A, B*/
(uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
MAP_REGION_FLAT(TEGRA_UARTC_BASE, 0x20000U, /* 128KB - UART C, G */
(uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
MAP_REGION_FLAT(TEGRA_UARTD_BASE, 0x30000U, /* 192KB - UART D, E, F */
(uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
#endif
MAP_REGION_FLAT(TEGRA_XUSB_PADCTL_BASE, 0x2000U, /* 8KB */
(uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
MAP_REGION_FLAT(TEGRA_GICD_BASE, 0x1000, /* 4KB */
(uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
MAP_REGION_FLAT(TEGRA_GICC_BASE, 0x1000, /* 4KB */
(uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
MAP_REGION_FLAT(TEGRA_SE0_BASE, 0x1000U, /* 4KB */
(uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
MAP_REGION_FLAT(TEGRA_PKA1_BASE, 0x1000U, /* 4KB */
(uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
MAP_REGION_FLAT(TEGRA_RNG1_BASE, 0x1000U, /* 4KB */
(uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
MAP_REGION_FLAT(TEGRA_HSP_DBELL_BASE, 0x1000U, /* 4KB */
(uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
#if ENABLE_CONSOLE_SPE
MAP_REGION_FLAT(TEGRA_CONSOLE_SPE_BASE, 0x1000U, /* 4KB */
(uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
#endif
MAP_REGION_FLAT(TEGRA_TMRUS_BASE, TEGRA_TMRUS_SIZE, /* 4KB */
(uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
MAP_REGION_FLAT(TEGRA_SCRATCH_BASE, 0x1000U, /* 4KB */
(uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
MAP_REGION_FLAT(TEGRA_SMMU2_BASE, 0x800000U, /* 8MB */
(uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
MAP_REGION_FLAT(TEGRA_SMMU1_BASE, 0x800000U, /* 8MB */
(uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
MAP_REGION_FLAT(TEGRA_SMMU0_BASE, 0x800000U, /* 8MB */
(uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
MAP_REGION_FLAT(TEGRA_BPMP_IPC_TX_PHYS_BASE, 0x10000U, /* 64KB */
(uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
MAP_REGION_FLAT(TEGRA_CAR_RESET_BASE, 0x10000U, /* 64KB */
(uint8_t)MT_DEVICE | (uint8_t)MT_RW | (uint8_t)MT_SECURE),
{0}
};
/*******************************************************************************
* Set up the pagetables as per the platform memory map & initialize the MMU
******************************************************************************/
const mmap_region_t *plat_get_mmio_map(void)
{
/* MMIO space */
return tegra_mmap;
}
/*******************************************************************************
* Handler to get the System Counter Frequency
******************************************************************************/
uint32_t plat_get_syscnt_freq2(void)
{
return 31250000;
}
#if !ENABLE_CONSOLE_SPE
/*******************************************************************************
* Maximum supported UART controllers
******************************************************************************/
#define TEGRA194_MAX_UART_PORTS 7
/*******************************************************************************
* This variable holds the UART port base addresses
******************************************************************************/
static uint32_t tegra194_uart_addresses[TEGRA194_MAX_UART_PORTS + 1] = {
0, /* undefined - treated as an error case */
TEGRA_UARTA_BASE,
TEGRA_UARTB_BASE,
TEGRA_UARTC_BASE,
TEGRA_UARTD_BASE,
TEGRA_UARTE_BASE,
TEGRA_UARTF_BASE,
TEGRA_UARTG_BASE
};
#endif
/*******************************************************************************
* Enable console corresponding to the console ID
******************************************************************************/
void plat_enable_console(int32_t id)
{
uint32_t console_clock = 0U;
#if ENABLE_CONSOLE_SPE
static console_t spe_console;
if (id == TEGRA_CONSOLE_SPE_ID) {
(void)console_spe_register(TEGRA_CONSOLE_SPE_BASE,
console_clock,
TEGRA_CONSOLE_BAUDRATE,
&spe_console);
console_set_scope(&spe_console, CONSOLE_FLAG_BOOT |
CONSOLE_FLAG_RUNTIME | CONSOLE_FLAG_CRASH);
}
#else
static console_t uart_console;
if ((id > 0) && (id < TEGRA194_MAX_UART_PORTS)) {
/*
* Reference clock used by the FPGAs is a lot slower.
*/
if (tegra_platform_is_fpga()) {
console_clock = TEGRA_BOOT_UART_CLK_13_MHZ;
} else {
console_clock = TEGRA_BOOT_UART_CLK_408_MHZ;
}
(void)console_16550_register(tegra194_uart_addresses[id],
console_clock,
TEGRA_CONSOLE_BAUDRATE,
&uart_console);
console_set_scope(&uart_console, CONSOLE_FLAG_BOOT |
CONSOLE_FLAG_RUNTIME | CONSOLE_FLAG_CRASH);
}
#endif
}
/*******************************************************************************
* Verify SCR settings
******************************************************************************/
static inline bool tegra194_is_scr_valid(void)
{
uint32_t scr_val;
bool ret = true;
for (uint8_t i = 0U; i < ARRAY_SIZE(t194_scr_settings); i++) {
scr_val = mmio_read_32((uintptr_t)t194_scr_settings[i].scr_addr);
if (scr_val != t194_scr_settings[i].scr_val) {
ERROR("Mismatch at SCR addr = 0x%x\n", t194_scr_settings[i].scr_addr);
ret = false;
}
}
return ret;
}
/*******************************************************************************
* Handler for early platform setup
******************************************************************************/
void plat_early_platform_setup(void)
{
const plat_params_from_bl2_t *params_from_bl2 = bl31_get_plat_params();
uint8_t enable_ccplex_lock_step = params_from_bl2->enable_ccplex_lock_step;
uint64_t actlr_elx;
/* Verify chip id is t194 */
assert(tegra_chipid_is_t194());
/* Verify SCR settings */
if (tegra_platform_is_silicon()) {
assert(tegra194_is_scr_valid());
}
/* sanity check MCE firmware compatibility */
mce_verify_firmware_version();
#if RAS_EXTENSION
/* Enable Uncorrectable RAS error */
tegra194_ras_enable();
#endif
/*
* Program XUSB STREAMIDs
* ======================
* T19x XUSB has support for XUSB virtualization. It will have one
* physical function (PF) and four Virtual function (VF)
*
* There were below two SIDs for XUSB until T186.
* 1) #define TEGRA_SID_XUSB_HOST 0x1bU
* 2) #define TEGRA_SID_XUSB_DEV 0x1cU
*
* We have below four new SIDs added for VF(s)
* 3) #define TEGRA_SID_XUSB_VF0 0x5dU
* 4) #define TEGRA_SID_XUSB_VF1 0x5eU
* 5) #define TEGRA_SID_XUSB_VF2 0x5fU
* 6) #define TEGRA_SID_XUSB_VF3 0x60U
*
* When virtualization is enabled then we have to disable SID override
* and program above SIDs in below newly added SID registers in XUSB
* PADCTL MMIO space. These registers are TZ protected and so need to
* be done in ATF.
* a) #define XUSB_PADCTL_HOST_AXI_STREAMID_PF_0 (0x136cU)
* b) #define XUSB_PADCTL_DEV_AXI_STREAMID_PF_0 (0x139cU)
* c) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_0 (0x1370U)
* d) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_1 (0x1374U)
* e) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_2 (0x1378U)
* f) #define XUSB_PADCTL_HOST_AXI_STREAMID_VF_3 (0x137cU)
*
* This change disables SID override and programs XUSB SIDs in
* above registers to support both virtualization and
* non-virtualization platforms
*/
if (tegra_platform_is_silicon() || tegra_platform_is_fpga()) {
mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
XUSB_PADCTL_HOST_AXI_STREAMID_PF_0, TEGRA_SID_XUSB_HOST);
assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE +
XUSB_PADCTL_HOST_AXI_STREAMID_PF_0) == TEGRA_SID_XUSB_HOST);
mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
XUSB_PADCTL_HOST_AXI_STREAMID_VF_0, TEGRA_SID_XUSB_VF0);
assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE +
XUSB_PADCTL_HOST_AXI_STREAMID_VF_0) == TEGRA_SID_XUSB_VF0);
mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
XUSB_PADCTL_HOST_AXI_STREAMID_VF_1, TEGRA_SID_XUSB_VF1);
assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE +
XUSB_PADCTL_HOST_AXI_STREAMID_VF_1) == TEGRA_SID_XUSB_VF1);
mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
XUSB_PADCTL_HOST_AXI_STREAMID_VF_2, TEGRA_SID_XUSB_VF2);
assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE +
XUSB_PADCTL_HOST_AXI_STREAMID_VF_2) == TEGRA_SID_XUSB_VF2);
mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
XUSB_PADCTL_HOST_AXI_STREAMID_VF_3, TEGRA_SID_XUSB_VF3);
assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE +
XUSB_PADCTL_HOST_AXI_STREAMID_VF_3) == TEGRA_SID_XUSB_VF3);
mmio_write_32(TEGRA_XUSB_PADCTL_BASE +
XUSB_PADCTL_DEV_AXI_STREAMID_PF_0, TEGRA_SID_XUSB_DEV);
assert(mmio_read_32(TEGRA_XUSB_PADCTL_BASE +
XUSB_PADCTL_DEV_AXI_STREAMID_PF_0) == TEGRA_SID_XUSB_DEV);
}
/*
* Enable dual execution optimized translations for all ELx.
*/
if (enable_ccplex_lock_step != 0U) {
actlr_elx = read_actlr_el3();
actlr_elx |= DENVER_CPU_ENABLE_DUAL_EXEC_EL3;
write_actlr_el3(actlr_elx);
/* check if the bit is actually set */
assert((read_actlr_el3() & DENVER_CPU_ENABLE_DUAL_EXEC_EL3) != 0ULL);
actlr_elx = read_actlr_el2();
actlr_elx |= DENVER_CPU_ENABLE_DUAL_EXEC_EL2;
write_actlr_el2(actlr_elx);
/* check if the bit is actually set */
assert((read_actlr_el2() & DENVER_CPU_ENABLE_DUAL_EXEC_EL2) != 0ULL);
actlr_elx = read_actlr_el1();
actlr_elx |= DENVER_CPU_ENABLE_DUAL_EXEC_EL1;
write_actlr_el1(actlr_elx);
/* check if the bit is actually set */
assert((read_actlr_el1() & DENVER_CPU_ENABLE_DUAL_EXEC_EL1) != 0ULL);
}
}
/* Secure IRQs for Tegra194 */
static const interrupt_prop_t tegra194_interrupt_props[] = {
INTR_PROP_DESC(TEGRA_SDEI_SGI_PRIVATE, PLAT_SDEI_CRITICAL_PRI,
GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE),
INTR_PROP_DESC(TEGRA194_TOP_WDT_IRQ, PLAT_TEGRA_WDT_PRIO,
GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE)
};
/*******************************************************************************
* Initialize the GIC and SGIs
******************************************************************************/
void plat_gic_setup(void)
{
tegra_gic_setup(tegra194_interrupt_props, ARRAY_SIZE(tegra194_interrupt_props));
tegra_gic_init();
/*
* Initialize the FIQ handler
*/
tegra_fiq_handler_setup();
}
/*******************************************************************************
* Return pointer to the BL31 params from previous bootloader
******************************************************************************/
struct tegra_bl31_params *plat_get_bl31_params(void)
{
uint64_t val;
val = (mmio_read_32(TEGRA_SCRATCH_BASE + SCRATCH_BL31_PARAMS_HI_ADDR) &
SCRATCH_BL31_PARAMS_HI_ADDR_MASK) >> SCRATCH_BL31_PARAMS_HI_ADDR_SHIFT;
val <<= 32;
val |= mmio_read_32(TEGRA_SCRATCH_BASE + SCRATCH_BL31_PARAMS_LO_ADDR);
return (struct tegra_bl31_params *)(uintptr_t)val;
}
/*******************************************************************************
* Return pointer to the BL31 platform params from previous bootloader
******************************************************************************/
plat_params_from_bl2_t *plat_get_bl31_plat_params(void)
{
uint64_t val;
val = (mmio_read_32(TEGRA_SCRATCH_BASE + SCRATCH_BL31_PLAT_PARAMS_HI_ADDR) &
SCRATCH_BL31_PLAT_PARAMS_HI_ADDR_MASK) >> SCRATCH_BL31_PLAT_PARAMS_HI_ADDR_SHIFT;
val <<= 32;
val |= mmio_read_32(TEGRA_SCRATCH_BASE + SCRATCH_BL31_PLAT_PARAMS_LO_ADDR);
return (plat_params_from_bl2_t *)(uintptr_t)val;
}
/*******************************************************************************
* Handler for late platform setup
******************************************************************************/
void plat_late_platform_setup(void)
{
#if ENABLE_STRICT_CHECKING_MODE
/*
* Enable strict checking after programming the GSC for
* enabling TZSRAM and TZDRAM
*/
mce_enable_strict_checking();
mce_verify_strict_checking();
#endif
}
/*******************************************************************************
* Handler to indicate support for System Suspend
******************************************************************************/
bool plat_supports_system_suspend(void)
{
return true;
}
/*******************************************************************************
* Platform specific runtime setup.
******************************************************************************/
void plat_runtime_setup(void)
{
/*
* During cold boot, it is observed that the arbitration
* bit is set in the Memory controller leading to false
* error interrupts in the non-secure world. To avoid
* this, clean the interrupt status register before
* booting into the non-secure world
*/
tegra_memctrl_clear_pending_interrupts();
/*
* During boot, USB3 and flash media (SDMMC/SATA) devices need
* access to IRAM. Because these clients connect to the MC and
* do not have a direct path to the IRAM, the MC implements AHB
* redirection during boot to allow path to IRAM. In this mode
* accesses to a programmed memory address aperture are directed
* to the AHB bus, allowing access to the IRAM. This mode must be
* disabled before we jump to the non-secure world.
*/
tegra_memctrl_disable_ahb_redirection();
/*
* Verify the integrity of the previously configured SMMU(s) settings
*/
tegra_smmu_verify();
}
@@ -0,0 +1,103 @@
/*
* Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <arch_helpers.h>
#include <assert.h>
#include <common/bl_common.h>
#include <lib/el3_runtime/context_mgmt.h>
#include <common/debug.h>
#include <errno.h>
#include <mce.h>
#include <mce_private.h>
#include <memctrl.h>
#include <common/runtime_svc.h>
#include <tegra_private.h>
#include <tegra_platform.h>
#include <smmu.h>
#include <stdbool.h>
/*******************************************************************************
* Tegra194 SiP SMCs
******************************************************************************/
#define TEGRA_SIP_GET_SMMU_PER 0xC200FF00U
#define TEGRA_SIP_CLEAR_RAS_CORRECTED_ERRORS 0xC200FF01U
/*******************************************************************************
* This function is responsible for handling all T194 SiP calls
******************************************************************************/
int32_t plat_sip_handler(uint32_t smc_fid,
uint64_t x1,
uint64_t x2,
uint64_t x3,
uint64_t x4,
const void *cookie,
void *handle,
uint64_t flags)
{
int32_t ret = 0;
uint32_t i, smmu_per[6] = {0};
uint32_t num_smmu_devices = plat_get_num_smmu_devices();
uint64_t per[3] = {0ULL};
(void)x1;
(void)x4;
(void)cookie;
(void)flags;
switch (smc_fid) {
case TEGRA_SIP_GET_SMMU_PER:
/* make sure we dont go past the array length */
assert(num_smmu_devices <= ARRAY_SIZE(smmu_per));
/* read all supported SMMU_PER records */
for (i = 0U; i < num_smmu_devices; i++) {
smmu_per[i] = tegra_smmu_read_32(i, SMMU_GSR0_PER);
}
/* pack results into 3 64bit variables. */
per[0] = smmu_per[0] | ((uint64_t)smmu_per[1] << 32U);
per[1] = smmu_per[2] | ((uint64_t)smmu_per[3] << 32U);
per[2] = smmu_per[4] | ((uint64_t)smmu_per[5] << 32U);
/* provide the results via X1-X3 CPU registers */
write_ctx_reg(get_gpregs_ctx(handle), CTX_GPREG_X1, per[0]);
write_ctx_reg(get_gpregs_ctx(handle), CTX_GPREG_X2, per[1]);
write_ctx_reg(get_gpregs_ctx(handle), CTX_GPREG_X3, per[2]);
break;
#if RAS_EXTENSION
case TEGRA_SIP_CLEAR_RAS_CORRECTED_ERRORS:
{
/*
* clear all RAS error records for corrected errors at first.
* x1 shall be 0 for first SMC call after FHI is asserted.
* */
uint64_t local_x1 = x1;
tegra194_ras_corrected_err_clear(&local_x1);
if (local_x1 == 0ULL) {
/* clear HSM corrected error status after all corrected
* RAS errors are cleared.
*/
mce_clear_hsm_corr_status();
}
write_ctx_reg(get_gpregs_ctx(handle), CTX_GPREG_X1, local_x1);
break;
}
#endif
default:
ret = -ENOTSUP;
break;
}
return ret;
}
@@ -0,0 +1,35 @@
/*
* Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/bl_common.h>
#include <common/debug.h>
#include <smmu.h>
#include <tegra_def.h>
#define BOARD_SYSTEM_FPGA_BASE U(1)
#define BASE_CONFIG_SMMU_DEVICES U(2)
#define MAX_NUM_SMMU_DEVICES U(3)
static uint32_t tegra_misc_read_32(uint32_t off)
{
return mmio_read_32((uintptr_t)TEGRA_MISC_BASE + off);
}
/*******************************************************************************
* Handler to return the support SMMU devices number
******************************************************************************/
uint32_t plat_get_num_smmu_devices(void)
{
uint32_t ret_num = MAX_NUM_SMMU_DEVICES;
uint32_t board_revid = ((tegra_misc_read_32(MISCREG_EMU_REVID) >> \
BOARD_SHIFT_BITS) & BOARD_MASK_BITS);
if (board_revid == BOARD_SYSTEM_FPGA_BASE) {
ret_num = BASE_CONFIG_SMMU_DEVICES;
}
return ret_num;
}
@@ -0,0 +1,150 @@
/*
* Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <asm_macros.S>
#include <plat/common/common_def.h>
#include <memctrl_v2.h>
#include <tegra_def.h>
#define TEGRA194_STATE_SYSTEM_SUSPEND 0x5C7
#define TEGRA194_STATE_SYSTEM_RESUME 0x600D
#define TEGRA194_MC_CTX_SIZE 0xFB
.align 4
.globl tegra194_cpu_reset_handler
/* CPU reset handler routine */
func tegra194_cpu_reset_handler
/* check if we are exiting system suspend state */
adr x0, __tegra194_system_suspend_state
ldr x1, [x0]
mov x2, #TEGRA194_STATE_SYSTEM_SUSPEND
lsl x2, x2, #16
add x2, x2, #TEGRA194_STATE_SYSTEM_SUSPEND
cmp x1, x2
bne boot_cpu
/* set system resume state */
mov x1, #TEGRA194_STATE_SYSTEM_RESUME
lsl x1, x1, #16
mov x2, #TEGRA194_STATE_SYSTEM_RESUME
add x1, x1, x2
str x1, [x0]
dsb sy
/* prepare to relocate to TZSRAM */
mov x0, #BL31_BASE
adr x1, __tegra194_cpu_reset_handler_end
adr x2, __tegra194_cpu_reset_handler_data
ldr x2, [x2, #8]
/* memcpy16 */
m_loop16:
cmp x2, #16
b.lt m_loop1
ldp x3, x4, [x1], #16
stp x3, x4, [x0], #16
sub x2, x2, #16
b m_loop16
/* copy byte per byte */
m_loop1:
cbz x2, boot_cpu
ldrb w3, [x1], #1
strb w3, [x0], #1
subs x2, x2, #1
b.ne m_loop1
/*
* Synchronization barriers to make sure that memory is flushed out
* before we start execution in SysRAM.
*/
dsb sy
isb
boot_cpu:
adr x0, __tegra194_cpu_reset_handler_data
ldr x0, [x0]
br x0
endfunc tegra194_cpu_reset_handler
/*
* Tegra194 reset data (offset 0x0 - 0x2490)
*
* 0x0000: secure world's entrypoint
* 0x0008: BL31 size (RO + RW)
* 0x0010: MC context start
* 0x2490: MC context end
*/
.align 4
.type __tegra194_cpu_reset_handler_data, %object
.globl __tegra194_cpu_reset_handler_data
__tegra194_cpu_reset_handler_data:
.quad tegra_secure_entrypoint
.quad __BL31_END__ - BL31_BASE
.globl __tegra194_system_suspend_state
__tegra194_system_suspend_state:
.quad 0
.align 4
__tegra194_mc_context:
.rept TEGRA194_MC_CTX_SIZE
.quad 0
.endr
.size __tegra194_cpu_reset_handler_data, \
. - __tegra194_cpu_reset_handler_data
.align 4
.globl __tegra194_cpu_reset_handler_end
__tegra194_cpu_reset_handler_end:
.globl tegra194_get_cpu_reset_handler_size
.globl tegra194_get_cpu_reset_handler_base
.globl tegra194_get_mc_ctx_offset
.globl tegra194_set_system_suspend_entry
/* return size of the CPU reset handler */
func tegra194_get_cpu_reset_handler_size
adr x0, __tegra194_cpu_reset_handler_end
adr x1, tegra194_cpu_reset_handler
sub x0, x0, x1
ret
endfunc tegra194_get_cpu_reset_handler_size
/* return the start address of the CPU reset handler */
func tegra194_get_cpu_reset_handler_base
adr x0, tegra194_cpu_reset_handler
ret
endfunc tegra194_get_cpu_reset_handler_base
/* return the size of the MC context */
func tegra194_get_mc_ctx_offset
adr x0, __tegra194_mc_context
adr x1, tegra194_cpu_reset_handler
sub x0, x0, x1
ret
endfunc tegra194_get_mc_ctx_offset
/* set system suspend state before SC7 entry */
func tegra194_set_system_suspend_entry
mov x0, #TEGRA_MC_BASE
mov x3, #MC_SECURITY_CFG3_0
ldr w1, [x0, x3]
lsl x1, x1, #32
mov x3, #MC_SECURITY_CFG0_0
ldr w2, [x0, x3]
orr x3, x1, x2 /* TZDRAM base */
adr x0, __tegra194_system_suspend_state
adr x1, tegra194_cpu_reset_handler
sub x2, x0, x1 /* offset in TZDRAM */
mov x0, #TEGRA194_STATE_SYSTEM_SUSPEND
lsl x0, x0, #16
add x0, x0, #TEGRA194_STATE_SYSTEM_SUSPEND
str x0, [x3, x2] /* set value in TZDRAM */
dsb sy
ret
endfunc tegra194_set_system_suspend_entry
@@ -0,0 +1,85 @@
#
# Copyright (c) 2019-2021, NVIDIA CORPORATION. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
include common/fdt_wrappers.mk
# platform configs
ENABLE_CONSOLE_SPE := 1
$(eval $(call add_define,ENABLE_CONSOLE_SPE))
ENABLE_STRICT_CHECKING_MODE := 1
$(eval $(call add_define,ENABLE_STRICT_CHECKING_MODE))
USE_GPC_DMA := 1
$(eval $(call add_define,USE_GPC_DMA))
RESET_TO_BL31 := 1
PROGRAMMABLE_RESET_ADDRESS := 1
COLD_BOOT_SINGLE_CPU := 1
# platform settings
TZDRAM_BASE := 0x40000000
$(eval $(call add_define,TZDRAM_BASE))
MAX_XLAT_TABLES := 25
$(eval $(call add_define,MAX_XLAT_TABLES))
MAX_MMAP_REGIONS := 30
$(eval $(call add_define,MAX_MMAP_REGIONS))
# enable RAS handling
HANDLE_EA_EL3_FIRST_NS := 1
RAS_EXTENSION := 1
# platform files
PLAT_INCLUDES += -Iplat/nvidia/tegra/include/t194 \
-I${SOC_DIR}/drivers/include
BL31_SOURCES += ${TEGRA_GICv2_SOURCES} \
drivers/ti/uart/aarch64/16550_console.S \
lib/cpus/aarch64/denver.S \
${TEGRA_DRIVERS}/bpmp_ipc/intf.c \
${TEGRA_DRIVERS}/bpmp_ipc/ivc.c \
${TEGRA_DRIVERS}/memctrl/memctrl_v2.c \
${TEGRA_DRIVERS}/smmu/smmu.c \
${SOC_DIR}/drivers/mce/mce.c \
${SOC_DIR}/drivers/mce/nvg.c \
${SOC_DIR}/drivers/mce/aarch64/nvg_helpers.S \
${SOC_DIR}/drivers/se/se.c \
${SOC_DIR}/plat_memctrl.c \
${SOC_DIR}/plat_psci_handlers.c \
${SOC_DIR}/plat_setup.c \
${SOC_DIR}/plat_secondary.c \
${SOC_DIR}/plat_sip_calls.c \
${SOC_DIR}/plat_smmu.c \
${SOC_DIR}/plat_trampoline.S
ifeq (${USE_GPC_DMA}, 1)
BL31_SOURCES += ${TEGRA_DRIVERS}/gpcdma/gpcdma.c
endif
ifeq (${ENABLE_CONSOLE_SPE},1)
BL31_SOURCES += ${TEGRA_DRIVERS}/spe/shared_console.S
endif
# RAS sources
ifeq (${RAS_EXTENSION},1)
BL31_SOURCES += lib/extensions/ras/std_err_record.c \
lib/extensions/ras/ras_common.c \
${SOC_DIR}/plat_ras.c
endif
# SPM dispatcher
ifeq (${SPD},spmd)
include lib/libfdt/libfdt.mk
# sources to support spmd
BL31_SOURCES += plat/common/plat_spmd_manifest.c \
${LIBFDT_SRCS}
BL31_SOURCES += ${FDT_WRAPPERS_SOURCES}
endif
@@ -0,0 +1,663 @@
/*
* Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2017-2020, NVIDIA CORPORATION. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef SE_PRIVATE_H
#define SE_PRIVATE_H
#include <stdbool.h>
#include <security_engine.h>
/*
* PMC registers
*/
/* SC7 context save scratch register for T210 */
#define PMC_SCRATCH43_REG_OFFSET U(0x22C)
/* Secure scratch registers */
#define PMC_SECURE_SCRATCH4_OFFSET 0xC0U
#define PMC_SECURE_SCRATCH5_OFFSET 0xC4U
#define PMC_SECURE_SCRATCH6_OFFSET 0x224U
#define PMC_SECURE_SCRATCH7_OFFSET 0x228U
#define PMC_SECURE_SCRATCH116_OFFSET 0xB28U
#define PMC_SECURE_SCRATCH117_OFFSET 0xB2CU
#define PMC_SECURE_SCRATCH120_OFFSET 0xB38U
#define PMC_SECURE_SCRATCH121_OFFSET 0xB3CU
#define PMC_SECURE_SCRATCH122_OFFSET 0xB40U
#define PMC_SECURE_SCRATCH123_OFFSET 0xB44U
/*
* AHB arbitration memory write queue
*/
#define ARAHB_MEM_WRQUE_MST_ID_OFFSET 0xFCU
#define ARAHB_MST_ID_SE2_MASK (0x1U << 13)
#define ARAHB_MST_ID_SE_MASK (0x1U << 14)
/**
* SE registers
*/
#define TEGRA_SE_AES_KEYSLOT_COUNT 16
#define SE_MAX_LAST_BLOCK_SIZE 0xFFFFF
/* SE Status register */
#define SE_STATUS_OFFSET 0x800U
#define SE_STATUS_SHIFT 0
#define SE_STATUS_IDLE \
((0U) << SE_STATUS_SHIFT)
#define SE_STATUS_BUSY \
((1U) << SE_STATUS_SHIFT)
#define SE_STATUS(x) \
((x) & ((0x3U) << SE_STATUS_SHIFT))
#define SE_MEM_INTERFACE_SHIFT 2
#define SE_MEM_INTERFACE_IDLE 0
#define SE_MEM_INTERFACE_BUSY 1
#define SE_MEM_INTERFACE(x) ((x) << SE_STATUS_SHIFT)
/* SE register definitions */
#define SE_SECURITY_REG_OFFSET 0x0
#define SE_SECURITY_TZ_LOCK_SOFT_SHIFT 5
#define SE_SECURE 0x0
#define SE_SECURITY_TZ_LOCK_SOFT(x) ((x) << SE_SECURITY_TZ_LOCK_SOFT_SHIFT)
#define SE_SEC_ENG_DIS_SHIFT 1
#define SE_DISABLE_FALSE 0
#define SE_DISABLE_TRUE 1
#define SE_SEC_ENG_DISABLE(x)((x) << SE_SEC_ENG_DIS_SHIFT)
/* SE config register */
#define SE_CONFIG_REG_OFFSET 0x14U
#define SE_CONFIG_ENC_ALG_SHIFT 12
#define SE_CONFIG_ENC_ALG_AES_ENC \
((1U) << SE_CONFIG_ENC_ALG_SHIFT)
#define SE_CONFIG_ENC_ALG_RNG \
((2U) << SE_CONFIG_ENC_ALG_SHIFT)
#define SE_CONFIG_ENC_ALG_SHA \
((3U) << SE_CONFIG_ENC_ALG_SHIFT)
#define SE_CONFIG_ENC_ALG_RSA \
((4U) << SE_CONFIG_ENC_ALG_SHIFT)
#define SE_CONFIG_ENC_ALG_NOP \
((0U) << SE_CONFIG_ENC_ALG_SHIFT)
#define SE_CONFIG_ENC_ALG(x) \
((x) & ((0xFU) << SE_CONFIG_ENC_ALG_SHIFT))
#define SE_CONFIG_DEC_ALG_SHIFT 8
#define SE_CONFIG_DEC_ALG_AES \
((1U) << SE_CONFIG_DEC_ALG_SHIFT)
#define SE_CONFIG_DEC_ALG_NOP \
((0U) << SE_CONFIG_DEC_ALG_SHIFT)
#define SE_CONFIG_DEC_ALG(x) \
((x) & ((0xFU) << SE_CONFIG_DEC_ALG_SHIFT))
#define SE_CONFIG_DST_SHIFT 2
#define SE_CONFIG_DST_MEMORY \
((0U) << SE_CONFIG_DST_SHIFT)
#define SE_CONFIG_DST_HASHREG \
((1U) << SE_CONFIG_DST_SHIFT)
#define SE_CONFIG_DST_KEYTAB \
((2U) << SE_CONFIG_DST_SHIFT)
#define SE_CONFIG_DST_SRK \
((3U) << SE_CONFIG_DST_SHIFT)
#define SE_CONFIG_DST_RSAREG \
((4U) << SE_CONFIG_DST_SHIFT)
#define SE_CONFIG_DST(x) \
((x) & ((0x7U) << SE_CONFIG_DST_SHIFT))
#define SE_CONFIG_ENC_MODE_SHIFT 24
#define SE_CONFIG_ENC_MODE_KEY128 \
((0UL) << SE_CONFIG_ENC_MODE_SHIFT)
#define SE_CONFIG_ENC_MODE_KEY192 \
((1UL) << SE_CONFIG_ENC_MODE_SHIFT)
#define SE_CONFIG_ENC_MODE_KEY256 \
((2UL) << SE_CONFIG_ENC_MODE_SHIFT)
#define SE_CONFIG_ENC_MODE_SHA1 \
((0UL) << SE_CONFIG_ENC_MODE_SHIFT)
#define SE_CONFIG_ENC_MODE_SHA224 \
((4UL) << SE_CONFIG_ENC_MODE_SHIFT)
#define SE_CONFIG_ENC_MODE_SHA256 \
((5UL) << SE_CONFIG_ENC_MODE_SHIFT)
#define SE_CONFIG_ENC_MODE_SHA384 \
((6UL) << SE_CONFIG_ENC_MODE_SHIFT)
#define SE_CONFIG_ENC_MODE_SHA512 \
((7UL) << SE_CONFIG_ENC_MODE_SHIFT)
#define SE_CONFIG_ENC_MODE(x)\
((x) & ((0xFFUL) << SE_CONFIG_ENC_MODE_SHIFT))
#define SE_CONFIG_DEC_MODE_SHIFT 16
#define SE_CONFIG_DEC_MODE_KEY128 \
((0UL) << SE_CONFIG_DEC_MODE_SHIFT)
#define SE_CONFIG_DEC_MODE_KEY192 \
((1UL) << SE_CONFIG_DEC_MODE_SHIFT)
#define SE_CONFIG_DEC_MODE_KEY256 \
((2UL) << SE_CONFIG_DEC_MODE_SHIFT)
#define SE_CONFIG_DEC_MODE_SHA1 \
((0UL) << SE_CONFIG_DEC_MODE_SHIFT)
#define SE_CONFIG_DEC_MODE_SHA224 \
((4UL) << SE_CONFIG_DEC_MODE_SHIFT)
#define SE_CONFIG_DEC_MODE_SHA256 \
((5UL) << SE_CONFIG_DEC_MODE_SHIFT)
#define SE_CONFIG_DEC_MODE_SHA384 \
((6UL) << SE_CONFIG_DEC_MODE_SHIFT)
#define SE_CONFIG_DEC_MODE_SHA512 \
((7UL) << SE_CONFIG_DEC_MODE_SHIFT)
#define SE_CONFIG_DEC_MODE(x)\
((x) & ((0xFFUL) << SE_CONFIG_DEC_MODE_SHIFT))
/* DRBG random number generator config */
#define SE_RNG_CONFIG_REG_OFFSET 0x340
#define DRBG_MODE_SHIFT 0
#define DRBG_MODE_NORMAL \
((0U) << DRBG_MODE_SHIFT)
#define DRBG_MODE_FORCE_INSTANTION \
((1U) << DRBG_MODE_SHIFT)
#define DRBG_MODE_FORCE_RESEED \
((2U) << DRBG_MODE_SHIFT)
#define SE_RNG_CONFIG_MODE(x) \
((x) & ((0x3U) << DRBG_MODE_SHIFT))
#define DRBG_SRC_SHIFT 2
#define DRBG_SRC_NONE \
((0U) << DRBG_SRC_SHIFT)
#define DRBG_SRC_ENTROPY \
((1U) << DRBG_SRC_SHIFT)
#define DRBG_SRC_LFSR \
((2U) << DRBG_SRC_SHIFT)
#define SE_RNG_SRC_CONFIG_MODE(x) \
((x) & ((0x3U) << DRBG_SRC_SHIFT))
/* DRBG random number generator entropy config */
#define SE_RNG_SRC_CONFIG_REG_OFFSET 0x344U
#define DRBG_RO_ENT_SRC_SHIFT 1
#define DRBG_RO_ENT_SRC_ENABLE \
((1U) << DRBG_RO_ENT_SRC_SHIFT)
#define DRBG_RO_ENT_SRC_DISABLE \
((0U) << DRBG_RO_ENT_SRC_SHIFT)
#define SE_RNG_SRC_CONFIG_RO_ENT_SRC(x) \
((x) & ((0x1U) << DRBG_RO_ENT_SRC_SHIFT))
#define DRBG_RO_ENT_SRC_LOCK_SHIFT 0
#define DRBG_RO_ENT_SRC_LOCK_ENABLE \
((1U) << DRBG_RO_ENT_SRC_LOCK_SHIFT)
#define DRBG_RO_ENT_SRC_LOCK_DISABLE \
((0U) << DRBG_RO_ENT_SRC_LOCK_SHIFT)
#define SE_RNG_SRC_CONFIG_RO_ENT_SRC_LOCK(x) \
((x) & ((0x1U) << DRBG_RO_ENT_SRC_LOCK_SHIFT))
#define DRBG_RO_ENT_IGNORE_MEM_SHIFT 12
#define DRBG_RO_ENT_IGNORE_MEM_ENABLE \
((1U) << DRBG_RO_ENT_IGNORE_MEM_SHIFT)
#define DRBG_RO_ENT_IGNORE_MEM_DISABLE \
((0U) << DRBG_RO_ENT_IGNORE_MEM_SHIFT)
#define SE_RNG_SRC_CONFIG_RO_ENT_IGNORE_MEM(x) \
((x) & ((0x1U) << DRBG_RO_ENT_IGNORE_MEM_SHIFT))
#define SE_RNG_RESEED_INTERVAL_REG_OFFSET 0x348
/* SE CRYPTO */
#define SE_CRYPTO_REG_OFFSET 0x304
#define SE_CRYPTO_HASH_SHIFT 0
#define SE_CRYPTO_HASH_DISABLE \
((0U) << SE_CRYPTO_HASH_SHIFT)
#define SE_CRYPTO_HASH_ENABLE \
((1U) << SE_CRYPTO_HASH_SHIFT)
#define SE_CRYPTO_XOR_POS_SHIFT 1
#define SE_CRYPTO_XOR_BYPASS \
((0U) << SE_CRYPTO_XOR_POS_SHIFT)
#define SE_CRYPTO_XOR_TOP \
((2U) << SE_CRYPTO_XOR_POS_SHIFT)
#define SE_CRYPTO_XOR_BOTTOM \
((3U) << SE_CRYPTO_XOR_POS_SHIFT)
#define SE_CRYPTO_INPUT_SEL_SHIFT 3
#define SE_CRYPTO_INPUT_AHB \
((0U) << SE_CRYPTO_INPUT_SEL_SHIFT)
#define SE_CRYPTO_INPUT_RANDOM \
((1U) << SE_CRYPTO_INPUT_SEL_SHIFT)
#define SE_CRYPTO_INPUT_AESOUT \
((2U) << SE_CRYPTO_INPUT_SEL_SHIFT)
#define SE_CRYPTO_INPUT_LNR_CTR \
((3U) << SE_CRYPTO_INPUT_SEL_SHIFT)
#define SE_CRYPTO_VCTRAM_SEL_SHIFT 5
#define SE_CRYPTO_VCTRAM_AHB \
((0U) << SE_CRYPTO_VCTRAM_SEL_SHIFT)
#define SE_CRYPTO_VCTRAM_AESOUT \
((2U) << SE_CRYPTO_VCTRAM_SEL_SHIFT)
#define SE_CRYPTO_VCTRAM_PREVAHB \
((3U) << SE_CRYPTO_VCTRAM_SEL_SHIFT)
#define SE_CRYPTO_IV_SEL_SHIFT 7
#define SE_CRYPTO_IV_ORIGINAL \
((0U) << SE_CRYPTO_IV_SEL_SHIFT)
#define SE_CRYPTO_IV_UPDATED \
((1U) << SE_CRYPTO_IV_SEL_SHIFT)
#define SE_CRYPTO_CORE_SEL_SHIFT 8
#define SE_CRYPTO_CORE_DECRYPT \
((0U) << SE_CRYPTO_CORE_SEL_SHIFT)
#define SE_CRYPTO_CORE_ENCRYPT \
((1U) << SE_CRYPTO_CORE_SEL_SHIFT)
#define SE_CRYPTO_KEY_INDEX_SHIFT 24
#define SE_CRYPTO_KEY_INDEX(x) (x << SE_CRYPTO_KEY_INDEX_SHIFT)
#define SE_CRYPTO_MEMIF_AHB \
((0U) << SE_CRYPTO_MEMIF_SHIFT)
#define SE_CRYPTO_MEMIF_MCCIF \
((1U) << SE_CRYPTO_MEMIF_SHIFT)
#define SE_CRYPTO_MEMIF_SHIFT 31
/* KEY TABLE */
#define SE_KEYTABLE_REG_OFFSET 0x31C
/* KEYIV PKT - key slot */
#define SE_KEYTABLE_SLOT_SHIFT 4
#define SE_KEYTABLE_SLOT(x) (x << SE_KEYTABLE_SLOT_SHIFT)
/* KEYIV PKT - KEYIV select */
#define SE_KEYIV_PKT_KEYIV_SEL_SHIFT 3
#define SE_CRYPTO_KEYIV_KEY \
((0U) << SE_KEYIV_PKT_KEYIV_SEL_SHIFT)
#define SE_CRYPTO_KEYIV_IVS \
((1U) << SE_KEYIV_PKT_KEYIV_SEL_SHIFT)
/* KEYIV PKT - IV select */
#define SE_KEYIV_PKT_IV_SEL_SHIFT 2
#define SE_CRYPTO_KEYIV_IVS_OIV \
((0U) << SE_KEYIV_PKT_IV_SEL_SHIFT)
#define SE_CRYPTO_KEYIV_IVS_UIV \
((1U) << SE_KEYIV_PKT_IV_SEL_SHIFT)
/* KEYIV PKT - key word */
#define SE_KEYIV_PKT_KEY_WORD_SHIFT 0
#define SE_KEYIV_PKT_KEY_WORD(x) \
((x) << SE_KEYIV_PKT_KEY_WORD_SHIFT)
/* KEYIV PKT - iv word */
#define SE_KEYIV_PKT_IV_WORD_SHIFT 0
#define SE_KEYIV_PKT_IV_WORD(x) \
((x) << SE_KEYIV_PKT_IV_WORD_SHIFT)
/* SE OPERATION */
#define SE_OPERATION_REG_OFFSET 0x8U
#define SE_OPERATION_SHIFT 0
#define SE_OP_ABORT \
((0x0U) << SE_OPERATION_SHIFT)
#define SE_OP_START \
((0x1U) << SE_OPERATION_SHIFT)
#define SE_OP_RESTART \
((0x2U) << SE_OPERATION_SHIFT)
#define SE_OP_CTX_SAVE \
((0x3U) << SE_OPERATION_SHIFT)
#define SE_OP_RESTART_IN \
((0x4U) << SE_OPERATION_SHIFT)
#define SE_OPERATION(x) \
((x) & ((0x7U) << SE_OPERATION_SHIFT))
/* SE CONTEXT */
#define SE_CTX_SAVE_CONFIG_REG_OFFSET 0x70
#define SE_CTX_SAVE_WORD_QUAD_SHIFT 0
#define SE_CTX_SAVE_WORD_QUAD(x) \
(x << SE_CTX_SAVE_WORD_QUAD_SHIFT)
#define SE_CTX_SAVE_WORD_QUAD_KEYS_0_3 \
((0U) << SE_CTX_SAVE_WORD_QUAD_SHIFT)
#define SE_CTX_SAVE_WORD_QUAD_KEYS_4_7 \
((1U) << SE_CTX_SAVE_WORD_QUAD_SHIFT)
#define SE_CTX_SAVE_WORD_QUAD_ORIG_IV \
((2U) << SE_CTX_SAVE_WORD_QUAD_SHIFT)
#define SE_CTX_SAVE_WORD_QUAD_UPD_IV \
((3U) << SE_CTX_SAVE_WORD_QUAD_SHIFT)
#define SE_CTX_SAVE_KEY_INDEX_SHIFT 8
#define SE_CTX_SAVE_KEY_INDEX(x) (x << SE_CTX_SAVE_KEY_INDEX_SHIFT)
#define SE_CTX_SAVE_STICKY_WORD_QUAD_SHIFT 24
#define SE_CTX_SAVE_STICKY_WORD_QUAD_STICKY_0_3 \
((0U) << SE_CTX_SAVE_STICKY_WORD_QUAD_SHIFT)
#define SE_CTX_SAVE_STICKY_WORD_QUAD_STICKY_4_7 \
((1U) << SE_CTX_SAVE_STICKY_WORD_QUAD_SHIFT)
#define SE_CTX_SAVE_STICKY_WORD_QUAD(x) \
(x << SE_CTX_SAVE_STICKY_WORD_QUAD_SHIFT)
#define SE_CTX_SAVE_SRC_SHIFT 29
#define SE_CTX_SAVE_SRC_STICKY_BITS \
((0U) << SE_CTX_SAVE_SRC_SHIFT)
#define SE_CTX_SAVE_SRC_RSA_KEYTABLE \
((1U) << SE_CTX_SAVE_SRC_SHIFT)
#define SE_CTX_SAVE_SRC_AES_KEYTABLE \
((2U) << SE_CTX_SAVE_SRC_SHIFT)
#define SE_CTX_SAVE_SRC_PKA1_STICKY_BITS \
((3U) << SE_CTX_SAVE_SRC_SHIFT)
#define SE_CTX_SAVE_SRC_MEM \
((4U) << SE_CTX_SAVE_SRC_SHIFT)
#define SE_CTX_SAVE_SRC_SRK \
((6U) << SE_CTX_SAVE_SRC_SHIFT)
#define SE_CTX_SAVE_SRC_PKA1_KEYTABLE \
((7U) << SE_CTX_SAVE_SRC_SHIFT)
#define SE_CTX_STICKY_WORD_QUAD_SHIFT 24
#define SE_CTX_STICKY_WORD_QUAD_WORDS_0_3 \
((0U) << SE_CTX_STICKY_WORD_QUAD_SHIFT)
#define SE_CTX_STICKY_WORD_QUAD_WORDS_4_7 \
((1U) << SE_CTX_STICKY_WORD_QUAD_SHIFT)
#define SE_CTX_STICKY_WORD_QUAD(x) (x << SE_CTX_STICKY_WORD_QUAD_SHIFT)
#define SE_CTX_SAVE_RSA_KEY_INDEX_SHIFT 16
#define SE_CTX_SAVE_RSA_KEY_INDEX(x) \
(x << SE_CTX_SAVE_RSA_KEY_INDEX_SHIFT)
#define SE_CTX_RSA_WORD_QUAD_SHIFT 12
#define SE_CTX_RSA_WORD_QUAD(x) \
(x << SE_CTX_RSA_WORD_QUAD_SHIFT)
#define SE_CTX_PKA1_WORD_QUAD_L_SHIFT 0
#define SE_CTX_PKA1_WORD_QUAD_L_SIZE \
((true ? 4:0) - \
(false ? 4:0) + 1)
#define SE_CTX_PKA1_WORD_QUAD_L(x)\
(((x) << SE_CTX_PKA1_WORD_QUAD_L_SHIFT) & 0x1f)
#define SE_CTX_PKA1_WORD_QUAD_H_SHIFT 12
#define SE_CTX_PKA1_WORD_QUAD_H(x)\
((((x) >> SE_CTX_PKA1_WORD_QUAD_L_SIZE) & 0xf) \
<< SE_CTX_PKA1_WORD_QUAD_H_SHIFT)
#define SE_RSA_KEY_INDEX_SLOT0_EXP 0
#define SE_RSA_KEY_INDEX_SLOT0_MOD 1
#define SE_RSA_KEY_INDEX_SLOT1_EXP 2
#define SE_RSA_KEY_INDEX_SLOT1_MOD 3
/* SE_CTX_SAVE_AUTO */
#define SE_CTX_SAVE_AUTO_REG_OFFSET 0x74U
/* Enable */
#define SE_CTX_SAVE_AUTO_ENABLE_SHIFT 0
#define SE_CTX_SAVE_AUTO_DIS \
((0U) << SE_CTX_SAVE_AUTO_ENABLE_SHIFT)
#define SE_CTX_SAVE_AUTO_EN \
((1U) << SE_CTX_SAVE_AUTO_ENABLE_SHIFT)
#define SE_CTX_SAVE_AUTO_ENABLE(x) \
((x) & ((0x1U) << SE_CTX_SAVE_AUTO_ENABLE_SHIFT))
/* Lock */
#define SE_CTX_SAVE_AUTO_LOCK_SHIFT 8
#define SE_CTX_SAVE_AUTO_LOCK_EN \
((1U) << SE_CTX_SAVE_AUTO_LOCK_SHIFT)
#define SE_CTX_SAVE_AUTO_LOCK_DIS \
((0U) << SE_CTX_SAVE_AUTO_LOCK_SHIFT)
#define SE_CTX_SAVE_AUTO_LOCK(x) \
((x) & ((0x1U) << SE_CTX_SAVE_AUTO_LOCK_SHIFT))
/* Current context save number of blocks*/
#define SE_CTX_SAVE_AUTO_CURR_CNT_SHIFT 16
#define SE_CTX_SAVE_AUTO_CURR_CNT_MASK 0x3FFU
#define SE_CTX_SAVE_GET_BLK_COUNT(x) \
(((x) >> SE_CTX_SAVE_AUTO_CURR_CNT_SHIFT) & \
SE_CTX_SAVE_AUTO_CURR_CNT_MASK)
#define SE_CTX_SAVE_SIZE_BLOCKS_SE1 133
#define SE_CTX_SAVE_SIZE_BLOCKS_SE2 646
/* SE TZRAM OPERATION - only for SE1 */
#define SE_TZRAM_OPERATION 0x540U
#define SE_TZRAM_OP_MODE_SHIFT 1
#define SE_TZRAM_OP_COMMAND_INIT 1
#define SE_TZRAM_OP_COMMAND_SHIFT 0
#define SE_TZRAM_OP_MODE_SAVE \
((0U) << SE_TZRAM_OP_MODE_SHIFT)
#define SE_TZRAM_OP_MODE_RESTORE \
((1U) << SE_TZRAM_OP_MODE_SHIFT)
#define SE_TZRAM_OP_MODE(x) \
((x) & ((0x1U) << SE_TZRAM_OP_MODE_SHIFT))
#define SE_TZRAM_OP_BUSY_SHIFT 2
#define SE_TZRAM_OP_BUSY_OFF \
((0U) << SE_TZRAM_OP_BUSY_SHIFT)
#define SE_TZRAM_OP_BUSY_ON \
((1U) << SE_TZRAM_OP_BUSY_SHIFT)
#define SE_TZRAM_OP_BUSY(x) \
((x) & ((0x1U) << SE_TZRAM_OP_BUSY_SHIFT))
#define SE_TZRAM_OP_REQ_SHIFT 0
#define SE_TZRAM_OP_REQ_IDLE \
((0U) << SE_TZRAM_OP_REQ_SHIFT)
#define SE_TZRAM_OP_REQ_INIT \
((1U) << SE_TZRAM_OP_REQ_SHIFT)
#define SE_TZRAM_OP_REQ(x) \
((x) & ((0x1U) << SE_TZRAM_OP_REQ_SHIFT))
/* SE Interrupt */
#define SE_INT_ENABLE_REG_OFFSET U(0xC)
#define SE_INT_STATUS_REG_OFFSET 0x10U
#define SE_INT_OP_DONE_SHIFT 4
#define SE_INT_OP_DONE_CLEAR \
((0U) << SE_INT_OP_DONE_SHIFT)
#define SE_INT_OP_DONE_ACTIVE \
((1U) << SE_INT_OP_DONE_SHIFT)
#define SE_INT_OP_DONE(x) \
((x) & ((0x1U) << SE_INT_OP_DONE_SHIFT))
/* SE TZRAM SECURITY */
#define SE_TZRAM_SEC_REG_OFFSET 0x4
#define SE_TZRAM_SEC_SETTING_SHIFT 0
#define SE_TZRAM_SECURE \
((0UL) << SE_TZRAM_SEC_SETTING_SHIFT)
#define SE_TZRAM_NONSECURE \
((1UL) << SE_TZRAM_SEC_SETTING_SHIFT)
#define SE_TZRAM_SEC_SETTING(x) \
((x) & ((0x1UL) << SE_TZRAM_SEC_SETTING_SHIFT))
/* PKA1 KEY SLOTS */
#define TEGRA_SE_PKA1_KEYSLOT_COUNT 4
/* SE error status */
#define SE_ERR_STATUS_REG_OFFSET 0x804U
#define SE_CRYPTO_KEYTABLE_DST_REG_OFFSET 0x330
#define SE_CRYPTO_KEYTABLE_DST_WORD_QUAD_SHIFT 0
#define SE_CRYPTO_KEYTABLE_DST_WORD_QUAD(x) \
(x << SE_CRYPTO_KEYTABLE_DST_WORD_QUAD_SHIFT)
#define SE_KEY_INDEX_SHIFT 8
#define SE_CRYPTO_KEYTABLE_DST_KEY_INDEX(x) (x << SE_KEY_INDEX_SHIFT)
/* SE linked list (LL) register */
#define SE_IN_LL_ADDR_REG_OFFSET 0x18U
#define SE_OUT_LL_ADDR_REG_OFFSET 0x24U
#define SE_BLOCK_COUNT_REG_OFFSET 0x318U
/* AES data sizes */
#define TEGRA_SE_KEY_256_SIZE 32
#define TEGRA_SE_KEY_192_SIZE 24
#define TEGRA_SE_KEY_128_SIZE 16
#define TEGRA_SE_AES_BLOCK_SIZE 16
#define TEGRA_SE_AES_MIN_KEY_SIZE 16
#define TEGRA_SE_AES_MAX_KEY_SIZE 32
#define TEGRA_SE_AES_IV_SIZE 16
#define TEGRA_SE_RNG_IV_SIZE 16
#define TEGRA_SE_RNG_DT_SIZE 16
#define TEGRA_SE_RNG_KEY_SIZE 16
#define TEGRA_SE_RNG_SEED_SIZE (TEGRA_SE_RNG_IV_SIZE + \
TEGRA_SE_RNG_KEY_SIZE + \
TEGRA_SE_RNG_DT_SIZE)
#define TEGRA_SE_RSA512_DIGEST_SIZE 64
#define TEGRA_SE_RSA1024_DIGEST_SIZE 128
#define TEGRA_SE_RSA1536_DIGEST_SIZE 192
#define TEGRA_SE_RSA2048_DIGEST_SIZE 256
#define SE_KEY_TABLE_ACCESS_REG_OFFSET 0x284
#define SE_KEY_READ_DISABLE_SHIFT 0
#define SE_CTX_BUFER_SIZE 1072
#define SE_CTX_DRBG_BUFER_SIZE 2112
/* SE blobs size in bytes */
#define SE_CTX_SAVE_RSA_KEY_LENGTH 1024
#define SE_CTX_SAVE_RANDOM_DATA_SIZE 16
#define SE_CTX_SAVE_STICKY_BITS_SIZE 16
#define SE2_CONTEXT_SAVE_PKA1_STICKY_BITS_LENGTH 16
#define SE2_CONTEXT_SAVE_PKA1_KEYS_LENGTH 8192
#define SE_CTX_KNOWN_PATTERN_SIZE 16
#define SE_CTX_KNOWN_PATTERN_SIZE_WORDS (SE_CTX_KNOWN_PATTERN_SIZE/4)
/* SE RSA */
#define TEGRA_SE_RSA_KEYSLOT_COUNT 2
#define SE_RSA_KEY_SIZE_REG_OFFSET 0x404
#define SE_RSA_EXP_SIZE_REG_OFFSET 0x408
#define SE_RSA_MAX_EXP_BIT_SIZE 2048
#define SE_RSA_MAX_EXP_SIZE32 \
(SE_RSA_MAX_EXP_BIT_SIZE >> 5)
#define SE_RSA_MAX_MOD_BIT_SIZE 2048
#define SE_RSA_MAX_MOD_SIZE32 \
(SE_RSA_MAX_MOD_BIT_SIZE >> 5)
/* SE_RSA_KEYTABLE_ADDR */
#define SE_RSA_KEYTABLE_ADDR 0x420
#define RSA_KEY_PKT_WORD_ADDR_SHIFT 0
#define RSA_KEY_PKT_EXPMOD_SEL_SHIFT \
((6U) << RSA_KEY_PKT_WORD_ADDR_SHIFT)
#define RSA_KEY_MOD \
((1U) << RSA_KEY_PKT_EXPMOD_SEL_SHIFT)
#define RSA_KEY_EXP \
((0U) << RSA_KEY_PKT_EXPMOD_SEL_SHIFT)
#define RSA_KEY_PKT_SLOT_SHIFT 7
#define RSA_KEY_SLOT_1 \
((0U) << RSA_KEY_PKT_SLOT_SHIFT)
#define RSA_KEY_SLOT_2 \
((1U) << RSA_KEY_PKT_SLOT_SHIFT)
#define RSA_KEY_PKT_INPUT_MODE_SHIFT 8
#define RSA_KEY_REG_INPUT \
((0U) << RSA_KEY_PKT_INPUT_MODE_SHIFT)
#define RSA_KEY_DMA_INPUT \
((1U) << RSA_KEY_PKT_INPUT_MODE_SHIFT)
/* SE_RSA_KEYTABLE_DATA */
#define SE_RSA_KEYTABLE_DATA 0x424
/* SE_RSA_CONFIG register */
#define SE_RSA_CONFIG 0x400
#define RSA_KEY_SLOT_SHIFT 24
#define RSA_KEY_SLOT(x) \
((x) << RSA_KEY_SLOT_SHIFT)
/*******************************************************************************
* Structure definition
******************************************************************************/
/* SE context blob */
#pragma pack(push, 1)
typedef struct tegra_aes_key_slot {
/* 0 - 7 AES key */
uint32_t key[8];
/* 8 - 11 Original IV */
uint32_t oiv[4];
/* 12 - 15 Updated IV */
uint32_t uiv[4];
} tegra_se_aes_key_slot_t;
#pragma pack(pop)
#pragma pack(push, 1)
typedef struct tegra_se_context {
/* random number */
unsigned char rand_data[SE_CTX_SAVE_RANDOM_DATA_SIZE];
/* Sticky bits */
unsigned char sticky_bits[SE_CTX_SAVE_STICKY_BITS_SIZE * 2];
/* AES key slots */
tegra_se_aes_key_slot_t key_slots[TEGRA_SE_AES_KEYSLOT_COUNT];
/* RSA key slots */
unsigned char rsa_keys[SE_CTX_SAVE_RSA_KEY_LENGTH];
} tegra_se_context_t;
#pragma pack(pop)
/* PKA context blob */
#pragma pack(push, 1)
typedef struct tegra_pka_context {
unsigned char sticky_bits[SE2_CONTEXT_SAVE_PKA1_STICKY_BITS_LENGTH];
unsigned char pka_keys[SE2_CONTEXT_SAVE_PKA1_KEYS_LENGTH];
} tegra_pka_context_t;
#pragma pack(pop)
/* SE context blob */
#pragma pack(push, 1)
typedef struct tegra_se_context_blob {
/* SE context */
tegra_se_context_t se_ctx;
/* Known Pattern */
unsigned char known_pattern[SE_CTX_KNOWN_PATTERN_SIZE];
} tegra_se_context_blob_t;
#pragma pack(pop)
/* SE2 and PKA1 context blob */
#pragma pack(push, 1)
typedef struct tegra_se2_context_blob {
/* SE2 context */
tegra_se_context_t se_ctx;
/* PKA1 context */
tegra_pka_context_t pka_ctx;
/* Known Pattern */
unsigned char known_pattern[SE_CTX_KNOWN_PATTERN_SIZE];
} tegra_se2_context_blob_t;
#pragma pack(pop)
/* SE AES key type 128bit, 192bit, 256bit */
typedef enum {
SE_AES_KEY128,
SE_AES_KEY192,
SE_AES_KEY256,
} tegra_se_aes_key_type_t;
/* SE RSA key slot */
typedef struct tegra_se_rsa_key_slot {
/* 0 - 63 exponent key */
uint32_t exponent[SE_RSA_MAX_EXP_SIZE32];
/* 64 - 127 modulus key */
uint32_t modulus[SE_RSA_MAX_MOD_SIZE32];
} tegra_se_rsa_key_slot_t;
/*******************************************************************************
* Inline functions definition
******************************************************************************/
static inline uint32_t tegra_se_read_32(const tegra_se_dev_t *dev, uint32_t offset)
{
return mmio_read_32(dev->se_base + offset);
}
static inline void tegra_se_write_32(const tegra_se_dev_t *dev, uint32_t offset, uint32_t val)
{
mmio_write_32(dev->se_base + offset, val);
}
static inline uint32_t tegra_pka_read_32(tegra_pka_dev_t *dev, uint32_t offset)
{
return mmio_read_32(dev->pka_base + offset);
}
static inline void tegra_pka_write_32(tegra_pka_dev_t *dev, uint32_t offset,
uint32_t val)
{
mmio_write_32(dev->pka_base + offset, val);
}
/*******************************************************************************
* Prototypes
******************************************************************************/
int tegra_se_start_normal_operation(const tegra_se_dev_t *, uint32_t);
int tegra_se_start_ctx_save_operation(const tegra_se_dev_t *, uint32_t);
#endif /* SE_PRIVATE_H */
@@ -0,0 +1,609 @@
/*
* Copyright (c) 2015-2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <cortex_a57.h>
#include <arch_helpers.h>
#include <common/debug.h>
#include <drivers/delay_timer.h>
#include <lib/mmio.h>
#include <lib/psci/psci.h>
#include <plat/common/platform.h>
#include <bpmp.h>
#include <flowctrl.h>
#include <lib/utils.h>
#include <memctrl.h>
#include <pmc.h>
#include <platform_def.h>
#include <security_engine.h>
#include <tegra_def.h>
#include <tegra_private.h>
#include <tegra_platform.h>
/*
* Register used to clear CPU reset signals. Each CPU has two reset
* signals: CPU reset (3:0) and Core reset (19:16).
*/
#define CPU_CMPLX_RESET_CLR 0x454
#define CPU_CORE_RESET_MASK 0x10001
/* Clock and Reset controller registers for system clock's settings */
#define SCLK_RATE 0x30
#define SCLK_BURST_POLICY 0x28
#define SCLK_BURST_POLICY_DEFAULT 0x10000000
static int cpu_powergate_mask[PLATFORM_MAX_CPUS_PER_CLUSTER];
static bool tegra_bpmp_available = true;
int32_t tegra_soc_validate_power_state(unsigned int power_state,
psci_power_state_t *req_state)
{
int state_id = psci_get_pstate_id(power_state);
const plat_params_from_bl2_t *plat_params = bl31_get_plat_params();
/* Sanity check the requested state id */
switch (state_id) {
case PSTATE_ID_CORE_POWERDN:
/*
* Core powerdown request only for afflvl 0
*/
req_state->pwr_domain_state[MPIDR_AFFLVL0] = state_id & 0xff;
break;
case PSTATE_ID_CLUSTER_IDLE:
/*
* Cluster idle request for afflvl 0
*/
req_state->pwr_domain_state[MPIDR_AFFLVL0] = PSTATE_ID_CORE_POWERDN;
req_state->pwr_domain_state[MPIDR_AFFLVL1] = state_id;
break;
case PSTATE_ID_SOC_POWERDN:
/*
* sc7entry-fw must be present in the system when the bpmp
* firmware is not present, for a successful System Suspend
* entry.
*/
if (!tegra_bpmp_init() && !plat_params->sc7entry_fw_base)
return PSCI_E_NOT_SUPPORTED;
/*
* System powerdown request only for afflvl 2
*/
for (uint32_t i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++)
req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE;
req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] =
PLAT_SYS_SUSPEND_STATE_ID;
break;
default:
ERROR("%s: unsupported state id (%d)\n", __func__, state_id);
return PSCI_E_INVALID_PARAMS;
}
return PSCI_E_SUCCESS;
}
/*******************************************************************************
* Platform handler to calculate the proper target power level at the
* specified affinity level.
******************************************************************************/
plat_local_state_t tegra_soc_get_target_pwr_state(unsigned int lvl,
const plat_local_state_t *states,
unsigned int ncpu)
{
plat_local_state_t target = PSCI_LOCAL_STATE_RUN;
int cpu = plat_my_core_pos();
int core_pos = read_mpidr() & MPIDR_CPU_MASK;
uint32_t bpmp_reply, data[3], val;
int ret;
/* get the power state at this level */
if (lvl == MPIDR_AFFLVL1)
target = *(states + core_pos);
if (lvl == MPIDR_AFFLVL2)
target = *(states + cpu);
if ((lvl == MPIDR_AFFLVL1) && (target == PSTATE_ID_CLUSTER_IDLE)) {
/* initialize the bpmp interface */
ret = tegra_bpmp_init();
if (ret != 0U) {
/*
* flag to indicate that BPMP firmware is not
* available and the CPU has to handle entry/exit
* for all power states
*/
tegra_bpmp_available = false;
/* Cluster idle not allowed */
target = PSCI_LOCAL_STATE_RUN;
/*******************************************
* BPMP is not present, so handle CC6 entry
* from the CPU
******************************************/
/* check if cluster idle state has been enabled */
val = mmio_read_32(TEGRA_CL_DVFS_BASE + DVFS_DFLL_CTRL);
if (val == ENABLE_CLOSED_LOOP) {
/*
* Acquire the cluster idle lock to stop
* other CPUs from powering up.
*/
tegra_fc_ccplex_pgexit_lock();
/* Cluster idle only from the last standing CPU */
if (tegra_pmc_is_last_on_cpu() && tegra_fc_is_ccx_allowed()) {
/* Cluster idle allowed */
target = PSTATE_ID_CLUSTER_IDLE;
} else {
/* release cluster idle lock */
tegra_fc_ccplex_pgexit_unlock();
}
}
} else {
/* Cluster power-down */
data[0] = (uint32_t)cpu;
data[1] = TEGRA_PM_CC6;
data[2] = TEGRA_PM_SC1;
ret = tegra_bpmp_send_receive_atomic(MRQ_DO_IDLE,
(void *)&data, (int)sizeof(data),
(void *)&bpmp_reply,
(int)sizeof(bpmp_reply));
/* check if cluster power down is allowed */
if ((ret != 0L) || (bpmp_reply != BPMP_CCx_ALLOWED)) {
/* Cluster power down not allowed */
target = PSCI_LOCAL_STATE_RUN;
}
}
} else if (((lvl == MPIDR_AFFLVL2) || (lvl == MPIDR_AFFLVL1)) &&
(target == PSTATE_ID_SOC_POWERDN)) {
/* System Suspend */
target = PSTATE_ID_SOC_POWERDN;
} else {
; /* do nothing */
}
return target;
}
int32_t tegra_soc_cpu_standby(plat_local_state_t cpu_state)
{
(void)cpu_state;
return PSCI_E_SUCCESS;
}
int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
{
u_register_t mpidr = read_mpidr();
const plat_local_state_t *pwr_domain_state =
target_state->pwr_domain_state;
unsigned int stateid_afflvl2 = pwr_domain_state[MPIDR_AFFLVL2];
unsigned int stateid_afflvl1 = pwr_domain_state[MPIDR_AFFLVL1];
unsigned int stateid_afflvl0 = pwr_domain_state[MPIDR_AFFLVL0];
uint32_t cfg;
int ret = PSCI_E_SUCCESS;
uint32_t val;
if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
assert((stateid_afflvl0 == PLAT_MAX_OFF_STATE) ||
(stateid_afflvl0 == PSTATE_ID_SOC_POWERDN));
assert((stateid_afflvl1 == PLAT_MAX_OFF_STATE) ||
(stateid_afflvl1 == PSTATE_ID_SOC_POWERDN));
/* Suspend se/se2 and pka1 for T210 B01 and se for T210 */
if (tegra_se_suspend() != 0) {
ret = PSCI_E_INTERN_FAIL;
}
} else if (stateid_afflvl1 == PSTATE_ID_CLUSTER_IDLE) {
assert(stateid_afflvl0 == PSTATE_ID_CORE_POWERDN);
if (!tegra_bpmp_available) {
/*
* When disabled, DFLL loses its state. Enable
* open loop state for the DFLL as we dont want
* garbage values being written to the pmic
* when we enter cluster idle state.
*/
mmio_write_32(TEGRA_CL_DVFS_BASE + DVFS_DFLL_CTRL,
ENABLE_OPEN_LOOP);
/* Find if the platform uses OVR2/MAX77621 PMIC */
cfg = mmio_read_32(TEGRA_CL_DVFS_BASE + DVFS_DFLL_OUTPUT_CFG);
if (cfg & DFLL_OUTPUT_CFG_CLK_EN_BIT) {
/* OVR2 */
/* PWM tristate */
val = mmio_read_32(TEGRA_MISC_BASE + PINMUX_AUX_DVFS_PWM);
val |= PINMUX_PWM_TRISTATE;
mmio_write_32(TEGRA_MISC_BASE + PINMUX_AUX_DVFS_PWM, val);
/*
* SCRATCH201[1] is being used to identify CPU
* PMIC in warmboot code.
* 0 : OVR2
* 1 : MAX77621
*/
tegra_pmc_write_32(PMC_SCRATCH201, 0x0);
} else {
/* MAX77621 */
tegra_pmc_write_32(PMC_SCRATCH201, 0x2);
}
}
/* Prepare for cluster idle */
tegra_fc_cluster_idle(mpidr);
} else if (stateid_afflvl0 == PSTATE_ID_CORE_POWERDN) {
/* Prepare for cpu powerdn */
tegra_fc_cpu_powerdn(mpidr);
} else {
ERROR("%s: Unknown state id (%d, %d, %d)\n", __func__,
stateid_afflvl2, stateid_afflvl1, stateid_afflvl0);
ret = PSCI_E_NOT_SUPPORTED;
}
return ret;
}
static void tegra_reset_all_dma_masters(void)
{
uint32_t val, mask;
/*
* Reset all possible DMA masters in the system.
*/
val = GPU_RESET_BIT;
mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_GPU_RESET_REG_OFFSET, val);
val = NVENC_RESET_BIT | TSECB_RESET_BIT | APE_RESET_BIT |
NVJPG_RESET_BIT | NVDEC_RESET_BIT;
mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_Y, val);
val = HOST1X_RESET_BIT | ISP_RESET_BIT | USBD_RESET_BIT |
VI_RESET_BIT | SDMMC4_RESET_BIT | SDMMC1_RESET_BIT |
SDMMC2_RESET_BIT;
mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_L, val);
val = USB2_RESET_BIT | APBDMA_RESET_BIT | AHBDMA_RESET_BIT;
mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_H, val);
val = XUSB_DEV_RESET_BIT | XUSB_HOST_RESET_BIT | TSEC_RESET_BIT |
PCIE_RESET_BIT | SDMMC3_RESET_BIT;
mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_U, val);
val = SE_RESET_BIT | HDA_RESET_BIT | SATA_RESET_BIT;
mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_V, val);
/*
* If any of the DMA masters are still alive, assume
* that the system has been compromised and reboot.
*/
val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_GPU_RESET_REG_OFFSET);
mask = GPU_RESET_BIT;
if ((val & mask) != mask)
tegra_pmc_system_reset();
mask = NVENC_RESET_BIT | TSECB_RESET_BIT | APE_RESET_BIT |
NVJPG_RESET_BIT | NVDEC_RESET_BIT;
val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_Y);
if ((val & mask) != mask)
tegra_pmc_system_reset();
mask = HOST1X_RESET_BIT | ISP_RESET_BIT | USBD_RESET_BIT |
VI_RESET_BIT | SDMMC4_RESET_BIT | SDMMC1_RESET_BIT |
SDMMC2_RESET_BIT;
val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_L);
if ((val & mask) != mask)
tegra_pmc_system_reset();
mask = USB2_RESET_BIT | APBDMA_RESET_BIT | AHBDMA_RESET_BIT;
val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_H);
if ((val & mask) != mask)
tegra_pmc_system_reset();
mask = XUSB_DEV_RESET_BIT | XUSB_HOST_RESET_BIT | TSEC_RESET_BIT |
PCIE_RESET_BIT | SDMMC3_RESET_BIT;
val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_U);
if ((val & mask) != mask)
tegra_pmc_system_reset();
val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_V);
mask = SE_RESET_BIT | HDA_RESET_BIT | SATA_RESET_BIT;
if ((val & mask) != mask)
tegra_pmc_system_reset();
}
int tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state)
{
u_register_t mpidr = read_mpidr();
const plat_local_state_t *pwr_domain_state =
target_state->pwr_domain_state;
unsigned int stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL];
const plat_params_from_bl2_t *plat_params = bl31_get_plat_params();
uint32_t val;
if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
if (tegra_chipid_is_t210_b01()) {
/* Save tzram contents */
tegra_se_save_tzram();
}
/* de-init the interface */
tegra_bpmp_suspend();
/*
* The CPU needs to load the System suspend entry firmware
* if nothing is running on the BPMP.
*/
if (!tegra_bpmp_available) {
/*
* BPMP firmware is not running on the co-processor, so
* we need to explicitly load the firmware to enable
* entry/exit to/from System Suspend and set the BPMP
* on its way.
*/
/* Power off BPMP before we proceed */
tegra_fc_bpmp_off();
/* bond out IRAM banks B, C and D */
mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_BOND_OUT_U,
IRAM_B_LOCK_BIT | IRAM_C_LOCK_BIT |
IRAM_D_LOCK_BIT);
/* bond out APB/AHB DMAs */
mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_BOND_OUT_H,
APB_DMA_LOCK_BIT | AHB_DMA_LOCK_BIT);
/* Power off BPMP before we proceed */
tegra_fc_bpmp_off();
/*
* Reset all the hardware blocks that can act as DMA
* masters on the bus.
*/
tegra_reset_all_dma_masters();
/*
* Mark PMC as accessible to the non-secure world
* to allow the COP to execute System Suspend
* sequence
*/
val = mmio_read_32(TEGRA_MISC_BASE + APB_SLAVE_SECURITY_ENABLE);
val &= ~PMC_SECURITY_EN_BIT;
mmio_write_32(TEGRA_MISC_BASE + APB_SLAVE_SECURITY_ENABLE, val);
/* clean up IRAM of any cruft */
zeromem((void *)(uintptr_t)TEGRA_IRAM_BASE,
TEGRA_IRAM_A_SIZE);
/* Copy the firmware to BPMP's internal RAM */
(void)memcpy((void *)(uintptr_t)TEGRA_IRAM_BASE,
(const void *)(plat_params->sc7entry_fw_base + SC7ENTRY_FW_HEADER_SIZE_BYTES),
plat_params->sc7entry_fw_size - SC7ENTRY_FW_HEADER_SIZE_BYTES);
/* Power on the BPMP and execute from IRAM base */
tegra_fc_bpmp_on(TEGRA_IRAM_BASE);
/* Wait until BPMP powers up */
do {
val = mmio_read_32(TEGRA_RES_SEMA_BASE + STA_OFFSET);
} while (val != SIGN_OF_LIFE);
}
/* enter system suspend */
tegra_fc_soc_powerdn(mpidr);
}
return PSCI_E_SUCCESS;
}
int32_t tegra_soc_pwr_domain_suspend_pwrdown_early(const psci_power_state_t *target_state)
{
return PSCI_E_NOT_SUPPORTED;
}
int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
{
const plat_params_from_bl2_t *plat_params = bl31_get_plat_params();
uint32_t cfg;
uint32_t val, entrypoint = 0;
uint64_t offset;
/* platform parameter passed by the previous bootloader */
if (plat_params->l2_ecc_parity_prot_dis != 1) {
/* Enable ECC Parity Protection for Cortex-A57 CPUs */
val = read_l2ctlr_el1();
val |= (uint64_t)CORTEX_A57_L2_ECC_PARITY_PROTECTION_BIT;
write_l2ctlr_el1(val);
}
/*
* Check if we are exiting from SOC_POWERDN.
*/
if (target_state->pwr_domain_state[PLAT_MAX_PWR_LVL] ==
PLAT_SYS_SUSPEND_STATE_ID) {
/*
* Security engine resume
*/
if (tegra_chipid_is_t210_b01()) {
tegra_se_resume();
}
/*
* Lock scratch registers which hold the CPU vectors
*/
tegra_pmc_lock_cpu_vectors();
/*
* Enable WRAP to INCR burst type conversions for
* incoming requests on the AXI slave ports.
*/
val = mmio_read_32(TEGRA_MSELECT_BASE + MSELECT_CONFIG);
val &= ~ENABLE_UNSUP_TX_ERRORS;
val |= ENABLE_WRAP_TO_INCR_BURSTS;
mmio_write_32(TEGRA_MSELECT_BASE + MSELECT_CONFIG, val);
/*
* Restore Boot and Power Management Processor (BPMP) reset
* address and reset it, if it is supported by the platform.
*/
if (!tegra_bpmp_available) {
tegra_fc_bpmp_off();
} else {
entrypoint = tegra_pmc_read_32(PMC_SCRATCH39);
tegra_fc_bpmp_on(entrypoint);
/* initialise the interface */
tegra_bpmp_resume();
}
if (plat_params->sc7entry_fw_base != 0U) {
/* sc7entry-fw is part of TZDRAM area */
offset = plat_params->tzdram_base - plat_params->sc7entry_fw_base;
tegra_memctrl_tzdram_setup(plat_params->sc7entry_fw_base,
plat_params->tzdram_size + offset);
}
if (!tegra_chipid_is_t210_b01()) {
/* restrict PMC access to secure world */
val = mmio_read_32(TEGRA_MISC_BASE + APB_SLAVE_SECURITY_ENABLE);
val |= PMC_SECURITY_EN_BIT;
mmio_write_32(TEGRA_MISC_BASE + APB_SLAVE_SECURITY_ENABLE, val);
}
}
/*
* Check if we are exiting cluster idle state
*/
if (target_state->pwr_domain_state[MPIDR_AFFLVL1] ==
PSTATE_ID_CLUSTER_IDLE) {
if (!tegra_bpmp_available) {
/* PWM un-tristate */
cfg = mmio_read_32(TEGRA_CL_DVFS_BASE + DVFS_DFLL_OUTPUT_CFG);
if (cfg & DFLL_OUTPUT_CFG_CLK_EN_BIT) {
val = mmio_read_32(TEGRA_MISC_BASE + PINMUX_AUX_DVFS_PWM);
val &= ~PINMUX_PWM_TRISTATE;
mmio_write_32(TEGRA_MISC_BASE + PINMUX_AUX_DVFS_PWM, val);
/* make sure the setting took effect */
val = mmio_read_32(TEGRA_MISC_BASE + PINMUX_AUX_DVFS_PWM);
assert((val & PINMUX_PWM_TRISTATE) == 0U);
}
/*
* Restore operation mode for the DFLL ring
* oscillator
*/
mmio_write_32(TEGRA_CL_DVFS_BASE + DVFS_DFLL_CTRL,
ENABLE_CLOSED_LOOP);
/* release cluster idle lock */
tegra_fc_ccplex_pgexit_unlock();
}
}
/*
* Mark this CPU as ON in the cpu_powergate_mask[],
* so that we use Flow Controller for all subsequent
* power ups.
*/
cpu_powergate_mask[plat_my_core_pos()] = 1;
/*
* T210 has a dedicated ARMv7 boot and power mgmt processor, BPMP. It's
* used for power management and boot purposes. Inform the BPMP that
* we have completed the cluster power up.
*/
tegra_fc_lock_active_cluster();
/*
* Resume PMC hardware block for Tegra210 platforms
*/
if (!tegra_chipid_is_t210_b01()) {
tegra_pmc_resume();
}
return PSCI_E_SUCCESS;
}
int tegra_soc_pwr_domain_on(u_register_t mpidr)
{
int cpu = mpidr & MPIDR_CPU_MASK;
uint32_t mask = CPU_CORE_RESET_MASK << cpu;
/* Deassert CPU reset signals */
mmio_write_32(TEGRA_CAR_RESET_BASE + CPU_CMPLX_RESET_CLR, mask);
/* Turn on CPU using flow controller or PMC */
if (cpu_powergate_mask[cpu] == 0) {
tegra_pmc_cpu_on(cpu);
} else {
tegra_fc_cpu_on(cpu);
}
return PSCI_E_SUCCESS;
}
int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
{
tegra_fc_cpu_off(read_mpidr() & MPIDR_CPU_MASK);
return PSCI_E_SUCCESS;
}
int tegra_soc_prepare_system_reset(void)
{
/*
* Set System Clock (SCLK) to POR default so that the clock source
* for the PMC APB clock would not be changed due to system reset.
*/
mmio_write_32((uintptr_t)TEGRA_CAR_RESET_BASE + SCLK_BURST_POLICY,
SCLK_BURST_POLICY_DEFAULT);
mmio_write_32((uintptr_t)TEGRA_CAR_RESET_BASE + SCLK_RATE, 0);
/* Wait 1 ms to make sure clock source/device logic is stabilized. */
mdelay(1);
/*
* Program the PMC in order to restart the system.
*/
tegra_pmc_system_reset();
return PSCI_E_SUCCESS;
}
__dead2 void tegra_soc_prepare_system_off(void)
{
ERROR("Tegra System Off: operation not handled.\n");
panic();
}
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <common/debug.h>
#include <lib/mmio.h>
#include <pmc.h>
#include <tegra_def.h>
#define SB_CSR 0x0
#define SB_CSR_NS_RST_VEC_WR_DIS (1 << 1)
/* CPU reset vector */
#define SB_AA64_RESET_LOW 0x30 /* width = 31:0 */
#define SB_AA64_RESET_HI 0x34 /* width = 11:0 */
extern void tegra_secure_entrypoint(void);
/*******************************************************************************
* Setup secondary CPU vectors
******************************************************************************/
void plat_secondary_setup(void)
{
uint32_t val;
uint64_t reset_addr = (uint64_t)tegra_secure_entrypoint;
INFO("Setting up secondary CPU boot\n");
/* setup secondary CPU vector */
mmio_write_32(TEGRA_SB_BASE + SB_AA64_RESET_LOW,
(reset_addr & 0xFFFFFFFF) | 1);
val = reset_addr >> 32;
mmio_write_32(TEGRA_SB_BASE + SB_AA64_RESET_HI, val & 0x7FF);
/* configure PMC */
tegra_pmc_cpu_setup(reset_addr);
tegra_pmc_lock_cpu_vectors();
}
@@ -0,0 +1,318 @@
/*
* Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch_helpers.h>
#include <assert.h>
#include <cortex_a57.h>
#include <common/bl_common.h>
#include <common/debug.h>
#include <common/interrupt_props.h>
#include <drivers/console.h>
#include <lib/xlat_tables/xlat_tables_v2.h>
#include <drivers/arm/gic_common.h>
#include <drivers/arm/gicv2.h>
#include <bl31/interrupt_mgmt.h>
#include <bpmp.h>
#include <flowctrl.h>
#include <memctrl.h>
#include <plat/common/platform.h>
#include <security_engine.h>
#include <tegra_def.h>
#include <tegra_platform.h>
#include <tegra_private.h>
/* sets of MMIO ranges setup */
#define MMIO_RANGE_0_ADDR 0x50000000
#define MMIO_RANGE_1_ADDR 0x60000000
#define MMIO_RANGE_2_ADDR 0x70000000
#define MMIO_RANGE_SIZE 0x200000
/*
* Table of regions to map using the MMU.
*/
static const mmap_region_t tegra_mmap[] = {
MAP_REGION_FLAT(TEGRA_IRAM_BASE, 0x40000, /* 256KB */
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(MMIO_RANGE_0_ADDR, MMIO_RANGE_SIZE,
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(MMIO_RANGE_1_ADDR, MMIO_RANGE_SIZE,
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(MMIO_RANGE_2_ADDR, MMIO_RANGE_SIZE,
MT_DEVICE | MT_RW | MT_SECURE),
{0}
};
/*******************************************************************************
* Set up the pagetables as per the platform memory map & initialize the MMU
******************************************************************************/
const mmap_region_t *plat_get_mmio_map(void)
{
/* Add the map region for security engine SE2 */
if (tegra_chipid_is_t210_b01()) {
mmap_add_region((uint64_t)TEGRA_SE2_BASE,
(uint64_t)TEGRA_SE2_BASE,
(uint64_t)TEGRA_SE2_RANGE_SIZE,
MT_DEVICE | MT_RW | MT_SECURE);
}
/* MMIO space */
return tegra_mmap;
}
/*******************************************************************************
* The Tegra power domain tree has a single system level power domain i.e. a
* single root node. The first entry in the power domain descriptor specifies
* the number of power domains at the highest power level.
*******************************************************************************
*/
const unsigned char tegra_power_domain_tree_desc[] = {
/* No of root nodes */
1,
/* No of clusters */
PLATFORM_CLUSTER_COUNT,
/* No of CPU cores - cluster0 */
PLATFORM_MAX_CPUS_PER_CLUSTER,
/* No of CPU cores - cluster1 */
PLATFORM_MAX_CPUS_PER_CLUSTER
};
/*******************************************************************************
* This function returns the Tegra default topology tree information.
******************************************************************************/
const unsigned char *plat_get_power_domain_tree_desc(void)
{
return tegra_power_domain_tree_desc;
}
/*******************************************************************************
* Handler to get the System Counter Frequency
******************************************************************************/
unsigned int plat_get_syscnt_freq2(void)
{
return 19200000;
}
/*******************************************************************************
* Maximum supported UART controllers
******************************************************************************/
#define TEGRA210_MAX_UART_PORTS 5
/*******************************************************************************
* This variable holds the UART port base addresses
******************************************************************************/
static uint32_t tegra210_uart_addresses[TEGRA210_MAX_UART_PORTS + 1] = {
0, /* undefined - treated as an error case */
TEGRA_UARTA_BASE,
TEGRA_UARTB_BASE,
TEGRA_UARTC_BASE,
TEGRA_UARTD_BASE,
TEGRA_UARTE_BASE,
};
/*******************************************************************************
* Enable console corresponding to the console ID
******************************************************************************/
void plat_enable_console(int32_t id)
{
static console_t uart_console;
uint32_t console_clock;
if ((id > 0) && (id < TEGRA210_MAX_UART_PORTS)) {
/*
* Reference clock used by the FPGAs is a lot slower.
*/
if (tegra_platform_is_fpga()) {
console_clock = TEGRA_BOOT_UART_CLK_13_MHZ;
} else {
console_clock = TEGRA_BOOT_UART_CLK_408_MHZ;
}
(void)console_16550_register(tegra210_uart_addresses[id],
console_clock,
TEGRA_CONSOLE_BAUDRATE,
&uart_console);
console_set_scope(&uart_console, CONSOLE_FLAG_BOOT |
CONSOLE_FLAG_RUNTIME | CONSOLE_FLAG_CRASH);
}
}
/*******************************************************************************
* Return pointer to the BL31 params from previous bootloader
******************************************************************************/
struct tegra_bl31_params *plat_get_bl31_params(void)
{
return NULL;
}
/*******************************************************************************
* Return pointer to the BL31 platform params from previous bootloader
******************************************************************************/
plat_params_from_bl2_t *plat_get_bl31_plat_params(void)
{
return NULL;
}
/*******************************************************************************
* Handler for early platform setup
******************************************************************************/
void plat_early_platform_setup(void)
{
const plat_params_from_bl2_t *plat_params = bl31_get_plat_params();
uint64_t val;
/* Verify chip id is t210 */
assert(tegra_chipid_is_t210());
/*
* Do initial security configuration to allow DRAM/device access.
*/
tegra_memctrl_tzdram_setup(plat_params->tzdram_base,
(uint32_t)plat_params->tzdram_size);
/* platform parameter passed by the previous bootloader */
if (plat_params->l2_ecc_parity_prot_dis != 1) {
/* Enable ECC Parity Protection for Cortex-A57 CPUs */
val = read_l2ctlr_el1();
val |= (uint64_t)CORTEX_A57_L2_ECC_PARITY_PROTECTION_BIT;
write_l2ctlr_el1(val);
}
/* Initialize security engine driver */
tegra_se_init();
}
/* Secure IRQs for Tegra186 */
static const interrupt_prop_t tegra210_interrupt_props[] = {
INTR_PROP_DESC(TEGRA_SDEI_SGI_PRIVATE, PLAT_SDEI_CRITICAL_PRI,
GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE),
INTR_PROP_DESC(TEGRA210_TIMER1_IRQ, PLAT_TEGRA_WDT_PRIO,
GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE),
INTR_PROP_DESC(TEGRA210_WDT_CPU_LEGACY_FIQ, PLAT_TEGRA_WDT_PRIO,
GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE),
};
/*******************************************************************************
* Handler for late platform setup
******************************************************************************/
void plat_late_platform_setup(void)
{
const plat_params_from_bl2_t *plat_params = bl31_get_plat_params();
uint64_t sc7entry_end, offset;
int ret;
uint32_t val;
/* memmap TZDRAM area containing the SC7 Entry Firmware */
if (plat_params->sc7entry_fw_base && plat_params->sc7entry_fw_size) {
assert(plat_params->sc7entry_fw_size <= TEGRA_IRAM_A_SIZE);
/*
* Verify that the SC7 entry firmware resides inside the TZDRAM
* aperture, _before_ the BL31 code and the start address is
* exactly 1MB from BL31 base.
*/
/* sc7entry-fw must be _before_ BL31 base */
assert(plat_params->tzdram_base > plat_params->sc7entry_fw_base);
sc7entry_end = plat_params->sc7entry_fw_base +
plat_params->sc7entry_fw_size;
assert(sc7entry_end < plat_params->tzdram_base);
/* sc7entry-fw start must be exactly 1MB behind BL31 base */
offset = plat_params->tzdram_base - plat_params->sc7entry_fw_base;
assert(offset == 0x100000);
/* secure TZDRAM area */
tegra_memctrl_tzdram_setup(plat_params->sc7entry_fw_base,
plat_params->tzdram_size + offset);
/* power off BPMP processor until SC7 entry */
tegra_fc_bpmp_off();
/* memmap SC7 entry firmware code */
ret = mmap_add_dynamic_region(plat_params->sc7entry_fw_base,
plat_params->sc7entry_fw_base,
plat_params->sc7entry_fw_size,
MT_SECURE | MT_RO_DATA);
assert(ret == 0);
/* restrict PMC access to secure world */
val = mmio_read_32(TEGRA_MISC_BASE + APB_SLAVE_SECURITY_ENABLE);
val |= PMC_SECURITY_EN_BIT;
mmio_write_32(TEGRA_MISC_BASE + APB_SLAVE_SECURITY_ENABLE, val);
}
if (!tegra_chipid_is_t210_b01()) {
/* restrict PMC access to secure world */
val = mmio_read_32(TEGRA_MISC_BASE + APB_SLAVE_SECURITY_ENABLE);
val |= PMC_SECURITY_EN_BIT;
mmio_write_32(TEGRA_MISC_BASE + APB_SLAVE_SECURITY_ENABLE, val);
}
}
/*******************************************************************************
* Initialize the GIC and SGIs
******************************************************************************/
void plat_gic_setup(void)
{
tegra_gic_setup(tegra210_interrupt_props, ARRAY_SIZE(tegra210_interrupt_props));
tegra_gic_init();
/* Enable handling for FIQs */
tegra_fiq_handler_setup();
/*
* Enable routing watchdog FIQs from the flow controller to
* the GICD.
*/
tegra_fc_enable_fiq_to_ccplex_routing();
}
/*******************************************************************************
* Handler to indicate support for System Suspend
******************************************************************************/
bool plat_supports_system_suspend(void)
{
const plat_params_from_bl2_t *plat_params = bl31_get_plat_params();
/*
* sc7entry-fw is only supported by Tegra210 SoCs.
*/
if (!tegra_chipid_is_t210_b01() && (plat_params->sc7entry_fw_base != 0U)) {
return true;
} else if (tegra_chipid_is_t210_b01()) {
return true;
} else {
return false;
}
}
/*******************************************************************************
* Platform specific runtime setup.
******************************************************************************/
void plat_runtime_setup(void)
{
/*
* During cold boot, it is observed that the arbitration
* bit is set in the Memory controller leading to false
* error interrupts in the non-secure world. To avoid
* this, clean the interrupt status register before
* booting into the non-secure world
*/
tegra_memctrl_clear_pending_interrupts();
/*
* During boot, USB3 and flash media (SDMMC/SATA) devices need
* access to IRAM. Because these clients connect to the MC and
* do not have a direct path to the IRAM, the MC implements AHB
* redirection during boot to allow path to IRAM. In this mode
* accesses to a programmed memory address aperture are directed
* to the AHB bus, allowing access to the IRAM. This mode must be
* disabled before we jump to the non-secure world.
*/
tegra_memctrl_disable_ahb_redirection();
}
@@ -0,0 +1,97 @@
/*
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <inttypes.h>
#include <stdint.h>
#include <arch.h>
#include <arch_helpers.h>
#include <assert.h>
#include <common/bl_common.h>
#include <common/debug.h>
#include <common/runtime_svc.h>
#include <errno.h>
#include <lib/mmio.h>
#include <lib/utils_def.h>
#include <memctrl.h>
#include <pmc.h>
#include <tegra_private.h>
#include <tegra_platform.h>
#include <tegra_def.h>
/*******************************************************************************
* PMC parameters
******************************************************************************/
#define PMC_READ U(0xaa)
#define PMC_WRITE U(0xbb)
/*******************************************************************************
* Tegra210 SiP SMCs
******************************************************************************/
#define TEGRA_SIP_PMC_COMMANDS U(0xC2FFFE00)
/*******************************************************************************
* This function is responsible for handling all T210 SiP calls
******************************************************************************/
int plat_sip_handler(uint32_t smc_fid,
uint64_t x1,
uint64_t x2,
uint64_t x3,
uint64_t x4,
const void *cookie,
void *handle,
uint64_t flags)
{
uint32_t val, ns;
/* Determine which security state this SMC originated from */
ns = is_caller_non_secure(flags);
if (!ns)
SMC_RET1(handle, SMC_UNK);
if (smc_fid == TEGRA_SIP_PMC_COMMANDS) {
/* check the address is within PMC range and is 4byte aligned */
if ((x2 >= TEGRA_PMC_SIZE) || (x2 & 0x3))
return -EINVAL;
switch (x2) {
/* Black listed PMC registers */
case PMC_SCRATCH1:
case PMC_SCRATCH31 ... PMC_SCRATCH33:
case PMC_SCRATCH40:
case PMC_SCRATCH42:
case PMC_SCRATCH43 ... PMC_SCRATCH48:
case PMC_SCRATCH50 ... PMC_SCRATCH51:
case PMC_SCRATCH56 ... PMC_SCRATCH57:
/* PMC secure-only registers are not accessible */
case PMC_DPD_ENABLE_0:
case PMC_FUSE_CONTROL_0:
case PMC_CRYPTO_OP_0:
case PMC_TSC_MULT_0:
case PMC_STICKY_BIT:
ERROR("%s: error offset=0x%" PRIx64 "\n", __func__, x2);
return -EFAULT;
default:
/* Valid register */
break;
}
/* Perform PMC read/write */
if (x1 == PMC_READ) {
val = mmio_read_32((uint32_t)(TEGRA_PMC_BASE + x2));
write_ctx_reg(get_gpregs_ctx(handle), CTX_GPREG_X1, val);
} else if (x1 == PMC_WRITE) {
mmio_write_32((uint32_t)(TEGRA_PMC_BASE + x2), (uint32_t)x3);
} else {
return -EINVAL;
}
} else {
return -ENOTSUP;
}
return 0;
}
@@ -0,0 +1,62 @@
#
# Copyright (c) 2015-2019, ARM Limited and Contributors. All rights reserved.
# Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
#
# SPDX-License-Identifier: BSD-3-Clause
#
TZDRAM_BASE := 0xFF800000
$(eval $(call add_define,TZDRAM_BASE))
ERRATA_TEGRA_INVALIDATE_BTB_AT_BOOT := 1
$(eval $(call add_define,ERRATA_TEGRA_INVALIDATE_BTB_AT_BOOT))
PLATFORM_CLUSTER_COUNT := 2
$(eval $(call add_define,PLATFORM_CLUSTER_COUNT))
PLATFORM_MAX_CPUS_PER_CLUSTER := 4
$(eval $(call add_define,PLATFORM_MAX_CPUS_PER_CLUSTER))
MAX_XLAT_TABLES := 10
$(eval $(call add_define,MAX_XLAT_TABLES))
MAX_MMAP_REGIONS := 16
$(eval $(call add_define,MAX_MMAP_REGIONS))
ENABLE_TEGRA_WDT_LEGACY_FIQ_HANDLING := 1
PLAT_INCLUDES += -Iplat/nvidia/tegra/include/t210 \
-I${SOC_DIR}/drivers/se
BL31_SOURCES += ${TEGRA_GICv2_SOURCES} \
drivers/ti/uart/aarch64/16550_console.S \
lib/cpus/aarch64/cortex_a53.S \
lib/cpus/aarch64/cortex_a57.S \
${TEGRA_DRIVERS}/bpmp/bpmp.c \
${TEGRA_DRIVERS}/flowctrl/flowctrl.c \
${TEGRA_DRIVERS}/memctrl/memctrl_v1.c \
${TEGRA_DRIVERS}/pmc/pmc.c \
${SOC_DIR}/plat_psci_handlers.c \
${SOC_DIR}/plat_setup.c \
${SOC_DIR}/drivers/se/security_engine.c \
${SOC_DIR}/plat_secondary.c \
${SOC_DIR}/plat_sip_calls.c
# Enable workarounds for selected Cortex-A57 erratas.
A57_DISABLE_NON_TEMPORAL_HINT := 1
ERRATA_A57_826974 := 1
ERRATA_A57_826977 := 1
ERRATA_A57_828024 := 1
ERRATA_A57_833471 := 1
# Enable workarounds for selected Cortex-A53 erratas.
A53_DISABLE_NON_TEMPORAL_HINT := 1
ERRATA_A53_826319 := 1
ERRATA_A53_836870 := 1
ERRATA_A53_855873 := 1
# Skip L1 $ flush when powering down Cortex-A57 CPUs
SKIP_A57_L1_FLUSH_PWR_DWN := 1
# Enable higher performance Non-cacheable load forwarding
A57_ENABLE_NONCACHEABLE_LOAD_FWD := 1