[PATCH 2/2] MIPS: Malta: support powering down

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch makes the mips_machine_halt function (used as _machine_halt &
pm_power_off) actually power down the Malta via the PIIX4. It may then
be powered back up by pressing the "ON/NMI" button (S4) on the board.

Tested-by: James Hogan <james.hogan@xxxxxxxxxx>
Signed-off-by: Paul Burton <paul.burton@xxxxxxxxxx>
---
 arch/mips/include/asm/mips-boards/piix4.h |  9 ++++
 arch/mips/mti-malta/malta-reset.c         | 71 +++++++++++++++++++++++++++++--
 arch/mips/pci/fixup-malta.c               |  6 +++
 3 files changed, 83 insertions(+), 3 deletions(-)

diff --git a/arch/mips/include/asm/mips-boards/piix4.h b/arch/mips/include/asm/mips-boards/piix4.h
index 9cf5404..a44faf4 100644
--- a/arch/mips/include/asm/mips-boards/piix4.h
+++ b/arch/mips/include/asm/mips-boards/piix4.h
@@ -55,4 +55,13 @@
 #define PIIX4_FUNC3_PMREGMISC			0x80
 #define   PIIX4_FUNC3_PMREGMISC_EN			(1 << 0)
 
+/* Power Management IO Space */
+#define PIIX4_FUNC3IO_PMSTS			0x00
+#define   PIIX4_FUNC3IO_PMSTS_PWRBTN_STS		(1 << 8)
+#define PIIX4_FUNC3IO_PMCNTRL			0x04
+#define   PIIX4_FUNC3IO_PMCNTRL_SUS_EN			(1 << 13)
+
+/* Data for magic special PCI cycle */
+#define PIIX4_SUSPEND_MAGIC			0x00120002
+
 #endif /* __ASM_MIPS_BOARDS_PIIX4_H */
diff --git a/arch/mips/mti-malta/malta-reset.c b/arch/mips/mti-malta/malta-reset.c
index d627d4b..ef04c8b 100644
--- a/arch/mips/mti-malta/malta-reset.c
+++ b/arch/mips/mti-malta/malta-reset.c
@@ -6,10 +6,13 @@
  * Carsten Langgaard, carstenl@xxxxxxxx
  * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
  */
+#include <linux/delay.h>
 #include <linux/io.h>
+#include <linux/pci.h>
 #include <linux/pm.h>
 
 #include <asm/reboot.h>
+#include <asm/mips-boards/piix4.h>
 
 #define SOFTRES_REG	0x1f000500
 #define GORESET		0x42
@@ -24,10 +27,72 @@ static void mips_machine_restart(char *command)
 
 static void mips_machine_halt(void)
 {
-	unsigned int __iomem *softres_reg =
-		ioremap(SOFTRES_REG, sizeof(unsigned int));
+	struct pci_bus *bus;
+	struct pci_dev *dev;
+	int spec_devid, res;
+	int io_region = PCI_BRIDGE_RESOURCES;
+	resource_size_t io;
+	u16 sts;
 
-	__raw_writel(GORESET, softres_reg);
+	/* Find the PIIX4 PM device */
+	dev = pci_get_subsys(PCI_VENDOR_ID_INTEL,
+			     PCI_DEVICE_ID_INTEL_82371AB_3, PCI_ANY_ID,
+			     PCI_ANY_ID, NULL);
+	if (!dev) {
+		printk("Failed to find PIIX4 PM\n");
+		goto fail;
+	}
+
+	/* Request access to the PIIX4 PM IO registers */
+	res = pci_request_region(dev, io_region, "PIIX4 PM IO registers");
+	if (res) {
+		printk("Failed to request PIIX4 PM IO registers (%d)\n", res);
+		goto fail_dev_put;
+	}
+
+	/* Find the offset to the PIIX4 PM IO registers */
+	io = pci_resource_start(dev, io_region);
+
+	/* Ensure the power button status is clear */
+	while (1) {
+		sts = inw(io + PIIX4_FUNC3IO_PMSTS);
+		if (!(sts & PIIX4_FUNC3IO_PMSTS_PWRBTN_STS))
+			break;
+		outw(sts, io + PIIX4_FUNC3IO_PMSTS);
+	}
+
+	/* Enable entry to suspend */
+	outw(PIIX4_FUNC3IO_PMCNTRL_SUS_EN, io + PIIX4_FUNC3IO_PMCNTRL);
+
+	/* If the special cycle occurs too soon this doesn't work... */
+	mdelay(10);
+
+	/* Find a reference to the PCI bus */
+	bus = pci_find_next_bus(NULL);
+	if (!bus) {
+		printk("Failed to find PCI bus\n");
+		goto fail_release_region;
+	}
+
+	/*
+	 * The PIIX4 will enter the suspend state only after seeing a special
+	 * cycle with the correct magic data on the PCI bus. Generate that
+	 * cycle now.
+	 */
+	spec_devid = PCI_DEVID(0, PCI_DEVFN(0x1f, 0x7));
+	pci_bus_write_config_dword(bus, spec_devid, 0, PIIX4_SUSPEND_MAGIC);
+
+	/* Give the system some time to power down */
+	mdelay(1000);
+
+	/* If all went well this will never execute */
+fail_release_region:
+	pci_release_region(dev, io_region);
+fail_dev_put:
+	pci_dev_put(dev);
+fail:
+	printk("Failed to power down, resetting\n");
+	mips_machine_restart(NULL);
 }
 
 static int __init mips_reboot_setup(void)
diff --git a/arch/mips/pci/fixup-malta.c b/arch/mips/pci/fixup-malta.c
index 2f9e52a..40e920c 100644
--- a/arch/mips/pci/fixup-malta.c
+++ b/arch/mips/pci/fixup-malta.c
@@ -68,6 +68,7 @@ static void malta_piix_func0_fixup(struct pci_dev *pdev)
 {
 	unsigned char reg_val;
 	u32 reg_val32;
+	u16 reg_val16;
 	/* PIIX PIRQC[A:D] irq mappings */
 	static int piixirqmap[PIIX4_FUNC0_PIRQRC_IRQ_ROUTING_MAX] = {
 		0,  0,	0,  3,
@@ -107,6 +108,11 @@ static void malta_piix_func0_fixup(struct pci_dev *pdev)
 	pci_read_config_byte(pdev, PIIX4_FUNC0_SERIRQC, &reg_val);
 	reg_val |= PIIX4_FUNC0_SERIRQC_EN | PIIX4_FUNC0_SERIRQC_CONT;
 	pci_write_config_byte(pdev, PIIX4_FUNC0_SERIRQC, reg_val);
+
+	/* Enable response to special cycles */
+	pci_read_config_word(pdev, PCI_COMMAND, &reg_val16);
+	pci_write_config_word(pdev, PCI_COMMAND,
+			      reg_val16 | PCI_COMMAND_SPECIAL);
 }
 
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0,
-- 
1.8.5.3



[Index of Archives]     [Linux MIPS Home]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Linux]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux