aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/soc/intel/apollolake/chip.h3
-rw-r--r--src/soc/intel/apollolake/include/soc/pm.h6
-rw-r--r--src/soc/intel/apollolake/pmc.c59
3 files changed, 68 insertions, 0 deletions
diff --git a/src/soc/intel/apollolake/chip.h b/src/soc/intel/apollolake/chip.h
index 16c3aeb76f..22217a4dea 100644
--- a/src/soc/intel/apollolake/chip.h
+++ b/src/soc/intel/apollolake/chip.h
@@ -106,6 +106,9 @@ struct soc_intel_apollolake_config {
/* Enable DPTF support */
int dptf_enable;
+
+ /* SLP S3 minimum assertion width. */
+ int slp_s3_assertion_width_usecs;
};
#endif /* _SOC_APOLLOLAKE_CHIP_H_ */
diff --git a/src/soc/intel/apollolake/include/soc/pm.h b/src/soc/intel/apollolake/include/soc/pm.h
index b3da3aa628..3ee7403b9b 100644
--- a/src/soc/intel/apollolake/include/soc/pm.h
+++ b/src/soc/intel/apollolake/include/soc/pm.h
@@ -151,6 +151,12 @@
#define RPS (1 << 2)
#define GEN_PMCON2 0x1024
#define GEN_PMCON3 0x1028
+# define SLP_S3_ASSERT_WIDTH_SHIFT 10
+# define SLP_S3_ASSERT_MASK (0x3 << SLP_S3_ASSERT_WIDTH_SHIFT)
+# define SLP_S3_ASSERT_60_USEC 0x0
+# define SLP_S3_ASSERT_1_MSEC 0x1
+# define SLP_S3_ASSERT_50_MSEC 0x2
+# define SLP_S3_ASSERT_2_SEC 0x3
#define ETR 0x1048
# define CF9_LOCK (1 << 31)
# define CF9_GLB_RST (1 << 20)
diff --git a/src/soc/intel/apollolake/pmc.c b/src/soc/intel/apollolake/pmc.c
index 30b7677a92..c58314494c 100644
--- a/src/soc/intel/apollolake/pmc.c
+++ b/src/soc/intel/apollolake/pmc.c
@@ -25,6 +25,7 @@
#include <soc/gpio.h>
#include <soc/pci_devs.h>
#include <soc/pm.h>
+#include <timer.h>
#include "chip.h"
/*
@@ -132,12 +133,70 @@ static void pch_set_acpi_mode(void)
}
}
+static int choose_slp_s3_assertion_width(int width_usecs)
+{
+ int i;
+ static const struct {
+ int max_width;
+ int value;
+ } slp_s3_settings[] = {
+ {
+ .max_width = 60,
+ .value = SLP_S3_ASSERT_60_USEC,
+ },
+ {
+ .max_width = 1 * USECS_PER_MSEC,
+ .value = SLP_S3_ASSERT_1_MSEC,
+ },
+ {
+ .max_width = 50 * USECS_PER_MSEC,
+ .value = SLP_S3_ASSERT_50_MSEC,
+ },
+ {
+ .max_width = 2 * USECS_PER_SEC,
+ .value = SLP_S3_ASSERT_2_SEC,
+ },
+ };
+
+ for (i = 0; i < ARRAY_SIZE(slp_s3_settings); i++) {
+ if (width_usecs <= slp_s3_settings[i].max_width)
+ break;
+ }
+
+ /* Provide conservative default if nothing set in devicetree
+ * or requested assertion width too large. */
+ if (width_usecs <= 0 || i == ARRAY_SIZE(slp_s3_settings))
+ i = ARRAY_SIZE(slp_s3_settings) - 1;
+
+ printk(BIOS_DEBUG, "SLP S3 assertion width: %d usecs\n",
+ slp_s3_settings[i].max_width);
+
+ return slp_s3_settings[i].value;
+}
+
+static void set_slp_s3_assertion_width(int width_usecs)
+{
+ uint32_t reg;
+ uintptr_t gen_pmcon3 = get_pmc_mmio_bar() + GEN_PMCON3;
+ int setting = choose_slp_s3_assertion_width(width_usecs);
+
+ reg = read32((void *)gen_pmcon3);
+ reg &= ~SLP_S3_ASSERT_MASK;
+ reg |= setting << SLP_S3_ASSERT_WIDTH_SHIFT;
+ write32((void *)gen_pmcon3, reg);
+}
+
static void pmc_init(struct device *dev)
{
+ const struct soc_intel_apollolake_config *cfg = dev->chip_info;
+
/* Set up GPE configuration */
pmc_gpe_init();
pch_set_acpi_mode();
+ if (cfg != NULL)
+ set_slp_s3_assertion_width(cfg->slp_s3_assertion_width_usecs);
+
/* Log power state */
pch_log_state();
}