diff options
author | Paul Burton <paul.burton@imgtec.com> | 2014-05-07 12:20:57 +0100 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2014-05-30 21:01:09 +0200 |
commit | b6911bba598f5d611f7fdbb87b5af7f1712dbe9d (patch) | |
tree | 8d19951428748909cd508251ebce1d1a5e2cf6ec /arch/mips/mti-malta | |
parent | 643c5705bc9d30b64ca320715eb210b853d1f27e (diff) |
MIPS: Malta: add suspend state entry code
This patch introduces code which will enter a suspend state via the
PIIX4. This can only be done when PCI support is enabled since it
requires access to PCI I/O space and the generation of a special cycle
on the PCI bus. In cases where PCI is disabled the mips_pm_suspend
function will simply always return an error.
Signed-off-by: Paul Burton <paul.burton@imgtec.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/6905/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/mti-malta')
-rw-r--r-- | arch/mips/mti-malta/Makefile | 2 | ||||
-rw-r--r-- | arch/mips/mti-malta/malta-pm.c | 96 |
2 files changed, 98 insertions, 0 deletions
diff --git a/arch/mips/mti-malta/Makefile b/arch/mips/mti-malta/Makefile index a8516013790..b9510ea8db5 100644 --- a/arch/mips/mti-malta/Makefile +++ b/arch/mips/mti-malta/Makefile @@ -8,3 +8,5 @@ obj-y := malta-amon.o malta-display.o malta-init.o \ malta-int.o malta-memory.o malta-platform.o \ malta-reset.o malta-setup.o malta-time.o + +obj-$(CONFIG_MIPS_MALTA_PM) += malta-pm.o diff --git a/arch/mips/mti-malta/malta-pm.c b/arch/mips/mti-malta/malta-pm.c new file mode 100644 index 00000000000..c1e456c01a4 --- /dev/null +++ b/arch/mips/mti-malta/malta-pm.c @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2014 Imagination Technologies + * Author: Paul Burton <paul.burton@imgtec.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/delay.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/pci.h> + +#include <asm/mach-malta/malta-pm.h> + +static struct pci_bus *pm_pci_bus; +static resource_size_t pm_io_offset; + +int mips_pm_suspend(unsigned state) +{ + int spec_devid; + u16 sts; + + if (!pm_pci_bus || !pm_io_offset) + return -ENODEV; + + /* Ensure the power button status is clear */ + while (1) { + sts = inw(pm_io_offset + PIIX4_FUNC3IO_PMSTS); + if (!(sts & PIIX4_FUNC3IO_PMSTS_PWRBTN_STS)) + break; + outw(sts, pm_io_offset + PIIX4_FUNC3IO_PMSTS); + } + + /* Enable entry to suspend */ + outw(state | PIIX4_FUNC3IO_PMCNTRL_SUS_EN, + pm_io_offset + PIIX4_FUNC3IO_PMCNTRL); + + /* If the special cycle occurs too soon this doesn't work... */ + mdelay(10); + + /* + * 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(pm_pci_bus, spec_devid, 0, + PIIX4_SUSPEND_MAGIC); + + /* Give the system some time to power down */ + mdelay(1000); + + return 0; +} + +static int __init malta_pm_setup(void) +{ + struct pci_dev *dev; + int res, io_region = PCI_BRIDGE_RESOURCES; + + /* Find a reference to the PCI bus */ + pm_pci_bus = pci_find_next_bus(NULL); + if (!pm_pci_bus) { + pr_warn("malta-pm: failed to find reference to PCI bus\n"); + return -ENODEV; + } + + /* 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) { + pr_warn("malta-pm: failed to find PIIX4 PM\n"); + return -ENODEV; + } + + /* Request access to the PIIX4 PM IO registers */ + res = pci_request_region(dev, io_region, "PIIX4 PM IO registers"); + if (res) { + pr_warn("malta-pm: failed to request PM IO registers (%d)\n", + res); + pci_dev_put(dev); + return -ENODEV; + } + + /* Find the offset to the PIIX4 PM IO registers */ + pm_io_offset = pci_resource_start(dev, io_region); + + pci_dev_put(dev); + return 0; +} + +late_initcall(malta_pm_setup); |