diff --git a/plat/nvidia/tegra/common/drivers/bpmp/bpmp.c b/plat/nvidia/tegra/common/drivers/bpmp/bpmp.c index 9a41a9b..31c7d80 100644 --- a/plat/nvidia/tegra/common/drivers/bpmp/bpmp.c +++ b/plat/nvidia/tegra/common/drivers/bpmp/bpmp.c @@ -16,7 +16,7 @@ #include #include -#define BPMP_TIMEOUT 2 +#define BPMP_TIMEOUT 500 /* 500ms */ static uint32_t channel_base[NR_CHANNELS]; static uint32_t bpmp_init_state = BPMP_INIT_PENDING; @@ -115,57 +115,109 @@ int tegra_bpmp_init(void) { - uint32_t val, base; + uint32_t val, base, timeout = BPMP_TIMEOUT; unsigned int ch; int ret = 0; - if (bpmp_init_state != BPMP_INIT_COMPLETE) { + if (bpmp_init_state == BPMP_INIT_PENDING) { /* check if the bpmp processor is alive. */ - val = mmio_read_32(TEGRA_RES_SEMA_BASE + STA_OFFSET); - if (val != SIGN_OF_LIFE) { - return -ENOTSUP; + do { + val = mmio_read_32(TEGRA_RES_SEMA_BASE + STA_OFFSET); + if (val != SIGN_OF_LIFE) { + mdelay(1); + timeout--; + } + + } while ((val != SIGN_OF_LIFE) && (timeout > 0U)); + + if (val == SIGN_OF_LIFE) { + + /* check if clock for the atomics block is enabled */ + val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_ENB_V); + if ((val & CAR_ENABLE_ATOMICS) == 0) { + ERROR("Clock to the atomics block is disabled\n"); + } + + /* check if the atomics block is out of reset */ + val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_CLR_V); + if ((val & CAR_ENABLE_ATOMICS) == CAR_ENABLE_ATOMICS) { + ERROR("Reset to the atomics block is asserted\n"); + } + + /* base address to get the result from Atomics */ + base = TEGRA_ATOMICS_BASE + RESULT0_REG_OFFSET; + + /* channel area is setup by BPMP before signaling handshake */ + for (ch = 0; ch < NR_CHANNELS; ch++) { + + /* issue command to get the channel base address */ + mmio_write_32(base, (ch << TRIGGER_ID_SHIFT) | + ATOMIC_CMD_GET); + + /* get the base address for the channel */ + channel_base[ch] = mmio_read_32(base); + + /* increment result register offset */ + base += 4U; + } + + /* mark state as "initialized" */ + bpmp_init_state = BPMP_INIT_COMPLETE; + + /* the channel values have to be visible across all cpus */ + flush_dcache_range((uint64_t)channel_base, + sizeof(channel_base)); + flush_dcache_range((uint64_t)&bpmp_init_state, + sizeof(bpmp_init_state)); + + INFO("%s: done\n", __func__); + + } else { + ERROR("BPMP not powered on\n"); + ret = -ETIMEDOUT; } - - /* check if clock for the atomics block is enabled */ - val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_CLK_ENB_V); - if ((val & CAR_ENABLE_ATOMICS) == 0) { - ERROR("Clock to the atomics block is disabled\n"); - } - - /* check if the atomics block is out of reset */ - val = mmio_read_32(TEGRA_CAR_RESET_BASE + TEGRA_RST_DEV_CLR_V); - if ((val & CAR_ENABLE_ATOMICS) == CAR_ENABLE_ATOMICS) { - ERROR("Reset to the atomics block is asserted\n"); - } - - /* base address to get the result from Atomics */ - base = TEGRA_ATOMICS_BASE + RESULT0_REG_OFFSET; - - /* channel area is setup by BPMP before signaling handshake */ - for (ch = 0; ch < NR_CHANNELS; ch++) { - - /* issue command to get the channel base address */ - mmio_write_32(base, (ch << TRIGGER_ID_SHIFT) | - ATOMIC_CMD_GET); - - /* get the base address for the channel */ - channel_base[ch] = mmio_read_32(base); - - /* increment result register offset */ - base += 4U; - } - - /* mark state as "initialized" */ - bpmp_init_state = BPMP_INIT_COMPLETE; - - /* the channel values have to be visible across all cpus */ - flush_dcache_range((uint64_t)channel_base, sizeof(channel_base)); - flush_dcache_range((uint64_t)&bpmp_init_state, - sizeof(bpmp_init_state)); - - INFO("%s: done\n", __func__); } return ret; } + +void tegra_bpmp_suspend(void) +{ + /* freeze the interface */ + bpmp_init_state = BPMP_SUSPEND_ENTRY; + flush_dcache_range((uint64_t)&bpmp_init_state, sizeof(bpmp_init_state)); +} + +void tegra_bpmp_resume(void) +{ + uint32_t val, timeout = 0; + + if (bpmp_init_state == BPMP_SUSPEND_ENTRY) { + + /* check if the bpmp processor is alive. */ + do { + + val = mmio_read_32(TEGRA_RES_SEMA_BASE + STA_OFFSET); + if (val != SIGN_OF_LIFE) { + mdelay(1); + timeout++; + } + + } while ((val != SIGN_OF_LIFE) && (timeout < BPMP_TIMEOUT)); + + if (val == SIGN_OF_LIFE) { + + INFO("%s: BPMP took %d ms to resume\n", __func__, timeout); + + /* mark state as "initialized" */ + bpmp_init_state = BPMP_INIT_COMPLETE; + + /* state has to be visible across all cpus */ + flush_dcache_range((uint64_t)&bpmp_init_state, + sizeof(bpmp_init_state)); + } else { + ERROR("BPMP not powered on\n"); + } + } +} diff --git a/plat/nvidia/tegra/include/drivers/bpmp.h b/plat/nvidia/tegra/include/drivers/bpmp.h index 03da6f6..0046f6c 100644 --- a/plat/nvidia/tegra/include/drivers/bpmp.h +++ b/plat/nvidia/tegra/include/drivers/bpmp.h @@ -29,6 +29,7 @@ /* flags to indicate bpmp driver's state */ #define BPMP_INIT_COMPLETE 0xBEEFF00DU #define BPMP_INIT_PENDING 0xDEADBEEFU +#define BPMP_SUSPEND_ENTRY 0xF00DCAFEU /* requests serviced by the bpmp */ #define MRQ_PING 0 @@ -107,6 +108,16 @@ int tegra_bpmp_init(void); /** + * Function to suspend the interface with the bpmp + */ +void tegra_bpmp_suspend(void); + +/** + * Function to resume the interface with the bpmp + */ +void tegra_bpmp_resume(void); + +/** * Handler to send a MRQ_* command to the bpmp */ int32_t tegra_bpmp_send_receive_atomic(int mrq, const void *ob_data, int ob_sz,