liblitedram: add sdram_spd.c

Add generic `sdram_read_spd` function which allows to read SPD data
with no need to think about paging.

Just provide SPD address, address from which you want to read the data,
buffer and length of the data.

Paging is taken care of inside the function.

Signed-off-by: Michal Sieron <msieron@antmicro.com>
This commit is contained in:
Michal Sieron 2023-01-09 16:19:15 +01:00
parent 0440733fc0
commit 39a8ca6fb6
3 changed files with 93 additions and 1 deletions

View File

@ -1,7 +1,7 @@
include ../include/generated/variables.mak include ../include/generated/variables.mak
include $(SOC_DIRECTORY)/software/common.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 all: liblitedram.a

View File

@ -0,0 +1,62 @@
// This file is Copyright (c) 2023 Antmicro <www.antmicro.com>
// License: BSD
#include <liblitedram/sdram_spd.h>
#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 */

View File

@ -0,0 +1,30 @@
// This file is Copyright (c) 2023 Antmicro <www.antmicro.com>
// License: BSD
#ifndef __SDRAM_SPD_H
#define __SDRAM_SPD_H
#include <stdbool.h>
#include <stdint.h>
#include <libbase/i2c.h>
#include <generated/sdram_phy.h>
#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 */