diff --git a/litex/soc/software/liblitedram/Makefile b/litex/soc/software/liblitedram/Makefile index cfa022f8d..0f26d194b 100644 --- a/litex/soc/software/liblitedram/Makefile +++ b/litex/soc/software/liblitedram/Makefile @@ -1,7 +1,7 @@ include ../include/generated/variables.mak include $(SOC_DIRECTORY)/software/common.mak -OBJECTS = sdram.o bist.o sdram_dbg.o +OBJECTS = sdram.o bist.o sdram_dbg.o sdram_spd.o all: liblitedram.a diff --git a/litex/soc/software/liblitedram/sdram_spd.c b/litex/soc/software/liblitedram/sdram_spd.c new file mode 100644 index 000000000..82b39b86c --- /dev/null +++ b/litex/soc/software/liblitedram/sdram_spd.c @@ -0,0 +1,62 @@ +// This file is Copyright (c) 2023 Antmicro +// License: BSD + +#include + +#ifdef CONFIG_HAS_I2C + +#if defined(SDRAM_PHY_DDR4) +/* + * In DDR4, addresses 0x36 (SPA0) and 0x37 (SPA1) are used to switch between two 256 byte pages. + */ +static bool sdram_select_spd_page(uint8_t page) { + uint8_t i2c_addr; + + if (page == 0) { + i2c_addr = 0x36; + } else if (page == 1) { + i2c_addr = 0x37; + } else { + return false; + } + + return i2c_poll(i2c_addr); +} +#else +static bool sdram_select_spd_page(uint8_t page) { + return true; +} +#endif + +bool sdram_read_spd(uint8_t spd, uint16_t addr, uint8_t *buf, uint16_t len, bool send_stop) { + uint8_t page; + uint16_t offset; + uint16_t temp_len; + bool temp_send_stop = false; + + bool ok = true; + + while (addr < SDRAM_SPD_SIZE && len > 0) { + page = addr / SDRAM_SPD_PAGE_SIZE; + ok &= sdram_select_spd_page(page); + + offset = addr % SDRAM_SPD_PAGE_SIZE; + + temp_len = SDRAM_SPD_PAGE_SIZE - offset; + if (temp_len >= len) { + temp_send_stop = send_stop; + temp_len = len; + } + + ok &= i2c_read(SPD_RW_ADDR(spd), offset, &buf[page * SDRAM_SPD_PAGE_SIZE], len, temp_send_stop, 1); + len -= temp_len; + addr += temp_len; + } + + return ok; +} +#else /* no CONFIG_HAS_I2C */ +bool sdram_read_spd(uint8_t spd, uint16_t addr, uint8_t *buf, uint16_t len, bool send_stop) { + return false; +} +#endif /* CONFIG_HAS_I2C */ diff --git a/litex/soc/software/liblitedram/sdram_spd.h b/litex/soc/software/liblitedram/sdram_spd.h new file mode 100644 index 000000000..c95fd64bc --- /dev/null +++ b/litex/soc/software/liblitedram/sdram_spd.h @@ -0,0 +1,30 @@ +// This file is Copyright (c) 2023 Antmicro +// License: BSD + +#ifndef __SDRAM_SPD_H +#define __SDRAM_SPD_H + +#include +#include +#include +#include + +#define SPD_RW_PREAMBLE 0b1010 +#define SPD_RW_ADDR(a210) ((SPD_RW_PREAMBLE << 3) | ((a210) & 0b111)) + +#if defined(SDRAM_PHY_DDR4) +#define SDRAM_SPD_PAGES 2 +#define SDRAM_SPD_PAGE_SIZE 256 +#elif defined(SDRAM_PHY_DDR3) +#define SDRAM_SPD_PAGES 1 +#define SDRAM_SPD_PAGE_SIZE 256 +#else +#define SDRAM_SPD_PAGES 1 +#define SDRAM_SPD_PAGE_SIZE 128 +#endif + +#define SDRAM_SPD_SIZE (SDRAM_SPD_PAGES * SDRAM_SPD_PAGE_SIZE) + +bool sdram_read_spd(uint8_t spd, uint16_t addr, uint8_t *buf, uint16_t len, bool send_stop); + +#endif /* __SDRAM_SPD_H */