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:
Alexandru Gagniuc 2014-04-14 16:35:34 -05:00
parent 22d90e34f9
commit 288c95882d
5 changed files with 75 additions and 12 deletions

View File

@ -27,6 +27,7 @@
#include <arch/io.h>
#include <device/device.h>
#include "hudson.h"
#include "smi.h"
#if CONFIG_HUDSON_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->preferred_pm_profile = FADT_PM_PROFILE;
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->acpi_enable = 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->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(0x62, ACPI_PM1_CNT_BLK);
pm_write16(0x64, ACPI_PM_TMR_BLK);
pm_write16(0x68, ACPI_GPE0_BLK);
/* CpuControl is in \_PR.CPU0, 6 bytes */
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
* the contents of the PM registers at
* index 60-6B to decode ACPI I/O address.
* 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->pm1b_evt_blk = 0x0000;
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_base = 0;
fadt->cst_cnt = 0x00; /* unused if SMI_CMD = 0 */
fadt->p_lvl2_lat = ACPI_FADT_C2_NOT_SUPPORTED;
fadt->p_lvl3_lat = ACPI_FADT_C3_NOT_SUPPORTED;
fadt->flush_size = 0; /* set to 0 if WBINVD is 1 in flags */

View File

@ -29,6 +29,8 @@
#define BIOSRAM_DATA 0xcd5
#define PM_INDEX 0xcd6
#define PM_DATA 0xcd7
#define PM2_INDEX 0xcd0
#define PM2_DATA 0xcd1
#define HUDSON_ACPI_IO_BASE 0x800
@ -46,9 +48,17 @@
#define PM1_TMR_BLK_ADDRESS 0x808 // AcpiPmTmrBlkAddr;
#define CPU_CNT_BLK_ADDRESS 0x810 // CpuControlBlkAddr;
#define GPE0_BLK_ADDRESS 0x820 // AcpiGpe0BlkAddr;
#define SMI_CMD_PORT 0xB0 // SmiCmdPortAddr;
#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);
u8 pm_read8(u8 reg);
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 s3_resume_init_data(void *FchParams);
#endif
#endif /* __PRE_RAM__ */
#endif /* __SMM__ */
#endif /* HUDSON_H */

View File

@ -10,6 +10,8 @@
#include <console/console.h>
#include <cpu/cpu.h>
#define HUDSON_SMI_ACPI_COMMAND 75
void smm_setup_structures(void *gnvs, void *tcg, void *smi1)
{
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 */
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);
}

View File

@ -52,6 +52,7 @@ static inline void smi_write16(uint8_t offset, uint16_t value)
#ifndef __SMM__
void hudson_enable_smi_generation(void);
void hudson_enable_gevent_smi(uint8_t gevent);
void hudson_enable_acpi_cmd_smi(void);
#endif
#endif /* _SOUTHBRIDGE_AMD_AGESA_HUDSON_SMI_H */

View File

@ -5,12 +5,14 @@
* Subject to the GNU GPL v2, or (at your option) any later version.
*/
#include "hudson.h"
#include "smi.h"
#include <console/console.h>
#include <cpu/x86/smm.h>
#include <delay.h>
#define SMI_0x88_ACPI_COMMAND (1 << 11)
enum smi_source {
SMI_SOURCE_SCI = (1 << 0),
@ -21,6 +23,28 @@ enum smi_source {
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)
{
return 0;
@ -62,6 +86,10 @@ static void process_smi_0x88(void)
{
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 */
smi_write32(0x88, status);
}