Tegra210: power off all DMA masters before System Suspend entry

This patch puts all the DMA masters in reset before starting the System
Suspend sequence. This helps us make sure that there are no rogue agents
in the system trying to over-write the SC7 Entry Firmware with their own.

Change-Id: I7eb39999d229951e612fbfeb9f86c4efb8f98b5a
Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
This commit is contained in:
Varun Wadekar 2018-03-05 10:19:37 -08:00
parent 278d599c11
commit 2d5560f928
3 changed files with 135 additions and 11 deletions

View File

@ -41,6 +41,7 @@
* iRAM memory constants
******************************************************************************/
#define TEGRA_IRAM_BASE U(0x40000000)
#define TEGRA_IRAM_A_SIZE U(0x10000) /* 64KB */
#define TEGRA_IRAM_SIZE U(40000) /* 256KB */
/*******************************************************************************
@ -95,23 +96,55 @@
* Tegra Clock and Reset Controller constants
******************************************************************************/
#define TEGRA_CAR_RESET_BASE U(0x60006000)
#define TEGRA_BOND_OUT_H U(0x74)
#define APB_DMA_LOCK_BIT (U(1) << 2)
#define AHB_DMA_LOCK_BIT (U(1) << 1)
#define TEGRA_BOND_OUT_U U(0x78)
#define IRAM_D_LOCK_BIT (U(1) << 23)
#define IRAM_C_LOCK_BIT (U(1) << 22)
#define IRAM_B_LOCK_BIT (U(1) << 21)
#define TEGRA_GPU_RESET_REG_OFFSET U(0x28C)
#define TEGRA_GPU_RESET_GPU_SET_OFFSET U(0x290)
#define GPU_RESET_BIT (U(1) << 24)
#define GPU_SET_BIT (U(1) << 24)
#define TEGRA_RST_DEV_SET_Y U(0x2a8)
#define NVENC_RESET_BIT (U(1) << 27)
#define TSECB_RESET_BIT (U(1) << 14)
#define APE_RESET_BIT (U(1) << 6)
#define NVJPG_RESET_BIT (U(1) << 3)
#define NVDEC_RESET_BIT (U(1) << 2)
#define TEGRA_RST_DEV_SET_L U(0x300)
#define HOST1X_RESET_BIT (U(1) << 28)
#define ISP_RESET_BIT (U(1) << 23)
#define USBD_RESET_BIT (U(1) << 22)
#define VI_RESET_BIT (U(1) << 20)
#define SDMMC4_RESET_BIT (U(1) << 15)
#define SDMMC1_RESET_BIT (U(1) << 14)
#define SDMMC2_RESET_BIT (U(1) << 9)
#define TEGRA_RST_DEV_SET_H U(0x308)
#define USB2_RESET_BIT (U(1) << 26)
#define APBDMA_RESET_BIT (U(1) << 2)
#define AHBDMA_RESET_BIT (U(1) << 1)
#define TEGRA_RST_DEV_SET_U U(0x310)
#define XUSB_DEV_RESET_BIT (U(1) << 31)
#define XUSB_HOST_RESET_BIT (U(1) << 25)
#define TSEC_RESET_BIT (U(1) << 19)
#define PCIE_RESET_BIT (U(1) << 6)
#define SDMMC3_RESET_BIT (U(1) << 5)
#define TEGRA_RST_DEVICES_V U(0x358)
#define TEGRA_RST_DEVICES_W U(0x35C)
#define ENTROPY_CLK_ENB_BIT (U(1) << 21)
#define TEGRA_CLK_OUT_ENB_V U(0x360)
#define SE_CLK_ENB_BIT (U(1) << 31)
#define TEGRA_CLK_OUT_ENB_W U(0x364)
#define ENTROPY_RESET_BIT (U(1) << 21)
#define TEGRA_RST_DEV_SET_V U(0x430)
#define SE_RESET_BIT (U(1) << 31)
#define HDA_RESET_BIT (U(1) << 29)
#define SATA_RESET_BIT (U(1) << 28)
#define TEGRA_RST_DEV_CLR_V U(0x434)
#define TEGRA_CLK_ENB_V U(0x440)
/* SE Clock Offsets */
#define TEGRA_RST_DEVICES_V 0x358UL
#define SE_RESET_BIT (0x1UL << 31)
#define TEGRA_RST_DEVICES_W 0x35CUL
#define ENTROPY_CLK_ENB_BIT (0x1UL << 21)
#define TEGRA_CLK_OUT_ENB_V 0x360UL
#define SE_CLK_ENB_BIT (0x1UL << 31)
#define TEGRA_CLK_OUT_ENB_W 0x364UL
#define ENTROPY_RESET_BIT (0x1UL << 21)
/*******************************************************************************
* Tegra Flow Controller constants
******************************************************************************/

View File

@ -21,6 +21,7 @@
#include <tegra_def.h>
#include <tegra_private.h>
#include <tegra_platform.h>
#include <utils.h>
/*
* Register used to clear CPU reset signals. Each CPU has two reset
@ -255,6 +256,74 @@ int tegra_soc_pwr_domain_suspend(const psci_power_state_t *target_state)
return ret;
}
static void tegra_reset_all_dma_masters(void)
{
uint32_t val, mask;
/*
* Reset all possible DMA masters in the system.
*/
val = GPU_RESET_BIT;
mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_GPU_RESET_REG_OFFSET, val);
val = NVENC_RESET_BIT | TSECB_RESET_BIT | APE_RESET_BIT |
NVJPG_RESET_BIT | NVDEC_RESET_BIT;
mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_Y, val);
val = HOST1X_RESET_BIT | ISP_RESET_BIT | USBD_RESET_BIT |
VI_RESET_BIT | SDMMC4_RESET_BIT | SDMMC1_RESET_BIT |
SDMMC2_RESET_BIT;
mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_L, val);
val = USB2_RESET_BIT | APBDMA_RESET_BIT | AHBDMA_RESET_BIT;
mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_H, val);
val = XUSB_DEV_RESET_BIT | XUSB_HOST_RESET_BIT | TSEC_RESET_BIT |
PCIE_RESET_BIT | SDMMC3_RESET_BIT;
mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_U, val);
val = SE_RESET_BIT | HDA_RESET_BIT | SATA_RESET_BIT;
mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_V, val);
/*
* If any of the DMA masters are still alive, assume
* that the system has been compromised and reboot.
*/
val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_GPU_RESET_REG_OFFSET);
mask = GPU_RESET_BIT;
if ((val & mask) != mask)
tegra_pmc_system_reset();
mask = NVENC_RESET_BIT | TSECB_RESET_BIT | APE_RESET_BIT |
NVJPG_RESET_BIT | NVDEC_RESET_BIT;
val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_Y);
if ((val & mask) != mask)
tegra_pmc_system_reset();
mask = HOST1X_RESET_BIT | ISP_RESET_BIT | USBD_RESET_BIT |
VI_RESET_BIT | SDMMC4_RESET_BIT | SDMMC1_RESET_BIT |
SDMMC2_RESET_BIT;
val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_L);
if ((val & mask) != mask)
tegra_pmc_system_reset();
mask = USB2_RESET_BIT | APBDMA_RESET_BIT | AHBDMA_RESET_BIT;
val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_H);
if ((val & mask) != mask)
tegra_pmc_system_reset();
mask = XUSB_DEV_RESET_BIT | XUSB_HOST_RESET_BIT | TSEC_RESET_BIT |
PCIE_RESET_BIT | SDMMC3_RESET_BIT;
val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_U);
if ((val & mask) != mask)
tegra_pmc_system_reset();
val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_SET_V);
mask = SE_RESET_BIT | HDA_RESET_BIT | SATA_RESET_BIT;
if ((val & mask) != mask)
tegra_pmc_system_reset();
}
int tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state)
{
u_register_t mpidr = read_mpidr();
@ -287,6 +356,28 @@ int tegra_soc_pwr_domain_power_down_wfi(const psci_power_state_t *target_state)
/* Power off BPMP before we proceed */
tegra_fc_bpmp_off();
/* bond out IRAM banks B, C and D */
mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_BOND_OUT_U,
IRAM_B_LOCK_BIT | IRAM_C_LOCK_BIT |
IRAM_D_LOCK_BIT);
/* bond out APB/AHB DMAs */
mmio_write_32(TEGRA_CAR_RESET_BASE + TEGRA_BOND_OUT_H,
APB_DMA_LOCK_BIT | AHB_DMA_LOCK_BIT);
/* Power off BPMP before we proceed */
tegra_fc_bpmp_off();
/*
* Reset all the hardware blocks that can act as DMA
* masters on the bus.
*/
tegra_reset_all_dma_masters();
/* clean up IRAM of any cruft */
zeromem((void *)(uintptr_t)TEGRA_IRAM_BASE,
TEGRA_IRAM_A_SIZE);
/* Copy the firmware to BPMP's internal RAM */
(void)memcpy((void *)(uintptr_t)TEGRA_IRAM_BASE,
(const void *)plat_params->sc7entry_fw_base,

View File

@ -160,7 +160,7 @@ void plat_late_platform_setup(void)
/* memmap TZDRAM area containing the SC7 Entry Firmware */
if (plat_params->sc7entry_fw_base && plat_params->sc7entry_fw_size) {
assert(plat_params->sc7entry_fw_size <= TEGRA_IRAM_SIZE);
assert(plat_params->sc7entry_fw_size <= TEGRA_IRAM_A_SIZE);
/*
* Verify that the SC7 entry firmware resides inside the TZDRAM