diff --git a/plat/nvidia/tegra/include/t210/tegra_def.h b/plat/nvidia/tegra/include/t210/tegra_def.h index 02c5f13..eed443d 100644 --- a/plat/nvidia/tegra/include/t210/tegra_def.h +++ b/plat/nvidia/tegra/include/t210/tegra_def.h @@ -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 ******************************************************************************/ diff --git a/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c b/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c index 4c49386..4e9206f 100644 --- a/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c +++ b/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c @@ -21,6 +21,7 @@ #include #include #include +#include /* * Register used to clear CPU reset signals. Each CPU has two reset @@ -255,6 +256,74 @@ 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 @@ /* 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, diff --git a/plat/nvidia/tegra/soc/t210/plat_setup.c b/plat/nvidia/tegra/soc/t210/plat_setup.c index 4fdd5a8..0aeb9ff 100644 --- a/plat/nvidia/tegra/soc/t210/plat_setup.c +++ b/plat/nvidia/tegra/soc/t210/plat_setup.c @@ -160,7 +160,7 @@ /* 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