From 39a8ca6fb6447f18ed7cf11d27844218fe481e70 Mon Sep 17 00:00:00 2001 From: Michal Sieron Date: Mon, 9 Jan 2023 16:19:15 +0100 Subject: [PATCH 1/6] 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 --- litex/soc/software/liblitedram/Makefile | 2 +- litex/soc/software/liblitedram/sdram_spd.c | 62 ++++++++++++++++++++++ litex/soc/software/liblitedram/sdram_spd.h | 30 +++++++++++ 3 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 litex/soc/software/liblitedram/sdram_spd.c create mode 100644 litex/soc/software/liblitedram/sdram_spd.h 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 */ From 2bdf04c19e283a0faf5b9b7b9b1b90a8ef64f5e2 Mon Sep 17 00:00:00 2001 From: Michal Sieron Date: Mon, 9 Jan 2023 16:22:09 +0100 Subject: [PATCH 2/6] cmds/cmd_litedram: read entire SPD Make use of added function `sdram_read_spd` to read entire SPD. Also a typo fix. Signed-off-by: Michal Sieron --- litex/soc/software/bios/cmds/cmd_litedram.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/litex/soc/software/bios/cmds/cmd_litedram.c b/litex/soc/software/bios/cmds/cmd_litedram.c index 1d9f104f8..498e4963f 100644 --- a/litex/soc/software/bios/cmds/cmd_litedram.c +++ b/litex/soc/software/bios/cmds/cmd_litedram.c @@ -12,6 +12,7 @@ #include #include +#include #include #include "../command.h" @@ -354,14 +355,11 @@ define_command(sdram_mr_write, sdram_mr_write_handler, "Write SDRAM Mode Registe * */ #ifdef CONFIG_HAS_I2C -#define SPD_RW_PREAMBLE 0b1010 -#define SPD_RW_ADDR(a210) ((SPD_RW_PREAMBLE << 3) | ((a210) & 0b111)) - static void sdram_spd_handler(int nb_params, char **params) { char *c; unsigned char spdaddr; - unsigned char buf[256]; + unsigned char buf[SDRAM_SPD_SIZE]; int len = sizeof(buf); bool send_stop = true; @@ -388,7 +386,7 @@ static void sdram_spd_handler(int nb_params, char **params) } } - if (!i2c_read(SPD_RW_ADDR(spdaddr), 0, buf, len, send_stop, 1)) { + if (!sdram_read_spd(spdaddr, 0, buf, (uint16_t)len, send_stop)) { printf("Error when reading SPD EEPROM"); return; } @@ -400,7 +398,7 @@ static void sdram_spd_handler(int nb_params, char **params) int cmp_result; cmp_result = memcmp(buf, (void *) SPD_BASE, SPD_SIZE); if (cmp_result == 0) { - printf("Memory conents matches the data used for gateware generation\n"); + printf("Memory contents matches the data used for gateware generation\n"); } else { printf("\nWARNING: memory differs from the data used during gateware generation:\n"); dump_bytes((void *) SPD_BASE, SPD_SIZE, 0); From fb068f6e4e7d028501198e2abb0a7c5522207768 Mon Sep 17 00:00:00 2001 From: Michal Sieron Date: Mon, 9 Jan 2023 16:24:06 +0100 Subject: [PATCH 3/6] liblitedram: create utils.c Right now there are only `print_size` and `print_progress` functions from memtest.c, but changed to use uint64_t. Signed-off-by: Michal Sieron --- litex/soc/software/liblitedram/Makefile | 2 +- litex/soc/software/liblitedram/utils.c | 28 +++++++++++++++++++++++++ litex/soc/software/liblitedram/utils.h | 12 +++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 litex/soc/software/liblitedram/utils.c create mode 100644 litex/soc/software/liblitedram/utils.h diff --git a/litex/soc/software/liblitedram/Makefile b/litex/soc/software/liblitedram/Makefile index 0f26d194b..51c3e8952 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 sdram_spd.o +OBJECTS = sdram.o bist.o sdram_dbg.o sdram_spd.o utils.o all: liblitedram.a diff --git a/litex/soc/software/liblitedram/utils.c b/litex/soc/software/liblitedram/utils.c new file mode 100644 index 000000000..7ffa5c749 --- /dev/null +++ b/litex/soc/software/liblitedram/utils.c @@ -0,0 +1,28 @@ +// This file is Copyright (c) 2023 Antmicro +// License: BSD + +#include + +#include + +#define KIB 1024 +#define MIB (KIB*1024) +#define GIB (MIB*1024) + +void print_size(uint64_t size) { + if (size < KIB) + printf("%lluB", size); + else if (size < MIB) + printf("%llu.%lluKiB", size/KIB, (size/1 - KIB*(size/KIB))/(KIB/10)); + else if (size < GIB) + printf("%llu.%lluMiB", size/MIB, (size/KIB - KIB*(size/MIB))/(KIB/10)); + else + printf("%llu.%lluGiB", size/GIB, (size/MIB - KIB*(size/GIB))/(KIB/10)); +} + +void print_progress(const char * header, uint64_t origin, uint64_t size) +{ + printf("%s 0x%llx-0x%llx ", header, origin, origin + size); + print_size(size); + printf(" \r"); +} diff --git a/litex/soc/software/liblitedram/utils.h b/litex/soc/software/liblitedram/utils.h new file mode 100644 index 000000000..68235563b --- /dev/null +++ b/litex/soc/software/liblitedram/utils.h @@ -0,0 +1,12 @@ +// This file is Copyright (c) 2023 Antmicro +// License: BSD + +#ifndef __SDRAM_UTILS_H +#define __SDRAM_UTILS_H + +#include + +void print_size(uint64_t size); +void print_progress(const char * header, uint64_t origin, uint64_t size); + +#endif /* __SDRAM_UTILS_H */ From 08d439f0216dbb7cabef1b52b044a97cea675959 Mon Sep 17 00:00:00 2001 From: Michal Sieron Date: Mon, 9 Jan 2023 16:26:07 +0100 Subject: [PATCH 4/6] soc/integration/builder: pass geom_settings when generating sdram_phy.h Signed-off-by: Michal Sieron --- litex/soc/integration/builder.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/litex/soc/integration/builder.py b/litex/soc/integration/builder.py index 28b653a13..a096054d7 100644 --- a/litex/soc/integration/builder.py +++ b/litex/soc/integration/builder.py @@ -227,7 +227,8 @@ class Builder: from litedram.init import get_sdram_phy_c_header sdram_contents = get_sdram_phy_c_header( self.soc.sdram.controller.settings.phy, - self.soc.sdram.controller.settings.timing) + self.soc.sdram.controller.settings.timing, + self.soc.sdram.controller.settings.geom) write_to_file(os.path.join(self.generated_dir, "sdram_phy.h"), sdram_contents) def _generate_csr_map(self): From bc592c0f715c49d20175ab17c1c64060daba3c6d Mon Sep 17 00:00:00 2001 From: Michal Sieron Date: Mon, 9 Jan 2023 16:26:07 +0100 Subject: [PATCH 5/6] liblitedram/utils: add get_supported_memory Add `get_supported_memory` function that reads SPD to calculate supported memory from the SDRAM. When it's not possible to read from the SPD (no I2C) or there are errors with the readout, it defaults to `SDRAM_PHY_SUPPORTED_MEMORY` defined in `generated/sdram_phy.h` by `litedram/init.py`. Signed-off-by: Michal Sieron --- litex/soc/software/liblitedram/utils.c | 33 ++++++++++++++++++++++++++ litex/soc/software/liblitedram/utils.h | 2 ++ 2 files changed, 35 insertions(+) diff --git a/litex/soc/software/liblitedram/utils.c b/litex/soc/software/liblitedram/utils.c index 7ffa5c749..480565163 100644 --- a/litex/soc/software/liblitedram/utils.c +++ b/litex/soc/software/liblitedram/utils.c @@ -4,6 +4,11 @@ #include #include +#include + +#include + +#include #define KIB 1024 #define MIB (KIB*1024) @@ -26,3 +31,31 @@ void print_progress(const char * header, uint64_t origin, uint64_t size) print_size(size); printf(" \r"); } + +uint64_t sdram_get_supported_memory(void) { +#ifdef CONFIG_HAS_I2C + +#if defined(SDRAM_PHY_DDR3) || defined(SDRAM_PHY_DDR4) + uint8_t buf; + + if (!sdram_read_spd(0x0, 4, &buf, 1, true)) { + printf("Couldn't read SDRAM size from the SPD, defaulting to 256 MB.\n"); + return 256 << 20; + } + + /* minimal supported is 256 Mb */ + uint64_t single_die_capacity = 256 << 20; + single_die_capacity <<= buf & 0x7; + + /* convert from bits to bytes (divide by 8) */ + single_die_capacity >>= 3; + + return SDRAM_PHY_MODULES * single_die_capacity; +#else + return SDRAM_PHY_SUPPORTED_MEMORY; +#endif + +#else /* no CONFIG_HAS_I2C */ + return SDRAM_PHY_SUPPORTED_MEMORY; +#endif /* CONFIG_HAS_I2C */ +} diff --git a/litex/soc/software/liblitedram/utils.h b/litex/soc/software/liblitedram/utils.h index 68235563b..09ff07091 100644 --- a/litex/soc/software/liblitedram/utils.h +++ b/litex/soc/software/liblitedram/utils.h @@ -9,4 +9,6 @@ void print_size(uint64_t size); void print_progress(const char * header, uint64_t origin, uint64_t size); +uint64_t sdram_get_supported_memory(void); + #endif /* __SDRAM_UTILS_H */ From 7fbf66b1a4c2e6fd9e8b8cecc1c6338f39045731 Mon Sep 17 00:00:00 2001 From: Michal Sieron Date: Mon, 9 Jan 2023 16:29:01 +0100 Subject: [PATCH 6/6] bios/main: pretty print memory sizes Always print MAIN-RAM and optionally print SDRAM. This is caused by the fact, that SDRAM size can be bigger than RAM declared in the memory map. Signed-off-by: Michal Sieron --- litex/soc/software/bios/main.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/litex/soc/software/bios/main.c b/litex/soc/software/bios/main.c index bdb9a926d..130e72fb1 100644 --- a/litex/soc/software/bios/main.c +++ b/litex/soc/software/bios/main.c @@ -40,6 +40,7 @@ #include #include +#include #include #include @@ -131,18 +132,28 @@ __attribute__((__used__)) int main(int i, char **c) (1 << (CONFIG_BUS_ADDRESS_WIDTH - 30))); printf("\e[1mCSR\e[0m:\t\t%d-bit data\n", CONFIG_CSR_DATA_WIDTH); - printf("\e[1mROM\e[0m:\t\t%dKiB\n", ROM_SIZE/1024); - printf("\e[1mSRAM\e[0m:\t\t%dKiB\n", SRAM_SIZE/1024); + printf("\e[1mROM\e[0m:\t\t"); + print_size(ROM_SIZE); + printf("\n"); + printf("\e[1mSRAM\e[0m:\t\t"); + print_size(SRAM_SIZE); + printf("\n"); #ifdef CONFIG_L2_SIZE - printf("\e[1mL2\e[0m:\t\t%dKiB\n", CONFIG_L2_SIZE/1024); + printf("\e[1mL2\e[0m:\t\t"); + print_size(CONFIG_L2_SIZE); + printf("\n"); #endif #ifdef CSR_SPIFLASH_CORE_BASE - printf("\e[1mFLASH\e[0m:\t\t%dKiB\n", SPIFLASH_MODULE_TOTAL_SIZE/1024); + printf("\e[1mFLASH\e[0m:\t\t"); + print_size(SPIFLASH_MODULE_TOTAL_SIZE); + printf("\n"); #endif #ifdef MAIN_RAM_SIZE #ifdef CSR_SDRAM_BASE - printf("\e[1mSDRAM\e[0m:\t\t%dKiB %d-bit @ %dMT/s ", - MAIN_RAM_SIZE/1024, + uint64_t supported_memory = sdram_get_supported_memory(); + printf("\e[1mSDRAM\e[0m:\t\t"); + print_size(supported_memory); + printf(" %d-bit @ %dMT/s ", sdram_get_databits(), sdram_get_freq()/1000000); printf("(CL-%d", @@ -150,9 +161,10 @@ __attribute__((__used__)) int main(int i, char **c) if (sdram_get_cwl() != -1) printf(" CWL-%d", sdram_get_cwl()); printf(")\n"); -#else - printf("\e[1mMAIN-RAM\e[0m:\t%dKiB \n", MAIN_RAM_SIZE/1024); #endif + printf("\e[1mMAIN-RAM\e[0m:\t"); + print_size(MAIN_RAM_SIZE); + printf("\n"); #endif printf("\n"); #endif