[coreboot-gerrit] New patch to review for coreboot: soc/apollolake: Add Helper functions to access Power Management Registers

Hannah Williams (hannah.williams@intel.com) gerrit at coreboot.org
Fri Apr 8 01:21:56 CEST 2016


Hannah Williams (hannah.williams at intel.com) just uploaded a new patch set to gerrit, which you can find at https://review.coreboot.org/14289

-gerrit

commit e31d338ddb953c4092804d7c9753019084ea6e32
Author: Hannah Williams <hannah.williams at intel.com>
Date:   Thu Feb 4 20:13:34 2016 -0800

    soc/apollolake: Add Helper functions to access Power Management Registers
    
    Change-Id: I928efea33030e03cbbaead6812c617d20446f7c9
    Signed-off-by: Hannah Williams <hannah.williams at intel.com>
---
 src/soc/intel/apollolake/Makefile.inc     |  66 ++++--
 src/soc/intel/apollolake/include/soc/pm.h |  93 +++++++-
 src/soc/intel/apollolake/pmutil.c         | 358 ++++++++++++++++++++++++++++++
 3 files changed, 492 insertions(+), 25 deletions(-)

diff --git a/src/soc/intel/apollolake/Makefile.inc b/src/soc/intel/apollolake/Makefile.inc
index 70ab515..fce4da3 100644
--- a/src/soc/intel/apollolake/Makefile.inc
+++ b/src/soc/intel/apollolake/Makefile.inc
@@ -2,48 +2,74 @@ ifeq ($(CONFIG_SOC_INTEL_APOLLOLAKE),y)
 
 subdirs-y += ../../../cpu/intel/microcode
 subdirs-y += ../../../cpu/intel/turbo
+subdirs-y += ../../../cpu/x86/cache
 subdirs-y += ../../../cpu/x86/lapic
 subdirs-y += ../../../cpu/x86/mtrr
 subdirs-y += ../../../cpu/x86/smm
 subdirs-y += ../../../cpu/x86/tsc
-subdirs-y += ../../../cpu/x86/cache
 
-bootblock-y += bootblock/bootblock.c
+bootblock-y += bootblock/bootblock_car.c
 bootblock-y += bootblock/cache_as_ram.S
-bootblock-y += bootblock/bootblock.c
-bootblock-y += car.c
+bootblock-y += bootblock/early_chipset_config.S
 bootblock-y += gpio.c
 bootblock-y += mmap_boot.c
-bootblock-y += placeholders.c
 bootblock-y += tsc_freq.c
-bootblock-$(CONFIG_SOC_UART_DEBUG) += uart_early.c
+bootblock-y += uart_early.c
 
-romstage-y += placeholders.c
-romstage-y += car.c
-romstage-$(CONFIG_PLATFORM_USES_FSP2_0) += romstage.c
+cpu_incs-y += $(src)/soc/intel/apollolake/romstage/entry.inc
 romstage-y += gpio.c
-romstage-$(CONFIG_SOC_UART_DEBUG) += uart_early.c
 romstage-y += memmap.c
 romstage-y += mmap_boot.c
-
-smm-y += placeholders.c
+romstage-y += romstage/romstage.c
+romstage-y += tsc_freq.c
+romstage-y += uart_early.c
+romstage-y += pmutil.c
 
 ramstage-$(CONFIG_HAVE_ACPI_TABLES) += acpi.c
-ramstage-y += cpu.c
+ramstage-y += car_teardown.c
 ramstage-y += chip.c
-ramstage-y += placeholders.c
+ramstage-y += cpu.c
 ramstage-y += gpio.c
-ramstage-$(CONFIG_SOC_UART_DEBUG) += uart_early.c
+ramstage-y += graphics.c
+ramstage-y += lpc.c
 ramstage-y += memmap.c
 ramstage-y += mmap_boot.c
-ramstage-y += uart.c
 ramstage-y += northbridge.c
+ramstage-y += spi.c
+ramstage-y += tsc_freq.c
+ramstage-y += uart.c
+ramstage-y += pmutil.c
 
-postcar-y += exit_car.S
-postcar-y += memmap.c
-postcar-y += mmap_boot.c
-postcar-$(CONFIG_SOC_UART_DEBUG) += uart_early.c
+smm-y += pmutil.c
+
+romstage-y += placeholders.c
+smm-y += placeholders.c
+ramstage-y += placeholders.c
 
 CPPFLAGS_common += -I$(src)/soc/intel/apollolake/include
 
+# This is a temporary workaround for properly linking romstage into CAR
+# It works because:
+#     1) .text is the first section of romstage, and all others follow after
+#     2) We override default CBFS rule for romstage, so it doesn't get relocated
+LDFLAGS_romstage += -Ttext=$(CONFIG_ROMSTAGE_CAR_ADDR)
+
+ifeq ($(CONFIG_USE_BLOBS),y)
+
+BLOB_DIR := 3rdparty/blobs/mainboard/$(CONFIG_MAINBOARD_DIR)
+SPI_FILE := $(call strip_quotes,$(BLOB_DIR)/$(CONFIG_PREBUILT_SPI_IMAGE))
+
+$(obj)/coreboot.pre: $(objcbfs)/romstage.elf $(CBFSTOOL) \
+		     $(objcbfs)/bootblock.bin $(objcbfs)/romstage.elf \
+		     $$(prebuilt-files)
+	@cp $(SPI_FILE) $@
+	@echo injecting bootblock
+	@$(CBFSTOOL) $@ write -r IBBL -f $(objcbfs)/bootblock.bin -d
+	@printf "    CBFS       $(CONFIG_CBFS_PREFIX)/romstage\n"
+	mv $@ $@.tmp
+	$(prebuild-files) true
+	mv $@.tmp $@
+
+endif
+
 endif
diff --git a/src/soc/intel/apollolake/include/soc/pm.h b/src/soc/intel/apollolake/include/soc/pm.h
index 286406b..1b68fc5 100644
--- a/src/soc/intel/apollolake/include/soc/pm.h
+++ b/src/soc/intel/apollolake/include/soc/pm.h
@@ -1,7 +1,7 @@
 /*
  * This file is part of the coreboot project.
  *
- * Copyright (C) 2016 Intel Corp.
+ * Copyright (C) 2015 Intel Corp.
  * (Written by Lance Zhao <lijian.zhao at intel.com> for Intel Corp.)
  *
  * This program is free software; you can redistribute it and/or modify
@@ -13,19 +13,102 @@
 #ifndef _SOC_APOLLOLAKE_PM_H_
 #define _SOC_APOLLOLAKE_PM_H_
 
-/* ACPI_BASE_ADDRESS / PMBASE */
+/* ACPI_BASE_ADDRESS */
 
 #define PM1_STS			0x00
+#define   WAK_STS	(1 << 15)
+#define   PWRBTN_STS	(1 << 8)
+
 #define PM1_EN			0x02
+#define   PCIEXPWAK_DIS (1 << 14)
+#define   USB_WAKE_EN   (1 << 13)
+#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_SHIFT 10
+#define   SLP_TYP       (7 << SLP_TYP_SHIFT)
+#define    SLP_TYP_S0   0
+#define    SLP_TYP_S3   5
+#define    SLP_TYP_S4   6
+#define    SLP_TYP_S5   7
+#define   SCI_EN        (1 << 0)
+
 #define PM1_TMR			0x08
 #define SMI_EN			0x40
+#define   USB_EN         (1 << 17) /* Legacy USB2 SMI logic */
+#define   PERIODIC_EN    (1 << 14) /* SMI on PERIODIC_STS in SMI_STS */
+#define   TCO_EN         (1 << 13) /* Enable TCO Logic (BIOSWE et al) */
+#define   BIOS_RLS       (1 <<  7) /* asserts SCI on bit set */
+#define   SWSMI_TMR_EN   (1 <<  6) /* start software smi timer on bit set */
+#define   APMC_EN        (1 <<  5) /* Writes to APM_CNT cause SMI# */
+#define   SLP_SMI_EN     (1 <<  4) /* Write to SLP_EN in PM1_CNT asserts SMI# */
+#define   BIOS_EN        (1 <<  2) /* Assert SMI# on setting GBL_RLS bit */
+#define   EOS            (1 <<  1) /* End of SMI (deassert SMI#) */
+#define   GBL_SMI_EN     (1 <<  0) /* SMI# generation at all? */
+
 #define SMI_STS			0x44
 #define GPE_CNTL		0x50
 #define DEVACT_STS		0x4c
+#define TCO_STS                 0x64
+#define   TCO_TIMEOUT           (1 << 3)
+#define TCO1_CNT                0x68
 
 #define GPE0_REG_MAX		4
-#define GPE0_STS(x)		(0x20 + (x * 4))
-#define GPE0_EN(x)		(0x30 + (x * 4))
+#define GPE0_REG_SIZE		32
+#define GPE0_STS(x)            (0x20 + (x * 4))
+#define GPE0_EN(x)             (0x30 + (x * 4))
+#define   PME_B0_EN             (1 << 13)
+
+
+
+/* Memory mapped IO registers behind PMC_BASE_ADDRESS */
+#define PRSTS           0x1000
+#define GEN_PMCON1      0x1020
+#       define PWR_FLR          (1 << 16)
+#       define SUS_PWR_FLR      (1 << 14)
+#define GEN_PMCON2      0x1024
+#       define RPS              (1 <<  2)
+
+/* Generic sleep state types */
+#define SLEEP_STATE_S0          0
+#define SLEEP_STATE_S3          3
+#define SLEEP_STATE_S5          5
+
+/* Track power state from reset to log events. */
+struct chipset_power_state {
+        uint16_t pm1_sts;
+        uint16_t pm1_en;
+        uint32_t pm1_cnt;
+        uint32_t gpe0_sts;
+        uint32_t gpe0_en;
+        uint32_t tco_sts;
+        uint32_t prsts;
+        uint32_t gen_pmcon1;
+        uint32_t gen_pmcon2;
+        int prev_sleep_state;
+} __attribute__((packed));
+
+int fill_power_state(struct chipset_power_state *ps);
+int chipset_prev_sleep_state(struct chipset_power_state *ps);
+
+/* Power Management Utility Functions. */
+uint32_t clear_smi_status(void);
+uint16_t clear_pm1_status(void);
+uint32_t clear_tco_status(void);
+uint32_t clear_gpe_status(void);
+uint32_t clear_alt_status(void);
+void clear_pmc_status(void);
+void enable_smi(uint32_t mask);
+void disable_smi(uint32_t mask);
+void enable_pm1(uint16_t events);
+void enable_pm1_control(uint32_t mask);
+void disable_pm1_control(uint32_t mask);
+void enable_gpe(uint32_t mask);
+void disable_gpe(uint32_t mask);
+void disable_all_gpe(void);
 
-#endif	/* _SOC_APOLLOLAKE_PM_H_ */
+#endif
diff --git a/src/soc/intel/apollolake/pmutil.c b/src/soc/intel/apollolake/pmutil.c
new file mode 100644
index 0000000..f618b81
--- /dev/null
+++ b/src/soc/intel/apollolake/pmutil.c
@@ -0,0 +1,358 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2013 Google Inc.
+ * Copyright (C) 2015-2016 Intel Corp.
+ *
+ * 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; version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <arch/io.h>
+#include <console/console.h>
+#include <rules.h>
+#include <device/pci_def.h>
+#include <soc/iomap.h>
+#include <soc/pm.h>
+#include <stdint.h>
+#include <device/device.h>
+#include <device/pci.h>
+
+
+static void print_num_status_bits(int num_bits, uint32_t status,
+				  const char * const bit_names[])
+{
+	int i;
+
+	if (!status)
+		return;
+
+	for (i = num_bits - 1; i >= 0; i--) {
+		if (status & (1 << i)) {
+			if (bit_names[i])
+				printk(BIOS_DEBUG, "%s ", bit_names[i]);
+			else
+				printk(BIOS_DEBUG, "BIT%d ", i);
+		}
+	}
+}
+
+static uint32_t print_smi_status(uint32_t smi_sts)
+{
+	static const char * const smi_sts_bits[] = {
+		[2] = "BIOS",
+		[4] = "SLP_SMI",
+		[5] = "APM",
+		[6] = "SWSMI_TMR",
+		[8] = "PM1",
+		[9] = "GPE0",
+		[10]= "GPIO_SMI",
+		[12] = "MCSMI",
+		[13] = "TCO",
+		[14] = "PERIODIC",
+		[15] = "SERIRQ",
+		[16] = "SMBUS_SMI",
+		[17] = "XHCI",
+		[18] = "HOST_SMBUS",
+		[19] = "SCS",
+		[20] = "PCI_EXP_SMI",
+		[26] = "SPI",
+	};
+
+	if (!smi_sts)
+		return 0;
+
+	printk(BIOS_DEBUG, "SMI_STS: ");
+	print_num_status_bits(27, smi_sts, smi_sts_bits);
+	printk(BIOS_DEBUG, "\n");
+
+	return smi_sts;
+}
+
+static uint32_t reset_smi_status(void)
+{
+	uint32_t smi_sts = inl(ACPI_PMIO_BASE + SMI_STS);
+	outl(smi_sts, ACPI_PMIO_BASE + SMI_STS);
+	return smi_sts;
+}
+
+uint32_t clear_smi_status(void)
+{
+	return print_smi_status(reset_smi_status());
+}
+
+void enable_smi(uint32_t mask)
+{
+	uint32_t smi_en = inl(ACPI_PMIO_BASE + SMI_EN);
+	smi_en |= mask;
+	outl(smi_en, ACPI_PMIO_BASE + SMI_EN);
+}
+
+void disable_smi(uint32_t mask)
+{
+	uint32_t smi_en = inl(ACPI_PMIO_BASE + SMI_EN);
+	smi_en &= ~mask;
+	outl(smi_en, ACPI_PMIO_BASE + SMI_EN);
+}
+
+void enable_pm1_control(uint32_t mask)
+{
+	uint32_t pm1_cnt = inl(ACPI_PMIO_BASE + PM1_CNT);
+	pm1_cnt |= mask;
+	outl(pm1_cnt, ACPI_PMIO_BASE + PM1_CNT);
+}
+
+void disable_pm1_control(uint32_t mask)
+{
+	uint32_t pm1_cnt = inl(ACPI_PMIO_BASE + PM1_CNT);
+	pm1_cnt &= ~mask;
+	outl(pm1_cnt, ACPI_PMIO_BASE + PM1_CNT);
+}
+
+static uint16_t reset_pm1_status(void)
+{
+	uint16_t pm1_sts = inw(ACPI_PMIO_BASE + PM1_STS);
+	outw(pm1_sts, ACPI_PMIO_BASE + PM1_STS);
+	return pm1_sts;
+}
+
+static uint16_t print_pm1_status(uint16_t pm1_sts)
+{
+	static const char * const pm1_sts_bits[] = {
+		[0] = "TMROF",
+		[5] = "GBL",
+		[8] = "PWRBTN",
+		[10] = "RTC",
+		[11] = "PRBTNOR",
+		[13] = "USB",
+		[14] = "PCIEXPWAK",
+		[15] = "WAK",
+	};
+
+	if (!pm1_sts)
+		return 0;
+
+	printk(BIOS_SPEW, "PM1_STS: ");
+	print_num_status_bits(16, pm1_sts, pm1_sts_bits);
+	printk(BIOS_SPEW, "\n");
+
+	return pm1_sts;
+}
+
+uint16_t clear_pm1_status(void)
+{
+	return print_pm1_status(reset_pm1_status());
+}
+
+void enable_pm1(uint16_t events)
+{
+	outw(events, ACPI_PMIO_BASE + PM1_EN);
+}
+
+static uint32_t print_tco_status(uint32_t tco_sts)
+{
+	static const char * const tco_sts_bits[] = {
+		[3] = "TIMEOUT",
+		[17] = "SECOND_TO",
+	};
+
+	if (!tco_sts)
+		return 0;
+
+	printk(BIOS_DEBUG, "TCO_STS: ");
+	print_num_status_bits(18, tco_sts, tco_sts_bits);
+	printk(BIOS_DEBUG, "\n");
+
+	return tco_sts;
+}
+
+static uint32_t reset_tco_status(void)
+{
+	uint32_t tco_sts = inl(ACPI_PMIO_BASE + TCO_STS);
+	uint32_t tco_en = inl(ACPI_PMIO_BASE + TCO1_CNT);
+
+	outl(tco_sts, ACPI_PMIO_BASE + TCO_STS);
+	return tco_sts & tco_en;
+}
+
+uint32_t clear_tco_status(void)
+{
+	return print_tco_status(reset_tco_status());
+}
+
+void enable_gpe(uint32_t mask)
+{
+	uint32_t gpe0_en = inl(ACPI_PMIO_BASE + GPE0_EN(0));
+	gpe0_en |= mask;
+	outl(gpe0_en, ACPI_PMIO_BASE + GPE0_EN(0));
+}
+
+void disable_gpe(uint32_t mask)
+{
+	uint32_t gpe0_en = inl(ACPI_PMIO_BASE + GPE0_EN(0));
+	gpe0_en &= ~mask;
+	outl(gpe0_en, ACPI_PMIO_BASE + GPE0_EN(0));
+}
+
+void disable_all_gpe(void)
+{
+	disable_gpe(~0);
+}
+
+
+static uint32_t reset_gpe_status(void)
+{
+	uint32_t gpe_sts = inl(ACPI_PMIO_BASE + GPE0_STS(0));
+	outl(gpe_sts, ACPI_PMIO_BASE + GPE0_STS(0));
+	return gpe_sts;
+}
+
+static uint32_t print_gpe_sts(uint32_t gpe_sts)
+{
+	static const char * const gpe_sts_bits[] = {
+		[1] = "HOTPLUG",
+		[2] = "SWGPE",
+		[3] = "PCIE_WAKE0",
+		[4] = "PUNIT",
+		[5] = "GUNIT",
+		[6] = "PCIE_WAKE1",
+		[7] = "PCIE_WAKE2",
+		[8] = "PCIE_WAKE3",
+		[9] = "PCI_EXP",
+		[10] = "BATLOW",
+		[11] = "CSE_PME",
+		[12] = "XDCI_PME",
+		[13] = "XHCI_PME",
+		[14] = "AVS_PME",
+		[15] = "GPIO_TIER1_SCI",
+		[16] = "SMB_WAK",
+		[17] = "SATA_PME",
+	};
+
+	if (!gpe_sts)
+		return gpe_sts;
+
+	printk(BIOS_DEBUG, "GPE0a_STS: ");
+	print_num_status_bits(18, gpe_sts, gpe_sts_bits);
+	printk(BIOS_DEBUG, "\n");
+
+	return gpe_sts;
+}
+
+uint32_t clear_gpe_status(void)
+{
+	return print_gpe_sts(reset_gpe_status());
+}
+
+static uint32_t reset_alt_status(void)
+{
+	return 0;
+}
+
+static uint32_t print_alt_sts(uint32_t alt_gpio_smi)
+{
+	uint32_t alt_gpio_sts;
+	static const char * const alt_gpio_smi_sts_bits[] = {
+		[0] = "SUS_GPIO_0",
+		[1] = "SUS_GPIO_1",
+		[2] = "SUS_GPIO_2",
+		[3] = "SUS_GPIO_3",
+		[4] = "SUS_GPIO_4",
+		[5] = "SUS_GPIO_5",
+		[6] = "SUS_GPIO_6",
+		[7] = "SUS_GPIO_7",
+		[8] = "CORE_GPIO_0",
+		[9] = "CORE_GPIO_1",
+		[10] = "CORE_GPIO_2",
+		[11] = "CORE_GPIO_3",
+		[12] = "CORE_GPIO_4",
+		[13] = "CORE_GPIO_5",
+		[14] = "CORE_GPIO_6",
+		[15] = "CORE_GPIO_7",
+	};
+
+	/* Status bits are in the upper 16 bits. */
+	alt_gpio_sts = alt_gpio_smi >> 16;
+	if (!alt_gpio_sts)
+		return alt_gpio_smi;
+
+	printk(BIOS_DEBUG, "ALT_GPIO_SMI: ");
+	print_num_status_bits(16, alt_gpio_sts, alt_gpio_smi_sts_bits);
+	printk(BIOS_DEBUG, "\n");
+
+	return alt_gpio_smi;
+}
+
+uint32_t clear_alt_status(void)
+{
+	return print_alt_sts(reset_alt_status());
+}
+
+void clear_pmc_status(void)
+{
+	uint32_t prsts;
+	uint32_t gen_pmcon1;
+
+	prsts = read32((void *)(PMC_BAR0 + PRSTS));
+	gen_pmcon1 = read32((void *)(PMC_BAR0 + GEN_PMCON1));
+
+	/* Clear the status bits. The RPS field is cleared on a 0 write. */
+	write32((void *)(PMC_BAR0 + GEN_PMCON1), gen_pmcon1 & ~RPS);
+	write32((void *)(PMC_BAR0 + PRSTS), prsts);
+}
+
+
+/* Return 0, 3, or 5 to indicate the previous sleep state. */
+int chipset_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 IS_ENABLED(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_PMIO_BASE + PM1_CNT);
+        }
+
+
+        return prev_sleep_state;
+}
+
+/* returns prev_sleep_state */
+int fill_power_state(struct chipset_power_state *ps)
+{
+        ps->pm1_sts = inw(ACPI_PMIO_BASE + PM1_STS);
+        ps->pm1_en = inw(ACPI_PMIO_BASE + PM1_EN);
+        ps->pm1_cnt = inl(ACPI_PMIO_BASE + PM1_CNT);
+        ps->gpe0_sts = inl(ACPI_PMIO_BASE + GPE0_STS(0));
+        ps->gpe0_en = inl(ACPI_PMIO_BASE + GPE0_EN(0));
+        ps->tco_sts = inl(ACPI_PMIO_BASE + TCO_STS);
+        ps->prsts = read32((void *)(PMC_BAR0 + PRSTS));
+        ps->gen_pmcon1 =read32((void *)(PMC_BAR0 + GEN_PMCON1));
+        ps->gen_pmcon2 = read32((void *)(PMC_BAR0 + GEN_PMCON2));
+
+        ps->prev_sleep_state = chipset_prev_sleep_state(ps);
+
+        printk(BIOS_DEBUG, "pm1_sts: %04x pm1_en: %04x pm1_cnt: %08x\n",
+                ps->pm1_sts, ps->pm1_en, ps->pm1_cnt);
+        printk(BIOS_DEBUG, "gpe0_sts: %08x gpe0_en: %08x tco_sts: %08x\n",
+                ps->gpe0_sts, ps->gpe0_en, ps->tco_sts);
+        printk(BIOS_DEBUG, "prsts: %08x gen_pmcon1: %08x gen_pmcon2: %08x\n",
+                ps->prsts, ps->gen_pmcon1, ps->gen_pmcon2);
+        printk(BIOS_DEBUG, "prev_sleep_state %d\n", ps->prev_sleep_state);
+	printk(BIOS_DEBUG, "smi_en: %08x smi_sts: %08x\n",
+		inl(ACPI_PMIO_BASE + SMI_EN), inl(ACPI_PMIO_BASE + SMI_STS));
+        return ps->prev_sleep_state;
+}



More information about the coreboot-gerrit mailing list