From 1a9c383bb624ed0bcb618b81ab671146a60514b0 Mon Sep 17 00:00:00 2001 From: Varun Wadekar Date: Mon, 21 Mar 2016 11:18:40 -0700 Subject: [PATCH 01/18] Tegra: Disable A57/A53 cache non-temporal hints This change disables the cache non-temporal hints for A57 and A53 CPUs on Tegra. Change-Id: I279d95aec5afbc3ca3cc4b34aa16de3f2c83a4fc Signed-off-by: Varun Wadekar --- plat/nvidia/tegra/platform.mk | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/plat/nvidia/tegra/platform.mk b/plat/nvidia/tegra/platform.mk index 756899cb75..b168634e3a 100644 --- a/plat/nvidia/tegra/platform.mk +++ b/plat/nvidia/tegra/platform.mk @@ -36,6 +36,14 @@ PSCI_EXTENDED_STATE_ID := 1 # Disable the PSCI platform compatibility layer ENABLE_PLAT_COMPAT := 0 +# Disable cache non-temporal hint for A57 +A57_DISABLE_NON_TEMPORAL_HINT := 0 +$(eval $(call add_define,A57_DISABLE_NON_TEMPORAL_HINT)) + +# Disable cache non-temporal hint for A53 +A53_DISABLE_NON_TEMPORAL_HINT := 0 +$(eval $(call add_define,A53_DISABLE_NON_TEMPORAL_HINT)) + include plat/nvidia/tegra/common/tegra_common.mk include ${SOC_DIR}/platform_${TARGET_SOC}.mk From 939dcf25e10639516f022fe67feebaa1d74d1678 Mon Sep 17 00:00:00 2001 From: Varun Wadekar Date: Thu, 24 Mar 2016 15:34:24 -0700 Subject: [PATCH 02/18] Tegra: relocate code to BL31_BASE during cold boot This patch adds support to relocate BL3-1 code to BL31_BASE in case we cold boot to a different address. This is particularly useful to maintain compatibility with legacy BL2 code. This patch also checks to see if the image base address matches either the TZDRAM or TZSRAM base. Change-Id: I72c96d7f89076701a6ac2537d4c06565c54dab9c Signed-off-by: Varun Wadekar --- .../tegra/common/aarch64/tegra_helpers.S | 41 +++++++++++++++++++ plat/nvidia/tegra/common/tegra_bl31_setup.c | 8 ++++ 2 files changed, 49 insertions(+) diff --git a/plat/nvidia/tegra/common/aarch64/tegra_helpers.S b/plat/nvidia/tegra/common/aarch64/tegra_helpers.S index 6851b1502f..8ca10e258a 100644 --- a/plat/nvidia/tegra/common/aarch64/tegra_helpers.S +++ b/plat/nvidia/tegra/common/aarch64/tegra_helpers.S @@ -254,6 +254,47 @@ endfunc plat_crash_console_putc */ 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 + mov x2, #BL31_SIZE +_loop16: + cmp x2, #16 + b.lt _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 * ----------------------------------- diff --git a/plat/nvidia/tegra/common/tegra_bl31_setup.c b/plat/nvidia/tegra/common/tegra_bl31_setup.c index 72da4b3c0a..59309feef8 100644 --- a/plat/nvidia/tegra/common/tegra_bl31_setup.c +++ b/plat/nvidia/tegra/common/tegra_bl31_setup.c @@ -135,6 +135,14 @@ void bl31_early_platform_setup(bl31_params_t *from_bl2, plat_bl31_params_from_bl2.tzdram_size = plat_params->tzdram_size; plat_bl31_params_from_bl2.uart_id = plat_params->uart_id; + /* + * 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 != BL31_BASE) && + (TEGRA_TZRAM_BASE != BL31_BASE)) + panic(); + /* * Get the base address of the UART controller to be used for the * console From 5ea0b028d4ff2f43a59eb827e7541532e3657500 Mon Sep 17 00:00:00 2001 From: Varun Wadekar Date: Mon, 28 Mar 2016 15:56:47 -0700 Subject: [PATCH 03/18] Tegra: handler for per-soc early setup This patch adds a weak handler for early platform setup which can be overriden by the soc-specific handlers to perform any early setup tasks. Change-Id: I1a7a98d59b2332a3030c6dca5a9b7be977177326 Signed-off-by: Varun Wadekar --- plat/nvidia/tegra/common/tegra_bl31_setup.c | 14 ++++++++++++++ plat/nvidia/tegra/include/tegra_private.h | 1 + 2 files changed, 15 insertions(+) diff --git a/plat/nvidia/tegra/common/tegra_bl31_setup.c b/plat/nvidia/tegra/common/tegra_bl31_setup.c index 59309feef8..cb38f95f59 100644 --- a/plat/nvidia/tegra/common/tegra_bl31_setup.c +++ b/plat/nvidia/tegra/common/tegra_bl31_setup.c @@ -79,6 +79,17 @@ static plat_params_from_bl2_t plat_bl31_params_from_bl2 = { ******************************************************************************/ extern uint64_t ns_image_entrypoint; +/******************************************************************************* + * The following platform setup functions are weakly defined. They + * provide typical implementations that will be overridden by a SoC. + ******************************************************************************/ +#pragma weak plat_early_platform_setup + +void plat_early_platform_setup(void) +{ + ; /* do nothing */ +} + /******************************************************************************* * 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 @@ -160,6 +171,9 @@ void bl31_early_platform_setup(bl31_params_t *from_bl2, /* Initialise crash console */ plat_crash_console_init(); + /* Early platform setup for Tegra SoCs */ + plat_early_platform_setup(); + INFO("BL3-1: Boot CPU: %s Processor [%lx]\n", (impl == DENVER_IMPL) ? "Denver" : "ARM", read_mpidr()); } diff --git a/plat/nvidia/tegra/include/tegra_private.h b/plat/nvidia/tegra/include/tegra_private.h index 75416ec3c0..ef4d55b4e9 100644 --- a/plat/nvidia/tegra/include/tegra_private.h +++ b/plat/nvidia/tegra/include/tegra_private.h @@ -83,6 +83,7 @@ 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); int bl31_check_ns_address(uint64_t base, uint64_t size_in_bytes); +void plat_early_platform_setup(void); /* Declarations for tegra_delay_timer.c */ void tegra_delay_timer_init(void); From 2d05f81025a06b74e527588df818ffd8e0a7d29f Mon Sep 17 00:00:00 2001 From: Wayne Lin Date: Thu, 31 Mar 2016 13:49:09 -0700 Subject: [PATCH 04/18] Tegra: allow SiP smc calls from Secure World This patch removes the restriction of allowing SiP calls only from the non-secure world. The secure world can issue SiP calls as a result of this patch now. Change-Id: Idd64e893ae8e114bba0196872d3ec544cac150bf Signed-off-by: Wayne Lin Signed-off-by: Varun Wadekar --- plat/nvidia/tegra/common/tegra_sip_calls.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/plat/nvidia/tegra/common/tegra_sip_calls.c b/plat/nvidia/tegra/common/tegra_sip_calls.c index 3bcd4418f0..77f039a422 100644 --- a/plat/nvidia/tegra/common/tegra_sip_calls.c +++ b/plat/nvidia/tegra/common/tegra_sip_calls.c @@ -60,7 +60,7 @@ int plat_sip_handler(uint32_t smc_fid, } /******************************************************************************* - * This function is responsible for handling all SiP calls from the NS world + * This function is responsible for handling all SiP calls ******************************************************************************/ uint64_t tegra_sip_handler(uint32_t smc_fid, uint64_t x1, @@ -71,14 +71,8 @@ uint64_t tegra_sip_handler(uint32_t smc_fid, void *handle, uint64_t flags) { - uint32_t ns; int err; - /* Determine which security state this SMC originated from */ - ns = is_caller_non_secure(flags); - if (!ns) - SMC_RET1(handle, SMC_UNK); - /* Check if this is a SoC specific SiP */ err = plat_sip_handler(smc_fid, x1, x2, x3, x4, cookie, handle, flags); if (err == 0) From 11bd24be5c294280bddf28bb48648de98a56a24f Mon Sep 17 00:00:00 2001 From: Varun Wadekar Date: Tue, 26 Apr 2016 11:38:38 -0700 Subject: [PATCH 05/18] Tegra: include platform_def.h to access UART macros This patch includes platform_def.h required to access UART macros - "TEGRA_BOOT_UART_CLK_IN_HZ" and "TEGRA_CONSOLE_BAUDRATE" from tegra_helpers.S. Change-Id: Ieb63968a48dc299d03e81ddeb1ccc871cf3397a1 Signed-off-by: Varun Wadekar --- plat/nvidia/tegra/common/aarch64/tegra_helpers.S | 1 + 1 file changed, 1 insertion(+) diff --git a/plat/nvidia/tegra/common/aarch64/tegra_helpers.S b/plat/nvidia/tegra/common/aarch64/tegra_helpers.S index 8ca10e258a..a57d1cb0a3 100644 --- a/plat/nvidia/tegra/common/aarch64/tegra_helpers.S +++ b/plat/nvidia/tegra/common/aarch64/tegra_helpers.S @@ -33,6 +33,7 @@ #include #include #include +#include #include #define MIDR_PN_CORTEX_A57 0xD07 From 2693f1dbc79f3e42b8c9d6d39d5d2e5f2b296ad8 Mon Sep 17 00:00:00 2001 From: Varun Wadekar Date: Thu, 5 May 2016 14:13:30 -0700 Subject: [PATCH 06/18] Tegra: implement common handler `plat_get_target_pwr_state()` This patch adds a platform handler to calculate the proper target power level at the specified affinity level. Tegra platforms assign a local state value in order of decreasing depth of the power state i.e. for two power states X & Y, if X < Y then X represents a shallower power state than Y. As a result, the coordinated target local power state for a power domain will be the maximum of the requested local power state values. Change-Id: I67360684b7f5b783fcfdd605b96da5375fa05417 Signed-off-by: Varun Wadekar --- plat/nvidia/tegra/common/tegra_common.mk | 1 - plat/nvidia/tegra/common/tegra_pm.c | 21 +++++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/plat/nvidia/tegra/common/tegra_common.mk b/plat/nvidia/tegra/common/tegra_common.mk index c9e92557c8..acea50be75 100644 --- a/plat/nvidia/tegra/common/tegra_common.mk +++ b/plat/nvidia/tegra/common/tegra_common.mk @@ -52,7 +52,6 @@ BL31_SOURCES += drivers/arm/gic/gic_v2.c \ drivers/delay_timer/delay_timer.c \ drivers/ti/uart/aarch64/16550_console.S \ plat/common/aarch64/platform_mp_stack.S \ - plat/common/plat_psci_common.c \ ${COMMON_DIR}/aarch64/tegra_helpers.S \ ${COMMON_DIR}/drivers/pmc/pmc.c \ ${COMMON_DIR}/tegra_bl31_setup.c \ diff --git a/plat/nvidia/tegra/common/tegra_pm.c b/plat/nvidia/tegra/common/tegra_pm.c index f5ef3e764b..11ea819729 100644 --- a/plat/nvidia/tegra/common/tegra_pm.c +++ b/plat/nvidia/tegra/common/tegra_pm.c @@ -318,3 +318,24 @@ int plat_setup_psci_ops(uintptr_t sec_entrypoint, 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) +{ + plat_local_state_t target = PLAT_MAX_RET_STATE, temp; + + assert(ncpu); + + do { + temp = *states++; + if ((temp > target) && (temp != PLAT_MAX_OFF_STATE)) + target = temp; + } while (--ncpu); + + return target; +} From 3eac92d2647e35c5c48e411d674cbd7f8ae349b0 Mon Sep 17 00:00:00 2001 From: Varun Wadekar Date: Fri, 6 May 2016 16:35:30 -0700 Subject: [PATCH 07/18] cpus: denver: remove barrier from denver_enable_dco() This patch removes unnecessary `isb` from the enable DCO sequence as there is no need to synchronize this operation. Change-Id: I0191e684bbc7fdba635c3afbc4e4ecd793b6f06f Signed-off-by: Varun Wadekar --- lib/cpus/aarch64/denver.S | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/cpus/aarch64/denver.S b/lib/cpus/aarch64/denver.S index 3e238a1c19..fcfae8ff66 100644 --- a/lib/cpus/aarch64/denver.S +++ b/lib/cpus/aarch64/denver.S @@ -59,7 +59,6 @@ func denver_enable_dco mov x1, #1 lsl x1, x1, x0 msr s3_0_c15_c0_2, x1 - isb ret endfunc denver_enable_dco From d33603016971adbe2aba04f96c2a45b56d33f99a Mon Sep 17 00:00:00 2001 From: Varun Wadekar Date: Mon, 28 Dec 2015 14:55:41 -0800 Subject: [PATCH 08/18] Tegra: GIC: enable FIQ interrupt handling Tegra chips support multiple FIQ interrupt sources. These interrupts are enabled in the GICD/GICC interfaces by the tegra_gic driver. A new FIQ handler would be added in a subsequent change which can be registered by the platform code. This patch adds the GIC programming as part of the tegra_gic_setup() which now takes an array of all the FIQ interrupts to be enabled for the platform. The Tegra132 and Tegra210 platforms right now do not register for any FIQ interrupts themselves, but will definitely use this support in the future. Change-Id: I0ea164be901cd6681167028fea0567399f18d4b8 Signed-off-by: Varun Wadekar --- plat/nvidia/tegra/common/tegra_bl31_setup.c | 6 +-- plat/nvidia/tegra/common/tegra_common.mk | 1 - plat/nvidia/tegra/common/tegra_gic.c | 47 ++++++++++++++++++++- plat/nvidia/tegra/common/tegra_pm.c | 2 +- plat/nvidia/tegra/include/t132/tegra_def.h | 5 +++ plat/nvidia/tegra/include/t210/tegra_def.h | 5 +++ plat/nvidia/tegra/include/tegra_private.h | 8 +++- plat/nvidia/tegra/soc/t132/plat_setup.c | 15 ++++++- plat/nvidia/tegra/soc/t210/plat_setup.c | 13 +++++- 9 files changed, 90 insertions(+), 12 deletions(-) diff --git a/plat/nvidia/tegra/common/tegra_bl31_setup.c b/plat/nvidia/tegra/common/tegra_bl31_setup.c index cb38f95f59..142839c81a 100644 --- a/plat/nvidia/tegra/common/tegra_bl31_setup.c +++ b/plat/nvidia/tegra/common/tegra_bl31_setup.c @@ -185,6 +185,9 @@ void bl31_platform_setup(void) { uint32_t tmp_reg; + /* Initialize the gic cpu and distributor interfaces */ + plat_gic_setup(); + /* * Initialize delay timer */ @@ -216,9 +219,6 @@ void bl31_platform_setup(void) tmp_reg = SCR_RES1_BITS | SCR_RW_BIT; write_scr(tmp_reg); - /* Initialize the gic cpu and distributor interfaces */ - tegra_gic_setup(); - INFO("BL3-1: Tegra platform setup complete\n"); } diff --git a/plat/nvidia/tegra/common/tegra_common.mk b/plat/nvidia/tegra/common/tegra_common.mk index acea50be75..de6cd04e1c 100644 --- a/plat/nvidia/tegra/common/tegra_common.mk +++ b/plat/nvidia/tegra/common/tegra_common.mk @@ -47,7 +47,6 @@ PLAT_BL_COMMON_SOURCES := lib/xlat_tables/xlat_tables_common.c \ COMMON_DIR := plat/nvidia/tegra/common BL31_SOURCES += drivers/arm/gic/gic_v2.c \ - drivers/arm/gic/gic_v3.c \ drivers/console/aarch64/console.S \ drivers/delay_timer/delay_timer.c \ drivers/ti/uart/aarch64/16550_console.S \ diff --git a/plat/nvidia/tegra/common/tegra_gic.c b/plat/nvidia/tegra/common/tegra_gic.c index ee12975748..786eefc1db 100644 --- a/plat/nvidia/tegra/common/tegra_gic.c +++ b/plat/nvidia/tegra/common/tegra_gic.c @@ -47,6 +47,9 @@ (GIC_HIGHEST_NS_PRIORITY << 16) | \ (GIC_HIGHEST_NS_PRIORITY << 24)) +static const unsigned int *g_irq_sec_ptr; +static unsigned int g_num_irqs; + /******************************************************************************* * Place the cpu interface in a state where it can never make a cpu exit wfi as * as result of an asserted interrupt. This is critical for powering down a cpu @@ -110,7 +113,9 @@ static void tegra_gic_pcpu_distif_setup(unsigned int gicd_base) ******************************************************************************/ static void tegra_gic_distif_setup(unsigned int gicd_base) { - unsigned int index, num_ints; + unsigned int index, num_ints, irq_num; + uint8_t target_cpus; + uint32_t val; /* * Mark out non-secure interrupts. Calculate number of @@ -128,6 +133,41 @@ static void tegra_gic_distif_setup(unsigned int gicd_base) GICD_IPRIORITYR_DEF_VAL); } + /* Configure SPI secure interrupts now */ + if (g_irq_sec_ptr) { + + /* Read the target CPU mask */ + target_cpus = TEGRA_SEC_IRQ_TARGET_MASK & GIC_TARGET_CPU_MASK; + + for (index = 0; index < g_num_irqs; index++) { + irq_num = g_irq_sec_ptr[index]; + + if (irq_num >= MIN_SPI_ID) { + + /* Configure as a secure interrupt */ + gicd_clr_igroupr(gicd_base, irq_num); + + /* Configure SPI priority */ + mmio_write_8(gicd_base + GICD_IPRIORITYR + + irq_num, + GIC_HIGHEST_SEC_PRIORITY & + GIC_PRI_MASK); + + /* Configure as level triggered */ + val = gicd_read_icfgr(gicd_base, irq_num); + val |= (3 << ((irq_num & 0xF) << 1)); + gicd_write_icfgr(gicd_base, irq_num, val); + + /* Route SPI to the target CPUs */ + gicd_set_itargetsr(gicd_base, irq_num, + target_cpus); + + /* Enable this interrupt */ + gicd_set_isenabler(gicd_base, irq_num); + } + } + } + /* * Configure the SGI and PPI. This is done in a separated function * because each CPU is responsible for initializing its own private @@ -139,8 +179,11 @@ static void tegra_gic_distif_setup(unsigned int gicd_base) gicd_write_ctlr(gicd_base, ENABLE_GRP0 | ENABLE_GRP1); } -void tegra_gic_setup(void) +void tegra_gic_setup(const unsigned int *irq_sec_ptr, unsigned int num_irqs) { + g_irq_sec_ptr = irq_sec_ptr; + g_num_irqs = num_irqs; + tegra_gic_cpuif_setup(TEGRA_GICC_BASE); tegra_gic_distif_setup(TEGRA_GICD_BASE); } diff --git a/plat/nvidia/tegra/common/tegra_pm.c b/plat/nvidia/tegra/common/tegra_pm.c index 11ea819729..ca49dabdbe 100644 --- a/plat/nvidia/tegra/common/tegra_pm.c +++ b/plat/nvidia/tegra/common/tegra_pm.c @@ -183,7 +183,7 @@ void tegra_pwr_domain_on_finish(const psci_power_state_t *target_state) /* * Initialize the GIC cpu and distributor interfaces */ - tegra_gic_setup(); + plat_gic_setup(); /* * Check if we are exiting from deep sleep. diff --git a/plat/nvidia/tegra/include/t132/tegra_def.h b/plat/nvidia/tegra/include/t132/tegra_def.h index 318f4def15..3bafb87dcd 100644 --- a/plat/nvidia/tegra/include/t132/tegra_def.h +++ b/plat/nvidia/tegra/include/t132/tegra_def.h @@ -48,6 +48,11 @@ #define PLAT_MAX_RET_STATE 1 #define PLAT_MAX_OFF_STATE (PSTATE_ID_SOC_POWERDN + 1) +/******************************************************************************* + * Secure IRQ definitions + ******************************************************************************/ +#define TEGRA_SEC_IRQ_TARGET_MASK 0x3 /* 2 Denver's */ + /******************************************************************************* * GIC memory map ******************************************************************************/ diff --git a/plat/nvidia/tegra/include/t210/tegra_def.h b/plat/nvidia/tegra/include/t210/tegra_def.h index ce85427e43..cc4c2d9fff 100644 --- a/plat/nvidia/tegra/include/t210/tegra_def.h +++ b/plat/nvidia/tegra/include/t210/tegra_def.h @@ -56,6 +56,11 @@ #define PLAT_MAX_RET_STATE 1 #define PLAT_MAX_OFF_STATE (PSTATE_ID_SOC_POWERDN + 1) +/******************************************************************************* + * Secure IRQ definitions + ******************************************************************************/ +#define TEGRA_SEC_IRQ_TARGET_MASK 0xF /* 4 A57's or 4 A53's */ + /******************************************************************************* * GIC memory map ******************************************************************************/ diff --git a/plat/nvidia/tegra/include/tegra_private.h b/plat/nvidia/tegra/include/tegra_private.h index ef4d55b4e9..f5ffa9e0d7 100644 --- a/plat/nvidia/tegra/include/tegra_private.h +++ b/plat/nvidia/tegra/include/tegra_private.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -42,6 +42,9 @@ #define TEGRA_DRAM_BASE 0x80000000 #define TEGRA_DRAM_END 0x27FFFFFFF +/******************************************************************************* + * Struct for parameters received from BL2 + ******************************************************************************/ typedef struct plat_params_from_bl2 { /* TZ memory size */ uint64_t tzdram_size; @@ -58,13 +61,14 @@ int32_t tegra_soc_validate_power_state(unsigned int power_state, /* Declarations for plat_setup.c */ const mmap_region_t *plat_get_mmio_map(void); uint32_t plat_get_console_from_id(int id); +void plat_gic_setup(void); /* Declarations for plat_secondary.c */ void plat_secondary_setup(void); int plat_lock_cpu_vectors(void); /* Declarations for tegra_gic.c */ -void tegra_gic_setup(void); +void tegra_gic_setup(const unsigned int *irq_sec_ptr, unsigned int num_irqs); void tegra_gic_cpuif_deactivate(void); /* Declarations for tegra_security.c */ diff --git a/plat/nvidia/tegra/soc/t132/plat_setup.c b/plat/nvidia/tegra/soc/t132/plat_setup.c index 337a2c59ff..651bd089f1 100644 --- a/plat/nvidia/tegra/soc/t132/plat_setup.c +++ b/plat/nvidia/tegra/soc/t132/plat_setup.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -28,8 +28,11 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include +#include +#include #include +#include +#include /******************************************************************************* * The Tegra power domain tree has a single system level power domain i.e. a @@ -106,3 +109,11 @@ uint32_t plat_get_console_from_id(int id) return tegra132_uart_addresses[id]; } + +/******************************************************************************* + * Initialize the GIC and SGIs + ******************************************************************************/ +void plat_gic_setup(void) +{ + tegra_gic_setup(NULL, 0); +} diff --git a/plat/nvidia/tegra/soc/t210/plat_setup.c b/plat/nvidia/tegra/soc/t210/plat_setup.c index 246faf8741..42eefe795b 100644 --- a/plat/nvidia/tegra/soc/t210/plat_setup.c +++ b/plat/nvidia/tegra/soc/t210/plat_setup.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * Copyright (c) 2015-2016, ARM Limited and Contributors. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -28,8 +28,11 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include +#include #include #include +#include #include /******************************************************************************* @@ -112,3 +115,11 @@ uint32_t plat_get_console_from_id(int id) return tegra210_uart_addresses[id]; } + +/******************************************************************************* + * Initialize the GIC and SGIs + ******************************************************************************/ +void plat_gic_setup(void) +{ + tegra_gic_setup(NULL, 0); +} From 78e2bd10aed75e2dd7d47abefd6270935fb889b7 Mon Sep 17 00:00:00 2001 From: Varun Wadekar Date: Mon, 28 Dec 2015 16:36:42 -0800 Subject: [PATCH 09/18] Tegra: implement FIQ interrupt handler This patch adds a handler for FIQ interrupts triggered when the CPU is in the NS world. The handler stores the NS world's context along with ELR_EL3/SPSR_EL3. The NS world driver issues an SMC initially to register it's handler. The monitor firmware stores this handler address and jumps to it when the FIQ interrupt fires. Upon entry into the NS world the driver then issues another SMC to get the CPU context when the FIQ fired. This allows the NS world driver to determine the CPU state and call stack when the interrupt fired. Generally, systems register watchdog interrupts as FIQs which are then used to get the CPU state during hangs/crashes. Change-Id: I733af61a08d1318c75acedbe9569a758744edd0c Signed-off-by: Varun Wadekar --- plat/nvidia/tegra/common/tegra_common.mk | 1 + plat/nvidia/tegra/common/tegra_fiq_glue.c | 162 +++++++++++++++++++++ plat/nvidia/tegra/common/tegra_sip_calls.c | 37 +++++ plat/nvidia/tegra/include/tegra_private.h | 13 ++ 4 files changed, 213 insertions(+) create mode 100644 plat/nvidia/tegra/common/tegra_fiq_glue.c diff --git a/plat/nvidia/tegra/common/tegra_common.mk b/plat/nvidia/tegra/common/tegra_common.mk index de6cd04e1c..7f789c5773 100644 --- a/plat/nvidia/tegra/common/tegra_common.mk +++ b/plat/nvidia/tegra/common/tegra_common.mk @@ -55,6 +55,7 @@ BL31_SOURCES += drivers/arm/gic/gic_v2.c \ ${COMMON_DIR}/drivers/pmc/pmc.c \ ${COMMON_DIR}/tegra_bl31_setup.c \ ${COMMON_DIR}/tegra_delay_timer.c \ + ${COMMON_DIR}/tegra_fiq_glue.c \ ${COMMON_DIR}/tegra_gic.c \ ${COMMON_DIR}/tegra_pm.c \ ${COMMON_DIR}/tegra_sip_calls.c \ diff --git a/plat/nvidia/tegra/common/tegra_fiq_glue.c b/plat/nvidia/tegra/common/tegra_fiq_glue.c new file mode 100644 index 0000000000..0c4d82c219 --- /dev/null +++ b/plat/nvidia/tegra/common/tegra_fiq_glue.c @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * Neither the name of ARM nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DEFINE_BAKERY_LOCK(tegra_fiq_lock); + +/******************************************************************************* + * Static variables + ******************************************************************************/ +static uint64_t ns_fiq_handler_addr; +static unsigned int fiq_handler_active; +static pcpu_fiq_state_t fiq_state[PLATFORM_CORE_COUNT]; + +/******************************************************************************* + * Handler for FIQ interrupts + ******************************************************************************/ +static uint64_t tegra_fiq_interrupt_handler(uint32_t id, + uint32_t flags, + void *handle, + void *cookie) +{ + cpu_context_t *ctx = cm_get_context(NON_SECURE); + el3_state_t *el3state_ctx = get_el3state_ctx(ctx); + int cpu = plat_my_core_pos(); + uint32_t irq; + + bakery_lock_get(&tegra_fiq_lock); + + /* + * 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, CTX_ELR_EL3); + fiq_state[cpu].spsr_el3 = read_ctx_reg(el3state_ctx, CTX_SPSR_EL3); + + /* + * Set the new ELR to continue execution in the NS world using the + * FIQ handler registered earlier. + */ + assert(ns_fiq_handler_addr); + write_ctx_reg(el3state_ctx, CTX_ELR_EL3, ns_fiq_handler_addr); + + /* + * Mark this interrupt as complete to avoid a FIQ storm. + */ + irq = plat_ic_acknowledge_interrupt(); + if (irq < 1022) + plat_ic_end_of_interrupt(irq); + + bakery_lock_release(&tegra_fiq_lock); + + return 0; +} + +/******************************************************************************* + * Setup handler for FIQ interrupts + ******************************************************************************/ +void tegra_fiq_handler_setup(void) +{ + uint64_t flags; + int rc; + + /* return if already registered */ + if (fiq_handler_active) + return; + + /* + * Register an interrupt handler for FIQ interrupts generated for + * NS interrupt sources + */ + flags = 0; + set_interrupt_rm_flag(flags, NON_SECURE); + rc = register_interrupt_type_handler(INTR_TYPE_S_EL1, + tegra_fiq_interrupt_handler, + flags); + if (rc) + panic(); + + /* 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 + ******************************************************************************/ +int tegra_fiq_get_intr_context(void) +{ + cpu_context_t *ctx = cm_get_context(NON_SECURE); + gp_regs_t *gpregs_ctx = get_gpregs_ctx(ctx); + el1_sys_regs_t *el1state_ctx = get_sysregs_ctx(ctx); + int 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, CTX_GPREG_X0, fiq_state[cpu].elr_el3); + write_ctx_reg(gpregs_ctx, CTX_GPREG_X1, fiq_state[cpu].spsr_el3); + + val = read_ctx_reg(gpregs_ctx, CTX_GPREG_SP_EL0); + write_ctx_reg(gpregs_ctx, CTX_GPREG_X2, val); + + val = read_ctx_reg(el1state_ctx, CTX_SP_EL1); + write_ctx_reg(gpregs_ctx, CTX_GPREG_X3, val); + + return 0; +} diff --git a/plat/nvidia/tegra/common/tegra_sip_calls.c b/plat/nvidia/tegra/common/tegra_sip_calls.c index 77f039a422..ba0e1ef52a 100644 --- a/plat/nvidia/tegra/common/tegra_sip_calls.c +++ b/plat/nvidia/tegra/common/tegra_sip_calls.c @@ -42,6 +42,8 @@ * 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 /******************************************************************************* * SoC specific SiP handler @@ -108,6 +110,41 @@ uint64_t tegra_sip_handler(uint32_t smc_fid, SMC_RET1(handle, 0); break; + /* + * 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) + 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); + break; + + /* + * 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 */ + tegra_fiq_get_intr_context(); + + SMC_RET0(handle); + break; + default: ERROR("%s: unhandled SMC (0x%x)\n", __func__, smc_fid); break; diff --git a/plat/nvidia/tegra/include/tegra_private.h b/plat/nvidia/tegra/include/tegra_private.h index f5ffa9e0d7..c65bacae73 100644 --- a/plat/nvidia/tegra/include/tegra_private.h +++ b/plat/nvidia/tegra/include/tegra_private.h @@ -54,6 +54,14 @@ typedef struct plat_params_from_bl2 { int uart_id; } plat_params_from_bl2_t; +/******************************************************************************* + * 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; + /* Declarations for plat_psci_handlers.c */ int32_t tegra_soc_validate_power_state(unsigned int power_state, psci_power_state_t *req_state); @@ -67,6 +75,11 @@ void plat_gic_setup(void); void plat_secondary_setup(void); int plat_lock_cpu_vectors(void); +/* Declarations for tegra_fiq_glue.c */ +void tegra_fiq_handler_setup(void); +int tegra_fiq_get_intr_context(void); +void tegra_fiq_set_ns_entrypoint(uint64_t entrypoint); + /* Declarations for tegra_gic.c */ void tegra_gic_setup(const unsigned int *irq_sec_ptr, unsigned int num_irqs); void tegra_gic_cpuif_deactivate(void); From 45eab456e6da0e79c51ffced6c3a46053a1adc70 Mon Sep 17 00:00:00 2001 From: Varun Wadekar Date: Fri, 20 May 2016 16:21:22 -0700 Subject: [PATCH 10/18] Tegra: GIC: differentiate between FIQs targeted towards EL3/S-EL1 This patch modifies the secure IRQ registration process to allow platforms to specify the target CPUs as well as the owner of the IRQ. IRQs "owned" by the EL3 would return INTR_TYPE_EL3 whereas those owned by the Trusted OS would return INTR_TYPE_S_EL1 as a result. Change-Id: I528f7c8220d0ae0c0f354e78d69e188abb666ef6 Signed-off-by: Varun Wadekar --- plat/nvidia/tegra/common/tegra_fiq_glue.c | 2 +- plat/nvidia/tegra/common/tegra_gic.c | 36 +++++++++++++--------- plat/nvidia/tegra/include/t132/tegra_def.h | 5 --- plat/nvidia/tegra/include/t210/tegra_def.h | 5 --- plat/nvidia/tegra/include/tegra_private.h | 14 ++++++++- 5 files changed, 36 insertions(+), 26 deletions(-) diff --git a/plat/nvidia/tegra/common/tegra_fiq_glue.c b/plat/nvidia/tegra/common/tegra_fiq_glue.c index 0c4d82c219..7fcc114c06 100644 --- a/plat/nvidia/tegra/common/tegra_fiq_glue.c +++ b/plat/nvidia/tegra/common/tegra_fiq_glue.c @@ -116,7 +116,7 @@ void tegra_fiq_handler_setup(void) */ flags = 0; set_interrupt_rm_flag(flags, NON_SECURE); - rc = register_interrupt_type_handler(INTR_TYPE_S_EL1, + rc = register_interrupt_type_handler(INTR_TYPE_EL3, tegra_fiq_interrupt_handler, flags); if (rc) diff --git a/plat/nvidia/tegra/common/tegra_gic.c b/plat/nvidia/tegra/common/tegra_gic.c index 786eefc1db..6864f8bf3d 100644 --- a/plat/nvidia/tegra/common/tegra_gic.c +++ b/plat/nvidia/tegra/common/tegra_gic.c @@ -47,7 +47,7 @@ (GIC_HIGHEST_NS_PRIORITY << 16) | \ (GIC_HIGHEST_NS_PRIORITY << 24)) -static const unsigned int *g_irq_sec_ptr; +static const irq_sec_cfg_t *g_irq_sec_ptr; static unsigned int g_num_irqs; /******************************************************************************* @@ -136,11 +136,9 @@ static void tegra_gic_distif_setup(unsigned int gicd_base) /* Configure SPI secure interrupts now */ if (g_irq_sec_ptr) { - /* Read the target CPU mask */ - target_cpus = TEGRA_SEC_IRQ_TARGET_MASK & GIC_TARGET_CPU_MASK; - for (index = 0; index < g_num_irqs; index++) { - irq_num = g_irq_sec_ptr[index]; + irq_num = (g_irq_sec_ptr + index)->irq; + target_cpus = (g_irq_sec_ptr + index)->target_cpus; if (irq_num >= MIN_SPI_ID) { @@ -179,7 +177,7 @@ static void tegra_gic_distif_setup(unsigned int gicd_base) gicd_write_ctlr(gicd_base, ENABLE_GRP0 | ENABLE_GRP1); } -void tegra_gic_setup(const unsigned int *irq_sec_ptr, unsigned int num_irqs) +void tegra_gic_setup(const irq_sec_cfg_t *irq_sec_ptr, unsigned int num_irqs) { g_irq_sec_ptr = irq_sec_ptr; g_num_irqs = num_irqs; @@ -228,12 +226,17 @@ uint32_t tegra_gic_interrupt_type_to_line(uint32_t type, uint32_t tegra_gic_get_pending_interrupt_type(void) { uint32_t id; + unsigned int index; id = gicc_read_hppir(TEGRA_GICC_BASE) & INT_ID_MASK; - /* Assume that all secure interrupts are S-EL1 interrupts */ - if (id < 1022) - return INTR_TYPE_S_EL1; + /* get the interrupt type */ + if (id < 1022) { + for (index = 0; index < g_num_irqs; index++) { + if (id == (g_irq_sec_ptr + index)->irq) + return (g_irq_sec_ptr + index)->type; + } + } if (id == GIC_SPURIOUS_INTERRUPT) return INTR_TYPE_INVAL; @@ -291,14 +294,19 @@ void tegra_gic_end_of_interrupt(uint32_t id) uint32_t tegra_gic_get_interrupt_type(uint32_t id) { uint32_t group; + unsigned int index; group = gicd_get_igroupr(TEGRA_GICD_BASE, id); - /* Assume that all secure interrupts are S-EL1 interrupts */ - if (group == GRP0) - return INTR_TYPE_S_EL1; - else - return INTR_TYPE_NS; + /* get the interrupt type */ + if (group == GRP0) { + for (index = 0; index < g_num_irqs; index++) { + if (id == (g_irq_sec_ptr + index)->irq) + return (g_irq_sec_ptr + index)->type; + } + } + + return INTR_TYPE_NS; } #else diff --git a/plat/nvidia/tegra/include/t132/tegra_def.h b/plat/nvidia/tegra/include/t132/tegra_def.h index 3bafb87dcd..318f4def15 100644 --- a/plat/nvidia/tegra/include/t132/tegra_def.h +++ b/plat/nvidia/tegra/include/t132/tegra_def.h @@ -48,11 +48,6 @@ #define PLAT_MAX_RET_STATE 1 #define PLAT_MAX_OFF_STATE (PSTATE_ID_SOC_POWERDN + 1) -/******************************************************************************* - * Secure IRQ definitions - ******************************************************************************/ -#define TEGRA_SEC_IRQ_TARGET_MASK 0x3 /* 2 Denver's */ - /******************************************************************************* * GIC memory map ******************************************************************************/ diff --git a/plat/nvidia/tegra/include/t210/tegra_def.h b/plat/nvidia/tegra/include/t210/tegra_def.h index cc4c2d9fff..ce85427e43 100644 --- a/plat/nvidia/tegra/include/t210/tegra_def.h +++ b/plat/nvidia/tegra/include/t210/tegra_def.h @@ -56,11 +56,6 @@ #define PLAT_MAX_RET_STATE 1 #define PLAT_MAX_OFF_STATE (PSTATE_ID_SOC_POWERDN + 1) -/******************************************************************************* - * Secure IRQ definitions - ******************************************************************************/ -#define TEGRA_SEC_IRQ_TARGET_MASK 0xF /* 4 A57's or 4 A53's */ - /******************************************************************************* * GIC memory map ******************************************************************************/ diff --git a/plat/nvidia/tegra/include/tegra_private.h b/plat/nvidia/tegra/include/tegra_private.h index c65bacae73..c09a153ca4 100644 --- a/plat/nvidia/tegra/include/tegra_private.h +++ b/plat/nvidia/tegra/include/tegra_private.h @@ -62,6 +62,18 @@ typedef struct pcpu_fiq_state { uint64_t spsr_el3; } pcpu_fiq_state_t; +/******************************************************************************* + * Struct describing per-FIQ configuration settings + ******************************************************************************/ +typedef struct irq_sec_cfg { + /* IRQ number */ + unsigned int irq; + /* Target CPUs servicing this interrupt */ + unsigned int target_cpus; + /* type = INTR_TYPE_S_EL1 or INTR_TYPE_EL3 */ + uint32_t type; +} irq_sec_cfg_t; + /* Declarations for plat_psci_handlers.c */ int32_t tegra_soc_validate_power_state(unsigned int power_state, psci_power_state_t *req_state); @@ -81,7 +93,7 @@ int tegra_fiq_get_intr_context(void); void tegra_fiq_set_ns_entrypoint(uint64_t entrypoint); /* Declarations for tegra_gic.c */ -void tegra_gic_setup(const unsigned int *irq_sec_ptr, unsigned int num_irqs); +void tegra_gic_setup(const irq_sec_cfg_t *irq_sec_ptr, unsigned int num_irqs); void tegra_gic_cpuif_deactivate(void); /* Declarations for tegra_security.c */ From 018b84803d3766c0733e50dc514d5f4ffce77cca Mon Sep 17 00:00:00 2001 From: Varun Wadekar Date: Thu, 12 May 2016 13:43:33 -0700 Subject: [PATCH 11/18] Tegra: enable ECC/Parity protection for Cortex-A57 CPUs This patch enables L2 ECC and Parity Protection for ARM Cortex-A57 CPUs for Tegra SoCs. Change-Id: I038fcd529991d0201a4951ce2730ab71b1c980f9 Signed-off-by: Varun Wadekar --- docs/plat/nvidia-tegra.md | 7 +++++ include/lib/cpus/aarch64/cortex_a57.h | 2 ++ .../tegra/common/aarch64/tegra_helpers.S | 30 ++++++++++++++++--- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/docs/plat/nvidia-tegra.md b/docs/plat/nvidia-tegra.md index f82085b136..b45fec6e5b 100644 --- a/docs/plat/nvidia-tegra.md +++ b/docs/plat/nvidia-tegra.md @@ -84,3 +84,10 @@ The PSCI implementation expects each platform to expose the 'power state' parameter to be used during the 'SYSTEM SUSPEND' call. The state-id field is implementation defined on Tegra SoCs and is preferably defined by tegra_def.h. + +Tegra configs +============= + +* 'tegra_enable_l2_ecc_parity_prot': This flag enables the L2 ECC and Parity + Protection bit, for ARM Cortex-A57 CPUs, during CPU boot. This flag will + be enabled by Tegrs SoCs during 'Cluster power up' or 'System Suspend' exit. diff --git a/include/lib/cpus/aarch64/cortex_a57.h b/include/lib/cpus/aarch64/cortex_a57.h index c5a218b725..9229a564e1 100644 --- a/include/lib/cpus/aarch64/cortex_a57.h +++ b/include/lib/cpus/aarch64/cortex_a57.h @@ -87,6 +87,8 @@ #define L2_DATA_RAM_LATENCY_3_CYCLES 0x2 #define L2_TAG_RAM_LATENCY_3_CYCLES 0x2 +#define L2_ECC_PARITY_PROTECTION_BIT (1 << 21) + /******************************************************************************* * L2 Extended Control register specific definitions. ******************************************************************************/ diff --git a/plat/nvidia/tegra/common/aarch64/tegra_helpers.S b/plat/nvidia/tegra/common/aarch64/tegra_helpers.S index a57d1cb0a3..70a7f3a9b9 100644 --- a/plat/nvidia/tegra/common/aarch64/tegra_helpers.S +++ b/plat/nvidia/tegra/common/aarch64/tegra_helpers.S @@ -68,6 +68,7 @@ .globl ns_image_entrypoint .globl tegra_bl31_phys_base .globl tegra_console_base + .globl tegra_enable_l2_ecc_parity_prot /* --------------------- * Common CPU init code @@ -76,8 +77,8 @@ .macro cpu_init_common /* ------------------------------------------------ - * We enable procesor retention and L2/CPUECTLR NS - * access for A57 CPUs only. + * We enable procesor retention, L2/CPUECTLR NS + * access and ECC/Parity protection for A57 CPUs * ------------------------------------------------ */ mrs x0, midr_el1 @@ -90,7 +91,7 @@ /* --------------------------- * Enable processor retention * --------------------------- - */ + */ mrs x0, L2ECTLR_EL1 mov x1, #RETENTION_ENTRY_TICKS_512 << L2ECTLR_RET_CTRL_SHIFT bic x0, x0, #L2ECTLR_RET_CTRL_MASK @@ -108,12 +109,26 @@ /* ------------------------------------------------------- * Enable L2 and CPU ECTLR RW access from non-secure world * ------------------------------------------------------- - */ + */ mov x0, #ACTLR_EL3_ENABLE_ALL_ACCESS msr actlr_el3, x0 msr actlr_el2, x0 isb + /* ------------------------------------------------------- + * Enable L2 ECC and Parity Protection + * ------------------------------------------------------- + */ + adr x0, tegra_enable_l2_ecc_parity_prot + ldr x0, [x0] + cbz x0, 1f + mrs x0, L2CTLR_EL1 + and x1, x0, #L2_ECC_PARITY_PROTECTION_BIT + cbnz x1, 1f + orr x0, x0, #L2_ECC_PARITY_PROTECTION_BIT + msr L2CTLR_EL1, x0 + isb + /* -------------------------------- * Enable the cycle count register * -------------------------------- @@ -454,3 +469,10 @@ tegra_bl31_phys_base: */ tegra_console_base: .quad 0 + + /* -------------------------------------------------- + * Enable L2 ECC and Parity Protection + * -------------------------------------------------- + */ +tegra_enable_l2_ecc_parity_prot: + .quad 0 From 207680c6ad8c7aa06d699fff43d59d2a965e144c Mon Sep 17 00:00:00 2001 From: Varun Wadekar Date: Wed, 1 Jun 2016 19:34:37 -0700 Subject: [PATCH 12/18] Tegra: restore TZRAM settings on "System Resume" This patch restores the TZRAM fence and the access permissions on exiting the "System Suspend" state. Change-Id: Ie313fca5a861c73f80df9639b01115780fb6e217 Signed-off-by: Varun Wadekar --- plat/nvidia/tegra/common/tegra_pm.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/plat/nvidia/tegra/common/tegra_pm.c b/plat/nvidia/tegra/common/tegra_pm.c index ca49dabdbe..389346f4ae 100644 --- a/plat/nvidia/tegra/common/tegra_pm.c +++ b/plat/nvidia/tegra/common/tegra_pm.c @@ -203,6 +203,12 @@ void tegra_pwr_domain_on_finish(const psci_power_state_t *target_state) plat_params = bl31_get_plat_params(); tegra_memctrl_tzdram_setup(plat_params->tzdram_base, plat_params->tzdram_size); + + /* + * Set up the TZRAM memory aperture to allow only secure world + * access + */ + tegra_memctrl_tzram_setup(TEGRA_TZRAM_BASE, TEGRA_TZRAM_SIZE); } /* From 08012f48752e2d8e603b0f4a4a17c86c1e901499 Mon Sep 17 00:00:00 2001 From: Varun Wadekar Date: Sat, 4 Jun 2016 22:08:50 -0700 Subject: [PATCH 13/18] Tegra: configure TZDRAM fence during early setup This patch configures the TZDRAM fence during early platform setup to allow the memory controller to enable DRAM encryption before the TZDRAM actually gets used. Change-Id: I0169ef9dda75699527b4e30c9e617a9036ba1d76 Signed-off-by: Varun Wadekar --- plat/nvidia/tegra/common/tegra_bl31_setup.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/plat/nvidia/tegra/common/tegra_bl31_setup.c b/plat/nvidia/tegra/common/tegra_bl31_setup.c index 142839c81a..5be9a998fd 100644 --- a/plat/nvidia/tegra/common/tegra_bl31_setup.c +++ b/plat/nvidia/tegra/common/tegra_bl31_setup.c @@ -171,6 +171,12 @@ void bl31_early_platform_setup(bl31_params_t *from_bl2, /* Initialise crash console */ plat_crash_console_init(); + /* + * Do initial security configuration to allow DRAM/device access. + */ + tegra_memctrl_tzdram_setup(plat_bl31_params_from_bl2.tzdram_base, + plat_bl31_params_from_bl2.tzdram_size); + /* Early platform setup for Tegra SoCs */ plat_early_platform_setup(); @@ -203,12 +209,6 @@ void bl31_platform_setup(void) */ tegra_memctrl_setup(); - /* - * Do initial security configuration to allow DRAM/device access. - */ - tegra_memctrl_tzdram_setup(plat_bl31_params_from_bl2.tzdram_base, - plat_bl31_params_from_bl2.tzdram_size); - /* * Set up the TZRAM memory aperture to allow only secure world * access From 4ce9a18282913d466752c3c9614ceb7946ecce8f Mon Sep 17 00:00:00 2001 From: Varun Wadekar Date: Mon, 6 Jun 2016 10:46:28 -0700 Subject: [PATCH 14/18] Tegra: return BL32 entry point info if it is valid This patch returns pointer to the BL32 entrypoint info only if it is valid. Change-Id: I71ce3c4626681753c94f3a7bbaa50c26c74874cb Signed-off-by: Varun Wadekar --- plat/nvidia/tegra/common/tegra_bl31_setup.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plat/nvidia/tegra/common/tegra_bl31_setup.c b/plat/nvidia/tegra/common/tegra_bl31_setup.c index 5be9a998fd..6237c805b2 100644 --- a/plat/nvidia/tegra/common/tegra_bl31_setup.c +++ b/plat/nvidia/tegra/common/tegra_bl31_setup.c @@ -100,7 +100,8 @@ entry_point_info_t *bl31_plat_get_next_image_ep_info(uint32_t type) if (type == NON_SECURE) return &bl33_image_ep_info; - if (type == SECURE) + /* return BL32 entry point info if it is valid */ + if (type == SECURE && bl32_image_ep_info.pc) return &bl32_image_ep_info; return NULL; From 8ab06d2f1e6bf7b6fdd2e96411dfb0b998fa2ce5 Mon Sep 17 00:00:00 2001 From: Varun Wadekar Date: Mon, 23 May 2016 11:41:07 -0700 Subject: [PATCH 15/18] Tegra: get BL31 arguments from previous bootloader This patch implements handlers which platforms can override to get the BL31 arguments passed by the previous bootloader. Change-Id: I6b9628a984644ce1b5de5aa6d7cd890e57241d89 Signed-off-by: Varun Wadekar --- plat/nvidia/tegra/common/tegra_bl31_setup.c | 24 +++++++++++++++++++++ plat/nvidia/tegra/include/tegra_private.h | 2 ++ 2 files changed, 26 insertions(+) diff --git a/plat/nvidia/tegra/common/tegra_bl31_setup.c b/plat/nvidia/tegra/common/tegra_bl31_setup.c index 6237c805b2..5ad3e7958f 100644 --- a/plat/nvidia/tegra/common/tegra_bl31_setup.c +++ b/plat/nvidia/tegra/common/tegra_bl31_setup.c @@ -84,12 +84,24 @@ extern uint64_t ns_image_entrypoint; * provide typical implementations that will be overridden by a SoC. ******************************************************************************/ #pragma weak plat_early_platform_setup +#pragma weak plat_get_bl31_params +#pragma weak plat_get_bl31_plat_params void plat_early_platform_setup(void) { ; /* do nothing */ } +bl31_params_t *plat_get_bl31_params(void) +{ + return NULL; +} + +plat_params_from_bl2_t *plat_get_bl31_plat_params(void) +{ + return NULL; +} + /******************************************************************************* * 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 @@ -129,10 +141,22 @@ void bl31_early_platform_setup(bl31_params_t *from_bl2, int impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK; #endif + /* + * 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, so provide handlers which + * they can override. + */ + if (from_bl2 == NULL) + 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(from_bl2); assert(from_bl2->bl33_ep_info); bl33_image_ep_info = *from_bl2->bl33_ep_info; diff --git a/plat/nvidia/tegra/include/tegra_private.h b/plat/nvidia/tegra/include/tegra_private.h index c09a153ca4..012bfd77bc 100644 --- a/plat/nvidia/tegra/include/tegra_private.h +++ b/plat/nvidia/tegra/include/tegra_private.h @@ -82,6 +82,8 @@ int32_t tegra_soc_validate_power_state(unsigned int power_state, const mmap_region_t *plat_get_mmio_map(void); uint32_t plat_get_console_from_id(int id); void plat_gic_setup(void); +bl31_params_t *plat_get_bl31_params(void); +plat_params_from_bl2_t *plat_get_bl31_plat_params(void); /* Declarations for plat_secondary.c */ void plat_secondary_setup(void); From 7eec50928c6e8f4232ca0a1b69b5efc7c048eb20 Mon Sep 17 00:00:00 2001 From: Varun Wadekar Date: Mon, 21 Mar 2016 10:22:12 -0700 Subject: [PATCH 16/18] stdlib: add memcpy16() to string.h This patch exports memcpy16() for platforms, as an option to memcpy(). Change-Id: I5d4e1cfb4608ec3674224b1447fdd740de549b1f Signed-off-by: Varun Wadekar --- include/lib/stdlib/string.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/lib/stdlib/string.h b/include/lib/stdlib/string.h index 902d9c1303..56677b2cf1 100644 --- a/include/lib/stdlib/string.h +++ b/include/lib/stdlib/string.h @@ -52,6 +52,7 @@ __BEGIN_DECLS void *memchr(const void *, int, size_t) __pure; int memcmp(const void *, const void *, size_t) __pure; void *memcpy(void * __restrict, const void * __restrict, size_t); +void *memcpy16(void * __restrict, const void * __restrict, size_t); void *memmove(void *, const void *, size_t); void *memset(void *, int, size_t); From da3849ecc034fb70c6c8b88889c19f79f2a587b7 Mon Sep 17 00:00:00 2001 From: Varun Wadekar Date: Mon, 23 May 2016 15:56:14 -0700 Subject: [PATCH 17/18] Tegra: relocate BL32 image to TZDRAM memory This patch adds support to relocate the BL32 image from the NS memory to TZDRAM during cold boot. The NS memory buffer is cleared out after the process completes. Change-Id: I1a033ffe73b8c309449f874d5187708d0a8846d2 Signed-off-by: Varun Wadekar --- plat/nvidia/tegra/common/tegra_bl31_setup.c | 41 +++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/plat/nvidia/tegra/common/tegra_bl31_setup.c b/plat/nvidia/tegra/common/tegra_bl31_setup.c index 5ad3e7958f..246a03e0e2 100644 --- a/plat/nvidia/tegra/common/tegra_bl31_setup.c +++ b/plat/nvidia/tegra/common/tegra_bl31_setup.c @@ -44,9 +44,12 @@ #include #include #include +#include #include #include +extern void zeromem16(void *mem, unsigned int length); + /******************************************************************************* * Declarations of linker defined symbols which will help us find the layout * of trusted SRAM @@ -140,6 +143,8 @@ void bl31_early_platform_setup(bl31_params_t *from_bl2, #if DEBUG int impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK; #endif + image_info_t bl32_img_info = { {0} }; + uint64_t tzdram_start, tzdram_end, bl32_start, bl32_end; /* * For RESET_TO_BL31 systems, BL31 is the first bootloader to run so @@ -202,6 +207,42 @@ void bl31_early_platform_setup(bl31_params_t *from_bl2, tegra_memctrl_tzdram_setup(plat_bl31_params_from_bl2.tzdram_base, plat_bl31_params_from_bl2.tzdram_size); + /* + * The previous bootloader might not have placed the BL32 image + * inside the TZDRAM. We check the BL32 image info to find out + * the base/PC values and relocate the image if necessary. + */ + if (from_bl2->bl32_image_info) { + + bl32_img_info = *from_bl2->bl32_image_info; + + /* Relocate BL32 if it resides outside of the TZDRAM */ + tzdram_start = plat_bl31_params_from_bl2.tzdram_base; + tzdram_end = plat_bl31_params_from_bl2.tzdram_base + + plat_bl31_params_from_bl2.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_image_ep_info.pc > tzdram_start); + assert(bl32_image_ep_info.pc < tzdram_end); + + /* relocate BL32 */ + if (bl32_start >= tzdram_end || bl32_end <= tzdram_start) { + + INFO("Relocate BL32 to TZDRAM\n"); + + memcpy16((void *)(uintptr_t)bl32_image_ep_info.pc, + (void *)(uintptr_t)bl32_start, + bl32_img_info.image_size); + + /* clean up non-secure intermediate buffer */ + zeromem16((void *)(uintptr_t)bl32_start, + bl32_img_info.image_size); + } + } + /* Early platform setup for Tegra SoCs */ plat_early_platform_setup(); From a7cd0953d67e949104b754296c1f5aab08d42e3f Mon Sep 17 00:00:00 2001 From: Varun Wadekar Date: Tue, 7 Jun 2016 12:00:06 -0700 Subject: [PATCH 18/18] Tegra: per-soc `get_target_pwr_state` handler This patch implements a per-soc handler to calculate the target power state for the cluster/system. A weak implementation of the handler is provided for platforms to use by default. For SoCs with multiple CPU clusters, this handler would provide the individual cluster/system state, allowing the PSCI service to flush caches during cluster/system power down. Change-Id: I568cdb42204f9841a8430bd9105bd694f71cf91d Signed-off-by: Varun Wadekar --- plat/nvidia/tegra/common/tegra_pm.c | 39 ++++++++++++++++------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/plat/nvidia/tegra/common/tegra_pm.c b/plat/nvidia/tegra/common/tegra_pm.c index 389346f4ae..b2703ddee3 100644 --- a/plat/nvidia/tegra/common/tegra_pm.c +++ b/plat/nvidia/tegra/common/tegra_pm.c @@ -57,6 +57,7 @@ extern uint64_t tegra_sec_entry_point; #pragma weak tegra_soc_pwr_domain_power_down_wfi #pragma weak tegra_soc_prepare_system_reset #pragma weak tegra_soc_prepare_system_off +#pragma weak tegra_soc_get_target_pwr_state int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state) { @@ -94,6 +95,23 @@ __dead2 void tegra_soc_prepare_system_off(void) panic(); } +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 = PLAT_MAX_RET_STATE, temp; + + assert(ncpu); + + do { + temp = *states++; + if ((temp > target) && (temp != PLAT_MAX_OFF_STATE)) + target = temp; + } while (--ncpu); + + return target; +} + /******************************************************************************* * 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 @@ -102,12 +120,9 @@ __dead2 void tegra_soc_prepare_system_off(void) ******************************************************************************/ void tegra_get_sys_suspend_power_state(psci_power_state_t *req_state) { - /* lower affinities use PLAT_MAX_OFF_STATE */ - for (int i = MPIDR_AFFLVL0; i < PLAT_MAX_PWR_LVL; i++) - req_state->pwr_domain_state[i] = PLAT_MAX_OFF_STATE; - - /* max affinity uses system suspend state id */ - req_state->pwr_domain_state[PLAT_MAX_PWR_LVL] = PSTATE_ID_SOC_POWERDN; + /* all affinities use system suspend state id */ + for (int i = MPIDR_AFFLVL0; i <= PLAT_MAX_PWR_LVL; i++) + req_state->pwr_domain_state[i] = PSTATE_ID_SOC_POWERDN; } /******************************************************************************* @@ -333,15 +348,5 @@ plat_local_state_t plat_get_target_pwr_state(unsigned int lvl, const plat_local_state_t *states, unsigned int ncpu) { - plat_local_state_t target = PLAT_MAX_RET_STATE, temp; - - assert(ncpu); - - do { - temp = *states++; - if ((temp > target) && (temp != PLAT_MAX_OFF_STATE)) - target = temp; - } while (--ncpu); - - return target; + return tegra_soc_get_target_pwr_state(lvl, states, ncpu); }