Re: [PATCH v2 13/14] power: reset: Add Intel PIIX4 poweroff driver

2016-09-19 Thread Sebastian Reichel
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 
> 
> ---
> 
> 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 000..11f0999
> --- /dev/null
> +++ b/drivers/power/reset/piix4-poweroff.c
> @@ -0,0 +1,104 @@
> +/*
> + * Copyright (C) 2016 Imagination Technologies
> + * Author: Paul Burton 
> + *
> + * 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 
> +#include 
> +#include 
> +#include 
> +#include 
> +
> +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");
> +   

Re: [PATCH v2 13/14] power: reset: Add Intel PIIX4 poweroff driver

2016-09-19 Thread Sebastian Reichel
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 
> 
> ---
> 
> 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 000..11f0999
> --- /dev/null
> +++ b/drivers/power/reset/piix4-poweroff.c
> @@ -0,0 +1,104 @@
> +/*
> + * Copyright (C) 2016 Imagination Technologies
> + * Author: Paul Burton 
> + *
> + * 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 
> +#include 
> +#include 
> +#include 
> +#include 
> +
> +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,