ASR_BASE
Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/marvell/linux/arch/arm/mach-mmp/pm.c b/marvell/linux/arch/arm/mach-mmp/pm.c
new file mode 100644
index 0000000..437c3d8
--- /dev/null
+++ b/marvell/linux/arch/arm/mach-mmp/pm.c
@@ -0,0 +1,166 @@
+/*
+ * linux/arch/arm/mach-mmp/pm.c
+ *
+ * Author: Fan Wu <fwu@marvell.com>
+ * Copyright: (C) 2012 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <asm/cputype.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <asm/mcpm.h>
+#include <linux/suspend.h>
+#include <asm/suspend.h>
+#include <soc/asr/asr18xx_lowpower.h>
+#include <linux/irqchip/arm-gic.h>
+#include <linux/irqchip/mmp.h>
+#include <linux/cpu_pm.h>
+#include "irqs.h"
+#include "pm.h"
+#include <soc/asr/mmp_cpuidle.h>
+
+struct platform_suspend *mmp_suspend;
+u32 detect_wakeup_status = 0;
+EXPORT_SYMBOL(detect_wakeup_status);
+
+#if !defined(CONFIG_CPU_ASR18XX)
+static int notrace mcpm_powerdown_finisher(unsigned long arg)
+{
+ u32 mpidr = read_cpuid_mpidr();
+ u32 cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+ u32 this_cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+
+ mcpm_set_entry_vector(cpu, this_cluster, cpu_resume);
+
+ asr_set_target_lpm_state(cpu, this_cluster, *((int *)arg), (int *)arg);
+
+ mcpm_cpu_suspend();
+ return 1;
+}
+#endif
+
+#if defined(CONFIG_CPU_ASR18XX)
+extern void asr18xx_pm_power_down(void);
+extern void asr18xx_pm_powered_up(void);
+extern void asr18xx_dcstat(unsigned long addr, unsigned int flag);
+extern int asr18xx_pm_check_constraint(void);
+static int notrace mmp_suspend_finish(unsigned long val)
+{
+ asr18xx_pm_power_down();
+ return 1;
+}
+#endif
+
+static int mmp_pm_enter(suspend_state_t state)
+{
+ unsigned int real_idx = mmp_suspend->suspend_state;
+
+ if (mmp_suspend->ops->pre_suspend_check) {
+ if (mmp_suspend->ops->pre_suspend_check())
+ return -EAGAIN;
+ }
+#if !defined(CONFIG_CPU_ASR18XX)
+ cpu_suspend((unsigned long)&real_idx, mcpm_powerdown_finisher);
+#else
+ cpu_suspend((unsigned long)&real_idx, mmp_suspend_finish);
+#endif
+ if (mmp_suspend->ops->post_chk_wakeup)
+ detect_wakeup_status = mmp_suspend->ops->post_chk_wakeup();
+
+ if (mmp_suspend->ops->post_clr_wakeup)
+ mmp_suspend->ops->post_clr_wakeup(detect_wakeup_status);
+
+ if (real_idx != mmp_suspend->suspend_state)
+ pr_info("WARNING!!! "
+ "Suspend Didn't enter the Expected Low power mode\n");
+#if !defined(CONFIG_CPU_ASR18XX)
+ mcpm_cpu_powered_up();
+#else
+ asr18xx_pm_powered_up();
+#endif
+ return 0;
+}
+
+static int mmp_pm_valid(suspend_state_t state)
+{
+ return ((state == PM_SUSPEND_STANDBY) || (state == PM_SUSPEND_MEM));
+}
+
+extern void asr_clear_wakeup_event_idx(void);
+/* Called after devices suspend, before noirq devices suspend */
+static int mmp_pm_prepare(void)
+{
+#ifdef CONFIG_CPU_ASR18XX
+ asr18xx_dcstat(0, 0);
+#endif
+ asr_clear_wakeup_event_idx();
+ return 0;
+}
+
+/* Called after noirq devices resume, before devices resume */
+static void mmp_pm_finish(void)
+{
+}
+
+/* Called after Non-boot CPUs have been Hotplug in if necessary */
+static void mmp_pm_wake(void)
+{
+}
+
+static const struct platform_suspend_ops mmp_pm_ops = {
+ .valid = mmp_pm_valid,
+ .prepare = mmp_pm_prepare,
+ .enter = mmp_pm_enter,
+ .finish = mmp_pm_finish,
+ .wake = mmp_pm_wake,
+};
+
+int mmp_set_wake(struct irq_data *data, unsigned int on)
+{
+ int irq = (int)data->hwirq;
+ struct irq_desc *desc = irq_to_desc(data->irq);
+
+ if (!mmp_suspend->ops->set_wake) {
+ WARN_ON("Platform set_wake function is not Existed!!");
+ return -EINVAL;
+ }
+ if (!desc) {
+ pr_err("irq_desc is NULL\n");
+ return -EINVAL;
+ }
+ if (on) {
+ if (desc->action)
+ desc->action->flags |= IRQF_NO_SUSPEND;
+ } else {
+ if (desc->action)
+ desc->action->flags &= ~IRQF_NO_SUSPEND;
+ }
+
+ mmp_suspend->ops->set_wake(irq, on);
+
+ return 0;
+}
+
+int __init mmp_platform_suspend_register(struct platform_suspend *plt_suspend)
+{
+ if (mmp_suspend)
+ return -EBUSY;
+
+ mmp_suspend = plt_suspend;
+
+ suspend_set_ops(&mmp_pm_ops);
+#ifndef CONFIG_CPU_ASR18XX
+ gic_arch_extn.irq_set_wake = mmp_set_wake;
+#else
+ icu_irq_chip.irq_set_wake = mmp_set_wake;
+#endif
+ if (mmp_suspend->ops->plt_suspend_init)
+ mmp_suspend->ops->plt_suspend_init();
+
+ return 0;
+}