x86: broadwell: Add power-control support
authorSimon Glass <sjg@chromium.org>
Sat, 12 Mar 2016 05:07:25 +0000 (22:07 -0700)
committerBin Meng <bmeng.cn@gmail.com>
Thu, 17 Mar 2016 02:27:26 +0000 (10:27 +0800)
Broadwell requires quite a bit of power-management setup. Add code to set
this up correctly.

Signed-off-by: Simon Glass <sjg@chromium.org>
Acked-by: Bin Meng <bmeng.cn@gmail.com>
[squashed in http://patchwork.ozlabs.org/patch/598373/]
Signed-off-by: Bin Meng <bmeng.cn@gmail.com>
arch/x86/cpu/broadwell/Makefile
arch/x86/cpu/broadwell/power_state.c [new file with mode: 0644]
arch/x86/include/asm/arch-broadwell/pm.h [new file with mode: 0644]

index a542feffc714903c19fd773672e3b27688a790d5..5a62afae59b6a68d95851d6a112adeb4c79ae413 100644 (file)
@@ -10,5 +10,6 @@ obj-y += lpc.o
 obj-y += northbridge.o
 obj-y += pch.o
 obj-y += pinctrl_broadwell.o
+obj-y += power_state.o
 obj-y += refcode.o
 obj-y += sata.o
diff --git a/arch/x86/cpu/broadwell/power_state.c b/arch/x86/cpu/broadwell/power_state.c
new file mode 100644 (file)
index 0000000..2b9a6bf
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * From coreboot src/soc/intel/broadwell/romstage/power_state.c
+ *
+ * Copyright (C) 2016 Google, Inc.
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+#include <common.h>
+#include <pci.h>
+#include <asm/io.h>
+#include <asm/intel_regs.h>
+#include <asm/arch/iomap.h>
+#include <asm/arch/lpc.h>
+#include <asm/arch/pch.h>
+#include <asm/arch/pm.h>
+
+/* Return 0, 3, or 5 to indicate the previous sleep state. */
+static int prev_sleep_state(struct chipset_power_state *ps)
+{
+       /* Default to S0. */
+       int prev_sleep_state = SLEEP_STATE_S0;
+
+       if (ps->pm1_sts & WAK_STS) {
+               switch ((ps->pm1_cnt & SLP_TYP) >> SLP_TYP_SHIFT) {
+#if CONFIG_HAVE_ACPI_RESUME
+               case SLP_TYP_S3:
+                       prev_sleep_state = SLEEP_STATE_S3;
+                       break;
+#endif
+               case SLP_TYP_S5:
+                       prev_sleep_state = SLEEP_STATE_S5;
+                       break;
+               }
+               /* Clear SLP_TYP. */
+               outl(ps->pm1_cnt & ~(SLP_TYP), ACPI_BASE_ADDRESS + PM1_CNT);
+       }
+
+       if (ps->gen_pmcon3 & (PWR_FLR | SUS_PWR_FLR))
+               prev_sleep_state = SLEEP_STATE_S5;
+
+       return prev_sleep_state;
+}
+
+static void dump_power_state(struct chipset_power_state *ps)
+{
+       debug("PM1_STS:   %04x\n", ps->pm1_sts);
+       debug("PM1_EN:    %04x\n", ps->pm1_en);
+       debug("PM1_CNT:   %08x\n", ps->pm1_cnt);
+       debug("TCO_STS:   %04x %04x\n", ps->tco1_sts, ps->tco2_sts);
+
+       debug("GPE0_STS:  %08x %08x %08x %08x\n",
+             ps->gpe0_sts[0], ps->gpe0_sts[1],
+             ps->gpe0_sts[2], ps->gpe0_sts[3]);
+       debug("GPE0_EN:   %08x %08x %08x %08x\n",
+             ps->gpe0_en[0], ps->gpe0_en[1],
+             ps->gpe0_en[2], ps->gpe0_en[3]);
+
+       debug("GEN_PMCON: %04x %04x %04x\n",
+             ps->gen_pmcon1, ps->gen_pmcon2, ps->gen_pmcon3);
+
+       debug("Previous Sleep State: S%d\n",
+             ps->prev_sleep_state);
+}
+
+/* Fill power state structure from ACPI PM registers */
+void power_state_get(struct udevice *pch_dev, struct chipset_power_state *ps)
+{
+       ps->pm1_sts = inw(ACPI_BASE_ADDRESS + PM1_STS);
+       ps->pm1_en = inw(ACPI_BASE_ADDRESS + PM1_EN);
+       ps->pm1_cnt = inl(ACPI_BASE_ADDRESS + PM1_CNT);
+       ps->tco1_sts = inw(ACPI_BASE_ADDRESS + TCO1_STS);
+       ps->tco2_sts = inw(ACPI_BASE_ADDRESS + TCO2_STS);
+       ps->gpe0_sts[0] = inl(ACPI_BASE_ADDRESS + GPE0_STS(0));
+       ps->gpe0_sts[1] = inl(ACPI_BASE_ADDRESS + GPE0_STS(1));
+       ps->gpe0_sts[2] = inl(ACPI_BASE_ADDRESS + GPE0_STS(2));
+       ps->gpe0_sts[3] = inl(ACPI_BASE_ADDRESS + GPE0_STS(3));
+       ps->gpe0_en[0] = inl(ACPI_BASE_ADDRESS + GPE0_EN(0));
+       ps->gpe0_en[1] = inl(ACPI_BASE_ADDRESS + GPE0_EN(1));
+       ps->gpe0_en[2] = inl(ACPI_BASE_ADDRESS + GPE0_EN(2));
+       ps->gpe0_en[3] = inl(ACPI_BASE_ADDRESS + GPE0_EN(3));
+
+       dm_pci_read_config16(pch_dev, GEN_PMCON_1, &ps->gen_pmcon1);
+       dm_pci_read_config16(pch_dev, GEN_PMCON_2, &ps->gen_pmcon2);
+       dm_pci_read_config16(pch_dev, GEN_PMCON_3, &ps->gen_pmcon3);
+
+       ps->prev_sleep_state = prev_sleep_state(ps);
+
+       dump_power_state(ps);
+}
diff --git a/arch/x86/include/asm/arch-broadwell/pm.h b/arch/x86/include/asm/arch-broadwell/pm.h
new file mode 100644 (file)
index 0000000..36ad842
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * From coreboot src/soc/intel/broadwell/include/soc/pm.h
+ *
+ * Copyright (C) 2016 Google, Inc.
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+
+#ifndef __ASM_ARCH_PM_H
+#define __ASM_ARCH_PM_H
+
+#define PM1_STS                        0x00
+#define  WAK_STS               (1 << 15)
+#define  PCIEXPWAK_STS         (1 << 14)
+#define  PRBTNOR_STS           (1 << 11)
+#define  RTC_STS               (1 << 10)
+#define  PWRBTN_STS            (1 << 8)
+#define  GBL_STS               (1 << 5)
+#define  BM_STS                        (1 << 4)
+#define  TMROF_STS             (1 << 0)
+#define PM1_EN                 0x02
+#define  PCIEXPWAK_DIS         (1 << 14)
+#define  RTC_EN                        (1 << 10)
+#define  PWRBTN_EN             (1 << 8)
+#define  GBL_EN                        (1 << 5)
+#define  TMROF_EN              (1 << 0)
+#define PM1_CNT                        0x04
+#define  SLP_EN                        (1 << 13)
+#define  SLP_TYP               (7 << 10)
+#define   SLP_TYP_SHIFT         10
+#define   SLP_TYP_S0           0
+#define   SLP_TYP_S1           1
+#define   SLP_TYP_S3           5
+#define   SLP_TYP_S4           6
+#define   SLP_TYP_S5           7
+#define  GBL_RLS               (1 << 2)
+#define  BM_RLD                        (1 << 1)
+#define  SCI_EN                        (1 << 0)
+#define PM1_TMR                        0x08
+#define SMI_EN                 0x30
+#define  XHCI_SMI_EN           (1 << 31)
+#define  ME_SMI_EN             (1 << 30)
+#define  GPIO_UNLOCK_SMI_EN    (1 << 27)
+#define  INTEL_USB2_EN         (1 << 18)
+#define  LEGACY_USB2_EN                (1 << 17)
+#define  PERIODIC_EN           (1 << 14)
+#define  TCO_EN                        (1 << 13)
+#define  MCSMI_EN              (1 << 11)
+#define  BIOS_RLS              (1 <<  7)
+#define  SWSMI_TMR_EN          (1 <<  6)
+#define  APMC_EN               (1 <<  5)
+#define  SLP_SMI_EN            (1 <<  4)
+#define  LEGACY_USB_EN         (1 <<  3)
+#define  BIOS_EN               (1 <<  2)
+#define  EOS                   (1 <<  1)
+#define  GBL_SMI_EN            (1 <<  0)
+#define SMI_STS                        0x34
+#define UPWRC                  0x3c
+#define  UPWRC_WS              (1 << 8)
+#define  UPWRC_WE              (1 << 1)
+#define  UPWRC_SMI             (1 << 0)
+#define GPE_CNTL               0x42
+#define  SWGPE_CTRL            (1 << 1)
+#define DEVACT_STS             0x44
+#define PM2_CNT                        0x50
+#define TCO1_CNT               0x60
+#define  TCO_TMR_HLT           (1 << 11)
+#define TCO1_STS               0x64
+#define  DMISCI_STS            (1 << 9)
+#define TCO2_STS               0x66
+#define  TCO2_STS_SECOND_TO    (1 << 1)
+
+#define GPE0_REG_MAX           4
+#define GPE0_REG_SIZE          32
+#define GPE0_STS(x)            (0x80 + (x * 4))
+#define  GPE_31_0              0       /* 0x80/0x90 = GPE[31:0] */
+#define  GPE_63_32             1       /* 0x84/0x94 = GPE[63:32] */
+#define  GPE_94_64             2       /* 0x88/0x98 = GPE[94:64] */
+#define  GPE_STD               3       /* 0x8c/0x9c = Standard GPE */
+#define   WADT_STS             (1 << 18)
+#define   GP27_STS             (1 << 16)
+#define   PME_B0_STS           (1 << 13)
+#define   ME_SCI_STS           (1 << 12)
+#define   PME_STS              (1 << 11)
+#define   BATLOW_STS           (1 << 10)
+#define   PCI_EXP_STS          (1 << 9)
+#define   SMB_WAK_STS          (1 << 7)
+#define   TCOSCI_STS           (1 << 6)
+#define   SWGPE_STS            (1 << 2)
+#define   HOT_PLUG_STS         (1 << 1)
+#define GPE0_EN(x)             (0x90 + (x * 4))
+#define   WADT_en              (1 << 18)
+#define   GP27_EN              (1 << 16)
+#define   PME_B0_EN            (1 << 13)
+#define   ME_SCI_EN            (1 << 12)
+#define   PME_EN               (1 << 11)
+#define   BATLOW_EN            (1 << 10)
+#define   PCI_EXP_EN           (1 << 9)
+#define   TCOSCI_EN            (1 << 6)
+#define   SWGPE_EN             (1 << 2)
+#define   HOT_PLUG_EN          (1 << 1)
+
+#define MAINBOARD_POWER_OFF    0
+#define MAINBOARD_POWER_ON     1
+#define MAINBOARD_POWER_KEEP   2
+
+#define SLEEP_STATE_S0         0
+#define SLEEP_STATE_S3         3
+#define SLEEP_STATE_S5         5
+
+struct chipset_power_state {
+       uint16_t pm1_sts;
+       uint16_t pm1_en;
+       uint32_t pm1_cnt;
+       uint16_t tco1_sts;
+       uint16_t tco2_sts;
+       uint32_t gpe0_sts[4];
+       uint32_t gpe0_en[4];
+       uint16_t gen_pmcon1;
+       uint16_t gen_pmcon2;
+       uint16_t gen_pmcon3;
+       int prev_sleep_state;
+       uint16_t hsio_version;
+       uint16_t hsio_checksum;
+};
+
+void power_state_get(struct udevice *pch_dev, struct chipset_power_state *ps);
+
+#endif