GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)
This commit is contained in:
+428
@@ -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
|
||||
+366
@@ -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;
|
||||
}
|
||||
+59
@@ -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
|
||||
+57
@@ -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);
|
||||
}
|
||||
+149
@@ -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());
|
||||
}
|
||||
+20
@@ -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;
|
||||
}
|
||||
+309
@@ -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);
|
||||
+158
@@ -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)
|
||||
);
|
||||
+28
@@ -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();
|
||||
}
|
||||
Reference in New Issue
Block a user