diff options
-rw-r--r-- | src/soc/intel/apollolake/chip.h | 5 | ||||
-rw-r--r-- | src/soc/intel/apollolake/gpio.c | 68 | ||||
-rw-r--r-- | src/soc/intel/apollolake/include/soc/gpe.h | 102 | ||||
-rw-r--r-- | src/soc/intel/apollolake/include/soc/gpio.h | 11 | ||||
-rw-r--r-- | src/soc/intel/apollolake/include/soc/gpio_defs.h | 22 | ||||
-rw-r--r-- | src/soc/intel/apollolake/include/soc/pm.h | 19 | ||||
-rw-r--r-- | src/soc/intel/apollolake/pmc.c | 68 |
7 files changed, 292 insertions, 3 deletions
diff --git a/src/soc/intel/apollolake/chip.h b/src/soc/intel/apollolake/chip.h index c83f9739fd..aabd42df42 100644 --- a/src/soc/intel/apollolake/chip.h +++ b/src/soc/intel/apollolake/chip.h @@ -21,6 +21,7 @@ #include <soc/gpio.h> #include <soc/intel/common/lpss_i2c.h> #include <device/i2c.h> +#include <soc/pm.h> #define CLKREQ_DISABLED 0xf #define APOLLOLAKE_I2C_DEV_MAX 8 @@ -96,6 +97,10 @@ struct soc_intel_apollolake_config { /* I2C bus configuration */ struct apollolake_i2c_config i2c[APOLLOLAKE_I2C_DEV_MAX]; + + uint8_t gpe0_dw1; /* GPE0_63_32 STS/EN */ + uint8_t gpe0_dw2; /* GPE0_95_64 STS/EN */ + uint8_t gpe0_dw3; /* GPE0_127_96 STS/EN */ }; #endif /* _SOC_APOLLOLAKE_CHIP_H_ */ diff --git a/src/soc/intel/apollolake/gpio.c b/src/soc/intel/apollolake/gpio.c index ac0d83b810..525c972b5c 100644 --- a/src/soc/intel/apollolake/gpio.c +++ b/src/soc/intel/apollolake/gpio.c @@ -19,6 +19,7 @@ #include <gpio.h> #include <soc/gpio.h> #include <soc/iosf.h> +#include <soc/pm.h> /* This list must be in order, from highest pad numbers, to lowest pad numbers*/ static const struct pad_community { @@ -150,3 +151,70 @@ uint16_t gpio_acpi_pin(gpio_t gpio_num) return gpio_num; } + +/* Helper function to map PMC register groups to tier1 sci groups */ +static int pmc_gpe_route_to_gpio(int route) +{ + switch(route) { + case PMC_GPE_SW_31_0: + return GPIO_GPE_SW_31_0; + case PMC_GPE_SW_63_32: + return GPIO_GPE_SW_63_32; + case PMC_GPE_NW_31_0: + return GPIO_GPE_NW_31_0; + case PMC_GPE_NW_63_32: + return GPIO_GPE_NW_63_32; + case PMC_GPE_NW_95_64: + return GPIO_GPE_NW_95_64; + case PMC_GPE_N_31_0: + return GPIO_GPE_N_31_0; + case PMC_GPE_N_63_32: + return GPIO_GPE_N_63_32; + case PMC_GPE_W_31_0: + return GPIO_GPE_W_31_0; + default: + return -1; + } +} + +void gpio_route_gpe(uint8_t gpe0b, uint8_t gpe0c, uint8_t gpe0d) +{ + int i; + uint32_t misccfg_mask; + uint32_t misccfg_value; + uint32_t value; + + /* Get the group here for community specific MISCCFG register. + * If any of these returns -1 then there is some error in devicetree + * where the group is probably hardcoded and does not comply with the + * PMC group defines. So we return from here and MISCFG is set to + * default. + */ + gpe0b = pmc_gpe_route_to_gpio(gpe0b); + if(gpe0b == -1) + return; + gpe0c = pmc_gpe_route_to_gpio(gpe0c); + if(gpe0c == -1) + return; + gpe0d = pmc_gpe_route_to_gpio(gpe0d); + if(gpe0d == -1) + return; + + misccfg_value = gpe0b << MISCCFG_GPE0_DW0_SHIFT; + misccfg_value |= gpe0c << MISCCFG_GPE0_DW1_SHIFT; + misccfg_value |= gpe0d << MISCCFG_GPE0_DW2_SHIFT; + + /* Program GPIO_MISCCFG */ + misccfg_mask = ~(MISCCFG_GPE0_DW2_MASK | + MISCCFG_GPE0_DW1_MASK | + MISCCFG_GPE0_DW0_MASK); + + for (i = 0; i < ARRAY_SIZE(gpio_communities); i++) { + const struct pad_community *comm = &gpio_communities[i]; + + value = iosf_read(comm->port, GPIO_MISCCFG); + value &= misccfg_mask; + value |= misccfg_value; + iosf_write(comm->port, GPIO_MISCCFG, value); + } +} diff --git a/src/soc/intel/apollolake/include/soc/gpe.h b/src/soc/intel/apollolake/include/soc/gpe.h index 8abbad86c6..5482ed379f 100644 --- a/src/soc/intel/apollolake/include/soc/gpe.h +++ b/src/soc/intel/apollolake/include/soc/gpe.h @@ -34,4 +34,106 @@ #define GPE0A_SMB_WAK_STS 16 #define GPE0A_SATA_PME_STS 17 +/* Group DW0 is reserved in Apollolake */ + +/* GPE_63_32 */ +#define GPE0_DW1_00 32 +#define GPE0_DW1_01 33 +#define GPE0_DW1_02 34 +#define GPE0_DW1_03 36 +#define GPE0_DW1_04 36 +#define GPE0_DW1_05 37 +#define GPE0_DW1_06 38 +#define GPE0_DW1_07 39 +#define GPE0_DW1_08 40 +#define GPE0_DW1_09 41 +#define GPE0_DW1_10 42 +#define GPE0_DW1_11 43 +#define GPE0_DW1_12 44 +#define GPE0_DW1_13 45 +#define GPE0_DW1_14 46 +#define GPE0_DW1_15 47 +#define GPE0_DW1_16 48 +#define GPE0_DW1_17 49 +#define GPE0_DW1_18 50 +#define GPE0_DW1_19 51 +#define GPE0_DW1_20 52 +#define GPE0_DW1_21 53 +#define GPE0_DW1_22 54 +#define GPE0_DW1_23 55 +#define GPE0_DW1_24 56 +#define GPE0_DW1_25 57 +#define GPE0_DW1_26 58 +#define GPE0_DW1_27 59 +#define GPE0_DW1_28 60 +#define GPE0_DW1_29 61 +#define GPE0_DW1_30 62 +#define GPE0_DW1_31 63 +/* GPE_95_64 */ +#define GPE0_DW2_00 64 +#define GPE0_DW2_01 65 +#define GPE0_DW2_02 66 +#define GPE0_DW2_03 67 +#define GPE0_DW2_04 68 +#define GPE0_DW2_05 69 +#define GPE0_DW2_06 70 +#define GPE0_DW2_07 71 +#define GPE0_DW2_08 72 +#define GPE0_DW2_09 73 +#define GPE0_DW2_10 74 +#define GPE0_DW2_11 75 +#define GPE0_DW2_12 76 +#define GPE0_DW2_13 77 +#define GPE0_DW2_14 78 +#define GPE0_DW2_15 79 +#define GPE0_DW2_16 80 +#define GPE0_DW2_17 81 +#define GPE0_DW2_18 82 +#define GPE0_DW2_19 83 +#define GPE0_DW2_20 84 +#define GPE0_DW2_21 85 +#define GPE0_DW2_22 86 +#define GPE0_DW2_23 87 +#define GPE0_DW2_24 88 +#define GPE0_DW2_25 89 +#define GPE0_DW2_26 90 +#define GPE0_DW2_27 91 +#define GPE0_DW2_28 92 +#define GPE0_DW2_29 93 +#define GPE0_DW2_30 94 +#define GPE0_DW2_31 95 +/* GPE_127_96 */ +#define GPE0_DW3_00 96 +#define GPE0_DW3_01 97 +#define GPE0_DW3_02 98 +#define GPE0_DW3_03 99 +#define GPE0_DW3_04 100 +#define GPE0_DW3_05 101 +#define GPE0_DW3_06 102 +#define GPE0_DW3_07 103 +#define GPE0_DW3_08 104 +#define GPE0_DW3_09 105 +#define GPE0_DW3_10 106 +#define GPE0_DW3_11 107 +#define GPE0_DW3_12 108 +#define GPE0_DW3_13 109 +#define GPE0_DW3_14 110 +#define GPE0_DW3_15 111 +#define GPE0_DW3_16 112 +#define GPE0_DW3_17 113 +#define GPE0_DW3_18 114 +#define GPE0_DW3_19 115 +#define GPE0_DW3_20 116 +#define GPE0_DW3_21 117 +#define GPE0_DW3_22 118 +#define GPE0_DW3_23 119 +#define GPE0_DW3_24 120 +#define GPE0_DW3_25 121 +#define GPE0_DW3_26 122 +#define GPE0_DW3_27 123 +#define GPE0_DW3_28 124 +#define GPE0_DW3_29 125 +#define GPE0_DW3_30 126 +#define GPE0_DW3_31 127 + #endif diff --git a/src/soc/intel/apollolake/include/soc/gpio.h b/src/soc/intel/apollolake/include/soc/gpio.h index c9d32ccf56..763cdefa4e 100644 --- a/src/soc/intel/apollolake/include/soc/gpio.h +++ b/src/soc/intel/apollolake/include/soc/gpio.h @@ -99,5 +99,16 @@ struct pad_config { void gpio_configure_pad(const struct pad_config *cfg); void gpio_configure_pads(const struct pad_config *cfg, size_t num_pads); +/* + * Set the GPIO groups for the GPE blocks. The values from PMC register GPE_CFG + * are passed which is then mapped to proper groups for MISCCFG. This basically + * sets the MISCCFG register bits: + * dw0 = gpe0_route[11:8]. This is ACPI GPE0b. + * dw1 = gpe0_route[15:12]. This is ACPI GPE0c. + * dw2 = gpe0_route[19:16]. This is ACPI GPE0d. + */ +void gpio_route_gpe(uint8_t gpe0b, uint8_t gpe0c, uint8_t gpe0d); + #endif /* __ACPI__ */ + #endif /* _SOC_APOLLOLAKE_GPIO_H_ */ diff --git a/src/soc/intel/apollolake/include/soc/gpio_defs.h b/src/soc/intel/apollolake/include/soc/gpio_defs.h index 30c4bdb272..c6e2c3cf91 100644 --- a/src/soc/intel/apollolake/include/soc/gpio_defs.h +++ b/src/soc/intel/apollolake/include/soc/gpio_defs.h @@ -23,6 +23,28 @@ #ifndef _SOC_APOLLOLAKE_GPIO_DEFS_H_ #define _SOC_APOLLOLAKE_GPIO_DEFS_H_ +/* + * Miscellaneous Configuration register(MISCCFG).These are community specific + * registers and are meant to house miscellaneous configuration fields per + * community. There are 8 GPIO groups: GPP_0 -> GPP_8 (Group 3 is absent) + */ +#define GPIO_MISCCFG 0x10 /* Miscellaneous Configuration offset */ +#define GPIO_GPE_SW_31_0 0 /* SOUTHWEST GPIO# 0 ~ 31 belong to GROUP0 */ +#define GPIO_GPE_SW_63_32 1 /* SOUTHWEST GPIO# 32 ~ 42 belong to GROUP1 */ +#define GPIO_GPE_W_31_0 2 /* WEST GPIO# 0 ~ 25 belong to GROUP2 */ +#define GPIO_GPE_NW_31_0 4 /* NORTHWEST GPIO# 0 ~ 17 belong to GROUP4 */ +#define GPIO_GPE_NW_63_32 5 /* NORTHWEST GPIO# 32 ~ 63 belong to GROUP5 */ +#define GPIO_GPE_NW_95_64 6 /* NORTHWEST GPIO# 64 ~ 76 belong to GROUP6 */ +#define GPIO_GPE_N_31_0 7 /* NORTH GPIO# 0 ~ 31 belong to GROUP7 */ +#define GPIO_GPE_N_63_32 8 /* NORTH GPIO# 32 ~ 61 belong to GROUP8 */ + +#define MISCCFG_GPE0_DW0_SHIFT 8 +#define MISCCFG_GPE0_DW0_MASK (0xf << MISCCFG_GPE0_DW0_SHIFT) +#define MISCCFG_GPE0_DW1_SHIFT 12 +#define MISCCFG_GPE0_DW1_MASK (0xf << MISCCFG_GPE0_DW1_SHIFT) +#define MISCCFG_GPE0_DW2_SHIFT 16 +#define MISCCFG_GPE0_DW2_MASK (0xf << MISCCFG_GPE0_DW2_SHIFT) + #define PAD_CFG0_TX_STATE (1 << 0) #define PAD_CFG0_RX_STATE (1 << 1) #define PAD_CFG0_TX_DISABLE (1 << 8) diff --git a/src/soc/intel/apollolake/include/soc/pm.h b/src/soc/intel/apollolake/include/soc/pm.h index 72f74a669c..99f922f244 100644 --- a/src/soc/intel/apollolake/include/soc/pm.h +++ b/src/soc/intel/apollolake/include/soc/pm.h @@ -129,9 +129,22 @@ # define RPS (1 << 2) #define GEN_PMCON3 0x1028 #define ETR 0x1048 -# define CF9_LOCK (1 << 31) -# define CF9_GLB_RST (1 << 20) - +# define CF9_LOCK (1 << 31) +# define CF9_GLB_RST (1 << 20) +#define GPIO_GPE_CFG 0x1050 +#define GPE0_DWX_MASK 0xf +#define GPE0_DW1_SHIFT 4 +#define GPE0_DW2_SHIFT 8 +#define GPE0_DW3_SHIFT 12 + +#define PMC_GPE_SW_31_0 0 +#define PMC_GPE_SW_63_32 1 +#define PMC_GPE_NW_31_0 3 +#define PMC_GPE_NW_63_32 4 +#define PMC_GPE_NW_95_64 5 +#define PMC_GPE_N_31_0 6 +#define PMC_GPE_N_63_32 7 +#define PMC_GPE_W_31_0 9 /* Generic sleep state types */ #define SLEEP_STATE_S0 0 diff --git a/src/soc/intel/apollolake/pmc.c b/src/soc/intel/apollolake/pmc.c index c88e14c4c0..94040c3650 100644 --- a/src/soc/intel/apollolake/pmc.c +++ b/src/soc/intel/apollolake/pmc.c @@ -18,8 +18,13 @@ #include <device/device.h> #include <device/pci.h> #include <device/pci_ids.h> +#include <console/console.h> #include <soc/iomap.h> #include <soc/pci_ids.h> +#include <soc/gpio.h> +#include <soc/pci_devs.h> +#include <soc/pm.h> +#include "chip.h" /* * The ACPI IO BAR (offset 0x20) is not PCI compliant. We've observed cases @@ -58,10 +63,73 @@ static void set_resources(device_t dev) report_resource_stored(dev, res, " ACPI BAR"); } +static void pmc_gpe_init(void) +{ + uint32_t gpio_cfg = 0; + uint32_t gpio_cfg_reg; + uint8_t dw1, dw2, dw3; + const struct soc_intel_apollolake_config *config; + + struct device *dev = NB_DEV_ROOT; + if (!dev || !dev->chip_info) { + printk(BIOS_ERR, "BUG! Could not find SOC devicetree config\n"); + return; + } + config = dev->chip_info; + + uintptr_t pmc_bar = get_pmc_mmio_bar(); + + const uint32_t gpio_cfg_mask = + (GPE0_DWX_MASK << GPE0_DW1_SHIFT) | + (GPE0_DWX_MASK << GPE0_DW2_SHIFT) | + (GPE0_DWX_MASK << GPE0_DW3_SHIFT); + + /* Assign to local variable */ + dw1 = config->gpe0_dw1; + dw2 = config->gpe0_dw2; + dw3 = config->gpe0_dw3; + + /* Making sure that bad values don't bleed into the other fields */ + dw1 &= GPE0_DWX_MASK; + dw2 &= GPE0_DWX_MASK; + dw3 &= GPE0_DWX_MASK; + + /* Route the GPIOs to the GPE0 block. Determine that all values + * are different, and if they aren't use the reset values. + * DW0 is reserved/unused */ + if (dw1 == dw2 || dw2 == dw3) { + printk(BIOS_INFO, "PMC: Using default GPE route.\n"); + gpio_cfg = read32((void *)pmc_bar + GPIO_GPE_CFG); + + dw1 = (gpio_cfg >> GPE0_DW1_SHIFT) & GPE0_DWX_MASK; + dw2 = (gpio_cfg >> GPE0_DW2_SHIFT) & GPE0_DWX_MASK; + dw3 = (gpio_cfg >> GPE0_DW3_SHIFT) & GPE0_DWX_MASK; + } else { + gpio_cfg |= (uint32_t)dw1 << GPE0_DW1_SHIFT; + gpio_cfg |= (uint32_t)dw2 << GPE0_DW2_SHIFT; + gpio_cfg |= (uint32_t)dw3 << GPE0_DW3_SHIFT; + } + + gpio_cfg_reg = read32((void *)pmc_bar + GPIO_GPE_CFG) & ~gpio_cfg_mask; + gpio_cfg_reg |= gpio_cfg & gpio_cfg_mask; + + write32((void *)pmc_bar + GPIO_GPE_CFG, gpio_cfg_reg); + + /* Set the routes in the GPIO communities as well. */ + gpio_route_gpe(dw1, dw2, dw3); +} + +static void pmc_init(struct device *dev) +{ + /* Set up GPE configuration */ + pmc_gpe_init(); +} + static const struct device_operations device_ops = { .read_resources = read_resources, .set_resources = set_resources, .enable_resources = pci_dev_enable_resources, + .init = &pmc_init, }; static const struct pci_driver pmc __pci_driver = { |