Commit abfcba1c authored by Olof Johansson's avatar Olof Johansson

Merge tag 'tegra-for-5.2-firmware' of...

Merge tag 'tegra-for-5.2-firmware' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux into arm/soc

firmware: tegra: Changes for v5.2-rc1

This set of changes includes improvements for Trusted Foundations and
also moves the source files for this support into the standard location
under drivers/firmware.

* tag 'tegra-for-5.2-firmware' of git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux:
  firmware: Move Trusted Foundations support
  ARM: tegra: Sort dependencies alphabetically
  ARM: tegra: Add firmware calls required for suspend-resume on Tegra30
  ARM: tegra: Always boot CPU in ARM-mode
  ARM: tegra: Don't apply CPU erratas in insecure mode
  ARM: tegra: Set up L2 cache using Trusted Foundations firmware
  ARM: trusted_foundations: Provide information about whether firmware is registered
  ARM: trusted_foundations: Make prepare_idle call to take mode argument
  ARM: trusted_foundations: Support L2 cache maintenance
Signed-off-by: default avatarOlof Johansson <olof@lixom.net>
parents 876e645f 4cb5d9ec
......@@ -900,8 +900,6 @@ config PLAT_PXA
config PLAT_VERSATILE
bool
source "arch/arm/firmware/Kconfig"
source "arch/arm/mm/Kconfig"
config IWMMXT
......
......@@ -290,7 +290,6 @@ core-y += arch/arm/kernel/ arch/arm/mm/ arch/arm/common/
core-y += arch/arm/probes/
core-y += arch/arm/net/
core-y += arch/arm/crypto/
core-y += arch/arm/firmware/
core-y += $(machdirs) $(platdirs)
drivers-$(CONFIG_OPROFILE) += arch/arm/oprofile/
......
config ARCH_SUPPORTS_FIRMWARE
bool
config ARCH_SUPPORTS_TRUSTED_FOUNDATIONS
bool
select ARCH_SUPPORTS_FIRMWARE
menu "Firmware options"
depends on ARCH_SUPPORTS_FIRMWARE
config TRUSTED_FOUNDATIONS
bool "Trusted Foundations secure monitor support"
depends on ARCH_SUPPORTS_TRUSTED_FOUNDATIONS
default y
help
Some devices (including most Tegra-based consumer devices on the
market) are booted with the Trusted Foundations secure monitor
active, requiring some core operations to be performed by the secure
monitor instead of the kernel.
This option allows the kernel to invoke the secure monitor whenever
required on devices using Trusted Foundations. See
arch/arm/include/asm/trusted_foundations.h or the
tlm,trusted-foundations device tree binding documentation for details
on how to use it.
Say n if you don't know what this is about.
endmenu
obj-$(CONFIG_TRUSTED_FOUNDATIONS) += trusted_foundations.o
# tf_generic_smc() fails to build with -fsanitize-coverage=trace-pc
KCOV_INSTRUMENT := n
......@@ -24,7 +24,7 @@ struct firmware_ops {
/*
* Inform the firmware we intend to enter CPU idle mode
*/
int (*prepare_idle)(void);
int (*prepare_idle)(unsigned long mode);
/*
* Enters CPU idle mode
*/
......
......@@ -2,7 +2,7 @@
menuconfig ARCH_TEGRA
bool "NVIDIA Tegra"
depends on ARCH_MULTI_V7
select ARCH_SUPPORTS_TRUSTED_FOUNDATIONS
select ARCH_HAS_RESET_CONTROLLER
select ARM_AMBA
select ARM_GIC
select CLKSRC_MMIO
......@@ -11,7 +11,6 @@ menuconfig ARCH_TEGRA
select HAVE_ARM_TWD if SMP
select PINCTRL
select PM_OPP
select ARCH_HAS_RESET_CONTROLLER
select RESET_CONTROLLER
select SOC_BUS
select ZONE_DMA if ARM_LPAE
......
......@@ -21,6 +21,8 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/firmware/trusted_foundations.h>
#include <asm/cpuidle.h>
#include <asm/smp_plat.h>
#include <asm/suspend.h>
......@@ -46,7 +48,7 @@ static int tegra114_idle_power_down(struct cpuidle_device *dev,
tegra_set_cpu_in_lp2();
cpu_pm_enter();
call_firmware_op(prepare_idle);
call_firmware_op(prepare_idle, TF_PM_MODE_LP2_NOFLUSH_L2);
/* Do suspend by ourselves if the firmware does not implement it */
if (call_firmware_op(do_idle, 0) == -ENOSYS)
......
......@@ -27,12 +27,15 @@
#include <linux/spinlock.h>
#include <linux/suspend.h>
#include <linux/firmware/trusted_foundations.h>
#include <soc/tegra/flowctrl.h>
#include <soc/tegra/fuse.h>
#include <soc/tegra/pm.h>
#include <soc/tegra/pmc.h>
#include <asm/cacheflush.h>
#include <asm/firmware.h>
#include <asm/idmap.h>
#include <asm/proc-fns.h>
#include <asm/smp_plat.h>
......@@ -159,6 +162,28 @@ int tegra_cpu_do_idle(void)
static int tegra_sleep_cpu(unsigned long v2p)
{
/*
* L2 cache disabling using kernel API only allowed when all
* secondary CPU's are offline. Cache have to be disabled with
* MMU-on if cache maintenance is done via Trusted Foundations
* firmware. Note that CPUIDLE won't ever enter powergate on Tegra30
* if any of secondary CPU's is online and this is the LP2-idle
* code-path only for Tegra20/30.
*/
if (trusted_foundations_registered())
outer_disable();
/*
* Note that besides of setting up CPU reset vector this firmware
* call may also do the following, depending on the FW version:
* 1) Disable L2. But this doesn't matter since we already
* disabled the L2.
* 2) Disable D-cache. This need to be taken into account in
* particular by the tegra_disable_clean_inv_dcache() which
* shall avoid the re-disable.
*/
call_firmware_op(prepare_idle, TF_PM_MODE_LP2);
setup_mm_for_reboot();
tegra_sleep_cpu_finish(v2p);
......@@ -197,6 +222,14 @@ void tegra_idle_lp2_last(void)
cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, &tegra_sleep_cpu);
/*
* Resume L2 cache if it wasn't re-enabled early during resume,
* which is the case for Tegra30 that has to re-enable the cache
* via firmware call. In other cases cache is already enabled and
* hence re-enabling is a no-op. This is always a no-op on Tegra114+.
*/
outer_resume();
restore_cpu_complex();
cpu_cluster_pm_exit();
}
......@@ -215,6 +248,15 @@ enum tegra_suspend_mode tegra_pm_validate_suspend_mode(
static int tegra_sleep_core(unsigned long v2p)
{
/*
* Cache have to be disabled with MMU-on if cache maintenance is done
* via Trusted Foundations firmware. This is a no-op on Tegra114+.
*/
if (trusted_foundations_registered())
outer_disable();
call_firmware_op(prepare_idle, TF_PM_MODE_LP1);
setup_mm_for_reboot();
tegra_sleep_core_finish(v2p);
......@@ -342,6 +384,14 @@ static int tegra_suspend_enter(suspend_state_t state)
cpu_suspend(PHYS_OFFSET - PAGE_OFFSET, tegra_sleep_func);
/*
* Resume L2 cache if it wasn't re-enabled early during resume,
* which is the case for Tegra30 that has to re-enable the cache
* via firmware call. In other cases cache is already enabled and
* hence re-enabling is a no-op.
*/
outer_resume();
switch (mode) {
case TEGRA_SUSPEND_LP1:
tegra_suspend_exit_lp1();
......
......@@ -20,6 +20,7 @@
#include <soc/tegra/flowctrl.h>
#include <soc/tegra/fuse.h>
#include <asm/assembler.h>
#include <asm/asm-offsets.h>
#include <asm/cache.h>
......@@ -29,8 +30,6 @@
#define PMC_SCRATCH41 0x140
#define RESET_DATA(x) ((TEGRA_RESET_##x)*4)
#ifdef CONFIG_PM_SLEEP
/*
* tegra_resume
......@@ -78,6 +77,7 @@ ENTRY(tegra_resume)
orr r1, r1, #1
str r1, [r0]
#endif
bl tegra_resume_trusted_foundations
#ifdef CONFIG_CACHE_L2X0
/* L2 cache resume & re-enable */
......@@ -90,6 +90,30 @@ end_ca9_scu_l2_resume:
b cpu_resume
ENDPROC(tegra_resume)
/*
* tegra_resume_trusted_foundations
*
* Trusted Foundations firmware initialization.
*
* Doesn't return if firmware presents.
* Corrupted registers: r1, r2
*/
ENTRY(tegra_resume_trusted_foundations)
/* Check whether Trusted Foundations firmware presents. */
mov32 r2, TEGRA_IRAM_BASE + TEGRA_IRAM_RESET_HANDLER_OFFSET
ldr r1, =__tegra_cpu_reset_handler_data_offset + \
RESET_DATA(TF_PRESENT)
ldr r1, [r2, r1]
cmp r1, #0
reteq lr
.arch_extension sec
/* First call after suspend wakes firmware. No arguments required. */
smc #0
b cpu_resume
ENDPROC(tegra_resume_trusted_foundations)
#endif
.align L1_CACHE_SHIFT
......@@ -115,12 +139,19 @@ ENTRY(__tegra_cpu_reset_handler_start)
* must be position-independent.
*/
.arm
.align L1_CACHE_SHIFT
ENTRY(__tegra_cpu_reset_handler)
cpsid aif, 0x13 @ SVC mode, interrupts disabled
tegra_get_soc_id TEGRA_APB_MISC_BASE, r6
adr r12, __tegra_cpu_reset_handler_data
ldr r5, [r12, #RESET_DATA(TF_PRESENT)]
cmp r5, #0
bne after_errata
#ifdef CONFIG_ARCH_TEGRA_2x_SOC
t20_check:
cmp r6, #TEGRA20
......@@ -155,7 +186,6 @@ after_errata:
and r10, r10, #0x3 @ R10 = CPU number
mov r11, #1
mov r11, r11, lsl r10 @ R11 = CPU mask
adr r12, __tegra_cpu_reset_handler_data
#ifdef CONFIG_SMP
/* Does the OS know about this CPU? */
......@@ -169,10 +199,9 @@ after_errata:
cmp r6, #TEGRA20
bne 1f
/* If not CPU0, don't let CPU0 reset CPU1 now that CPU1 is coming up. */
mov32 r5, TEGRA_IRAM_BASE + TEGRA_IRAM_RESET_HANDLER_OFFSET
mov r0, #CPU_NOT_RESETTABLE
cmp r10, #0
strbne r0, [r5, #__tegra20_cpu1_resettable_status_offset]
strbne r0, [r12, #RESET_DATA(RESETTABLE_STATUS)]
1:
#endif
......@@ -277,14 +306,13 @@ ENDPROC(__tegra_cpu_reset_handler)
.align L1_CACHE_SHIFT
.type __tegra_cpu_reset_handler_data, %object
.globl __tegra_cpu_reset_handler_data
.globl __tegra_cpu_reset_handler_data_offset
.equ __tegra_cpu_reset_handler_data_offset, \
. - __tegra_cpu_reset_handler_start
__tegra_cpu_reset_handler_data:
.rept TEGRA_RESET_DATA_SIZE
.long 0
.endr
.globl __tegra20_cpu1_resettable_status_offset
.equ __tegra20_cpu1_resettable_status_offset, \
. - __tegra_cpu_reset_handler_start
.byte 0
.align L1_CACHE_SHIFT
ENTRY(__tegra_cpu_reset_handler_end)
......@@ -19,6 +19,8 @@
#include <linux/init.h>
#include <linux/io.h>
#include <linux/firmware/trusted_foundations.h>
#include <soc/tegra/fuse.h>
#include <asm/cacheflush.h>
......@@ -89,6 +91,8 @@ static void __init tegra_cpu_reset_handler_enable(void)
void __init tegra_cpu_reset_handler_init(void)
{
__tegra_cpu_reset_handler_data[TEGRA_RESET_TF_PRESENT] =
trusted_foundations_registered();
#ifdef CONFIG_SMP
__tegra_cpu_reset_handler_data[TEGRA_RESET_MASK_PRESENT] =
......
......@@ -25,7 +25,11 @@
#define TEGRA_RESET_STARTUP_SECONDARY 3
#define TEGRA_RESET_STARTUP_LP2 4
#define TEGRA_RESET_STARTUP_LP1 5
#define TEGRA_RESET_DATA_SIZE 6
#define TEGRA_RESET_RESETTABLE_STATUS 6
#define TEGRA_RESET_TF_PRESENT 7
#define TEGRA_RESET_DATA_SIZE 8
#define RESET_DATA(x) ((TEGRA_RESET_##x)*4)
#ifndef __ASSEMBLY__
......@@ -49,7 +53,8 @@ void __tegra_cpu_reset_handler_end(void);
(u32)__tegra_cpu_reset_handler_start)))
#define tegra20_cpu1_resettable_status \
(IO_ADDRESS(TEGRA_IRAM_BASE + TEGRA_IRAM_RESET_HANDLER_OFFSET + \
(u32)__tegra20_cpu1_resettable_status_offset))
((u32)&__tegra_cpu_reset_handler_data[TEGRA_RESET_RESETTABLE_STATUS] - \
(u32)__tegra_cpu_reset_handler_start)))
#endif
#define tegra_cpu_reset_handler_offset \
......
......@@ -28,6 +28,7 @@
#include <asm/cache.h>
#include "irammap.h"
#include "reset.h"
#include "sleep.h"
#define EMC_CFG 0xc
......@@ -53,6 +54,9 @@
#define APB_MISC_XM2CFGCPADCTRL2 0x8e4
#define APB_MISC_XM2CFGDPADCTRL2 0x8e8
#define __tegra20_cpu1_resettable_status_offset \
(__tegra_cpu_reset_handler_data_offset + RESET_DATA(RESETTABLE_STATUS))
.macro pll_enable, rd, r_car_base, pll_base
ldr \rd, [\r_car_base, #\pll_base]
tst \rd, #(1 << 30)
......
......@@ -49,8 +49,9 @@ ENTRY(tegra_disable_clean_inv_dcache)
/* Disable the D-cache */
mrc p15, 0, r2, c1, c0, 0
tst r2, #CR_C @ see tegra_sleep_cpu()
bic r2, r2, #CR_C
mcr p15, 0, r2, c1, c0, 0
mcrne p15, 0, r2, c1, c0, 0
isb
/* Flush the D-cache */
......@@ -132,10 +133,13 @@ ENTRY(tegra_shut_off_mmu)
#ifdef CONFIG_CACHE_L2X0
/* Disable L2 cache */
check_cpu_part_num 0xc09, r9, r10
movweq r2, #:lower16:(TEGRA_ARM_PERIF_BASE + 0x3000)
movteq r2, #:upper16:(TEGRA_ARM_PERIF_BASE + 0x3000)
moveq r3, #0
streq r3, [r2, #L2X0_CTRL]
retne r0
mov32 r2, TEGRA_ARM_PERIF_BASE + 0x3000
ldr r3, [r2, #L2X0_CTRL]
tst r3, #L2X0_CTRL_EN @ see tegra_sleep_cpu()
mov r3, #0
strne r3, [r2, #L2X0_CTRL]
#endif
ret r0
ENDPROC(tegra_shut_off_mmu)
......
......@@ -35,15 +35,17 @@
#include <linux/sys_soc.h>
#include <linux/usb/tegra_usb_phy.h>
#include <linux/firmware/trusted_foundations.h>
#include <soc/tegra/fuse.h>
#include <soc/tegra/pmc.h>
#include <asm/firmware.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/mach/arch.h>
#include <asm/mach/time.h>
#include <asm/mach-types.h>
#include <asm/setup.h>
#include <asm/trusted_foundations.h>
#include "board.h"
#include "common.h"
......@@ -74,6 +76,7 @@ static void __init tegra_init_early(void)
{
of_register_trusted_foundations();
tegra_cpu_reset_handler_init();
call_firmware_op(l2x0_init);
}
static void __init tegra_dt_init_irq(void)
......
......@@ -267,6 +267,22 @@ config TI_SCI_PROTOCOL
This protocol library is used by client drivers to use the features
provided by the system controller.
config TRUSTED_FOUNDATIONS
bool "Trusted Foundations secure monitor support"
depends on ARM
help
Some devices (including most early Tegra-based consumer devices on
the market) are booted with the Trusted Foundations secure monitor
active, requiring some core operations to be performed by the secure
monitor instead of the kernel.
This option allows the kernel to invoke the secure monitor whenever
required on devices using Trusted Foundations. See the functions and
comments in linux/firmware/trusted_foundations.h or the device tree
bindings for "tlm,trusted-foundations" for details on how to use it.
Choose N if you don't know what this is about.
config HAVE_ARM_SMCCC
bool
......
......@@ -23,6 +23,7 @@ obj-$(CONFIG_QCOM_SCM_64) += qcom_scm-64.o
obj-$(CONFIG_QCOM_SCM_32) += qcom_scm-32.o
CFLAGS_qcom_scm-32.o :=$(call as-instr,.arch armv7-a\n.arch_extension sec,-DREQUIRES_SEC=1) -march=armv7-a
obj-$(CONFIG_TI_SCI_PROTOCOL) += ti_sci.o
obj-$(CONFIG_TRUSTED_FOUNDATIONS) += trusted_foundations.o
obj-$(CONFIG_ARM_SCMI_PROTOCOL) += arm_scmi/
obj-y += broadcom/
......
......@@ -17,8 +17,17 @@
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/of.h>
#include <linux/firmware/trusted_foundations.h>
#include <asm/firmware.h>
#include <asm/trusted_foundations.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/outercache.h>
#define TF_CACHE_MAINT 0xfffff100
#define TF_CACHE_ENABLE 1
#define TF_CACHE_DISABLE 2
#define TF_SET_CPU_BOOT_ADDR_SMC 0xfffff200
......@@ -60,16 +69,75 @@ static int tf_set_cpu_boot_addr(int cpu, unsigned long boot_addr)
return 0;
}
static int tf_prepare_idle(void)
static int tf_prepare_idle(unsigned long mode)
{
tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S1_NOFLUSH_L2, cpu_boot_addr);
switch (mode) {
case TF_PM_MODE_LP0:
tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S3, cpu_boot_addr);
break;
case TF_PM_MODE_LP1:
tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S2, cpu_boot_addr);
break;
case TF_PM_MODE_LP1_NO_MC_CLK:
tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S2_NO_MC_CLK,
cpu_boot_addr);
break;
case TF_PM_MODE_LP2:
tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S1, cpu_boot_addr);
break;
case TF_PM_MODE_LP2_NOFLUSH_L2:
tf_generic_smc(TF_CPU_PM, TF_CPU_PM_S1_NOFLUSH_L2,
cpu_boot_addr);
break;
default:
return -EINVAL;
}
return 0;
}
#ifdef CONFIG_CACHE_L2X0
static void tf_cache_write_sec(unsigned long val, unsigned int reg)
{
u32 l2x0_way_mask = 0xff;
switch (reg) {
case L2X0_CTRL:
if (l2x0_saved_regs.aux_ctrl & L310_AUX_CTRL_ASSOCIATIVITY_16)
l2x0_way_mask = 0xffff;
if (val == L2X0_CTRL_EN)
tf_generic_smc(TF_CACHE_MAINT, TF_CACHE_ENABLE,
l2x0_saved_regs.aux_ctrl);
else
tf_generic_smc(TF_CACHE_MAINT, TF_CACHE_DISABLE,
l2x0_way_mask);
break;
default:
break;
}
}
static int tf_init_cache(void)
{
outer_cache.write_sec = tf_cache_write_sec;
return 0;
}
#endif /* CONFIG_CACHE_L2X0 */
static const struct firmware_ops trusted_foundations_ops = {
.set_cpu_boot_addr = tf_set_cpu_boot_addr,
.prepare_idle = tf_prepare_idle,
#ifdef CONFIG_CACHE_L2X0
.l2x0_init = tf_init_cache,
#endif
};
void register_trusted_foundations(struct trusted_foundations_platform_data *pd)
......@@ -101,3 +169,8 @@ void of_register_trusted_foundations(void)
panic("Trusted Foundation: missing version-minor property\n");
register_trusted_foundations(&pdata);
}
bool trusted_foundations_registered(void)
{
return firmware_ops == &trusted_foundations_ops;
}
......@@ -23,14 +23,24 @@
* PSCI standard.
*/
#ifndef __ASM_ARM_TRUSTED_FOUNDATIONS_H
#define __ASM_ARM_TRUSTED_FOUNDATIONS_H
#ifndef __FIRMWARE_TRUSTED_FOUNDATIONS_H
#define __FIRMWARE_TRUSTED_FOUNDATIONS_H
#include <linux/printk.h>
#include <linux/bug.h>
#include <linux/of.h>
#include <linux/cpu.h>
#include <linux/smp.h>
#include <linux/types.h>
#include <asm/hardware/cache-l2x0.h>
#include <asm/outercache.h>
#define TF_PM_MODE_LP0 0
#define TF_PM_MODE_LP1 1
#define TF_PM_MODE_LP1_NO_MC_CLK 2
#define TF_PM_MODE_LP2 3
#define TF_PM_MODE_LP2_NOFLUSH_L2 4
struct trusted_foundations_platform_data {
unsigned int version_major;
......@@ -41,8 +51,12 @@ struct trusted_foundations_platform_data {
void register_trusted_foundations(struct trusted_foundations_platform_data *pd);
void of_register_trusted_foundations(void);
bool trusted_foundations_registered(void);
#else /* CONFIG_TRUSTED_FOUNDATIONS */
static inline void tf_dummy_write_sec(unsigned long val, unsigned int reg)
{
}
static inline void register_trusted_foundations(
struct trusted_foundations_platform_data *pd)
......@@ -53,6 +67,10 @@ static inline void register_trusted_foundations(
*/
pr_err("No support for Trusted Foundations, continuing in degraded mode.\n");
pr_err("Secondary processors as well as CPU PM will be disabled.\n");
#if IS_ENABLED(CONFIG_CACHE_L2X0)
pr_err("L2X0 cache will be kept disabled.\n");
outer_cache.write_sec = tf_dummy_write_sec;
#endif
#if IS_ENABLED(CONFIG_SMP)
setup_max_cpus = 0;
#endif
......@@ -68,6 +86,11 @@ static inline void of_register_trusted_foundations(void)
if (of_find_compatible_node(NULL, NULL, "tlm,trusted-foundations"))
register_trusted_foundations(NULL);
}
static inline bool trusted_foundations_registered(void)
{
return false;
}
#endif /* CONFIG_TRUSTED_FOUNDATIONS */
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment