From d37a1322a0ec632880b4f5f4acd22bc1ade0d186 Mon Sep 17 00:00:00 2001 From: Varun Wadekar <vwadekar@nvidia.com> Date: Wed, 4 Apr 2018 11:09:41 -0700 Subject: [PATCH] Tegra: bpmp: suspend/resume handlers This patch adds suspend and resume handlers for the BPMP interface. Mark the interface as "suspended" before entering System Suspend and verify that BPMP is alive on exit. Change-Id: I74ccbc86125079b46d06360fc4c7e8a5acfbdfb2 Signed-off-by: Varun Wadekar <vwadekar@nvidia.com> --- plat/nvidia/tegra/common/drivers/bpmp/bpmp.c | 124 +++++++++++++------ plat/nvidia/tegra/include/drivers/bpmp.h | 11 ++ 2 files changed, 99 insertions(+), 36 deletions(-) diff --git a/plat/nvidia/tegra/common/drivers/bpmp/bpmp.c b/plat/nvidia/tegra/common/drivers/bpmp/bpmp.c index 9a41a9bb5..31c7d8051 100644 --- a/plat/nvidia/tegra/common/drivers/bpmp/bpmp.c +++ b/plat/nvidia/tegra/common/drivers/bpmp/bpmp.c @@ -16,7 +16,7 @@ #include <string.h> #include <tegra_def.h> -#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 @@ int32_t tegra_bpmp_send_receive_atomic(int mrq, const void *ob_data, int ob_sz, 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--; + } - /* 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"); - } + } while ((val != SIGN_OF_LIFE) && (timeout > 0U)); - /* 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"); - } + if (val == SIGN_OF_LIFE) { - /* base address to get the result from Atomics */ - base = TEGRA_ATOMICS_BASE + RESULT0_REG_OFFSET; + /* 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"); + } - /* channel area is setup by BPMP before signaling handshake */ - for (ch = 0; ch < NR_CHANNELS; ch++) { + /* 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"); + } - /* issue command to get the channel base address */ - mmio_write_32(base, (ch << TRIGGER_ID_SHIFT) | - ATOMIC_CMD_GET); + /* base address to get the result from Atomics */ + base = TEGRA_ATOMICS_BASE + RESULT0_REG_OFFSET; - /* get the base address for the channel */ - channel_base[ch] = mmio_read_32(base); + /* channel area is setup by BPMP before signaling handshake */ + for (ch = 0; ch < NR_CHANNELS; ch++) { - /* increment result register offset */ - base += 4U; - } + /* issue command to get the channel base address */ + mmio_write_32(base, (ch << TRIGGER_ID_SHIFT) | + ATOMIC_CMD_GET); - /* mark state as "initialized" */ - bpmp_init_state = BPMP_INIT_COMPLETE; + /* get the base address for the channel */ + channel_base[ch] = mmio_read_32(base); - /* 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)); + /* 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__); - INFO("%s: done\n", __func__); + } else { + ERROR("BPMP not powered on\n"); + ret = -ETIMEDOUT; + } } 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 03da6f68b..0046f6cc7 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 @@ -106,6 +107,16 @@ typedef struct mb_data { */ 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 */ -- GitLab