lkml.org 
[lkml]   [2016]   [Sep]   [19]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    Date
    From
    SubjectRe: [PATCH v2 13/14] power: reset: Add Intel PIIX4 poweroff driver
    Hi,

    On Mon, Sep 19, 2016 at 10:21:30PM +0100, Paul Burton wrote:
    > Add a driver which allows powering off the system via an Intel PIIX4
    > southbridge, by entering the PIIX4 SOff state. This is useful on the
    > MIPS Malta development board, where it will power down the FPGA based
    > board until its ON/NMI button is pressed, or the QEMU implementation of
    > the MIPS Malta board where it will cause QEMU to exit.
    >
    > Signed-off-by: Paul Burton <paul.burton@imgtec.com>
    >
    > ---
    >
    > Changes in v2:
    > - Add MODULE_LICENSE
    > - Allow non-MIPS builds with COMPILE_TEST
    >
    > drivers/power/reset/Kconfig | 10 ++++
    > drivers/power/reset/Makefile | 1 +
    > drivers/power/reset/piix4-poweroff.c | 104 +++++++++++++++++++++++++++++++++++
    > 3 files changed, 115 insertions(+)
    > create mode 100644 drivers/power/reset/piix4-poweroff.c
    >
    > diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
    > index c74c3f6..abeb772 100644
    > --- a/drivers/power/reset/Kconfig
    > +++ b/drivers/power/reset/Kconfig
    > @@ -104,6 +104,16 @@ config POWER_RESET_MSM
    > help
    > Power off and restart support for Qualcomm boards.
    >
    > +config POWER_RESET_PIIX4_POWEROFF
    > + tristate "Intel PIIX4 power-off driver"
    > + depends on PCI
    > + depends on MIPS || COMPILE_TEST
    > + help
    > + This driver supports powering off a system using the Intel PIIX4
    > + southbridge, for example the MIPS Malta development board. The
    > + southbridge SOff state is entered in response to a request to
    > + power off the system.
    > +
    > config POWER_RESET_LTC2952
    > bool "LTC2952 PowerPath power-off driver"
    > depends on OF_GPIO
    > diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
    > index 1be307c..11dae3b 100644
    > --- a/drivers/power/reset/Makefile
    > +++ b/drivers/power/reset/Makefile
    > @@ -10,6 +10,7 @@ obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o
    > obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o
    > obj-$(CONFIG_POWER_RESET_IMX) += imx-snvs-poweroff.o
    > obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o
    > +obj-$(CONFIG_POWER_RESET_PIIX4_POWEROFF) += piix4-poweroff.o
    > obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o
    > obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o
    > obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o
    > diff --git a/drivers/power/reset/piix4-poweroff.c b/drivers/power/reset/piix4-poweroff.c
    > new file mode 100644
    > index 0000000..11f0999
    > --- /dev/null
    > +++ b/drivers/power/reset/piix4-poweroff.c
    > @@ -0,0 +1,104 @@
    > +/*
    > + * Copyright (C) 2016 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/io.h>
    > +#include <linux/module.h>
    > +#include <linux/pci.h>
    > +#include <linux/pm.h>
    > +
    > +static struct pci_dev *pm_dev;
    > +static resource_size_t io_offset;
    > +
    > +enum piix4_pm_io_reg {
    > + PIIX4_FUNC3IO_PMSTS = 0x00,
    > +#define PIIX4_FUNC3IO_PMSTS_PWRBTN_STS BIT(8)
    > + PIIX4_FUNC3IO_PMCNTRL = 0x04,
    > +#define PIIX4_FUNC3IO_PMCNTRL_SUS_EN BIT(13)
    > +#define PIIX4_FUNC3IO_PMCNTRL_SUS_TYP_SOFF (0x0 << 10)
    > +};
    > +
    > +#define PIIX4_SUSPEND_MAGIC 0x00120002
    > +
    > +static void piix4_poweroff(void)
    > +{
    > + int spec_devid;
    > + u16 sts;
    > +
    > + /* Ensure the power button status is clear */
    > + while (1) {
    > + sts = inw(io_offset + PIIX4_FUNC3IO_PMSTS);
    > + if (!(sts & PIIX4_FUNC3IO_PMSTS_PWRBTN_STS))
    > + break;
    > + outw(sts, io_offset + PIIX4_FUNC3IO_PMSTS);
    > + }
    > +
    > + /* Enable entry to suspend */
    > + outw(PIIX4_FUNC3IO_PMCNTRL_SUS_TYP_SOFF | PIIX4_FUNC3IO_PMCNTRL_SUS_EN,
    > + 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_dev->bus, spec_devid, 0,
    > + PIIX4_SUSPEND_MAGIC);
    > +
    > + /* Give the system some time to power down, then error */
    > + mdelay(1000);
    > + pr_emerg("Unable to poweroff system\n");
    > +}
    > +
    > +static int piix4_poweroff_probe(struct pci_dev *dev,
    > + const struct pci_device_id *id)
    > +{
    > + int res, io_region = PCI_BRIDGE_RESOURCES;

    if (pm_dev)
    return -EINVAL;

    > + /* Request access to the PIIX4 PM IO registers */
    > + res = pci_request_region(dev, io_region, "PIIX4 PM IO registers");
    > + if (res) {
    > + dev_err(&dev->dev, "failed to request PM IO registers: %d\n",
    > + res);
    > + return res;
    > + }
    > +
    > + pm_dev = dev;
    > + io_offset = pci_resource_start(dev, io_region);
    > + pm_power_off = piix4_poweroff;
    > +
    > + return 0;
    > +}
    > +
    > +static void piix4_poweroff_remove(struct pci_dev *dev)
    > +{
    > + if (pm_power_off == piix4_poweroff)
    > + pm_power_off = NULL;

    pci_release_region()

    > +}
    > +
    > +static const struct pci_device_id piix4_poweroff_ids[] = {
    > + { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) },
    > + { 0 },
    > +};
    > +
    > +static struct pci_driver piix4_poweroff_driver = {
    > + .name = "piix4-poweroff",
    > + .id_table = piix4_poweroff_ids,
    > + .probe = piix4_poweroff_probe,
    > + .remove = piix4_poweroff_remove,
    > +};
    > +
    > +module_pci_driver(piix4_poweroff_driver);
    > +MODULE_AUTHOR("Paul Burton <paul.burton@imgtec.com>");
    > +MODULE_LICENSE("GPL");

    -- Sebastian
    [unhandled content-type:application/pgp-signature]
    \
     
     \ /
      Last update: 2016-09-20 01:43    [W:4.247 / U:0.172 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site