summaryrefslogtreecommitdiff
path: root/src/southbridge
diff options
context:
space:
mode:
Diffstat (limited to 'src/southbridge')
-rw-r--r--src/southbridge/via/vt8237r/vt8237r.h38
-rw-r--r--src/southbridge/via/vt8237r/vt8237r_early_smbus.c106
-rw-r--r--src/southbridge/via/vt8237r/vt8237r_ide.c8
3 files changed, 109 insertions, 43 deletions
diff --git a/src/southbridge/via/vt8237r/vt8237r.h b/src/southbridge/via/vt8237r/vt8237r.h
index f1a8e6886e..6c3b68e5bb 100644
--- a/src/southbridge/via/vt8237r/vt8237r.h
+++ b/src/southbridge/via/vt8237r/vt8237r.h
@@ -30,4 +30,42 @@
#define VT8237R_HPET_ADDR 0xfed00000ULL
#define VT8237R_APIC_BASE 0xfec00000ULL
+/* IDE specific defines */
+#define IDE_CS 0x40
+#define IDE_CONF_I 0x41
+#define IDE_CONF_II 0x42
+#define IDE_CONF_FIFO 0x43
+#define IDE_MISC_I 0x44
+#define IDE_MISC_II 0x45
+#define IDE_UDMA 0x50
+
+/* SMBus specific */
+#define VT8237R_POWER_WELL 0x94
+#define VT8237R_SMBUS_IO_BASE_REG 0xd0
+#define VT8237R_SMBUS_HOST_CONF 0xd2
+
+#define SMBHSTSTAT (VT8237R_SMBUS_IO_BASE + 0x0)
+#define SMBSLVSTAT (VT8237R_SMBUS_IO_BASE + 0x1)
+#define SMBHSTCTL (VT8237R_SMBUS_IO_BASE + 0x2)
+#define SMBHSTCMD (VT8237R_SMBUS_IO_BASE + 0x3)
+#define SMBXMITADD (VT8237R_SMBUS_IO_BASE + 0x4)
+#define SMBHSTDAT0 (VT8237R_SMBUS_IO_BASE + 0x5)
+
+#define HOST_RESET 0xff
+/* 1 in the 0 bit of SMBHSTADD states to READ. */
+#define READ_CMD 0x01
+#define SMBUS_TIMEOUT (100 * 1000 * 10)
+#define I2C_TRANS_CMD 0x40
+#define CLOCK_SLAVE_ADDRESS 0x69
+
+#if DEBUG_SMBUS == 1
+#define PRINT_DEBUG(x) print_debug(x)
+#define PRINT_DEBUG_HEX16(x) print_debug_hex16(x)
+#else
+#define PRINT_DEBUG(x)
+#define PRINT_DEBUG_HEX16(x)
+#endif
+
+#define SMBUS_DELAY() inb(0x80)
+
#endif
diff --git a/src/southbridge/via/vt8237r/vt8237r_early_smbus.c b/src/southbridge/via/vt8237r/vt8237r_early_smbus.c
index 4834c5799d..e3e17111f3 100644
--- a/src/southbridge/via/vt8237r/vt8237r_early_smbus.c
+++ b/src/southbridge/via/vt8237r/vt8237r_early_smbus.c
@@ -20,41 +20,21 @@
*/
#include <device/pci_ids.h>
+#include <spd.h>
#include "vt8237r.h"
-#define VT8237R_POWER_WELL 0x94
-#define VT8237R_SMBUS_IO_BASE_REG 0xd0
-#define VT8237R_SMBUS_HOST_CONF 0xd2
-
-#define SMBHSTSTAT (VT8237R_SMBUS_IO_BASE + 0x0)
-#define SMBSLVSTAT (VT8237R_SMBUS_IO_BASE + 0x1)
-#define SMBHSTCTL (VT8237R_SMBUS_IO_BASE + 0x2)
-#define SMBHSTCMD (VT8237R_SMBUS_IO_BASE + 0x3)
-#define SMBXMITADD (VT8237R_SMBUS_IO_BASE + 0x4)
-#define SMBHSTDAT0 (VT8237R_SMBUS_IO_BASE + 0x5)
-
-#define HOST_RESET 0xff
-/* 1 in the 0 bit of SMBHSTADD states to READ. */
-#define READ_CMD 0x01
-#define SMBUS_TIMEOUT (100 * 1000 * 10)
-#define I2C_TRANS_CMD 0x40
-#define CLOCK_SLAVE_ADDRESS 0x69
-
-#if DEBUG_SMBUS == 1
-#define PRINT_DEBUG(x) print_debug(x)
-#define PRINT_DEBUG_HEX16(x) print_debug_hex16(x)
-#else
-#define PRINT_DEBUG(x)
-#define PRINT_DEBUG_HEX16(x)
-#endif
-
-#define SMBUS_DELAY() inb(0x80)
-
+/**
+ * Print an error, should it occur. If no error, just exit.
+ *
+ * @param host_status The data returned on the host status register after a
+ * transaction is processed.
+ * @param loops The number of times a transaction was attempted.
+ */
static void smbus_print_error(u8 host_status, int loops)
{
/* Check if there actually was an error. */
- if (host_status == 0x00 || host_status == 0x40 ||
- host_status == 0x42)
+ if ((host_status == 0x00 || host_status == 0x40 ||
+ host_status == 0x42) && (loops < SMBUS_TIMEOUT))
return;
if (loops >= SMBUS_TIMEOUT)
@@ -66,11 +46,14 @@ static void smbus_print_error(u8 host_status, int loops)
if (host_status & (1 << 2))
print_err("Device error\r\n");
if (host_status & (1 << 1))
- print_err("Interrupt/SMI# was Successful Completion\r\n");
+ print_debug("Interrupt/SMI# Completed Successfully\r\n");
if (host_status & (1 << 0))
print_err("Host busy\r\n");
}
+/**
+ * Wait for the smbus to become ready to process the next transaction
+ */
static void smbus_wait_until_ready(void)
{
int loops;
@@ -79,11 +62,14 @@ static void smbus_wait_until_ready(void)
loops = 0;
/* Yes, this is a mess, but it's the easiest way to do it. */
- while ((inb(SMBHSTSTAT) & 1) == 1 && loops <= SMBUS_TIMEOUT)
+ while ((inb(SMBHSTSTAT) & 1) == 1 && loops < SMBUS_TIMEOUT)
++loops;
smbus_print_error(inb(SMBHSTSTAT), loops);
}
+/**
+ * Reset and take ownership of the smbus
+ */
static void smbus_reset(void)
{
outb(HOST_RESET, SMBHSTSTAT);
@@ -95,9 +81,15 @@ static void smbus_reset(void)
PRINT_DEBUG("\r\n");
}
-u8 smbus_read_byte(u32 dimm, u32 offset)
+/**
+ * Read a byte from the smbus
+ *
+ * @param dimm The address location of the dimm on the smbus
+ * @param offset The offset the data is located at
+ */
+u8 smbus_read_byte(u8 dimm, u8 offset)
{
- u32 val;
+ u8 val;
PRINT_DEBUG("DIMM ");
PRINT_DEBUG_HEX16(dimm);
@@ -131,10 +123,12 @@ u8 smbus_read_byte(u32 dimm, u32 offset)
/* Probably don't have to do this, but it can't hurt. */
smbus_reset();
- /* Can I just "return inb(SMBHSTDAT0)"? */
return val;
}
+/**
+ * Enable the smbus on vt8237r-based systems
+ */
void enable_smbus(void)
{
device_t dev;
@@ -166,3 +160,45 @@ void enable_smbus(void)
/* Reset the internal pointer. */
inb(SMBHSTCTL);
}
+
+/**
+ * A fixup for some systems that need time for the smbus to "warm up". This is
+ * needed on some vt823x based systems, where the smbus spurts out bad data for
+ * a short time after power on. This has been seen on the Via Epia-series and
+ * Jetway J7F2-series. It reads the ID byte from SMBus, looking for
+ * known-good data from a slot/address. Exits on either good data or a timeout.
+ *
+ * This should probably go into some global file, but one would need to be
+ * created just for it. If some other chip needs/wants it, we can worry about it
+ * then.
+ *
+ * @param ctrl The memory controller and smbus addresses
+ */
+void smbus_fixup(const struct mem_controller *ctrl)
+{
+ int i, ram_slots, current_slot = 0;
+ u8 result = 0;
+
+ ram_slots = ARRAY_SIZE(ctrl->channel0);
+ if (!ram_slots) {
+ print_err("smbus_fixup thinks there are no ram slots!\r\n");
+ return;
+ }
+
+ PRINT_DEBUG("Waiting for smbus to warm up");
+
+ /* Bad SPD data should be either 0 or 0xff, but YMMV. So we look for the
+ * ID bytes of SDRAM, DDR, DDR2, and DDR3 (and anything in between).
+ * vt8237r has only been seen on DDR and DDR2 based systems, so far */
+ for(i = 0; (i < SMBUS_TIMEOUT && ((result < SPD_MEMORY_TYPE_SDRAM) ||
+ (result > SPD_MEMORY_TYPE_SDRAM_DDR3))); i++)
+ {
+ if (current_slot > ram_slots) current_slot = 0;
+ result = smbus_read_byte(ctrl->channel0[current_slot],
+ SPD_MEMORY_TYPE);
+ current_slot++;
+ PRINT_DEBUG(".");
+ }
+ if (i >= SMBUS_TIMEOUT) print_err("SMBus timed out while warming up\r\n");
+ else PRINT_DEBUG("Done\r\n");
+}
diff --git a/src/southbridge/via/vt8237r/vt8237r_ide.c b/src/southbridge/via/vt8237r/vt8237r_ide.c
index 39b735831c..93a214f502 100644
--- a/src/southbridge/via/vt8237r/vt8237r_ide.c
+++ b/src/southbridge/via/vt8237r/vt8237r_ide.c
@@ -27,14 +27,6 @@
#include "vt8237r.h"
#include "chip.h"
-#define IDE_CS 0x40
-#define IDE_CONF_I 0x41
-#define IDE_CONF_II 0x42
-#define IDE_CONF_FIFO 0x43
-#define IDE_MISC_I 0x44
-#define IDE_MISC_II 0x45
-#define IDE_UDMA 0x50
-
/**
* No native mode. Interrupts from unconnected HDDs might occur if
* IRQ14/15 is used for PCI. Therefore no native mode support.