diff mbox

[4/5] powerpc/85xx: Add suspend/resume support

Message ID 20090827173021.GD739@oksana.dev.rtsoft.ru (mailing list archive)
State Superseded
Delegated to: Kumar Gala
Headers show

Commit Message

Anton Vorontsov Aug. 27, 2009, 5:30 p.m. UTC
This patch adds suspend/resume support for MPC8540-compatible and
MPC8569 CPUs.

MPC8540-compatible PMCs are trivial: we just write SLP bit into PM
control and status register.

MPC8569 is a bit trickier, QE turns off during suspend and so on
resume we must reload QE microcode firmware and reset QE.

So far we don't support Deep Sleep mode as found in newer MPC85xx
CPUs (i.e. MPC8536). It can be relatively easy implemented though,
and for it we reserve 'mem' suspend type.

Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
 arch/powerpc/Kconfig                  |    2 +-
 arch/powerpc/platforms/85xx/Makefile  |    1 +
 arch/powerpc/platforms/85xx/suspend.c |  115 +++++++++++++++++++++++++++++++++
 3 files changed, 117 insertions(+), 1 deletions(-)
 create mode 100644 arch/powerpc/platforms/85xx/suspend.c

Comments

Kumar Gala Aug. 28, 2009, 5:38 a.m. UTC | #1
On Aug 27, 2009, at 12:30 PM, Anton Vorontsov wrote:

> This patch adds suspend/resume support for MPC8540-compatible and
> MPC8569 CPUs.
>
> MPC8540-compatible PMCs are trivial: we just write SLP bit into PM
> control and status register.
>
> MPC8569 is a bit trickier, QE turns off during suspend and so on
> resume we must reload QE microcode firmware and reset QE.
>
> So far we don't support Deep Sleep mode as found in newer MPC85xx
> CPUs (i.e. MPC8536). It can be relatively easy implemented though,
> and for it we reserve 'mem' suspend type.
>
> Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
> ---
> arch/powerpc/Kconfig                  |    2 +-
> arch/powerpc/platforms/85xx/Makefile  |    1 +
> arch/powerpc/platforms/85xx/suspend.c |  115 ++++++++++++++++++++++++ 
> +++++++++
> 3 files changed, 117 insertions(+), 1 deletions(-)
> create mode 100644 arch/powerpc/platforms/85xx/suspend.c

How did you test this?

I'd also like to get Scott's Ack on this and the device tree patches  
before accepting them.

- k
Anton Vorontsov Aug. 28, 2009, 3:15 p.m. UTC | #2
On Fri, Aug 28, 2009 at 12:38:51AM -0500, Kumar Gala wrote:
> 
> On Aug 27, 2009, at 12:30 PM, Anton Vorontsov wrote:
> 
> >This patch adds suspend/resume support for MPC8540-compatible and
> >MPC8569 CPUs.
> >
> >MPC8540-compatible PMCs are trivial: we just write SLP bit into PM
> >control and status register.
> >
> >MPC8569 is a bit trickier, QE turns off during suspend and so on
> >resume we must reload QE microcode firmware and reset QE.
> >
> >So far we don't support Deep Sleep mode as found in newer MPC85xx
> >CPUs (i.e. MPC8536). It can be relatively easy implemented though,
> >and for it we reserve 'mem' suspend type.
> >
> >Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
> >---
> >arch/powerpc/Kconfig                  |    2 +-
> >arch/powerpc/platforms/85xx/Makefile  |    1 +
> >arch/powerpc/platforms/85xx/suspend.c |  115
> >+++++++++++++++++++++++++++++++++
> >3 files changed, 117 insertions(+), 1 deletions(-)
> >create mode 100644 arch/powerpc/platforms/85xx/suspend.c
> 
> How did you test this?

--- Prerequisites:

1. Following patches should be applied in addition:

   rtc: Set wakeup capability for I2C and SPI RTC drivers
   [5/5] ucc_geth: Implement suspend/resume and Wake-On-LAN support
   [4/5] ucc_geth: Remove UGETH_MAGIC_PACKET Kconfig symbol and code
   [3/5] ucc_geth: Factor out MAC initialization steps into a call
   [2/5] powerpc/qe: Implement qe_alive_during_sleep() helper function
   [1/5] ucc_geth: Fix NULL pointer dereference in uec_get_ethtool_stats()

2. QE microcode should be placed into /lib/firmware/, i.e.
   wget http://opensource.freescale.com/firmware/fsl_qe_ucode_8569_10.zip
   unzip fsl_qe_ucode_8569_10.zip
   cp fsl_qe_ucode_8569_10.bin /<nfsroot>/lib/firmware/fsl_qe_ucode_8569.bin

--- Wakeup on RTC alarm:

# cd /sys/class/rtc/rtc0/
# echo $(( `cat since_epoch` + 10 )) > wakealarm
# echo standby > /sys/power/state
mpc85xx-pmc e00e0080.power: firmware: requesting fsl_qe_ucode_8569.bin
PM: Syncing filesystems ... done.
Freezing user space processes ... (elapsed 0.02 seconds) done.
Freezing remaining freezable tasks ... (elapsed 0.01 seconds) done.


The board is now suspended, CPU asserted ASLEEP signal that is
reflected by the ASLEEP LED on the board (the LED is near UEC2
port). 10 seconds later the board will wakeup:

qe-firmware: firmware 'MPC8569 QE Microcode Rel_B6900155' for 8569 V1.0
qe-firmware: uploading microcode 'MPC8569 QE Microcode Rel_B69001' version 1.0.0
pci 0000:00:00.0: enabling device (0106 -> 0107)
Restarting tasks ... done.
PHY: mdio@e0082120:07 - Link is Up - 100/Full

--- Wakeup on PHY/link changes (no magic packet support in MPC8569, as
    QE turns off during sleep):

# ethtool -s eth0 wol p
# echo standby > /sys/power/state
PM: Syncing filesystems ... done.
Freezing user space processes ... (elapsed 0.00 seconds) done.
Freezing remaining freezable tasks ... (elapsed 0.00 seconds) done.


To wakeup, trigger the PHY interrupt (e.g. pull out the ethernet
cable from eth0):

qe-firmware: firmware 'MPC8569 QE Microcode Rel_B6900155' for 8569 V1.0
qe-firmware: uploading microcode 'MPC8569 QE Microcode Rel_B69001' version 1.0.0
pci 0000:00:00.0: enabling device (0106 -> 0107)
Restarting tasks ... done.


UCC magic packet detection was tested on MPC8360E-MDS boards
(ethtool -s eth0 wol g), I'll send power management support
patches for 83xx QE boards soon.

Thanks,
diff mbox

Patch

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index d00131c..46ebfe6 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -212,7 +212,7 @@  config ARCH_HIBERNATION_POSSIBLE
 
 config ARCH_SUSPEND_POSSIBLE
 	def_bool y
-	depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx
+	depends on ADB_PMU || PPC_EFIKA || PPC_LITE5200 || PPC_83xx || PPC_85xx
 
 config PPC_DCR_NATIVE
 	bool
diff --git a/arch/powerpc/platforms/85xx/Makefile b/arch/powerpc/platforms/85xx/Makefile
index 835733f..cd1ad6e 100644
--- a/arch/powerpc/platforms/85xx/Makefile
+++ b/arch/powerpc/platforms/85xx/Makefile
@@ -2,6 +2,7 @@ 
 # Makefile for the PowerPC 85xx linux kernel.
 #
 obj-$(CONFIG_SMP) += smp.o
+obj-$(CONFIG_SUSPEND) += suspend.o
 
 obj-$(CONFIG_MPC8540_ADS) += mpc85xx_ads.o
 obj-$(CONFIG_MPC8560_ADS) += mpc85xx_ads.o
diff --git a/arch/powerpc/platforms/85xx/suspend.c b/arch/powerpc/platforms/85xx/suspend.c
new file mode 100644
index 0000000..d4ca5e2
--- /dev/null
+++ b/arch/powerpc/platforms/85xx/suspend.c
@@ -0,0 +1,115 @@ 
+/*
+ * Suspend/resume support
+ *
+ * Copyright © 2009  MontaVista Software, Inc.
+ *
+ * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * 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 <linux/init.h>
+#include <linux/types.h>
+#include <linux/suspend.h>
+#include <linux/device.h>
+#include <linux/of_platform.h>
+#include <linux/firmware.h>
+#include <asm/qe.h>
+
+struct pmc_regs {
+	__be32 pmcsr;
+#define PMCSR_SLP	(1 << 17)
+};
+
+struct pmc_data {
+	unsigned int flags;
+#define PMC_NEED_QE_RELOAD (1 << 0)
+
+	const char *fw_name;
+};
+
+static struct device *pmc_dev;
+static struct pmc_regs __iomem *pmc_regs;
+static const struct pmc_data *pmc_data;
+static struct qe_firmware *pmc_qefw;
+
+static int pmc_suspend_enter(suspend_state_t state)
+{
+	out_be32(&pmc_regs->pmcsr, PMCSR_SLP);
+
+	if (pmc_qefw) {
+		int ret;
+
+		ret = qe_upload_firmware(pmc_qefw);
+		if (ret)
+			dev_err(pmc_dev, "could not upload firmware\n");
+
+		qe_reset();
+	}
+	return 0;
+}
+
+static int pmc_suspend_valid(suspend_state_t state)
+{
+	if (state != PM_SUSPEND_STANDBY)
+		return 0;
+
+	if (pmc_data && pmc_data->flags & PMC_NEED_QE_RELOAD && !pmc_qefw) {
+		const struct firmware *fw;
+		int ret;
+
+		ret = request_firmware(&fw, pmc_data->fw_name, pmc_dev);
+		if (ret) {
+			dev_err(pmc_dev, "could not request firmware %s\n",
+				pmc_data->fw_name);
+			return 0;
+		}
+
+		pmc_qefw = (struct qe_firmware *)fw->data;
+	}
+
+	return 1;
+}
+
+static struct platform_suspend_ops pmc_suspend_ops = {
+	.valid = pmc_suspend_valid,
+	.enter = pmc_suspend_enter,
+};
+
+static int pmc_probe(struct of_device *ofdev, const struct of_device_id *id)
+{
+	pmc_regs = of_iomap(ofdev->node, 0);
+	if (!pmc_regs)
+		return -ENOMEM;
+
+	pmc_dev = &ofdev->dev;
+	pmc_data = id->data;
+	suspend_set_ops(&pmc_suspend_ops);
+	return 0;
+}
+
+static struct pmc_data mpc8569_pmc_data = {
+	.flags = PMC_NEED_QE_RELOAD,
+	.fw_name = "fsl_qe_ucode_8569.bin",
+};
+
+static const struct of_device_id pmc_ids[] = {
+	{ .compatible = "fsl,mpc8569-pmc", .data = &mpc8569_pmc_data, },
+	{ .compatible = "fsl,mpc8548-pmc", },
+	{ },
+};
+
+static struct of_platform_driver pmc_driver = {
+	.driver.name = "mpc85xx-pmc",
+	.match_table = pmc_ids,
+	.probe = pmc_probe,
+};
+
+static int pmc_init(void)
+{
+	return of_register_platform_driver(&pmc_driver);
+}
+device_initcall(pmc_init);