summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 453879c)
raw | patch | inline | side by side (parent: 453879c)
author | Vaibhav Bedia <vaibhav.bedia@ti.com> | |
Thu, 9 Feb 2012 17:37:26 +0000 (23:07 +0530) | ||
committer | Sekhar Nori <nsekhar@ti.com> | |
Fri, 9 Mar 2012 09:06:27 +0000 (14:36 +0530) |
Add some error handling and update the code to
make use of DeepSleep0 mode.
Signed-off-by: Vaibhav Bedia <vaibhav.bedia@ti.com>
make use of DeepSleep0 mode.
Signed-off-by: Vaibhav Bedia <vaibhav.bedia@ti.com>
arch/arm/mach-omap2/pm33xx.c | patch | blob | history | |
arch/arm/mach-omap2/sleep33xx.S | patch | blob | history |
index b9473e8e958a5884506cc5bc56c398ccc4032a01..09b96d56c839b5008dba0f5a79ffc4fd3e228b01 100644 (file)
void (*am33xx_do_wfi_sram)(void);
-#define DS_MODE DS1_ID /* DS0/1_ID */
+#define DS_MODE DS0_ID /* DS0/1_ID */
#ifdef CONFIG_SUSPEND
static int m3_state;
static struct device *mpu_dev;
bool enable_deep_sleep = true;
+static int global_suspend_flag = 0;
+
static suspend_state_t suspend_state = PM_SUSPEND_ON;
struct a8_wkup_m3_ipc_data {
} am33xx_lp_ipc;
static int am33xx_set_low_power_state(struct a8_wkup_m3_ipc_data *);
+static void am33xx_verify_lp_state(void);
+
static int am33xx_do_sram_idle(long unsigned int state)
{
{
int ret = 0;
- /* Block console output in case it is on one of the OMAP UARTs */
- if (!is_suspending()) {
- if (!console_trylock()) {
- ret = -EAGAIN;
- goto err;
- }
- }
+ struct omap_hwmod *cpgmac_oh, *gpmc_oh, *usb_oh;
+
+ cpgmac_oh = omap_hwmod_lookup("cpgmac0");
+ usb_oh = omap_hwmod_lookup("usb_otg_hs");
+ gpmc_oh = omap_hwmod_lookup("gpmc");
+
+ omap_hwmod_enable(cpgmac_oh);
+ omap_hwmod_enable(usb_oh);
+ omap_hwmod_enable(gpmc_oh);
+
+ omap_hwmod_idle(cpgmac_oh);
+ omap_hwmod_idle(usb_oh);
+ omap_hwmod_idle(gpmc_oh);
ret = cpu_suspend(0, am33xx_do_sram_idle);
if (ret)
pr_err("Could not suspend\n");
- else
- goto done;
-err:
- pr_err("Console still active\n");
-done:
return ret;
}
omap_mbox_disable_irq(m3_mbox, IRQ_RX);
- disable_hlt();
suspend_state = state;
return ret;
}
+static void am33xx_m3_state_machine_reset(void)
+{
+ int ret = 0;
+
+ am33xx_lp_ipc.resume_addr = 0x0;
+ am33xx_lp_ipc.sleep_mode = 0xe;
+ am33xx_lp_ipc.ipc_data1 = DS_IPC_DEFAULT;
+ am33xx_lp_ipc.ipc_data2 = DS_IPC_DEFAULT;
+
+ am33xx_set_low_power_state(&am33xx_lp_ipc);
+
+ ret = omap_mbox_msg_send(m3_mbox, 0xABCDABCD);
+ if (!ret) {
+ pr_debug("Message sent for resetting M3 state machine\n");
+ omap_mbox_msg_rx_flush(m3_mbox);
+ }
+}
+
static void am33xx_pm_end(void)
{
suspend_state = PM_SUSPEND_ON;
- if (!is_suspending())
- console_unlock();
+ /* Check the global suspend flag followed by the IPC register */
+ am33xx_verify_lp_state();
+
+ /* TODO: This should be handled via some MBX API */
+ if (m3_mbox->ops->ack_irq)
+ m3_mbox->ops->ack_irq(m3_mbox, IRQ_RX);
omap_mbox_enable_irq(m3_mbox, IRQ_RX);
+
+ /* M3 state machine will get reset in a successful iteration,
+ * for now we go ahead and reset it again to catch the bad
+ * iterations
+ */
+ am33xx_m3_state_machine_reset();
+
return;
}
int am33xx_set_low_power_state(struct a8_wkup_m3_ipc_data *data)
{
- __raw_writel(data->resume_addr, ipc_regs);
- __raw_writel(data->sleep_mode, ipc_regs + 0x4);
- __raw_writel(data->ipc_data1, ipc_regs + 0x8);
- __raw_writel(data->ipc_data2, ipc_regs + 0xc);
+ writel(data->resume_addr, ipc_regs);
+ writel(data->sleep_mode, ipc_regs + 0x4);
+ writel(data->ipc_data1, ipc_regs + 0x8);
+ writel(data->ipc_data2, ipc_regs + 0xc);
return 0;
}
+static void am33xx_verify_lp_state(void)
+{
+ int status;
+
+ if (global_suspend_flag) {
+ pr_err("Kernel core reported suspend failure\n");
+ goto clear_old_status;
+ }
+
+ /* If it's a failed transition and we check the old status,
+ * the failure will be erroneoulsy logged as a pass
+ * and the worst part is that the next WFI in the idle loop
+ * will be intercepted by M3 as a signal to cut-off
+ * the power to A8
+ *
+ * So, we MUST reset the M3 state machine even if the
+ * result is pass. Other option could be to clear the
+ * the CMD_STAT bits in the resume path and that also
+ * should be done
+ */
+ status = readl(ipc_regs + 0x4);
+ status &= 0xffff0000;
+
+ if (status == 0x0)
+ pr_info("DeepSleep transition passed\n");
+ else if (status == 0x10000)
+ pr_info("DeepSleep transition failed\n");
+ else
+ pr_info("Status = %0x\n", status);
+
+
+clear_old_status:
+ /* After decoding we write back the bad status */
+ status = readl(ipc_regs + 0x4);
+ status &= 0xffff0000;
+ status |= 0x10000;
+ writel(status, ipc_regs + 0x4);
+}
+
/*
* Dummy notifier for the mailbox
* TODO: Can this be completely removed?
m3_state++;
if (m3_eoi) {
- __raw_writel(0x1, m3_eoi);
- __raw_writel(0x0, m3_eoi);
+ writel(0x1, m3_eoi);
+ writel(0x0, m3_eoi);
return IRQ_HANDLED;
} else {
pr_err("%s unexpected interrupt. "
index f80b1c3a7acc86aa2d005e1c35c33a6ef6c25634..826688f874f5ec5caad1dc62634125e9feb6ab5d 100644 (file)
#include <asm/memory.h>
#include <asm/assembler.h>
#include <mach/io.h>
+#include <plat/emif.h>
+#include "cm33xx.h"
#include <plat/emif.h>
#include <plat/sram.h>
ddr_phy_base:
.word DDR_PHY_BASE_ADDR
-
ddr2_ratio_val:
.word DDR2_RATIO
data0_rd_dqs_slave_ratio0_val: