[U-Boot] [PATCH v2 32/50] x86: sysreset: Implement power-off if available

Bin Meng bmeng.cn at gmail.com
Wed May 1 14:50:15 UTC 2019


Hi Simon,

On Fri, Apr 26, 2019 at 12:00 PM Simon Glass <sjg at chromium.org> wrote:
>
> On modern x86 devices we can power the system off using the power-
> management features of the PCH. Add an implementation for this.
>
> Signed-off-by: Simon Glass <sjg at chromium.org>
> ---
>
> Changes in v2:
> - Add new patch to implement power-off if available
>
>  drivers/sysreset/sysreset_x86.c | 82 +++++++++++++++++++++++++++++++++
>  1 file changed, 82 insertions(+)
>
> diff --git a/drivers/sysreset/sysreset_x86.c b/drivers/sysreset/sysreset_x86.c
> index d484ec5de49..bd759aa8bf4 100644
> --- a/drivers/sysreset/sysreset_x86.c
> +++ b/drivers/sysreset/sysreset_x86.c
> @@ -7,14 +7,80 @@
>
>  #include <common.h>
>  #include <dm.h>
> +#include <pch.h>
>  #include <sysreset.h>
>  #include <asm/io.h>
>  #include <asm/processor.h>
>  #include <efi_loader.h>
>
> +struct x86_sysreset_platdata {
> +       struct udevice *pch;
> +};
> +
> +#define   PWRBTN_STS   (1 << 8)
> +
> +#define   SLP_EN       (1 << 13)
> +#define   SLP_TYP      (7 << 10)
> +#define    SLP_TYP_S5  7
> +

There are macros from acpi_s3.h that can be used directly here.

> +/*
> + * Power down the machine by using the power management sleep control
> + * of the chipset. This will currently only work on Intel chipsets.
> + * However, adapting it to new chipsets is fairly simple. You will
> + * have to find the IO address of the power management register block
> + * in your southbridge, and look up the appropriate SLP_TYP_S5 value
> + * from your southbridge's data sheet.
> + *
> + * This function never returns.
> + */
> +int pch_sysreset_power_off(struct udevice *dev)
> +{
> +       struct x86_sysreset_platdata *plat = dev_get_platdata(dev);
> +       struct pch_pmbase_info pm;
> +       u32 reg32;
> +       int ret;
> +
> +       if (!plat->pch)
> +               return -ENOENT;
> +       ret = pch_ioctl(plat->pch, PCH_REQ_PMBASE_INFO, &pm, sizeof(pm));
> +       if (ret)
> +               return ret;
> +
> +
> +       /* Mask interrupts or system might stay in a coma

nits: wrong multi-line comment format

> +        * (not executing code anymore, but not powered off either)
> +        */
> +       asm("cli");
> +
> +       /*
> +        * Avoid any GPI waking the system from S5* or the system might stay in
> +        * a coma
> +        */
> +       outl(0x00000000, pm.base + pm.gpio0_en_ofs);
> +
> +       /* Clear Power Button Status */
> +       outw(PWRBTN_STS, pm.base + pm.pm1_sts_ofs);
> +
> +       /* PMBASE + 4, Bit 10-12, Sleeping Type, * set to 111 -> S5, soft_off */
> +       reg32 = inl(pm.base + pm.pm1_cnt_ofs);
> +
> +       /* Set Sleeping Type to S5 (poweroff) */
> +       reg32 &= ~(SLP_EN | SLP_TYP);
> +       reg32 |= SLP_TYP_S5;
> +       outl(reg32, pm.base + pm.pm1_cnt_ofs);
> +
> +       /* Now set the Sleep Enable bit */
> +       reg32 |= SLP_EN;
> +       outl(reg32, pm.base + pm.pm1_cnt_ofs);
> +
> +       for (;;)
> +               asm("hlt");
> +}
> +
>  static int x86_sysreset_request(struct udevice *dev, enum sysreset_t type)
>  {
>         int value;
> +       int ret;
>
>         switch (type) {
>         case SYSRESET_WARM:
> @@ -23,6 +89,11 @@ static int x86_sysreset_request(struct udevice *dev, enum sysreset_t type)
>         case SYSRESET_COLD:
>                 value = SYS_RST | RST_CPU | FULL_RST;
>                 break;
> +       case SYSRESET_POWER_OFF:
> +               ret = pch_sysreset_power_off(dev);
> +               if (ret)
> +                       return ret;
> +               return -EINPROGRESS;
>         default:
>                 return -ENOSYS;
>         }
> @@ -57,6 +128,15 @@ void __efi_runtime EFIAPI efi_reset_system(
>  }
>  #endif
>
> +static int x86_sysreset_probe(struct udevice *dev)
> +{
> +       struct x86_sysreset_platdata *plat = dev_get_platdata(dev);
> +
> +       /* Locate the PCH if there is one. It isn't essential */
> +       uclass_first_device(UCLASS_PCH, &plat->pch);
> +
> +       return 0;
> +}
>
>  static const struct udevice_id x86_sysreset_ids[] = {
>         { .compatible = "x86,reset" },
> @@ -72,4 +152,6 @@ U_BOOT_DRIVER(x86_sysreset) = {
>         .id = UCLASS_SYSRESET,
>         .of_match = x86_sysreset_ids,
>         .ops = &x86_sysreset_ops,
> +       .probe = x86_sysreset_probe,
> +       .platdata_auto_alloc_size       = sizeof(struct x86_sysreset_platdata),
>  };
> --

Other than above two,
Reviewed-by: Bin Meng <bmeng.cn at gmail.com>

Regards,
Bin


More information about the U-Boot mailing list