summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/ddr_spd.c82
-rw-r--r--include/ddr_spd.h6
2 files changed, 88 insertions, 0 deletions
diff --git a/common/ddr_spd.c b/common/ddr_spd.c
index 9394c57fa3..0ba5eaceae 100644
--- a/common/ddr_spd.c
+++ b/common/ddr_spd.c
@@ -429,3 +429,85 @@ void ddr_spd_print(uint8_t *record)
printf("%02X", record[i]);
printf("\n");
}
+
+#define SPD_SPA0_ADDRESS 0x36
+#define SPD_SPA1_ADDRESS 0x37
+
+static int select_page(void *ctx,
+ int (*xfer)(void *ctx, struct i2c_msg *msgs, int num),
+ uint8_t addr)
+{
+ struct i2c_msg msg = {
+ .addr = addr,
+ .len = 0,
+ };
+ int ret;
+
+ ret = xfer(ctx, &msg, 1);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int read_buf(void *ctx,
+ int (*xfer)(void *ctx, struct i2c_msg *msgs, int num),
+ uint8_t addr, int page, void *buf)
+{
+ uint8_t pos = 0;
+ int ret;
+ struct i2c_msg msg[2] = {
+ {
+ .addr = addr,
+ .len = 1,
+ .buf = &pos,
+ }, {
+ .addr = addr,
+ .len = 256,
+ .flags = I2C_M_RD,
+ .buf = buf,
+ }
+ };
+
+ ret = select_page(ctx, xfer, page);
+ if (ret < 0)
+ return ret;
+
+ ret = xfer(ctx, msg, 2);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+/**
+ * spd_read_eeprom - Read contents of a SPD EEPROM
+ * @ctx: Context pointer for the xfer function
+ * @xfer: I2C message transfer function
+ * @addr: I2C bus address for the EEPROM
+ * @buf: buffer to read the SPD data to
+ *
+ * This function takes a I2C message transfer function and reads the contents
+ * from a SPD EEPROM to the buffer provided at @buf. The buffer should at least
+ * have a size of 512 bytes. Returns 0 for success or a negative error code
+ * otherwise.
+ */
+int spd_read_eeprom(void *ctx,
+ int (*xfer)(void *ctx, struct i2c_msg *msgs, int num),
+ uint8_t addr, void *buf)
+{
+ unsigned char *buf8 = buf;
+ int ret;
+
+ ret = read_buf(ctx, xfer, addr, SPD_SPA0_ADDRESS, buf);
+ if (ret < 0)
+ return ret;
+
+ if (buf8[2] == SPD_MEMTYPE_DDR4) {
+ ret = read_buf(ctx, xfer, addr, SPD_SPA1_ADDRESS, buf + 256);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
diff --git a/include/ddr_spd.h b/include/ddr_spd.h
index 051275141f..95d0eb04b6 100644
--- a/include/ddr_spd.h
+++ b/include/ddr_spd.h
@@ -6,6 +6,8 @@
#ifndef _DDR_SPD_H_
#define _DDR_SPD_H_
+#include <i2c/i2c.h>
+
/*
* Format from "JEDEC Standard No. 21-C,
* Appendix D: Rev 1.0: SPD's for DDR SDRAM
@@ -562,4 +564,8 @@ void ddr2_spd_dump(const struct ddr2_spd_eeprom *spd);
int ddr3_spd_check(const struct ddr3_spd_eeprom *spd);
int ddr4_spd_check(const struct ddr4_spd_eeprom *spd);
+int spd_read_eeprom(void *ctx,
+ int (*xfer)(void *ctx, struct i2c_msg *msgs, int num),
+ uint8_t addr, void *buf);
+
#endif /* _DDR_SPD_H_ */