summaryrefslogtreecommitdiff
path: root/plat/nvidia
diff options
context:
space:
mode:
authorVarun Wadekar <vwadekar@nvidia.com>2018-04-04 11:09:41 -0700
committerVarun Wadekar <vwadekar@nvidia.com>2019-01-31 08:49:50 -0800
commitd37a1322a0ec632880b4f5f4acd22bc1ade0d186 (patch)
treec275237c4b70bdaf639887e1f79abf449a826d18 /plat/nvidia
parent1ffaaec9ec409c4ab57baeda7772f2f3e2ccf4be (diff)
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>
Diffstat (limited to 'plat/nvidia')
-rw-r--r--plat/nvidia/tegra/common/drivers/bpmp/bpmp.c124
-rw-r--r--plat/nvidia/tegra/include/drivers/bpmp.h11
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 9a41a9bb..31c7d805 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 03da6f68..0046f6cc 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 @@ 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
*/
int32_t tegra_bpmp_send_receive_atomic(int mrq, const void *ob_data, int ob_sz,