soc/intel/common/block/gpio: add code for NMI enabling
Especially server boards, like the Supermicro X11SSM-F, often have a NMI button and NMI functionality that can be triggered via IPMI. The purpose of this is to cause the OS to create a system crashdump from a hang system or for debugging. Add code for enabling NMI interrupts on GPIOs configured with PAD_CFG_GPI_NMI. The enabling mechanism is the same as SMI, so the SMI function was copied and adapted. The `pad_community` struct gained two variables for the registers. Also register the NMI for LINT1 in the MADT in accordance to ACPI spec. Test: Linux detects the NMI correctly in dmesg: [ 0.053734] ACPI: LAPIC_NMI (acpi_id[0xff] high edge lint[0x1]) Signed-off-by: Michael Niewöhner <foss@mniewoehner.de> Change-Id: I4fc1a35c99c6a28b20e08a80b97bb4b8624935c9 Reviewed-on: https://review.coreboot.org/c/coreboot/+/48090 Reviewed-by: Tim Wawrzynczak <twawrzynczak@chromium.org> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
parent
c3ab442cc1
commit
14512f9a9b
|
@ -79,6 +79,9 @@ static unsigned long acpi_madt_irq_overrides(unsigned long current)
|
||||||
current +=
|
current +=
|
||||||
acpi_create_madt_irqoverride((void *)current, 0, sci, sci, flags);
|
acpi_create_madt_irqoverride((void *)current, 0, sci, sci, flags);
|
||||||
|
|
||||||
|
/* NMI */
|
||||||
|
current += acpi_create_madt_lapic_nmi((acpi_madt_lapic_nmi_t *)current, 0xff, 5, 1);
|
||||||
|
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,6 +48,10 @@
|
||||||
((group) * sizeof(uint32_t)))
|
((group) * sizeof(uint32_t)))
|
||||||
#define GPI_SMI_EN_OFFSET(comm, group) ((comm)->gpi_smi_en_reg_0 + \
|
#define GPI_SMI_EN_OFFSET(comm, group) ((comm)->gpi_smi_en_reg_0 + \
|
||||||
((group) * sizeof(uint32_t)))
|
((group) * sizeof(uint32_t)))
|
||||||
|
#define GPI_NMI_STS_OFFSET(comm, group) ((comm)->gpi_nmi_sts_reg_0 + \
|
||||||
|
((group) * sizeof(uint32_t)))
|
||||||
|
#define GPI_NMI_EN_OFFSET(comm, group) ((comm)->gpi_nmi_en_reg_0 + \
|
||||||
|
((group) * sizeof(uint32_t)))
|
||||||
#define GPI_IS_OFFSET(comm, group) ((comm)->gpi_int_sts_reg_0 + \
|
#define GPI_IS_OFFSET(comm, group) ((comm)->gpi_int_sts_reg_0 + \
|
||||||
((group) * sizeof(uint32_t)))
|
((group) * sizeof(uint32_t)))
|
||||||
#define GPI_IE_OFFSET(comm, group) ((comm)->gpi_int_en_reg_0 + \
|
#define GPI_IE_OFFSET(comm, group) ((comm)->gpi_int_en_reg_0 + \
|
||||||
|
@ -176,6 +180,35 @@ static void gpi_enable_smi(const struct pad_config *cfg,
|
||||||
pcr_or32(comm->port, en_reg, en_value);
|
pcr_or32(comm->port, en_reg, en_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void gpi_enable_nmi(const struct pad_config *cfg,
|
||||||
|
const struct pad_community *comm)
|
||||||
|
{
|
||||||
|
uint16_t sts_reg;
|
||||||
|
uint16_t en_reg;
|
||||||
|
uint32_t en_value;
|
||||||
|
int group;
|
||||||
|
int pin;
|
||||||
|
|
||||||
|
if (((cfg->pad_config[0]) & PAD_CFG0_ROUTE_NMI) != PAD_CFG0_ROUTE_NMI)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Do not configure NMI if the platform doesn't support it */
|
||||||
|
if (!comm->gpi_nmi_sts_reg_0 || !comm->gpi_nmi_en_reg_0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pin = relative_pad_in_comm(comm, cfg->pad);
|
||||||
|
group = gpio_group_index(comm, pin);
|
||||||
|
sts_reg = GPI_NMI_STS_OFFSET(comm, group);
|
||||||
|
en_reg = GPI_NMI_EN_OFFSET(comm, group);
|
||||||
|
en_value = gpio_bitmask_within_group(comm, pin);
|
||||||
|
|
||||||
|
/* Write back 1 to reset the sts bit */
|
||||||
|
pcr_rmw32(comm->port, sts_reg, en_value, 0);
|
||||||
|
|
||||||
|
/* Set enable bits */
|
||||||
|
pcr_or32(comm->port, en_reg, en_value);
|
||||||
|
}
|
||||||
|
|
||||||
static void gpio_configure_itss(const struct pad_config *cfg, uint16_t port,
|
static void gpio_configure_itss(const struct pad_config *cfg, uint16_t port,
|
||||||
uint16_t pad_cfg_offset)
|
uint16_t pad_cfg_offset)
|
||||||
{
|
{
|
||||||
|
@ -283,6 +316,7 @@ static void gpio_configure_pad(const struct pad_config *cfg)
|
||||||
gpio_configure_itss(cfg, comm->port, config_offset);
|
gpio_configure_itss(cfg, comm->port, config_offset);
|
||||||
gpio_configure_owner(cfg, comm);
|
gpio_configure_owner(cfg, comm);
|
||||||
gpi_enable_smi(cfg, comm);
|
gpi_enable_smi(cfg, comm);
|
||||||
|
gpi_enable_nmi(cfg, comm);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gpio_configure_pads(const struct pad_config *cfg, size_t num_pads)
|
void gpio_configure_pads(const struct pad_config *cfg, size_t num_pads)
|
||||||
|
|
|
@ -111,6 +111,8 @@ struct pad_community {
|
||||||
uint16_t gpi_int_en_reg_0; /* offset to GPI Int Enable Reg 0 */
|
uint16_t gpi_int_en_reg_0; /* offset to GPI Int Enable Reg 0 */
|
||||||
uint16_t gpi_smi_sts_reg_0; /* offset to GPI SMI STS Reg 0 */
|
uint16_t gpi_smi_sts_reg_0; /* offset to GPI SMI STS Reg 0 */
|
||||||
uint16_t gpi_smi_en_reg_0; /* offset to GPI SMI EN Reg 0 */
|
uint16_t gpi_smi_en_reg_0; /* offset to GPI SMI EN Reg 0 */
|
||||||
|
uint16_t gpi_nmi_sts_reg_0; /* offset to GPI NMI STS Reg 0 */
|
||||||
|
uint16_t gpi_nmi_en_reg_0; /* offset to GPI NMI EN Reg 0 */
|
||||||
uint16_t pad_cfg_base; /* offset to first PAD_GFG_DW0 Reg */
|
uint16_t pad_cfg_base; /* offset to first PAD_GFG_DW0 Reg */
|
||||||
uint8_t gpi_status_offset; /* specifies offset in struct
|
uint8_t gpi_status_offset; /* specifies offset in struct
|
||||||
gpi_status */
|
gpi_status */
|
||||||
|
|
|
@ -522,6 +522,9 @@ unsigned long acpi_madt_irq_overrides(unsigned long current)
|
||||||
irqovr = (void *)current;
|
irqovr = (void *)current;
|
||||||
current += acpi_create_madt_irqoverride(irqovr, 0, sci, sci, flags);
|
current += acpi_create_madt_irqoverride(irqovr, 0, sci, sci, flags);
|
||||||
|
|
||||||
|
/* NMI */
|
||||||
|
current += acpi_create_madt_lapic_nmi((acpi_madt_lapic_nmi_t *)current, 0xff, 5, 1);
|
||||||
|
|
||||||
return current;
|
return current;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue