|
@@ -0,0 +1,155 @@
|
|
|
|
+/*
|
|
|
|
+ * OMAP3 Power Management Routines
|
|
|
|
+ *
|
|
|
|
+ * Copyright (C) 2006-2008 Nokia Corporation
|
|
|
|
+ * Tony Lindgren <tony@atomide.com>
|
|
|
|
+ * Jouni Hogander
|
|
|
|
+ *
|
|
|
|
+ * Copyright (C) 2007 Texas Instruments, Inc.
|
|
|
|
+ * Rajendra Nayak <rnayak@ti.com>
|
|
|
|
+ *
|
|
|
|
+ * Copyright (C) 2005 Texas Instruments, Inc.
|
|
|
|
+ * Richard Woodruff <r-woodruff2@ti.com>
|
|
|
|
+ *
|
|
|
|
+ * Based on pm.c for omap1
|
|
|
|
+ *
|
|
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
|
|
+ * it under the terms of the GNU General Public License version 2 as
|
|
|
|
+ * published by the Free Software Foundation.
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+#include <linux/pm.h>
|
|
|
|
+#include <linux/suspend.h>
|
|
|
|
+#include <linux/interrupt.h>
|
|
|
|
+#include <linux/module.h>
|
|
|
|
+#include <linux/list.h>
|
|
|
|
+#include <linux/err.h>
|
|
|
|
+#include <linux/gpio.h>
|
|
|
|
+#include <linux/clk.h>
|
|
|
|
+#include <linux/delay.h>
|
|
|
|
+#include <linux/slab.h>
|
|
|
|
+#include <linux/omap-dma.h>
|
|
|
|
+#include <linux/platform_data/gpio-omap.h>
|
|
|
|
+
|
|
|
|
+#include <trace/events/power.h>
|
|
|
|
+
|
|
|
|
+#include <asm/fncpy.h>
|
|
|
|
+#include <asm/suspend.h>
|
|
|
|
+#include <asm/system_misc.h>
|
|
|
|
+
|
|
|
|
+#include "clockdomain.h"
|
|
|
|
+#include "powerdomain.h"
|
|
|
|
+#include "soc.h"
|
|
|
|
+#include "common.h"
|
|
|
|
+#include "cm3xxx.h"
|
|
|
|
+#include "cm-regbits-34xx.h"
|
|
|
|
+#include "gpmc.h"
|
|
|
|
+#include "prm-regbits-34xx.h"
|
|
|
|
+#include "prm3xxx.h"
|
|
|
|
+#include "pm.h"
|
|
|
|
+#include "sdrc.h"
|
|
|
|
+#include "sram.h"
|
|
|
|
+#include "control.h"
|
|
|
|
+
|
|
|
|
+/* pm34xx errata defined in pm.h */
|
|
|
|
+u16 pm34xx_errata;
|
|
|
|
+
|
|
|
|
+struct power_state {
|
|
|
|
+ struct powerdomain *pwrdm;
|
|
|
|
+ u32 next_state;
|
|
|
|
+#ifdef CONFIG_SUSPEND
|
|
|
|
+ u32 saved_state;
|
|
|
|
+#endif
|
|
|
|
+ struct list_head node;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static LIST_HEAD(pwrst_list);
|
|
|
|
+
|
|
|
|
+static int (*_omap_save_secure_sram)(u32 *addr);
|
|
|
|
+void (*omap3_do_wfi_sram)(void);
|
|
|
|
+
|
|
|
|
+static struct powerdomain *mpu_pwrdm, *neon_pwrdm;
|
|
|
|
+static struct powerdomain *core_pwrdm, *per_pwrdm;
|
|
|
|
+
|
|
|
|
+static void omap3_core_save_context(void)
|
|
|
|
+{
|
|
|
|
+ omap3_ctrl_save_padconf();
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Force write last pad into memory, as this can fail in some
|
|
|
|
+ * cases according to errata 1.157, 1.185
|
|
|
|
+ */
|
|
|
|
+ omap_ctrl_writel(omap_ctrl_readl(OMAP343X_PADCONF_ETK_D14),
|
|
|
|
+ OMAP343X_CONTROL_MEM_WKUP + 0x2a0);
|
|
|
|
+
|
|
|
|
+ /* Save the Interrupt controller context */
|
|
|
|
+ omap_intc_save_context();
|
|
|
|
+ /* Save the GPMC context */
|
|
|
|
+ omap3_gpmc_save_context();
|
|
|
|
+ /* Save the system control module context, padconf already save above*/
|
|
|
|
+ omap3_control_save_context();
|
|
|
|
+ omap_dma_global_context_save();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void omap3_core_restore_context(void)
|
|
|
|
+{
|
|
|
|
+ /* Restore the control module context, padconf restored by h/w */
|
|
|
|
+ omap3_control_restore_context();
|
|
|
|
+ /* Restore the GPMC context */
|
|
|
|
+ omap3_gpmc_restore_context();
|
|
|
|
+ /* Restore the interrupt controller context */
|
|
|
|
+ omap_intc_restore_context();
|
|
|
|
+ omap_dma_global_context_restore();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * FIXME: This function should be called before entering off-mode after
|
|
|
|
+ * OMAP3 secure services have been accessed. Currently it is only called
|
|
|
|
+ * once during boot sequence, but this works as we are not using secure
|
|
|
|
+ * services.
|
|
|
|
+ */
|
|
|
|
+static void omap3_save_secure_ram_context(void)
|
|
|
|
+{
|
|
|
|
+ u32 ret;
|
|
|
|
+ int mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);
|
|
|
|
+
|
|
|
|
+ if (omap_type() != OMAP2_DEVICE_TYPE_GP) {
|
|
|
|
+ /*
|
|
|
|
+ * MPU next state must be set to POWER_ON temporarily,
|
|
|
|
+ * otherwise the WFI executed inside the ROM code
|
|
|
|
+ * will hang the system.
|
|
|
|
+ */
|
|
|
|
+ pwrdm_set_next_pwrst(mpu_pwrdm, PWRDM_POWER_ON);
|
|
|
|
+ ret = _omap_save_secure_sram((u32 *)
|
|
|
|
+ __pa(omap3_secure_ram_storage));
|
|
|
|
+ pwrdm_set_next_pwrst(mpu_pwrdm, mpu_next_state);
|
|
|
|
+ /* Following is for error tracking, it should not happen */
|
|
|
|
+ if (ret) {
|
|
|
|
+ pr_err("save_secure_sram() returns %08x\n", ret);
|
|
|
|
+ while (1)
|
|
|
|
+ ;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * PRCM Interrupt Handler Helper Function
|
|
|
|
+ *
|
|
|
|
+ * The purpose of this function is to clear any wake-up events latched
|
|
|
|
+ * in the PRCM PM_WKST_x registers. It is possible that a wake-up event
|
|
|
|
+ * may occur whilst attempting to clear a PM_WKST_x register and thus
|
|
|
|
+ * set another bit in this register. A while loop is used to ensure
|
|
|
|
+ * that any peripheral wake-up events occurring while attempting to
|
|
|
|
+ * clear the PM_WKST_x are detected and cleared.
|
|
|
|
+ */
|
|
|
|
+static int prcm_clear_mod_irqs(s16 module, u8 regs, u32 ignore_bits)
|
|
|
|
+{
|
|
|
|
+ u32 wkst, fclk, iclk, clken;
|
|
|
|
+ u16 wkst_off = (regs == 3) ? OMAP3430ES2_PM_WKST3 : PM_WKST1;
|
|
|
|
+ u16 fclk_off = (regs == 3) ? OMAP3430ES2_CM_FCLKEN3 : CM_FCLKEN1;
|
|
|
|
+ u16 iclk_off = (regs == 3) ? CM_ICLKEN3 : CM_ICLKEN1;
|
|
|
|
+ u16 grpsel_off = (regs == 3) ?
|
|
|
|
+ OMAP3430ES2_PM_MPUGRPSEL3 : OMAP3430_PM_MPUGRPSEL;
|
|
|
|
+ int c = 0;
|
|
|
|
+
|
|
|
|
+ wkst = omap2_prm_read_mod_reg(module, wkst_off);
|