From 82f1fc1c923e218d1bc510a427b22c0743f8a057 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 1 Mar 2019 16:00:46 +0100 Subject: ddr_spd: Add function to read eeprom Signed-off-by: Sascha Hauer --- common/ddr_spd.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ include/ddr_spd.h | 6 ++++ 2 files changed, 88 insertions(+) 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 + /* * 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_ */ -- cgit v1.2.3