Commit d37a1322 authored by Varun Wadekar's avatar Varun Wadekar
Browse files

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: default avatarVarun Wadekar <vwadekar@nvidia.com>
parent 1ffaaec9
......@@ -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");
}
}
}
......@@ -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
*/
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment