summaryrefslogtreecommitdiff
path: root/src/soc/amd/stoneyridge/smbus_spd.c
diff options
context:
space:
mode:
authorMarc Jones <marcj303@gmail.com>2017-05-04 21:17:45 -0600
committerMartin Roth <martinroth@google.com>2017-06-26 00:45:41 +0000
commit244848462def7075e0c812a2f71c408668cacfe4 (patch)
treefde926f45d478b36eaebfd1261886c973b803857 /src/soc/amd/stoneyridge/smbus_spd.c
parenta0199d8e1a96d94828b31f77e0a29a282871a76a (diff)
downloadcoreboot-244848462def7075e0c812a2f71c408668cacfe4.tar.xz
soc: Add AMD Stoney Ridge southbridge code
Copy the Hudson/Kern code from southbridge/amd/pi/hudson. This is the first of a series of patches to migrate Stoney Ridge support from cpu, northbridge, and southbridge to soc/ Changes: - add soc/amd/stoneyridge and soc/amd/common - remove all other Husdon versions - update include paths, etc - clean up Kconfig and Makefile - create chip.c to contain chip_ops Change-Id: Ib88a868e654ad127be70ecc506f6b90b784f8d1b Signed-off-by: Marc Jones <marcj303@gmail.com> Reviewed-on: https://review.coreboot.org/19722 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Martin Roth <martinroth@google.com>
Diffstat (limited to 'src/soc/amd/stoneyridge/smbus_spd.c')
-rw-r--r--src/soc/amd/stoneyridge/smbus_spd.c148
1 files changed, 148 insertions, 0 deletions
diff --git a/src/soc/amd/stoneyridge/smbus_spd.c b/src/soc/amd/stoneyridge/smbus_spd.c
new file mode 100644
index 0000000000..8d67b1e678
--- /dev/null
+++ b/src/soc/amd/stoneyridge/smbus_spd.c
@@ -0,0 +1,148 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2012 Advanced Micro Devices, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <device/pci_def.h>
+#include <device/device.h>
+
+/* warning: Porting.h includes an open #pragma pack(1) */
+#include <Porting.h>
+#include <AGESA.h>
+#include <amdlib.h>
+
+#include <northbridge/amd/pi/dimmSpd.h>
+
+/*-----------------------------------------------------------------------------
+ *
+ * readSmbusByteData - read a single SPD byte from any offset
+ */
+
+static int readSmbusByteData (int iobase, int address, char *buffer, int offset)
+{
+ unsigned int status;
+ UINT64 limit;
+
+ address |= 1; // set read bit
+
+ __outbyte (iobase + 0, 0xFF); // clear error status
+ __outbyte (iobase + 1, 0x1F); // clear error status
+ __outbyte (iobase + 3, offset); // offset in eeprom
+ __outbyte (iobase + 4, address); // slave address and read bit
+ __outbyte (iobase + 2, 0x48); // read byte command
+
+ // time limit to avoid hanging for unexpected error status (should never happen)
+ limit = __rdtsc () + 2000000000 / 10;
+ for (;;)
+ {
+ status = __inbyte (iobase);
+ if (__rdtsc () > limit) break;
+ if ((status & 2) == 0) continue; // SMBusInterrupt not set, keep waiting
+ if ((status & 1) == 1) continue; // HostBusy set, keep waiting
+ break;
+ }
+
+ buffer [0] = __inbyte (iobase + 5);
+ if (status == 2) status = 0; // check for done with no errors
+ return status;
+}
+
+/*-----------------------------------------------------------------------------
+ *
+ * readSmbusByte - read a single SPD byte from the default offset
+ * this function is faster function readSmbusByteData
+ */
+
+static int readSmbusByte (int iobase, int address, char *buffer)
+{
+ unsigned int status;
+ UINT64 limit;
+
+ __outbyte (iobase + 0, 0xFF); // clear error status
+ __outbyte (iobase + 2, 0x44); // read command
+
+ // time limit to avoid hanging for unexpected error status
+ limit = __rdtsc () + 2000000000 / 10;
+ for (;;)
+ {
+ status = __inbyte (iobase);
+ if (__rdtsc () > limit) break;
+ if ((status & 2) == 0) continue; // SMBusInterrupt not set, keep waiting
+ if ((status & 1) == 1) continue; // HostBusy set, keep waiting
+ break;
+ }
+
+ buffer [0] = __inbyte (iobase + 5);
+ if (status == 2) status = 0; // check for done with no errors
+ return status;
+}
+
+/*---------------------------------------------------------------------------
+ *
+ * readspd - Read one or more SPD bytes from a DIMM.
+ * Start with offset zero and read sequentially.
+ * Optimization relies on autoincrement to avoid
+ * sending offset for every byte.
+ * Reads 128 bytes in 7-8 ms at 400 KHz.
+ */
+
+static int readspd (int iobase, int SmbusSlaveAddress, char *buffer, int count)
+{
+ int index, error;
+
+ printk(BIOS_SPEW, "-------------READING SPD-----------\n");
+ printk(BIOS_SPEW, "iobase: 0x%08X, SmbusSlave: 0x%08X, count: %d\n",
+ iobase, SmbusSlaveAddress, count);
+
+ /* read the first byte using offset zero */
+ error = readSmbusByteData (iobase, SmbusSlaveAddress, buffer, 0);
+
+ if (error) {
+ printk(BIOS_ERR, "-------------SPD READ ERROR-----------\n");
+ return error;
+ }
+
+ /* read the remaining bytes using auto-increment for speed */
+ for (index = 1; index < count; index++)
+ {
+ error = readSmbusByte (iobase, SmbusSlaveAddress, &buffer [index]);
+ if (error) {
+ printk(BIOS_ERR, "-------------SPD READ ERROR-----------\n");
+ return error;
+ }
+ }
+ printk(BIOS_SPEW, "\n");
+ printk(BIOS_SPEW, "-------------FINISHED READING SPD-----------\n");
+
+ return 0;
+}
+
+static void writePmReg (int reg, int data)
+{
+ __outbyte (0xCD6, reg);
+ __outbyte (0xCD7, data);
+}
+
+static void setupFch (int ioBase)
+{
+ writePmReg (0x2D, ioBase >> 8);
+ writePmReg (0x2C, ioBase | 1);
+ __outbyte (ioBase + 0x0E, 66000000 / 400000 / 4); // set SMBus clock to 400 KHz
+}
+
+int hudson_readSpd(int spdAddress, char *buf, size_t len)
+{
+ int ioBase = 0xB00;
+ setupFch (ioBase);
+ return readspd (ioBase, spdAddress, buf, len);
+}