Commit 50402b17 authored by Varun Wadekar's avatar Varun Wadekar
Browse files

Tegra186: implement support for System Suspend



This patch adds the chip level support for System Suspend entry
and exit. As part of the entry sequence we first query the MCE
firmware to check if it is safe to enter system suspend. Once
we get a green light, we save hardware block settings and enter
the power state. As expected, all the hardware settings are
restored once we exit the power state.

Change-Id: I6d192d7568d6a555eb10efdfd45f6d79c20f74ea
Signed-off-by: default avatarVarun Wadekar <vwadekar@nvidia.com>
parent ea96ac17
...@@ -81,6 +81,7 @@ ...@@ -81,6 +81,7 @@
#define HARDWARE_MINOR_REVISION_MASK 0xf0000 #define HARDWARE_MINOR_REVISION_MASK 0xf0000
#define HARDWARE_MINOR_REVISION_SHIFT 0x10 #define HARDWARE_MINOR_REVISION_SHIFT 0x10
#define HARDWARE_REVISION_A01 1 #define HARDWARE_REVISION_A01 1
#define MISCREG_PFCFG 0x200C
/******************************************************************************* /*******************************************************************************
* Tegra Memory Controller constants * Tegra Memory Controller constants
...@@ -105,6 +106,16 @@ ...@@ -105,6 +106,16 @@
#define TEGRA_GICD_BASE 0x03881000 #define TEGRA_GICD_BASE 0x03881000
#define TEGRA_GICC_BASE 0x03882000 #define TEGRA_GICC_BASE 0x03882000
/*******************************************************************************
* Security Engine related constants
******************************************************************************/
#define TEGRA_SE0_BASE 0x03AC0000
#define SE_MUTEX_WATCHDOG_NS_LIMIT 0x6C
#define TEGRA_PKA1_BASE 0x03AD0000
#define PKA_MUTEX_WATCHDOG_NS_LIMIT 0x8144
#define TEGRA_RNG1_BASE 0x03AE0000
#define RNG_MUTEX_WATCHDOG_NS_LIMIT 0xFE0
/******************************************************************************* /*******************************************************************************
* Tegra Clock and Reset Controller constants * Tegra Clock and Reset Controller constants
******************************************************************************/ ******************************************************************************/
...@@ -124,6 +135,9 @@ ...@@ -124,6 +135,9 @@
* Tegra scratch registers constants * Tegra scratch registers constants
******************************************************************************/ ******************************************************************************/
#define TEGRA_SCRATCH_BASE 0x0C390000 #define TEGRA_SCRATCH_BASE 0x0C390000
#define SECURE_SCRATCH_RSV6 0x680
#define SECURE_SCRATCH_RSV11_LO 0x6A8
#define SECURE_SCRATCH_RSV11_HI 0x6AC
/******************************************************************************* /*******************************************************************************
* Tegra Memory Mapped Control Register Access Bus constants * Tegra Memory Mapped Control Register Access Bus constants
......
...@@ -262,7 +262,6 @@ int mce_command_handler(mce_cmd_t cmd, uint64_t arg0, uint64_t arg1, ...@@ -262,7 +262,6 @@ int mce_command_handler(mce_cmd_t cmd, uint64_t arg0, uint64_t arg1,
/* update context to return SC7 status value */ /* update context to return SC7 status value */
write_ctx_reg(gp_regs, CTX_GPREG_X1, ret); write_ctx_reg(gp_regs, CTX_GPREG_X1, ret);
write_ctx_reg(gp_regs, CTX_GPREG_X3, ret); write_ctx_reg(gp_regs, CTX_GPREG_X3, ret);
ret = 0;
break; break;
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include <denver.h> #include <denver.h>
#include <mce.h> #include <mce.h>
#include <psci.h> #include <psci.h>
#include <smmu.h>
#include <t18x_ari.h> #include <t18x_ari.h>
#include <tegra_private.h> #include <tegra_private.h>
...@@ -48,7 +49,10 @@ extern void prepare_cpu_pwr_dwn(void); ...@@ -48,7 +49,10 @@ extern void prepare_cpu_pwr_dwn(void);
/* constants to get power state's wake time */ /* constants to get power state's wake time */
#define TEGRA186_WAKE_TIME_MASK 0xFFFFFF #define TEGRA186_WAKE_TIME_MASK 0xFFFFFF
#define TEGRA186_WAKE_TIME_SHIFT 4 #define TEGRA186_WAKE_TIME_SHIFT 4
/* context size to save during system suspend */
#define TEGRA186_SE_CONTEXT_SIZE 3
static uint32_t se_regs[TEGRA186_SE_CONTEXT_SIZE];
static unsigned int wake_time[PLATFORM_CORE_COUNT]; static unsigned int wake_time[PLATFORM_CORE_COUNT];
/* System power down state */ /* System power down state */
...@@ -89,9 +93,15 @@ int32_t tegra_soc_validate_power_state(unsigned int power_state, ...@@ -89,9 +93,15 @@ int32_t tegra_soc_validate_power_state(unsigned int power_state,
int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state) int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
{ {
const plat_local_state_t *pwr_domain_state; const plat_local_state_t *pwr_domain_state;
unsigned int stateid_afflvl0; unsigned int stateid_afflvl0, stateid_afflvl2;
int cpu = read_mpidr() & MPIDR_CPU_MASK; int cpu = read_mpidr() & MPIDR_CPU_MASK;
int impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK; int impl = (read_midr() >> MIDR_IMPL_SHIFT) & MIDR_IMPL_MASK;
cpu_context_t *ctx = cm_get_context(NON_SECURE);
gp_regs_t *gp_regs = get_gpregs_ctx(ctx);
uint32_t val;
assert(ctx);
assert(gp_regs);
if (impl == DENVER_IMPL) if (impl == DENVER_IMPL)
cpu |= 0x4; cpu |= 0x4;
...@@ -100,6 +110,8 @@ int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state) ...@@ -100,6 +110,8 @@ int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
pwr_domain_state = target_state->pwr_domain_state; pwr_domain_state = target_state->pwr_domain_state;
stateid_afflvl0 = pwr_domain_state[MPIDR_AFFLVL0] & stateid_afflvl0 = pwr_domain_state[MPIDR_AFFLVL0] &
TEGRA186_STATE_ID_MASK; TEGRA186_STATE_ID_MASK;
stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL] &
TEGRA186_STATE_ID_MASK;
if (stateid_afflvl0 == PSTATE_ID_CORE_IDLE) { if (stateid_afflvl0 == PSTATE_ID_CORE_IDLE) {
...@@ -113,6 +125,42 @@ int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state) ...@@ -113,6 +125,42 @@ int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
(void)mce_command_handler(MCE_CMD_ENTER_CSTATE, (void)mce_command_handler(MCE_CMD_ENTER_CSTATE,
TEGRA_ARI_CORE_C7, wake_time[cpu], 0); TEGRA_ARI_CORE_C7, wake_time[cpu], 0);
} else if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) {
/* loop until SC7 is allowed */
do {
val = mce_command_handler(MCE_CMD_IS_SC7_ALLOWED,
TEGRA_ARI_CORE_C7,
MCE_CORE_SLEEP_TIME_INFINITE,
0);
} while (val == 0);
/* save SE registers */
se_regs[0] = mmio_read_32(TEGRA_SE0_BASE +
SE_MUTEX_WATCHDOG_NS_LIMIT);
se_regs[1] = mmio_read_32(TEGRA_RNG1_BASE +
RNG_MUTEX_WATCHDOG_NS_LIMIT);
se_regs[2] = mmio_read_32(TEGRA_PKA1_BASE +
PKA_MUTEX_WATCHDOG_NS_LIMIT);
/* save 'Secure Boot' Processor Feature Config Register */
val = mmio_read_32(TEGRA_MISC_BASE + MISCREG_PFCFG);
mmio_write_32(TEGRA_SCRATCH_BASE + SECURE_SCRATCH_RSV6, val);
/* save SMMU context */
tegra_smmu_save_context();
/* Prepare for system suspend */
write_ctx_reg(gp_regs, CTX_GPREG_X4, 1);
write_ctx_reg(gp_regs, CTX_GPREG_X5, 0);
write_ctx_reg(gp_regs, CTX_GPREG_X6, 1);
(void)mce_command_handler(MCE_CMD_UPDATE_CSTATE_INFO,
TEGRA_ARI_CLUSTER_CC7, 0, TEGRA_ARI_SYSTEM_SC7);
/* Enter system suspend state */
(void)mce_command_handler(MCE_CMD_ENTER_CSTATE,
TEGRA_ARI_CORE_C7, MCE_CORE_SLEEP_TIME_INFINITE, 0);
} else { } else {
ERROR("%s: Unknown state id\n", __func__); ERROR("%s: Unknown state id\n", __func__);
return PSCI_E_NOT_SUPPORTED; return PSCI_E_NOT_SUPPORTED;
...@@ -140,6 +188,29 @@ int tegra_soc_pwr_domain_on(u_register_t mpidr) ...@@ -140,6 +188,29 @@ int tegra_soc_pwr_domain_on(u_register_t mpidr)
return PSCI_E_SUCCESS; return PSCI_E_SUCCESS;
} }
int tegra_soc_pwr_domain_on_finish(const psci_power_state_t *target_state)
{
int state_id = target_state->pwr_domain_state[PLAT_MAX_PWR_LVL];
/*
* Check if we are exiting from deep sleep and restore SE
* context if we are.
*/
if (state_id == PSTATE_ID_SOC_POWERDN) {
mmio_write_32(TEGRA_SE0_BASE + SE_MUTEX_WATCHDOG_NS_LIMIT,
se_regs[0]);
mmio_write_32(TEGRA_RNG1_BASE + RNG_MUTEX_WATCHDOG_NS_LIMIT,
se_regs[1]);
mmio_write_32(TEGRA_PKA1_BASE + PKA_MUTEX_WATCHDOG_NS_LIMIT,
se_regs[2]);
/* Init SMMU */
tegra_smmu_init();
}
return PSCI_E_SUCCESS;
}
int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state) int tegra_soc_pwr_domain_off(const psci_power_state_t *target_state)
{ {
cpu_context_t *ctx = cm_get_context(NON_SECURE); cpu_context_t *ctx = cm_get_context(NON_SECURE);
......
/* /*
* 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 * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
...@@ -73,13 +73,21 @@ static const mmap_region_t tegra_mmap[] = { ...@@ -73,13 +73,21 @@ static const mmap_region_t tegra_mmap[] = {
MT_DEVICE | MT_RW | MT_SECURE), MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(TEGRA_GICD_BASE, 0x20000, /* 128KB */ MAP_REGION_FLAT(TEGRA_GICD_BASE, 0x20000, /* 128KB */
MT_DEVICE | MT_RW | MT_SECURE), MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(TEGRA_SE0_BASE, 0x10000, /* 64KB */
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(TEGRA_PKA1_BASE, 0x10000, /* 64KB */
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(TEGRA_RNG1_BASE, 0x10000, /* 64KB */
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(TEGRA_CAR_RESET_BASE, 0x10000, /* 64KB */ MAP_REGION_FLAT(TEGRA_CAR_RESET_BASE, 0x10000, /* 64KB */
MT_DEVICE | MT_RW | MT_SECURE), MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(TEGRA_PMC_BASE, 0x40000, /* 256KB */ MAP_REGION_FLAT(TEGRA_PMC_BASE, 0x40000, /* 256KB */
MT_DEVICE | MT_RW | MT_SECURE), MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(TEGRA_SCRATCH_BASE, 0x10000, /* 64KB */
MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(TEGRA_MMCRAB_BASE, 0x60000, /* 384KB */ MAP_REGION_FLAT(TEGRA_MMCRAB_BASE, 0x60000, /* 384KB */
MT_DEVICE | MT_RW | MT_SECURE), MT_DEVICE | MT_RW | MT_SECURE),
MAP_REGION_FLAT(TEGRA_SMMU_BASE, 0x10000, /* 64KB */ MAP_REGION_FLAT(TEGRA_SMMU_BASE, 0x1000000, /* 64KB */
MT_DEVICE | MT_RW | MT_SECURE), MT_DEVICE | MT_RW | MT_SECURE),
{0} {0}
}; };
......
...@@ -42,10 +42,10 @@ $(eval $(call add_define,PLATFORM_CLUSTER_COUNT)) ...@@ -42,10 +42,10 @@ $(eval $(call add_define,PLATFORM_CLUSTER_COUNT))
PLATFORM_MAX_CPUS_PER_CLUSTER := 4 PLATFORM_MAX_CPUS_PER_CLUSTER := 4
$(eval $(call add_define,PLATFORM_MAX_CPUS_PER_CLUSTER)) $(eval $(call add_define,PLATFORM_MAX_CPUS_PER_CLUSTER))
MAX_XLAT_TABLES := 12 MAX_XLAT_TABLES := 15
$(eval $(call add_define,MAX_XLAT_TABLES)) $(eval $(call add_define,MAX_XLAT_TABLES))
MAX_MMAP_REGIONS := 12 MAX_MMAP_REGIONS := 15
$(eval $(call add_define,MAX_MMAP_REGIONS)) $(eval $(call add_define,MAX_MMAP_REGIONS))
# platform files # platform files
......
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