mirror of
https://github.com/fail0verflow/switch-coreboot.git
synced 2025-05-04 01:39:18 -04:00
soc/intel/apollolake: Add GPE routing code
This patch adds the basic framework for SCI to GPE routing code. BUG = chrome-os-partner:53438 TEST = Toogle pch_sci_l from ec console using gpioset command and see that the sci counter increases in /sys/firmware/acpi/interrupt and also 9 in /proc/interrupts. Change-Id: I3b3198276530bf6513d94e9bea02ab9751212adf Signed-off-by: Shaunak Saha <shaunak.saha@intel.com> Reviewed-on: https://review.coreboot.org/15324 Reviewed-by: Aaron Durbin <adurbin@chromium.org> Tested-by: build bot (Jenkins)
This commit is contained in:
parent
0b806285a7
commit
5b6c5a500e
7 changed files with 291 additions and 2 deletions
|
@ -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_ */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 = {
|
||||
|
|
Loading…
Add table
Reference in a new issue