diff --git a/plat/nvidia/tegra/common/drivers/flowctrl/flowctrl.c b/plat/nvidia/tegra/common/drivers/flowctrl/flowctrl.c index 4f89cf4..bdd3ee7 100644 --- a/plat/nvidia/tegra/common/drivers/flowctrl/flowctrl.c +++ b/plat/nvidia/tegra/common/drivers/flowctrl/flowctrl.c @@ -257,22 +257,19 @@ } /******************************************************************************* - * Reset BPMP processor + * Power ON BPMP processor ******************************************************************************/ -void tegra_fc_reset_bpmp(void) +void tegra_fc_bpmp_on(uint32_t entrypoint) { - uint32_t val; - /* halt BPMP */ tegra_fc_write_32(FLOWCTRL_HALT_BPMP_EVENTS, FLOWCTRL_WAITEVENT); /* Assert BPMP reset */ mmio_write_32(TEGRA_CAR_RESET_BASE + CLK_RST_DEV_L_SET, CLK_BPMP_RST); - /* Restore reset address (stored in PMC_SCRATCH39) */ - val = tegra_pmc_read_32(PMC_SCRATCH39); - mmio_write_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR, val); - while (val != mmio_read_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR)) + /* Set reset address (stored in PMC_SCRATCH39) */ + mmio_write_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR, entrypoint); + while (entrypoint != mmio_read_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR)) ; /* wait till value reaches EVP_BPMP_RESET_VECTOR */ /* Wait for 2us before de-asserting the reset signal. */ @@ -286,6 +283,23 @@ } /******************************************************************************* + * Power OFF BPMP processor + ******************************************************************************/ +void tegra_fc_bpmp_off(void) +{ + /* halt BPMP */ + tegra_fc_write_32(FLOWCTRL_HALT_BPMP_EVENTS, FLOWCTRL_WAITEVENT); + + /* Assert BPMP reset */ + mmio_write_32(TEGRA_CAR_RESET_BASE + CLK_RST_DEV_L_SET, CLK_BPMP_RST); + + /* Clear reset address */ + mmio_write_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR, 0); + while (0 != mmio_read_32(TEGRA_EVP_BASE + EVP_BPMP_RESET_VECTOR)) + ; /* wait till value reaches EVP_BPMP_RESET_VECTOR */ +} + +/******************************************************************************* * Route legacy FIQ to the GICD ******************************************************************************/ void tegra_fc_enable_fiq_to_ccplex_routing(void) diff --git a/plat/nvidia/tegra/common/tegra_bl31_setup.c b/plat/nvidia/tegra/common/tegra_bl31_setup.c index 0d0bc74..c9beb14 100644 --- a/plat/nvidia/tegra/common/tegra_bl31_setup.c +++ b/plat/nvidia/tegra/common/tegra_bl31_setup.c @@ -162,13 +162,15 @@ } /* - * Parse platform specific parameters - TZDRAM aperture base and size + * Parse platform specific parameters */ assert(plat_params != NULL); plat_bl31_params_from_bl2.tzdram_base = plat_params->tzdram_base; plat_bl31_params_from_bl2.tzdram_size = plat_params->tzdram_size; plat_bl31_params_from_bl2.uart_id = plat_params->uart_id; plat_bl31_params_from_bl2.l2_ecc_parity_prot_dis = plat_params->l2_ecc_parity_prot_dis; + plat_bl31_params_from_bl2.sc7entry_fw_size = plat_params->sc7entry_fw_size; + plat_bl31_params_from_bl2.sc7entry_fw_base = plat_params->sc7entry_fw_base; /* * It is very important that we run either from TZDRAM or TZSRAM base. diff --git a/plat/nvidia/tegra/include/drivers/flowctrl.h b/plat/nvidia/tegra/include/drivers/flowctrl.h index bf7e82f..54336b0 100644 --- a/plat/nvidia/tegra/include/drivers/flowctrl.h +++ b/plat/nvidia/tegra/include/drivers/flowctrl.h @@ -77,6 +77,8 @@ mmio_write_32(TEGRA_FLOWCTRL_BASE + off, val); } +void tegra_fc_bpmp_on(uint32_t entrypoint); +void tegra_fc_bpmp_off(void); void tegra_fc_ccplex_pgexit_lock(void); void tegra_fc_ccplex_pgexit_unlock(void); void tegra_fc_cluster_idle(uint32_t midr); @@ -88,7 +90,6 @@ void tegra_fc_enable_fiq_to_ccplex_routing(void); bool tegra_fc_is_ccx_allowed(void); void tegra_fc_lock_active_cluster(void); -void tegra_fc_reset_bpmp(void); void tegra_fc_soc_powerdn(uint32_t midr); #endif /* FLOWCTRL_H */ diff --git a/plat/nvidia/tegra/include/drivers/pmc.h b/plat/nvidia/tegra/include/drivers/pmc.h index b9090b4..53317de 100644 --- a/plat/nvidia/tegra/include/drivers/pmc.h +++ b/plat/nvidia/tegra/include/drivers/pmc.h @@ -26,6 +26,7 @@ #define PMC_SECURE_DISABLE3_WRITE35_ON (U(1) << 22) #define PMC_SECURE_SCRATCH34 U(0x368) #define PMC_SECURE_SCRATCH35 U(0x36c) +#define PMC_SCRATCH201 U(0x844) static inline uint32_t tegra_pmc_read_32(uint32_t off) { diff --git a/plat/nvidia/tegra/include/t210/tegra_def.h b/plat/nvidia/tegra/include/t210/tegra_def.h index c4ce767..02c5f13 100644 --- a/plat/nvidia/tegra/include/t210/tegra_def.h +++ b/plat/nvidia/tegra/include/t210/tegra_def.h @@ -40,7 +40,8 @@ /******************************************************************************* * iRAM memory constants ******************************************************************************/ -#define TEGRA_IRAM_BASE 0x40000000 +#define TEGRA_IRAM_BASE U(0x40000000) +#define TEGRA_IRAM_SIZE U(40000) /* 256KB */ /******************************************************************************* * GIC memory map diff --git a/plat/nvidia/tegra/include/tegra_private.h b/plat/nvidia/tegra/include/tegra_private.h index 40aeaf8..cdd9e08 100644 --- a/plat/nvidia/tegra/include/tegra_private.h +++ b/plat/nvidia/tegra/include/tegra_private.h @@ -46,6 +46,10 @@ int32_t l2_ecc_parity_prot_dis; /* SHMEM base address for storing the boot logs */ uint64_t boot_profiler_shmem_base; + /* System Suspend Entry Firmware size */ + uint64_t sc7entry_fw_size; + /* System Suspend Entry Firmware base address */ + uint64_t sc7entry_fw_base; } plat_params_from_bl2_t; /******************************************************************************* diff --git a/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c b/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c index bb3b8fe..4c49386 100644 --- a/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c +++ b/plat/nvidia/tegra/soc/t210/plat_psci_handlers.c @@ -41,6 +41,7 @@ psci_power_state_t *req_state) { int state_id = psci_get_pstate_id(power_state); + const plat_params_from_bl2_t *plat_params = bl31_get_plat_params(); /* Sanity check the requested state id */ switch (state_id) { @@ -62,6 +63,15 @@ break; case PSTATE_ID_SOC_POWERDN: + + /* + * sc7entry-fw must be present in the system when the bpmp + * firmware is not present, for a successful System Suspend + * entry. + */ + if (!tegra_bpmp_init() && !plat_params->sc7entry_fw_base) + return PSCI_E_NOT_SUPPORTED; + /* * System powerdown request only for afflvl 2 */ @@ -205,12 +215,26 @@ if (!tegra_bpmp_available) { - /* PWM tristate */ + /* Find if the platform uses OVR2/MAX77621 PMIC */ cfg = mmio_read_32(TEGRA_CL_DVFS_BASE + DVFS_DFLL_OUTPUT_CFG); if (cfg & DFLL_OUTPUT_CFG_CLK_EN_BIT) { + /* OVR2 */ + + /* PWM tristate */ val = mmio_read_32(TEGRA_MISC_BASE + PINMUX_AUX_DVFS_PWM); val |= PINMUX_PWM_TRISTATE; mmio_write_32(TEGRA_MISC_BASE + PINMUX_AUX_DVFS_PWM, val); + + /* + * SCRATCH201[1] is being used to identify CPU + * PMIC in warmboot code. + * 0 : OVR2 + * 1 : MAX77621 + */ + tegra_pmc_write_32(PMC_SCRATCH201, 0x0); + } else { + /* MAX77621 */ + tegra_pmc_write_32(PMC_SCRATCH201, 0x2); } } @@ -237,6 +261,8 @@ const plat_local_state_t *pwr_domain_state = target_state->pwr_domain_state; unsigned int stateid_afflvl2 = pwr_domain_state[PLAT_MAX_PWR_LVL]; + const plat_params_from_bl2_t *plat_params = bl31_get_plat_params(); + uint32_t val; if (stateid_afflvl2 == PSTATE_ID_SOC_POWERDN) { @@ -245,6 +271,36 @@ tegra_se_save_tzram(); } + /* + * The CPU needs to load the System suspend entry firmware + * if nothing is running on the BPMP. + */ + if (!tegra_bpmp_available) { + + /* + * BPMP firmware is not running on the co-processor, so + * we need to explicitly load the firmware to enable + * entry/exit to/from System Suspend and set the BPMP + * on its way. + */ + + /* Power off BPMP before we proceed */ + tegra_fc_bpmp_off(); + + /* Copy the firmware to BPMP's internal RAM */ + (void)memcpy((void *)(uintptr_t)TEGRA_IRAM_BASE, + (const void *)plat_params->sc7entry_fw_base, + plat_params->sc7entry_fw_size); + + /* Power on the BPMP and execute from IRAM base */ + tegra_fc_bpmp_on(TEGRA_IRAM_BASE); + + /* Wait until BPMP powers up */ + do { + val = mmio_read_32(TEGRA_RES_SEMA_BASE + STA_OFFSET); + } while (val != SIGN_OF_LIFE); + } + /* enter system suspend */ tegra_fc_soc_powerdn(mpidr); } @@ -256,7 +312,7 @@ { const plat_params_from_bl2_t *plat_params = bl31_get_plat_params(); uint32_t cfg; - uint32_t val; + uint32_t val, entrypoint = 0; /* platform parameter passed by the previous bootloader */ if (plat_params->l2_ecc_parity_prot_dis != 1) { @@ -295,10 +351,14 @@ /* * Restore Boot and Power Management Processor (BPMP) reset - * address and reset it. + * address and reset it, if it is supported by the platform. */ - if (tegra_bpmp_available) - tegra_fc_reset_bpmp(); + if (!tegra_bpmp_available) { + tegra_fc_bpmp_off(); + } else { + entrypoint = tegra_pmc_read_32(PMC_SCRATCH39); + tegra_fc_bpmp_on(entrypoint); + } } /* diff --git a/plat/nvidia/tegra/soc/t210/plat_setup.c b/plat/nvidia/tegra/soc/t210/plat_setup.c index 25105ba..4fdd5a8 100644 --- a/plat/nvidia/tegra/soc/t210/plat_setup.c +++ b/plat/nvidia/tegra/soc/t210/plat_setup.c @@ -5,6 +5,7 @@ */ #include +#include #include #include #include @@ -150,6 +151,42 @@ GICV2_INTR_GROUP0, GIC_INTR_CFG_EDGE), }; +void plat_late_platform_setup(void) +{ + const plat_params_from_bl2_t *plat_params = bl31_get_plat_params(); + uint64_t tzdram_start, tzdram_end, sc7entry_end; + int ret; + + /* 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); + + /* + * Verify that the SC7 entry firmware resides inside the TZDRAM + * aperture, _after_ the BL31 code. + */ + tzdram_start = plat_params->tzdram_base; + tzdram_end = plat_params->tzdram_base + plat_params->tzdram_size; + sc7entry_end = plat_params->sc7entry_fw_base + + plat_params->sc7entry_fw_size; + if ((plat_params->sc7entry_fw_base < (tzdram_start + BL31_SIZE)) || + (sc7entry_end > tzdram_end)) { + panic(); + } + + /* power off BPMP processor until SC7 entry */ + tegra_fc_bpmp_off(); + + /* memmap SC7 entry firmware code */ + ret = mmap_add_dynamic_region(plat_params->sc7entry_fw_base, + plat_params->sc7entry_fw_base, + plat_params->sc7entry_fw_size, + MT_NS | MT_RO | MT_EXECUTE_NEVER); + assert(ret == 0); + } +} + /******************************************************************************* * Initialize the GIC and SGIs ******************************************************************************/