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): 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); 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 diff --git a/litex/soc/software/liblitedram/Makefile b/litex/soc/software/liblitedram/Makefile index cfa022f8d..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 +OBJECTS = sdram.o bist.o sdram_dbg.o sdram_spd.o utils.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 */ diff --git a/litex/soc/software/liblitedram/utils.c b/litex/soc/software/liblitedram/utils.c new file mode 100644 index 000000000..480565163 --- /dev/null +++ b/litex/soc/software/liblitedram/utils.c @@ -0,0 +1,61 @@ +// This file is Copyright (c) 2023 Antmicro +// License: BSD + +#include + +#include +#include + +#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"); +} + +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 new file mode 100644 index 000000000..09ff07091 --- /dev/null +++ b/litex/soc/software/liblitedram/utils.h @@ -0,0 +1,14 @@ +// 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); + +uint64_t sdram_get_supported_memory(void); + +#endif /* __SDRAM_UTILS_H */