summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/southbridge/amd/agesa/hudson/Makefile.inc3
-rw-r--r--src/southbridge/amd/agesa/hudson/smi.c60
-rw-r--r--src/southbridge/amd/agesa/hudson/smi.h57
-rw-r--r--src/southbridge/amd/agesa/hudson/smihandler.c100
4 files changed, 220 insertions, 0 deletions
diff --git a/src/southbridge/amd/agesa/hudson/Makefile.inc b/src/southbridge/amd/agesa/hudson/Makefile.inc
index 54a93d23f8..b92e850664 100644
--- a/src/southbridge/amd/agesa/hudson/Makefile.inc
+++ b/src/southbridge/amd/agesa/hudson/Makefile.inc
@@ -22,6 +22,9 @@ ramstage-$(CONFIG_HAVE_ACPI_RESUME) += resume.c
romstage-y += imc.c
ramstage-y += imc.c
+smm-$(CONFIG_HAVE_SMI_HANDLER) += smihandler.c
+ramstage-$(CONFIG_HAVE_SMI_HANDLER) += smi.c
+
# ROMSIG At ROMBASE + 0x20000:
# +-----------+---------------+----------------+------------+
# |0x55AA55AA |EC ROM Address |GEC ROM Address |USB3 ROM |
diff --git a/src/southbridge/amd/agesa/hudson/smi.c b/src/southbridge/amd/agesa/hudson/smi.c
new file mode 100644
index 0000000000..bb5e192f53
--- /dev/null
+++ b/src/southbridge/amd/agesa/hudson/smi.c
@@ -0,0 +1,60 @@
+/*
+ * Utilities for SMM setup
+ *
+ * Copyright (C) 2014 Alexandru Gagniuc <mr.nuke.me@gmail.com>
+ * Subject to the GNU GPL v2, or (at your option) any later version.
+ */
+
+#include "smi.h"
+
+#include <console/console.h>
+#include <cpu/cpu.h>
+
+void smm_setup_structures(void *gnvs, void *tcg, void *smi1)
+{
+ printk(BIOS_DEBUG, "smm_setup_structures STUB!!!\n");
+}
+
+/** Set the EOS bit and enable SMI generation from southbridge */
+void hudson_enable_smi_generation(void)
+{
+ uint32_t reg = smi_read32(SMI_REG_SMITRIG0);
+ reg &= ~SMITRG0_SMIENB; /* Enable SMI generation */
+ reg |= SMITRG0_EOS; /* Set EOS bit */
+ smi_write32(SMI_REG_SMITRIG0, reg);
+}
+
+static void enable_smi(uint8_t smi_num)
+{
+ uint8_t reg32_offset, bit_offset;
+ uint32_t reg32;
+
+ /* SMI sources range from [0:149] */
+ if (smi_num > 149) {
+ printk(BIOS_WARNING, "BUG: Invalid SMI: %u\n", smi_num);
+ return;
+ }
+
+ /* 16 sources per register, 2 bits per source; registers are 4 bytes */
+ reg32_offset = (smi_num / 16) * 4;
+ bit_offset = (smi_num % 16) * 2;
+
+ reg32 = smi_read32(SMI_REG_CONTROL0 + reg32_offset);
+ reg32 &= ~(3 << (bit_offset));
+ reg32 |= (SMI_SRC_MODE_SMI << (bit_offset));
+ smi_write32(SMI_REG_CONTROL0 + reg32_offset, reg32);
+
+}
+
+/** Enable generation of SMIs for given GPE */
+void hudson_enable_gevent_smi(uint8_t gevent)
+{
+ /* GEVENT pins range from [0:23] */
+ if (gevent > 23) {
+ printk(BIOS_WARNING, "BUG: Invalid GEVENT: %u\n", gevent);
+ return;
+ }
+
+ /* SMI0 source is GEVENT0 and so on */
+ enable_smi(gevent);
+}
diff --git a/src/southbridge/amd/agesa/hudson/smi.h b/src/southbridge/amd/agesa/hudson/smi.h
new file mode 100644
index 0000000000..f7120c8b19
--- /dev/null
+++ b/src/southbridge/amd/agesa/hudson/smi.h
@@ -0,0 +1,57 @@
+/*
+ * Utilities for SMI handlers and SMM setup
+ *
+ * Copyright (C) 2014 Alexandru Gagniuc <mr.nuke.me@gmail.com>
+ * Subject to the GNU GPL v2, or (at your option) any later version.
+ */
+
+#ifndef _SOUTHBRIDGE_AMD_AGESA_HUDSON_SMI_H
+#define _SOUTHBRIDGE_AMD_AGESA_HUDSON_SMI_H
+
+#include <arch/io.h>
+
+/* ACPI_MMIO_BASE + 0x200 -- leave this string here so grep catches it.
+ * This is defined by AGESA, but we dpn't include AGESA headers to avoid
+ * polluting the namesace.
+ */
+#define SMI_BASE 0xfed80200
+
+#define SMI_REG_SMITRIG0 0x98
+#define SMITRG0_EOS (1 << 28)
+#define SMITRG0_SMIENB (1 << 31)
+
+#define SMI_REG_CONTROL0 0xa0
+
+enum smi_src_mode {
+ SMI_SRC_MODE_DISABLE = 0,
+ SMI_SRC_MODE_SMI = 1,
+ SMI_SRC_MODE_NMI = 2,
+ SMI_SRC_MODE_IRQ13 = 3,
+};
+
+static inline uint32_t smi_read32(uint8_t offset)
+{
+ return read32(SMI_BASE + offset);
+}
+
+static inline void smi_write32(uint8_t offset, uint32_t value)
+{
+ write32(SMI_BASE + offset, value);
+}
+
+static inline uint16_t smi_read16(uint8_t offset)
+{
+ return read16(SMI_BASE + offset);
+}
+
+static inline void smi_write16(uint8_t offset, uint16_t value)
+{
+ write16(SMI_BASE + offset, value);
+}
+
+#ifndef __SMM__
+void hudson_enable_smi_generation(void);
+void hudson_enable_gevent_smi(uint8_t gevent);
+#endif
+
+#endif /* _SOUTHBRIDGE_AMD_AGESA_HUDSON_SMI_H */
diff --git a/src/southbridge/amd/agesa/hudson/smihandler.c b/src/southbridge/amd/agesa/hudson/smihandler.c
new file mode 100644
index 0000000000..0bf0cdd1d3
--- /dev/null
+++ b/src/southbridge/amd/agesa/hudson/smihandler.c
@@ -0,0 +1,100 @@
+/*
+ * SMI handler for Hudson southbridges
+ *
+ * Copyright (C) 2014 Alexandru Gagniuc <mr.nuke.me@gmail.com>
+ * Subject to the GNU GPL v2, or (at your option) any later version.
+ */
+
+#include "smi.h"
+
+#include <console/console.h>
+#include <cpu/x86/smm.h>
+#include <delay.h>
+
+
+enum smi_source {
+ SMI_SOURCE_SCI = (1 << 0),
+ SMI_SOURCE_GPE = (1 << 1),
+ SMI_SOURCE_0x84 = (1 << 2),
+ SMI_SOURCE_0x88 = (1 << 3),
+ SMI_SOURCE_IRQ_TRAP = (1 << 4),
+ SMI_SOURCE_0x90 = (1 << 5)
+};
+
+int southbridge_io_trap_handler(int smif)
+{
+ return 0;
+}
+
+static void process_smi_sci(void)
+{
+ const uint32_t status = smi_read32(0x10);
+
+ /* Clear events to prevent re-entering SMI if event isn't handled */
+ smi_write32(0x10, status);
+}
+
+static void process_gpe_smi(void)
+{
+ const uint32_t status = smi_read32(0x80);
+
+ /* Clear events to prevent re-entering SMI if event isn't handled */
+ smi_write32(0x80, status);
+}
+
+static void process_smi_0x84(void)
+{
+ const uint32_t status = smi_read32(0x84);
+
+ /* Clear events to prevent re-entering SMI if event isn't handled */
+ smi_write32(0x84, status);
+}
+
+static void process_smi_0x88(void)
+{
+ const uint32_t status = smi_read32(0x88);
+
+ /* Clear events to prevent re-entering SMI if event isn't handled */
+ smi_write32(0x88, status);
+}
+
+static void process_smi_0x8c(void)
+{
+ const uint32_t status = smi_read32(0x8c);
+
+ /* Clear events to prevent re-entering SMI if event isn't handled */
+ smi_write32(0x8c, status);
+}
+
+static void process_smi_0x90(void)
+{
+ const uint32_t status = smi_read32(0x90);
+
+ /* Clear events to prevent re-entering SMI if event isn't handled */
+ smi_write32(0x90, status);
+}
+
+void southbridge_smi_handler(unsigned int node, smm_state_save_area_t *state_save)
+{
+ const uint16_t smi_src = smi_read16(0x94);
+
+ if (smi_src & SMI_SOURCE_SCI)
+ process_smi_sci();
+ if (smi_src & SMI_SOURCE_GPE)
+ process_gpe_smi();
+ if (smi_src & SMI_SOURCE_0x84)
+ process_smi_0x84();
+ if (smi_src & SMI_SOURCE_0x88)
+ process_smi_0x88();
+ if (smi_src & SMI_SOURCE_IRQ_TRAP)
+ process_smi_0x8c();
+ if (smi_src & SMI_SOURCE_0x90)
+ process_smi_0x90();
+}
+
+void southbridge_smi_set_eos(void)
+{
+ uint32_t reg = smi_read32(SMI_REG_SMITRIG0);
+ reg |= SMITRG0_EOS;
+ smi_write32(SMI_REG_SMITRIG0, reg);
+}