diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/soc/amd/stoneyridge/include/soc/smi.h | 38 | ||||
-rw-r--r-- | src/soc/amd/stoneyridge/include/soc/southbridge.h | 2 | ||||
-rw-r--r-- | src/soc/amd/stoneyridge/sb_util.c | 10 | ||||
-rw-r--r-- | src/soc/amd/stoneyridge/smi_util.c | 53 |
4 files changed, 98 insertions, 5 deletions
diff --git a/src/soc/amd/stoneyridge/include/soc/smi.h b/src/soc/amd/stoneyridge/include/soc/smi.h index 797f4e8578..34d3d74848 100644 --- a/src/soc/amd/stoneyridge/include/soc/smi.h +++ b/src/soc/amd/stoneyridge/include/soc/smi.h @@ -20,7 +20,18 @@ #include <arch/io.h> +#define SMI_GEVENTS 24 +#define SCIMAPS 58 +#define SCI_GPES 32 + +#define SMI_EVENT_STATUS 0x0 +#define SMI_EVENT_ENABLE 0x04 +#define SMI_SCI_TRIG 0x08 +#define SMI_SCI_LEVEL 0x0c #define SMI_SCI_STATUS 0x10 +#define SMI_SCI_EN 0x14 +#define SMI_SCI_MAP0 0x40 +# define SMI_SCI_MAP(X) (SMI_SCI_MAP0 + (X)) /* SMI source and status */ #define SMITYPE_AGPIO65 0 @@ -189,9 +200,21 @@ enum smi_mode { SMI_MODE_IRQ13 = 3, }; -enum smi_lvl { - SMI_LVL_LOW = 0, - SMI_LVL_HIGH = 1, +enum smi_sci_type { + NONE, + SCI, + SMI, + BOTH, +}; + +enum smi_sci_lvl { + SMI_SCI_LVL_LOW, + SMI_SCI_LVL_HIGH, +}; + +enum smi_sci_dir { + SMI_SCI_EDG, + SMI_SCI_LVL, }; struct smi_sources_t { @@ -199,10 +222,19 @@ struct smi_sources_t { void (*handler)(void); }; +struct sci_source { + uint8_t scimap; /* SCIMAP 0-57 */ + uint8_t gpe; /* 32 GPEs */ + uint8_t direction; /* Active High or Low, smi_sci_lvl */ + uint8_t level; /* Edge or Level, smi_sci_dir */ +}; + uint16_t pm_acpi_smi_cmd_port(void); void configure_smi(uint8_t smi_num, uint8_t mode); void configure_gevent_smi(uint8_t gevent, uint8_t mode, uint8_t level); +void configure_scimap(const struct sci_source *sci); void disable_gevent_smi(uint8_t gevent); +void gpe_configure_sci(const struct sci_source *scis, size_t num_gpes); #ifndef __SMM__ void enable_smi_generation(void); diff --git a/src/soc/amd/stoneyridge/include/soc/southbridge.h b/src/soc/amd/stoneyridge/include/soc/southbridge.h index 8e04b68ab2..55ded9ffa8 100644 --- a/src/soc/amd/stoneyridge/include/soc/southbridge.h +++ b/src/soc/amd/stoneyridge/include/soc/southbridge.h @@ -276,8 +276,10 @@ u32 pm_read32(u8 reg); void pm_write8(u8 reg, u8 value); void pm_write16(u8 reg, u16 value); void pm_write32(u8 reg, u32 value); +u8 smi_read8(u8 reg); u16 smi_read16(u8 reg); u32 smi_read32(u8 reg); +void smi_write8(u8 reg, u8 value); void smi_write16(u8 reg, u16 value); void smi_write32(u8 reg, u32 value); uint16_t pm_acpi_pm_cnt_blk(void); diff --git a/src/soc/amd/stoneyridge/sb_util.c b/src/soc/amd/stoneyridge/sb_util.c index bdb199aa1e..ebf791d6ff 100644 --- a/src/soc/amd/stoneyridge/sb_util.c +++ b/src/soc/amd/stoneyridge/sb_util.c @@ -65,6 +65,16 @@ void smi_write16(uint8_t offset, uint16_t value) write16((void *)(APU_SMI_BASE + offset), value); } +uint8_t smi_read8(uint8_t offset) +{ + return read8((void *)(APU_SMI_BASE + offset)); +} + +void smi_write8(uint8_t offset, uint8_t value) +{ + write8((void *)(APU_SMI_BASE + offset), value); +} + uint16_t pm_acpi_pm_cnt_blk(void) { return pm_read16(PM1_CNT_BLK); diff --git a/src/soc/amd/stoneyridge/smi_util.c b/src/soc/amd/stoneyridge/smi_util.c index 96e9d6156b..7b176dee30 100644 --- a/src/soc/amd/stoneyridge/smi_util.c +++ b/src/soc/amd/stoneyridge/smi_util.c @@ -35,13 +35,13 @@ void configure_smi(uint8_t smi_num, uint8_t mode) * @param gevent The GEVENT pin number. Valid values are 0 thru 23 * @param mode The type of event this pin should generate. Note that only * SMI_MODE_SMI generates an SMI. SMI_MODE_DISABLE disables events. - * @param level SMI_LVL_LOW or SMI_LVL_HIGH + * @param level SMI__SCI_LVL_LOW or SMI_SCI_LVL_HIGH */ void configure_gevent_smi(uint8_t gevent, uint8_t mode, uint8_t level) { uint32_t reg32; /* GEVENT pins range from [0:23] */ - if (gevent > 23) { + if (gevent >= SMI_GEVENTS) { printk(BIOS_WARNING, "BUG: Invalid GEVENT: %u\n", gevent); return; } @@ -56,6 +56,55 @@ void configure_gevent_smi(uint8_t gevent, uint8_t mode, uint8_t level) smi_write32(SMI_REG_SMITRIG0, reg32); } +/** + * Configure generation of SCIs. + */ +void configure_scimap(const struct sci_source *sci) +{ + uint32_t reg32; + + /* GEVENT pins range */ + if (sci->scimap >= SCIMAPS) { + printk(BIOS_WARNING, "BUG: Invalid SCIMAP: %u\n", + sci->scimap); + return; + } + + /* GPEs range from [0:31] */ + if (sci->gpe >= SCI_GPES) { + printk(BIOS_WARNING, "BUG: Invalid SCI GPE: %u\n", sci->gpe); + return; + } + + printk(BIOS_DEBUG, "SCIMAP %u maps to GPE %u (active %s, %s trigger)\n", + sci->scimap, sci->gpe, + (!!sci->direction) ? "high" : "low", + (!!sci->level) ? "level" : "edge"); + + /* Map Gevent to SCI GPE# */ + smi_write8(SMI_SCI_MAP(sci->scimap), sci->gpe); + + /* Set the trigger direction (high/low) */ + reg32 = smi_read32(SMI_SCI_TRIG); + reg32 &= ~(1 << sci->gpe); + reg32 |= !!sci->direction << sci->gpe; + smi_write32(SMI_SCI_TRIG, reg32); + + /* Set the trigger level (edge/level) */ + reg32 = smi_read32(SMI_SCI_LEVEL); + reg32 &= ~(1 << sci->gpe); + reg32 |= !!sci->level << sci->gpe; + smi_write32(SMI_SCI_LEVEL, reg32); +} + +void gpe_configure_sci(const struct sci_source *scis, size_t num_gpes) +{ + size_t i; + + for (i = 0; i < num_gpes; i++) + configure_scimap(scis + i); +} + /** Disable events from given GEVENT pin */ void disable_gevent_smi(uint8_t gevent) { |