southbridge/hudson: Add support for ACPI enable/disable via SMI
This enables the ACPI SMI command port in the FADT table, and sets up the hardware accordingly. If we have SMI enabled, then we don't set the SCI_EN bit at boot, causing the OS to send the ACPI_ENABLE command, as required by the ACPI spec. This gives us a chance to hook into the mainboard_smi_apmc() handler. Change-Id: Ib4c63d55b3132578dcae48bfe2092d4ea35821dd Signed-off-by: Alexandru Gagniuc <mr.nuke.me@gmail.com> Reviewed-on: http://review.coreboot.org/5511 Tested-by: build bot (Jenkins) Reviewed-by: Aaron Durbin <adurbin@gmail.com>
This commit is contained in:
parent
22d90e34f9
commit
288c95882d
|
@ -27,6 +27,7 @@
|
||||||
#include <arch/io.h>
|
#include <arch/io.h>
|
||||||
#include <device/device.h>
|
#include <device/device.h>
|
||||||
#include "hudson.h"
|
#include "hudson.h"
|
||||||
|
#include "smi.h"
|
||||||
|
|
||||||
#if CONFIG_HUDSON_LEGACY_FREE
|
#if CONFIG_HUDSON_LEGACY_FREE
|
||||||
#define FADT_BOOT_ARCH ACPI_FADT_LEGACY_FREE
|
#define FADT_BOOT_ARCH ACPI_FADT_LEGACY_FREE
|
||||||
|
@ -63,26 +64,41 @@ void acpi_create_fadt(acpi_fadt_t * fadt, acpi_facs_t * facs, void *dsdt)
|
||||||
fadt->model = 0; /* reserved, should be 0 ACPI 3.0 */
|
fadt->model = 0; /* reserved, should be 0 ACPI 3.0 */
|
||||||
fadt->preferred_pm_profile = FADT_PM_PROFILE;
|
fadt->preferred_pm_profile = FADT_PM_PROFILE;
|
||||||
fadt->sci_int = 9; /* HUDSON - IRQ 09 – ACPI SCI */
|
fadt->sci_int = 9; /* HUDSON - IRQ 09 – ACPI SCI */
|
||||||
|
|
||||||
|
/* We write to this port further down; configure it first */
|
||||||
|
pm_write16(0x62, ACPI_PM1_CNT_BLK);
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_HAVE_SMI_HANDLER)) {
|
||||||
|
fadt->smi_cmd = ACPI_SMI_CTL_PORT;
|
||||||
|
fadt->acpi_enable = ACPI_SMI_CMD_ENABLE;
|
||||||
|
fadt->acpi_disable = ACPI_SMI_CMD_DISABLE;
|
||||||
|
fadt->s4bios_req = 0; /* Not supported */
|
||||||
|
fadt->pstate_cnt = 0; /* Not supported */
|
||||||
|
fadt->cst_cnt = 0; /* Not supported */
|
||||||
|
hudson_enable_acpi_cmd_smi();
|
||||||
|
outl(0x0, ACPI_PM1_CNT_BLK); /* clear SCI_EN */
|
||||||
|
} else {
|
||||||
fadt->smi_cmd = 0; /* disable system management mode */
|
fadt->smi_cmd = 0; /* disable system management mode */
|
||||||
fadt->acpi_enable = 0; /* unused if SMI_CMD = 0 */
|
fadt->acpi_enable = 0; /* unused if SMI_CMD = 0 */
|
||||||
fadt->acpi_disable = 0; /* unused if SMI_CMD = 0 */
|
fadt->acpi_disable = 0; /* unused if SMI_CMD = 0 */
|
||||||
fadt->s4bios_req = 0; /* unused if SMI_CMD = 0 */
|
fadt->s4bios_req = 0; /* unused if SMI_CMD = 0 */
|
||||||
fadt->pstate_cnt = 0; /* unused if SMI_CMD = 0 */
|
fadt->pstate_cnt = 0; /* unused if SMI_CMD = 0 */
|
||||||
|
fadt->cst_cnt = 0x00; /* unused if SMI_CMD = 0 */
|
||||||
|
outl(0x1, ACPI_PM1_CNT_BLK); /* set SCI_EN */
|
||||||
|
}
|
||||||
|
|
||||||
pm_write16(0x60, ACPI_PM_EVT_BLK);
|
pm_write16(0x60, ACPI_PM_EVT_BLK);
|
||||||
pm_write16(0x62, ACPI_PM1_CNT_BLK);
|
|
||||||
pm_write16(0x64, ACPI_PM_TMR_BLK);
|
pm_write16(0x64, ACPI_PM_TMR_BLK);
|
||||||
pm_write16(0x68, ACPI_GPE0_BLK);
|
pm_write16(0x68, ACPI_GPE0_BLK);
|
||||||
/* CpuControl is in \_PR.CPU0, 6 bytes */
|
/* CpuControl is in \_PR.CPU0, 6 bytes */
|
||||||
pm_write16(0x66, ACPI_CPU_CONTROL);
|
pm_write16(0x66, ACPI_CPU_CONTROL);
|
||||||
pm_write16(0x6A, 0); /* AcpiSmiCmd */
|
pm_write16(0x6a, fadt->smi_cmd);
|
||||||
|
|
||||||
pm_write8(0x74, 1<<0 | 1<<1 | 1<<4 | 1<<2); /* AcpiDecodeEnable, When set, SB uses
|
pm_write8(0x74, 1<<0 | 1<<1 | 1<<4 | 1<<2); /* AcpiDecodeEnable, When set, SB uses
|
||||||
* the contents of the PM registers at
|
* the contents of the PM registers at
|
||||||
* index 60-6B to decode ACPI I/O address.
|
* index 60-6B to decode ACPI I/O address.
|
||||||
* AcpiSmiEn & SmiCmdEn*/
|
* AcpiSmiEn & SmiCmdEn*/
|
||||||
/* RTC_En_En, TMR_En_En, GBL_EN_EN */
|
|
||||||
outl(0x1, ACPI_PM1_CNT_BLK); /* set SCI_EN */
|
|
||||||
fadt->pm1a_evt_blk = ACPI_PM_EVT_BLK;
|
fadt->pm1a_evt_blk = ACPI_PM_EVT_BLK;
|
||||||
fadt->pm1b_evt_blk = 0x0000;
|
fadt->pm1b_evt_blk = 0x0000;
|
||||||
fadt->pm1a_cnt_blk = ACPI_PM1_CNT_BLK;
|
fadt->pm1a_cnt_blk = ACPI_PM1_CNT_BLK;
|
||||||
|
@ -100,7 +116,6 @@ void acpi_create_fadt(acpi_fadt_t * fadt, acpi_facs_t * facs, void *dsdt)
|
||||||
fadt->gpe1_blk_len = 0;
|
fadt->gpe1_blk_len = 0;
|
||||||
fadt->gpe1_base = 0;
|
fadt->gpe1_base = 0;
|
||||||
|
|
||||||
fadt->cst_cnt = 0x00; /* unused if SMI_CMD = 0 */
|
|
||||||
fadt->p_lvl2_lat = ACPI_FADT_C2_NOT_SUPPORTED;
|
fadt->p_lvl2_lat = ACPI_FADT_C2_NOT_SUPPORTED;
|
||||||
fadt->p_lvl3_lat = ACPI_FADT_C3_NOT_SUPPORTED;
|
fadt->p_lvl3_lat = ACPI_FADT_C3_NOT_SUPPORTED;
|
||||||
fadt->flush_size = 0; /* set to 0 if WBINVD is 1 in flags */
|
fadt->flush_size = 0; /* set to 0 if WBINVD is 1 in flags */
|
||||||
|
|
|
@ -29,6 +29,8 @@
|
||||||
#define BIOSRAM_DATA 0xcd5
|
#define BIOSRAM_DATA 0xcd5
|
||||||
#define PM_INDEX 0xcd6
|
#define PM_INDEX 0xcd6
|
||||||
#define PM_DATA 0xcd7
|
#define PM_DATA 0xcd7
|
||||||
|
#define PM2_INDEX 0xcd0
|
||||||
|
#define PM2_DATA 0xcd1
|
||||||
|
|
||||||
#define HUDSON_ACPI_IO_BASE 0x800
|
#define HUDSON_ACPI_IO_BASE 0x800
|
||||||
|
|
||||||
|
@ -46,9 +48,17 @@
|
||||||
#define PM1_TMR_BLK_ADDRESS 0x808 // AcpiPmTmrBlkAddr;
|
#define PM1_TMR_BLK_ADDRESS 0x808 // AcpiPmTmrBlkAddr;
|
||||||
#define CPU_CNT_BLK_ADDRESS 0x810 // CpuControlBlkAddr;
|
#define CPU_CNT_BLK_ADDRESS 0x810 // CpuControlBlkAddr;
|
||||||
#define GPE0_BLK_ADDRESS 0x820 // AcpiGpe0BlkAddr;
|
#define GPE0_BLK_ADDRESS 0x820 // AcpiGpe0BlkAddr;
|
||||||
#define SMI_CMD_PORT 0xB0 // SmiCmdPortAddr;
|
|
||||||
#define SPIROM_BASE_ADDRESS_REGISTER 0xA0
|
#define SPIROM_BASE_ADDRESS_REGISTER 0xA0
|
||||||
|
|
||||||
|
#define ACPI_SMI_CTL_PORT 0xb2
|
||||||
|
#define ACPI_SMI_CMD_CST_CONTROL 0xde
|
||||||
|
#define ACPI_SMI_CMD_PST_CONTROL 0xad
|
||||||
|
#define ACPI_SMI_CMD_DISABLE 0xbe
|
||||||
|
#define ACPI_SMI_CMD_ENABLE 0xef
|
||||||
|
#define ACPI_SMI_CMD_S4_REQ 0xc0
|
||||||
|
|
||||||
|
#ifndef __SMM__
|
||||||
|
|
||||||
void pm_write8(u8 reg, u8 value);
|
void pm_write8(u8 reg, u8 value);
|
||||||
u8 pm_read8(u8 reg);
|
u8 pm_read8(u8 reg);
|
||||||
void pm_write16(u8 reg, u16 value);
|
void pm_write16(u8 reg, u16 value);
|
||||||
|
@ -70,6 +80,7 @@ void hudson_enable(device_t dev);
|
||||||
void __attribute__((weak)) hudson_setup_sata_phys(struct device *dev);
|
void __attribute__((weak)) hudson_setup_sata_phys(struct device *dev);
|
||||||
void s3_resume_init_data(void *FchParams);
|
void s3_resume_init_data(void *FchParams);
|
||||||
|
|
||||||
#endif
|
#endif /* __PRE_RAM__ */
|
||||||
|
#endif /* __SMM__ */
|
||||||
|
|
||||||
#endif /* HUDSON_H */
|
#endif /* HUDSON_H */
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
#include <console/console.h>
|
#include <console/console.h>
|
||||||
#include <cpu/cpu.h>
|
#include <cpu/cpu.h>
|
||||||
|
|
||||||
|
#define HUDSON_SMI_ACPI_COMMAND 75
|
||||||
|
|
||||||
void smm_setup_structures(void *gnvs, void *tcg, void *smi1)
|
void smm_setup_structures(void *gnvs, void *tcg, void *smi1)
|
||||||
{
|
{
|
||||||
printk(BIOS_DEBUG, "smm_setup_structures STUB!!!\n");
|
printk(BIOS_DEBUG, "smm_setup_structures STUB!!!\n");
|
||||||
|
@ -58,3 +60,9 @@ void hudson_enable_gevent_smi(uint8_t gevent)
|
||||||
/* SMI0 source is GEVENT0 and so on */
|
/* SMI0 source is GEVENT0 and so on */
|
||||||
enable_smi(gevent);
|
enable_smi(gevent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Enable SMIs on writes to ACPI SMI command port */
|
||||||
|
void hudson_enable_acpi_cmd_smi(void)
|
||||||
|
{
|
||||||
|
enable_smi(HUDSON_SMI_ACPI_COMMAND);
|
||||||
|
}
|
||||||
|
|
|
@ -52,6 +52,7 @@ static inline void smi_write16(uint8_t offset, uint16_t value)
|
||||||
#ifndef __SMM__
|
#ifndef __SMM__
|
||||||
void hudson_enable_smi_generation(void);
|
void hudson_enable_smi_generation(void);
|
||||||
void hudson_enable_gevent_smi(uint8_t gevent);
|
void hudson_enable_gevent_smi(uint8_t gevent);
|
||||||
|
void hudson_enable_acpi_cmd_smi(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* _SOUTHBRIDGE_AMD_AGESA_HUDSON_SMI_H */
|
#endif /* _SOUTHBRIDGE_AMD_AGESA_HUDSON_SMI_H */
|
||||||
|
|
|
@ -5,12 +5,14 @@
|
||||||
* Subject to the GNU GPL v2, or (at your option) any later version.
|
* Subject to the GNU GPL v2, or (at your option) any later version.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "hudson.h"
|
||||||
#include "smi.h"
|
#include "smi.h"
|
||||||
|
|
||||||
#include <console/console.h>
|
#include <console/console.h>
|
||||||
#include <cpu/x86/smm.h>
|
#include <cpu/x86/smm.h>
|
||||||
#include <delay.h>
|
#include <delay.h>
|
||||||
|
|
||||||
|
#define SMI_0x88_ACPI_COMMAND (1 << 11)
|
||||||
|
|
||||||
enum smi_source {
|
enum smi_source {
|
||||||
SMI_SOURCE_SCI = (1 << 0),
|
SMI_SOURCE_SCI = (1 << 0),
|
||||||
|
@ -21,6 +23,28 @@ enum smi_source {
|
||||||
SMI_SOURCE_0x90 = (1 << 5)
|
SMI_SOURCE_0x90 = (1 << 5)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void hudson_apmc_smi_handler(void)
|
||||||
|
{
|
||||||
|
u32 reg32;
|
||||||
|
const uint8_t cmd = inb(ACPI_SMI_CTL_PORT);
|
||||||
|
|
||||||
|
switch (cmd) {
|
||||||
|
case ACPI_SMI_CMD_ENABLE:
|
||||||
|
reg32 = inl(ACPI_PM1_CNT_BLK);
|
||||||
|
reg32 |= (1 << 0); /* SCI_EN */
|
||||||
|
outl(reg32, ACPI_PM1_CNT_BLK);
|
||||||
|
break;
|
||||||
|
case ACPI_SMI_CMD_DISABLE:
|
||||||
|
reg32 = inl(ACPI_PM1_CNT_BLK);
|
||||||
|
reg32 &= ~(1 << 0); /* clear SCI_EN */
|
||||||
|
outl(ACPI_PM1_CNT_BLK, reg32);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mainboard_smi_apmc)
|
||||||
|
mainboard_smi_apmc(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
int southbridge_io_trap_handler(int smif)
|
int southbridge_io_trap_handler(int smif)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -62,6 +86,10 @@ static void process_smi_0x88(void)
|
||||||
{
|
{
|
||||||
const uint32_t status = smi_read32(0x88);
|
const uint32_t status = smi_read32(0x88);
|
||||||
|
|
||||||
|
if (status & SMI_0x88_ACPI_COMMAND) {
|
||||||
|
/* Command received via ACPI SMI command port */
|
||||||
|
hudson_apmc_smi_handler();
|
||||||
|
}
|
||||||
/* Clear events to prevent re-entering SMI if event isn't handled */
|
/* Clear events to prevent re-entering SMI if event isn't handled */
|
||||||
smi_write32(0x88, status);
|
smi_write32(0x88, status);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue