diff mbox series

[U-Boot,28/40] x86: Add a sysreset driver for the Intel PCH

Message ID 20190130035935.235565-29-sjg@chromium.org
State Superseded
Delegated to: Bin Meng
Headers show
Series x86: Add support for booting from TPL | expand

Commit Message

Simon Glass Jan. 30, 2019, 3:59 a.m. UTC
Intel SoCs support a fairly stardard reset mechanism which can support
powering off the device. Add support for this and enable it by default on
broadwell, which already has the necessary pm.h header file.

This driver augments the standard x86 sysreset driver.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 arch/x86/cpu/broadwell/Kconfig        |   1 +
 drivers/sysreset/Kconfig              |   9 ++
 drivers/sysreset/Makefile             |   1 +
 drivers/sysreset/sysreset_intel_pch.c | 125 ++++++++++++++++++++++++++
 4 files changed, 136 insertions(+)
 create mode 100644 drivers/sysreset/sysreset_intel_pch.c

Comments

Bin Meng Feb. 22, 2019, 7:19 a.m. UTC | #1
Hi Simon,

On Wed, Jan 30, 2019 at 12:00 PM Simon Glass <sjg@chromium.org> wrote:
>
> Intel SoCs support a fairly stardard reset mechanism which can support
> powering off the device. Add support for this and enable it by default on
> broadwell, which already has the necessary pm.h header file.
>
> This driver augments the standard x86 sysreset driver.
>

I think we need update the existing sysreset_x86 driver to support
SYSRESET_POWER_OFF, instead of creating a new driver to do such.

We can add a new PCH ioctl code to get the pmbase, and do the ACPI
power off in the sysreset_x86 driver.

> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
>
>  arch/x86/cpu/broadwell/Kconfig        |   1 +
>  drivers/sysreset/Kconfig              |   9 ++
>  drivers/sysreset/Makefile             |   1 +
>  drivers/sysreset/sysreset_intel_pch.c | 125 ++++++++++++++++++++++++++
>  4 files changed, 136 insertions(+)
>  create mode 100644 drivers/sysreset/sysreset_intel_pch.c
>

Regards,
Bin
Simon Glass April 3, 2019, 2:22 a.m. UTC | #2
Hi Bin,

On Fri, 22 Feb 2019 at 00:20, Bin Meng <bmeng.cn@gmail.com> wrote:
>
> Hi Simon,
>
> On Wed, Jan 30, 2019 at 12:00 PM Simon Glass <sjg@chromium.org> wrote:
> >
> > Intel SoCs support a fairly stardard reset mechanism which can support
> > powering off the device. Add support for this and enable it by default on
> > broadwell, which already has the necessary pm.h header file.
> >
> > This driver augments the standard x86 sysreset driver.
> >
>
> I think we need update the existing sysreset_x86 driver to support
> SYSRESET_POWER_OFF, instead of creating a new driver to do such.
>
> We can add a new PCH ioctl code to get the pmbase, and do the ACPI
> power off in the sysreset_x86 driver.

So are you saying that the registers are the same for all x86 chips?
From what I can tell, the offsets vary.

Regards,
Simon

>
> > Signed-off-by: Simon Glass <sjg@chromium.org>
> > ---
> >
> >  arch/x86/cpu/broadwell/Kconfig        |   1 +
> >  drivers/sysreset/Kconfig              |   9 ++
> >  drivers/sysreset/Makefile             |   1 +
> >  drivers/sysreset/sysreset_intel_pch.c | 125 ++++++++++++++++++++++++++
> >  4 files changed, 136 insertions(+)
> >  create mode 100644 drivers/sysreset/sysreset_intel_pch.c
> >
>
> Regards,
> Bin
Bin Meng April 3, 2019, 8:42 a.m. UTC | #3
Hi Simon,

On Wed, Apr 3, 2019 at 10:22 AM Simon Glass <sjg@chromium.org> wrote:
>
> Hi Bin,
>
> On Fri, 22 Feb 2019 at 00:20, Bin Meng <bmeng.cn@gmail.com> wrote:
> >
> > Hi Simon,
> >
> > On Wed, Jan 30, 2019 at 12:00 PM Simon Glass <sjg@chromium.org> wrote:
> > >
> > > Intel SoCs support a fairly stardard reset mechanism which can support
> > > powering off the device. Add support for this and enable it by default on
> > > broadwell, which already has the necessary pm.h header file.
> > >
> > > This driver augments the standard x86 sysreset driver.
> > >
> >
> > I think we need update the existing sysreset_x86 driver to support
> > SYSRESET_POWER_OFF, instead of creating a new driver to do such.
> >
> > We can add a new PCH ioctl code to get the pmbase, and do the ACPI
> > power off in the sysreset_x86 driver.
>
> So are you saying that the registers are the same for all x86 chips?
> From what I can tell, the offsets vary.

Yes, the offsets might be different, so instead of getting only the
pmbase, we need do something like getting ACPI PM register block
information from the PCH driver. That's how acpi_create_fadt() passes
ACPI register block information to the OS.

Regards,
Bin
Simon Glass April 6, 2019, 2:02 a.m. UTC | #4
Hi Bin,

On Wed, 3 Apr 2019 at 02:42, Bin Meng <bmeng.cn@gmail.com> wrote:
>
> Hi Simon,
>
> On Wed, Apr 3, 2019 at 10:22 AM Simon Glass <sjg@chromium.org> wrote:
> >
> > Hi Bin,
> >
> > On Fri, 22 Feb 2019 at 00:20, Bin Meng <bmeng.cn@gmail.com> wrote:
> > >
> > > Hi Simon,
> > >
> > > On Wed, Jan 30, 2019 at 12:00 PM Simon Glass <sjg@chromium.org> wrote:
> > > >
> > > > Intel SoCs support a fairly stardard reset mechanism which can support
> > > > powering off the device. Add support for this and enable it by default on
> > > > broadwell, which already has the necessary pm.h header file.
> > > >
> > > > This driver augments the standard x86 sysreset driver.
> > > >
> > >
> > > I think we need update the existing sysreset_x86 driver to support
> > > SYSRESET_POWER_OFF, instead of creating a new driver to do such.
> > >
> > > We can add a new PCH ioctl code to get the pmbase, and do the ACPI
> > > power off in the sysreset_x86 driver.
> >
> > So are you saying that the registers are the same for all x86 chips?
> > From what I can tell, the offsets vary.
>
> Yes, the offsets might be different, so instead of getting only the
> pmbase, we need do something like getting ACPI PM register block
> information from the PCH driver. That's how acpi_create_fadt() passes
> ACPI register block information to the OS.

That doesn't make a lot of sense to me. If the register layout is
different, why not just use different drivers?

I suppose we could put the common code (with parameters) in a separate
file and call it from the driver. The parameters would presumably be:

PMBASE
GPE0_EN(0)
PM1_STS
PM1_CNT

Regards,
Simon
Bin Meng April 6, 2019, 1:26 p.m. UTC | #5
Hi Simon,

On Sat, Apr 6, 2019 at 10:02 AM Simon Glass <sjg@chromium.org> wrote:
>
> Hi Bin,
>
> On Wed, 3 Apr 2019 at 02:42, Bin Meng <bmeng.cn@gmail.com> wrote:
> >
> > Hi Simon,
> >
> > On Wed, Apr 3, 2019 at 10:22 AM Simon Glass <sjg@chromium.org> wrote:
> > >
> > > Hi Bin,
> > >
> > > On Fri, 22 Feb 2019 at 00:20, Bin Meng <bmeng.cn@gmail.com> wrote:
> > > >
> > > > Hi Simon,
> > > >
> > > > On Wed, Jan 30, 2019 at 12:00 PM Simon Glass <sjg@chromium.org> wrote:
> > > > >
> > > > > Intel SoCs support a fairly stardard reset mechanism which can support
> > > > > powering off the device. Add support for this and enable it by default on
> > > > > broadwell, which already has the necessary pm.h header file.
> > > > >
> > > > > This driver augments the standard x86 sysreset driver.
> > > > >
> > > >
> > > > I think we need update the existing sysreset_x86 driver to support
> > > > SYSRESET_POWER_OFF, instead of creating a new driver to do such.
> > > >
> > > > We can add a new PCH ioctl code to get the pmbase, and do the ACPI
> > > > power off in the sysreset_x86 driver.
> > >
> > > So are you saying that the registers are the same for all x86 chips?
> > > From what I can tell, the offsets vary.
> >
> > Yes, the offsets might be different, so instead of getting only the
> > pmbase, we need do something like getting ACPI PM register block
> > information from the PCH driver. That's how acpi_create_fadt() passes
> > ACPI register block information to the OS.
>
> That doesn't make a lot of sense to me. If the register layout is
> different, why not just use different drivers?
>

Yes, the register layout might be different but the programming model
is the same and well defined in the ACPI spec.

> I suppose we could put the common code (with parameters) in a separate
> file and call it from the driver. The parameters would presumably be:
>
> PMBASE
> GPE0_EN(0)
> PM1_STS
> PM1_CNT

That's why I suggest to ask PCH driver to provide these offsets in a
struct via an ioctl call to the sysreset driver.

Regards,
Bin
diff mbox series

Patch

diff --git a/arch/x86/cpu/broadwell/Kconfig b/arch/x86/cpu/broadwell/Kconfig
index 5b015c89d9..2955ffc55b 100644
--- a/arch/x86/cpu/broadwell/Kconfig
+++ b/arch/x86/cpu/broadwell/Kconfig
@@ -18,6 +18,7 @@  config INTEL_BROADWELL
 	imply USB
 	imply USB_EHCI_HCD
 	imply VIDEO_BROADWELL_IGD
+	imply SYSRESET_INTEL_PCH
 
 if INTEL_BROADWELL
 
diff --git a/drivers/sysreset/Kconfig b/drivers/sysreset/Kconfig
index 8ce3e2e207..f88412adcc 100644
--- a/drivers/sysreset/Kconfig
+++ b/drivers/sysreset/Kconfig
@@ -23,6 +23,15 @@  config SYSRESET_GPIO
 	  example on Microblaze where reset logic can be controlled via GPIO
 	  pin which triggers cpu reset.
 
+config SYSRESET_INTEL_PCH
+	bool "Enable support for Intel PCH reset driver"
+	depends on X86
+	help
+	  Enable this option to get reset support on Intel SoCs which have
+	  a common Platform-Controller Hub (PCH). This driver supports powering
+	  off the device. It augments the standard x86 sysreset driver which
+	  provides normal reset options.
+
 config SYSRESET_MICROBLAZE
 	bool "Enable support for Microblaze soft reset"
 	depends on MICROBLAZE
diff --git a/drivers/sysreset/Makefile b/drivers/sysreset/Makefile
index b3728ac17f..2add6cb37a 100644
--- a/drivers/sysreset/Makefile
+++ b/drivers/sysreset/Makefile
@@ -8,6 +8,7 @@  obj-$(CONFIG_ARCH_ROCKCHIP) += sysreset_rockchip.o
 obj-$(CONFIG_ARCH_STI) += sysreset_sti.o
 obj-$(CONFIG_SANDBOX) += sysreset_sandbox.o
 obj-$(CONFIG_SYSRESET_GPIO) += sysreset_gpio.o
+obj-$(CONFIG_SYSRESET_INTEL_PCH) += sysreset_intel_pch.o
 obj-$(CONFIG_SYSRESET_MCP83XX) += sysreset_mpc83xx.o
 obj-$(CONFIG_SYSRESET_MICROBLAZE) += sysreset_microblaze.o
 obj-$(CONFIG_SYSRESET_PSCI) += sysreset_psci.o
diff --git a/drivers/sysreset/sysreset_intel_pch.c b/drivers/sysreset/sysreset_intel_pch.c
new file mode 100644
index 0000000000..b60fa40dda
--- /dev/null
+++ b/drivers/sysreset/sysreset_intel_pch.c
@@ -0,0 +1,125 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Google Inc,
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * Reset driver for intel x86 processors with a PCH. Supports powering the
+ * device off.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <sysreset.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <asm/arch/pch.h>
+#include <asm/arch/pm.h>
+
+struct x86_reset_platdata {
+	struct udevice *pch;
+};
+
+/*
+ * 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_reset_platdata *plat = dev_get_platdata(dev);
+	u16 pmbase;
+	u32 reg32;
+	int ret;
+
+	if (!plat->pch)
+		return -ENOENT;
+
+	/* Find the base address of the powermanagement registers */
+	ret = dm_pci_read_config16(plat->pch, 0x40, &pmbase);
+	if (ret)
+		return ret;
+
+	pmbase &= 0xfffe;
+
+	/* Mask interrupts or system might stay in a coma
+	 * (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, pmbase + GPE0_EN(0));
+
+	/* Clear Power Button Status */
+	outw(PWRBTN_STS, pmbase + PM1_STS);
+
+	/* PMBASE + 4, Bit 10-12, Sleeping Type, * set to 111 -> S5, soft_off */
+	reg32 = inl(pmbase + PM1_CNT);
+
+	/* Set Sleeping Type to S5 (poweroff) */
+	reg32 &= ~(SLP_EN | SLP_TYP);
+	reg32 |= SLP_TYP_S5;
+	outl(reg32, pmbase + PM1_CNT);
+
+	/* Now set the Sleep Enable bit */
+	reg32 |= SLP_EN;
+	outl(reg32, pmbase + PM1_CNT);
+
+	for (;;)
+		asm("hlt");
+}
+
+static int pch_sysreset_request(struct udevice *dev, enum sysreset_t type)
+{
+	int ret;
+
+	switch (type) {
+	case SYSRESET_POWER_OFF:
+		ret = pch_sysreset_power_off(dev);
+		if (ret)
+			return ret;
+		break;
+	default:
+		return -ENOSYS;
+	}
+
+	return -EINPROGRESS;
+}
+
+static int pch_sysreset_ofdata_to_platdata(struct udevice *dev)
+{
+	struct x86_reset_platdata *plat = dev_get_platdata(dev);
+	int ret;
+
+	ret = uclass_get_device_by_phandle(UCLASS_PCH, dev, "intel,pch",
+					   &plat->pch);
+	if (ret && ret != -ENOENT)
+		return log_ret(ret);
+
+	return 0;
+}
+
+static const struct udevice_id pch_sysreset_ids[] = {
+	{ .compatible = "intel,pch-reset" },
+	{ }
+};
+
+static struct sysreset_ops pch_sysreset_ops = {
+	.request = pch_sysreset_request,
+};
+
+U_BOOT_DRIVER(pch_sysreset) = {
+	.name = "pch-sysreset",
+	.id = UCLASS_SYSRESET,
+	.of_match = pch_sysreset_ids,
+	.ops = &pch_sysreset_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+	.ofdata_to_platdata	= pch_sysreset_ofdata_to_platdata,
+};