soc_sdram, bios/sdram: support sdram init for csr_data_width <= 32

Enable SDRAM to be initialized when csr_data_width > 8 bits.
Currently, csr_data_width up to 32 bits is supported.

Read leveling tested with csr_data_width [8, 16, 32] on the
ecp5-versa5g and trellisboard (using yosys/trellis/nextpnr),
and on the nexys4ddr (using Vivado).

Signed-off-by: Gabriel Somlo <gsomlo@gmail.com>
This commit is contained in:
Gabriel Somlo 2019-11-17 10:08:50 -05:00
parent af52203c00
commit 3ef13fd27a
2 changed files with 109 additions and 57 deletions

View File

@ -29,8 +29,8 @@ class SoCSDRAM(SoCCore):
def __init__(self, platform, clk_freq, l2_size=8192, **kwargs): def __init__(self, platform, clk_freq, l2_size=8192, **kwargs):
SoCCore.__init__(self, platform, clk_freq, **kwargs) SoCCore.__init__(self, platform, clk_freq, **kwargs)
if not self.integrated_main_ram_size: if not self.integrated_main_ram_size:
if self.cpu_type is not None and self.csr_data_width != 8: if self.cpu_type is not None and self.csr_data_width > 32:
raise NotImplementedError("BIOS supports SDRAM initialization only for csr_data_width=8") raise NotImplementedError("BIOS supports SDRAM initialization only for csr_data_width<=32")
self.l2_size = l2_size self.l2_size = l2_size
self._sdram_phy = [] self._sdram_phy = []

View File

@ -20,6 +20,8 @@
#include <hw/flags.h> #include <hw/flags.h>
#include <system.h> #include <system.h>
#include <inet.h> // for hton/ntoh (byteswap) functions
#include "sdram.h" #include "sdram.h"
// FIXME(hack): If we don't have main ram, just target the sram instead. // FIXME(hack): If we don't have main ram, just target the sram instead.
@ -55,6 +57,26 @@ __attribute__((unused)) static void cdelay(int i)
#define DFII_ADDR_SHIFT CONFIG_CSR_ALIGNMENT/8 #define DFII_ADDR_SHIFT CONFIG_CSR_ALIGNMENT/8
#define CSR_DATA_BYTES CONFIG_CSR_DATA_WIDTH/8
#define DFII_PIX_DATA_BYTES DFII_PIX_DATA_SIZE*CSR_DATA_BYTES
#if CSR_DATA_BYTES == 1
typedef uint8_t csr_dw_t;
#define csr_dw_hton(x) (x)
#define csr_dw_ntoh(x) (x)
#elif CSR_DATA_BYTES == 2
typedef uint16_t csr_dw_t;
#define csr_dw_hton(x) htons(x)
#define csr_dw_ntoh(x) ntohs(x)
#elif CSR_DATA_BYTES == 4
typedef uint32_t csr_dw_t;
#define csr_dw_hton(x) htonl(x)
#define csr_dw_ntoh(x) ntohl(x)
#else
#error Unsupported CSR data width
#endif
void sdrsw(void) void sdrsw(void)
{ {
sdram_dfii_control_write(DFII_CONTROL_CKE|DFII_CONTROL_ODT|DFII_CONTROL_RESET_N); sdram_dfii_control_write(DFII_CONTROL_CKE|DFII_CONTROL_ODT|DFII_CONTROL_RESET_N);
@ -96,18 +118,23 @@ void sdrrdbuf(int dq)
{ {
int i, p; int i, p;
int first_byte, step; int first_byte, step;
csr_dw_t buf[DFII_PIX_DATA_SIZE];
unsigned char *buf_bytes = (unsigned char *)&(buf[0]);
if(dq < 0) { if(dq < 0) {
first_byte = 0; first_byte = 0;
step = 1; step = 1;
} else { } else {
first_byte = DFII_PIX_DATA_SIZE/2 - 1 - dq; first_byte = DFII_PIX_DATA_BYTES/2 - 1 - dq;
step = DFII_PIX_DATA_SIZE/2; step = DFII_PIX_DATA_BYTES/2;
} }
for(p=0;p<DFII_NPHASES;p++) for(p=0;p<DFII_NPHASES;p++) {
for(i=first_byte;i<DFII_PIX_DATA_SIZE;i+=step) for(i=0;i<DFII_PIX_DATA_SIZE;i++)
printf("%02x", MMPTR(sdram_dfii_pix_rddata_addr[p]+DFII_ADDR_SHIFT*i)); buf[i] = csr_dw_ntoh(MMPTR(sdram_dfii_pix_rddata_addr[p]+DFII_ADDR_SHIFT*i));
for(i=first_byte;i<DFII_PIX_DATA_BYTES;i+=step)
printf("%02x", buf_bytes[i]);
}
printf("\n"); printf("\n");
} }
@ -149,8 +176,9 @@ void sdrrderr(char *count)
char *c; char *c;
int _count; int _count;
int i, j, p; int i, j, p;
unsigned char prev_data[DFII_NPHASES*DFII_PIX_DATA_SIZE]; csr_dw_t prev_data[DFII_NPHASES][DFII_PIX_DATA_SIZE];
unsigned char errs[DFII_NPHASES*DFII_PIX_DATA_SIZE]; csr_dw_t err_data[DFII_NPHASES][DFII_PIX_DATA_SIZE];
unsigned char *errs = (unsigned char *)&(err_data[0][0]);
if(*count == 0) { if(*count == 0) {
printf("sdrrderr <count>\n"); printf("sdrrderr <count>\n");
@ -162,8 +190,9 @@ void sdrrderr(char *count)
return; return;
} }
for(i=0;i<DFII_NPHASES*DFII_PIX_DATA_SIZE;i++) for(p=0;p<DFII_NPHASES;p++)
errs[i] = 0; for(i=0;i<DFII_PIX_DATA_SIZE;i++)
err_data[p][i] = 0;
for(addr=0;addr<16;addr++) { for(addr=0;addr<16;addr++) {
sdram_dfii_pird_address_write(addr*8); sdram_dfii_pird_address_write(addr*8);
sdram_dfii_pird_baddress_write(0); sdram_dfii_pird_baddress_write(0);
@ -171,40 +200,40 @@ void sdrrderr(char *count)
cdelay(15); cdelay(15);
for(p=0;p<DFII_NPHASES;p++) for(p=0;p<DFII_NPHASES;p++)
for(i=0;i<DFII_PIX_DATA_SIZE;i++) for(i=0;i<DFII_PIX_DATA_SIZE;i++)
prev_data[p*DFII_PIX_DATA_SIZE+i] = MMPTR(sdram_dfii_pix_rddata_addr[p]+DFII_ADDR_SHIFT*i); prev_data[p][i] = csr_dw_ntoh(MMPTR(sdram_dfii_pix_rddata_addr[p]+DFII_ADDR_SHIFT*i));
for(j=0;j<_count;j++) { for(j=0;j<_count;j++) {
command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS|DFII_COMMAND_RDDATA); command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS|DFII_COMMAND_RDDATA);
cdelay(15); cdelay(15);
for(p=0;p<DFII_NPHASES;p++) for(p=0;p<DFII_NPHASES;p++)
for(i=0;i<DFII_PIX_DATA_SIZE;i++) { for(i=0;i<DFII_PIX_DATA_SIZE;i++) {
unsigned char new_data; csr_dw_t new_data = csr_dw_ntoh(MMPTR(sdram_dfii_pix_rddata_addr[p]+DFII_ADDR_SHIFT*i));
new_data = MMPTR(sdram_dfii_pix_rddata_addr[p]+DFII_ADDR_SHIFT*i); err_data[p][i] |= prev_data[p][i] ^ new_data;
errs[p*DFII_PIX_DATA_SIZE+i] |= prev_data[p*DFII_PIX_DATA_SIZE+i] ^ new_data; prev_data[p][i] = new_data;
prev_data[p*DFII_PIX_DATA_SIZE+i] = new_data;
} }
} }
} }
for(i=0;i<DFII_NPHASES*DFII_PIX_DATA_SIZE;i++) for(i=0;i<DFII_NPHASES*DFII_PIX_DATA_BYTES;i++)
printf("%02x", errs[i]); printf("%02x", errs[i]);
printf("\n"); printf("\n");
for(p=0;p<DFII_NPHASES;p++) for(p=0;p<DFII_NPHASES;p++)
for(i=0;i<DFII_PIX_DATA_SIZE;i++) for(i=0;i<DFII_PIX_DATA_BYTES;i++)
printf("%2x", DFII_PIX_DATA_SIZE/2 - 1 - (i % (DFII_PIX_DATA_SIZE/2))); printf("%2x", DFII_PIX_DATA_BYTES/2 - 1 - (i % (DFII_PIX_DATA_BYTES/2)));
printf("\n"); printf("\n");
} }
void sdrwr(char *startaddr) void sdrwr(char *startaddr)
{ {
int i, p;
char *c; char *c;
unsigned int addr; unsigned int addr;
int i; csr_dw_t buf[DFII_PIX_DATA_SIZE];
int p; unsigned char *buf_bytes = (unsigned char *)&(buf[0]);
if(*startaddr == 0) { if(*startaddr == 0) {
printf("sdrrd <address>\n"); printf("sdrwr <address>\n");
return; return;
} }
addr = strtoul(startaddr, &c, 0); addr = strtoul(startaddr, &c, 0);
@ -213,9 +242,12 @@ void sdrwr(char *startaddr)
return; return;
} }
for(p=0;p<DFII_NPHASES;p++) for(p=0;p<DFII_NPHASES;p++) {
for(i=0;i<DFII_PIX_DATA_BYTES;i++)
buf_bytes[i] = 0x10*p + i;
for(i=0;i<DFII_PIX_DATA_SIZE;i++) for(i=0;i<DFII_PIX_DATA_SIZE;i++)
MMPTR(sdram_dfii_pix_wrdata_addr[p]+DFII_ADDR_SHIFT*i) = 0x10*p + i; MMPTR(sdram_dfii_pix_wrdata_addr[p]+DFII_ADDR_SHIFT*i) = csr_dw_hton(buf[i]);
}
sdram_dfii_piwr_address_write(addr); sdram_dfii_piwr_address_write(addr);
sdram_dfii_piwr_baddress_write(0); sdram_dfii_piwr_baddress_write(0);
@ -227,15 +259,15 @@ void sdrwr(char *startaddr)
#if defined (USDDRPHY) #if defined (USDDRPHY)
#define ERR_DDRPHY_DELAY 512 #define ERR_DDRPHY_DELAY 512
#define ERR_DDRPHY_BITSLIP 8 #define ERR_DDRPHY_BITSLIP 8
#define NBMODULES DFII_PIX_DATA_SIZE/2 #define NBMODULES DFII_PIX_DATA_BYTES/2
#elif defined (ECP5DDRPHY) #elif defined (ECP5DDRPHY)
#define ERR_DDRPHY_DELAY 8 #define ERR_DDRPHY_DELAY 8
#define ERR_DDRPHY_BITSLIP 1 #define ERR_DDRPHY_BITSLIP 1
#define NBMODULES DFII_PIX_DATA_SIZE/4 #define NBMODULES DFII_PIX_DATA_BYTES/4
#else #else
#define ERR_DDRPHY_DELAY 32 #define ERR_DDRPHY_DELAY 32
#define ERR_DDRPHY_BITSLIP 8 #define ERR_DDRPHY_BITSLIP 8
#define NBMODULES DFII_PIX_DATA_SIZE/2 #define NBMODULES DFII_PIX_DATA_BYTES/2
#endif #endif
#ifdef CSR_DDRPHY_WLEVEL_EN_ADDR #ifdef CSR_DDRPHY_WLEVEL_EN_ADDR
@ -290,10 +322,7 @@ static void write_delay_inc(int module) {
int write_level(void) int write_level(void)
{ {
int i, j, k; int i, j, k, l;
int dq_address;
unsigned char dq;
int err_ddrphy_wdly; int err_ddrphy_wdly;
@ -305,6 +334,9 @@ int write_level(void)
int delays[NBMODULES]; int delays[NBMODULES];
csr_dw_t buf[DFII_PIX_DATA_SIZE];
unsigned char *buf_bytes = (unsigned char *)&(buf[0]);
int ok; int ok;
err_ddrphy_wdly = ERR_DDRPHY_DELAY - ddrphy_half_sys8x_taps_read(); err_ddrphy_wdly = ERR_DDRPHY_DELAY - ddrphy_half_sys8x_taps_read();
@ -315,7 +347,6 @@ int write_level(void)
cdelay(100); cdelay(100);
for(i=0;i<NBMODULES;i++) { for(i=0;i<NBMODULES;i++) {
printf("m%d: |", i); printf("m%d: |", i);
dq_address = sdram_dfii_pix_rddata_addr[0]+DFII_ADDR_SHIFT*(NBMODULES-1-i);
/* rst delay */ /* rst delay */
write_delay_rst(i); write_delay_rst(i);
@ -331,8 +362,9 @@ int write_level(void)
for (k=0; k<128; k++) { for (k=0; k<128; k++) {
ddrphy_wlevel_strobe_write(1); ddrphy_wlevel_strobe_write(1);
cdelay(10); cdelay(10);
dq = MMPTR(dq_address); for (l=0;l<DFII_PIX_DATA_SIZE;l++)
if (dq != 0) buf[l] = csr_dw_ntoh(MMPTR(sdram_dfii_pix_rddata_addr[0]+DFII_ADDR_SHIFT*l));
if (buf_bytes[NBMODULES-1-i] != 0)
one_count++; one_count++;
else else
zero_count++; zero_count++;
@ -444,15 +476,18 @@ static void read_bitslip_inc(char m)
static int read_level_scan(int module, int bitslip) static int read_level_scan(int module, int bitslip)
{ {
unsigned int prv; unsigned int prv;
unsigned char prs[DFII_NPHASES*DFII_PIX_DATA_SIZE]; csr_dw_t prs[DFII_NPHASES][DFII_PIX_DATA_SIZE];
csr_dw_t tst[DFII_PIX_DATA_SIZE];
unsigned char *prs_bytes, *tst_bytes;
int p, i, j; int p, i, j;
int score; int score;
/* Generate pseudo-random sequence */ /* Generate pseudo-random sequence */
prv = 42; prv = 42;
for(i=0;i<DFII_NPHASES*DFII_PIX_DATA_SIZE;i++) { for(p=0;p<DFII_NPHASES;p++)
for(i=0;i<DFII_PIX_DATA_SIZE;i++) {
prv = 1664525*prv + 1013904223; prv = 1664525*prv + 1013904223;
prs[i] = prv; prs[p][i] = prv;
} }
/* Activate */ /* Activate */
@ -464,7 +499,7 @@ static int read_level_scan(int module, int bitslip)
/* Write test pattern */ /* Write test pattern */
for(p=0;p<DFII_NPHASES;p++) for(p=0;p<DFII_NPHASES;p++)
for(i=0;i<DFII_PIX_DATA_SIZE;i++) for(i=0;i<DFII_PIX_DATA_SIZE;i++)
MMPTR(sdram_dfii_pix_wrdata_addr[p]+DFII_ADDR_SHIFT*i) = prs[DFII_PIX_DATA_SIZE*p+i]; MMPTR(sdram_dfii_pix_wrdata_addr[p]+DFII_ADDR_SHIFT*i) = csr_dw_hton(prs[p][i]);
sdram_dfii_piwr_address_write(0); sdram_dfii_piwr_address_write(0);
sdram_dfii_piwr_baddress_write(0); sdram_dfii_piwr_baddress_write(0);
command_pwr(DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS|DFII_COMMAND_WRDATA); command_pwr(DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS|DFII_COMMAND_WRDATA);
@ -477,7 +512,7 @@ static int read_level_scan(int module, int bitslip)
printf("m%d, b%d: |", module, bitslip); printf("m%d, b%d: |", module, bitslip);
read_delay_rst(module); read_delay_rst(module);
for(j=0; j<ERR_DDRPHY_DELAY;j++) { for(j=0; j<ERR_DDRPHY_DELAY;j++) {
int working; int working = 1;
int show = 1; int show = 1;
#ifdef USDDRPHY #ifdef USDDRPHY
show = (j%16 == 0); show = (j%16 == 0);
@ -487,11 +522,15 @@ static int read_level_scan(int module, int bitslip)
#endif #endif
command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS|DFII_COMMAND_RDDATA); command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS|DFII_COMMAND_RDDATA);
cdelay(15); cdelay(15);
working = 1;
for(p=0;p<DFII_NPHASES;p++) { for(p=0;p<DFII_NPHASES;p++) {
if(MMPTR(sdram_dfii_pix_rddata_addr[p]+DFII_ADDR_SHIFT*(NBMODULES-module-1)) != prs[DFII_PIX_DATA_SIZE*p+(NBMODULES-module-1)]) /* read back test pattern */
working = 0; for(i=0;i<DFII_PIX_DATA_SIZE;i++)
if(MMPTR(sdram_dfii_pix_rddata_addr[p]+DFII_ADDR_SHIFT*(2*NBMODULES-module-1)) != prs[DFII_PIX_DATA_SIZE*p+2*NBMODULES-module-1]) tst[i] = csr_dw_ntoh(MMPTR(sdram_dfii_pix_rddata_addr[p]+DFII_ADDR_SHIFT*i));
prs_bytes = (unsigned char *)&(prs[p][0]);
tst_bytes = (unsigned char *)&(tst[0]);
/* verify bytes matching current 'module' */
if (prs_bytes[ NBMODULES-1-module] != tst_bytes[ NBMODULES-1-module] ||
prs_bytes[2*NBMODULES-1-module] != tst_bytes[2*NBMODULES-1-module])
working = 0; working = 0;
} }
#ifdef ECP5DDRPHY #ifdef ECP5DDRPHY
@ -517,7 +556,9 @@ static int read_level_scan(int module, int bitslip)
static void read_level(int module) static void read_level(int module)
{ {
unsigned int prv; unsigned int prv;
unsigned char prs[DFII_NPHASES*DFII_PIX_DATA_SIZE]; csr_dw_t prs[DFII_NPHASES][DFII_PIX_DATA_SIZE];
csr_dw_t tst[DFII_PIX_DATA_SIZE];
unsigned char *prs_bytes, *tst_bytes;
int p, i, j; int p, i, j;
int working; int working;
int delay, delay_min, delay_max; int delay, delay_min, delay_max;
@ -526,9 +567,10 @@ static void read_level(int module)
/* Generate pseudo-random sequence */ /* Generate pseudo-random sequence */
prv = 42; prv = 42;
for(i=0;i<DFII_NPHASES*DFII_PIX_DATA_SIZE;i++) { for(p=0;p<DFII_NPHASES;p++)
for(i=0;i<DFII_PIX_DATA_SIZE;i++) {
prv = 1664525*prv + 1013904223; prv = 1664525*prv + 1013904223;
prs[i] = prv; prs[p][i] = prv;
} }
/* Activate */ /* Activate */
@ -540,7 +582,7 @@ static void read_level(int module)
/* Write test pattern */ /* Write test pattern */
for(p=0;p<DFII_NPHASES;p++) for(p=0;p<DFII_NPHASES;p++)
for(i=0;i<DFII_PIX_DATA_SIZE;i++) for(i=0;i<DFII_PIX_DATA_SIZE;i++)
MMPTR(sdram_dfii_pix_wrdata_addr[p]+DFII_ADDR_SHIFT*i) = prs[DFII_PIX_DATA_SIZE*p+i]; MMPTR(sdram_dfii_pix_wrdata_addr[p]+DFII_ADDR_SHIFT*i) = csr_dw_hton(prs[p][i]);
sdram_dfii_piwr_address_write(0); sdram_dfii_piwr_address_write(0);
sdram_dfii_piwr_baddress_write(0); sdram_dfii_piwr_baddress_write(0);
command_pwr(DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS|DFII_COMMAND_WRDATA); command_pwr(DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS|DFII_COMMAND_WRDATA);
@ -560,9 +602,14 @@ static void read_level(int module)
cdelay(15); cdelay(15);
working = 1; working = 1;
for(p=0;p<DFII_NPHASES;p++) { for(p=0;p<DFII_NPHASES;p++) {
if(MMPTR(sdram_dfii_pix_rddata_addr[p]+DFII_ADDR_SHIFT*(NBMODULES-module-1)) != prs[DFII_PIX_DATA_SIZE*p+(NBMODULES-module-1)]) /* read back test pattern */
working = 0; for(i=0;i<DFII_PIX_DATA_SIZE;i++)
if(MMPTR(sdram_dfii_pix_rddata_addr[p]+DFII_ADDR_SHIFT*(2*NBMODULES-module-1)) != prs[DFII_PIX_DATA_SIZE*p+2*NBMODULES-module-1]) tst[i] = csr_dw_ntoh(MMPTR(sdram_dfii_pix_rddata_addr[p]+DFII_ADDR_SHIFT*i));
prs_bytes = (unsigned char *)&(prs[p][0]);
tst_bytes = (unsigned char *)&(tst[0]);
/* verify bytes matching current 'module' */
if (prs_bytes[ NBMODULES-1-module] != tst_bytes[ NBMODULES-1-module] ||
prs_bytes[2*NBMODULES-1-module] != tst_bytes[2*NBMODULES-1-module])
working = 0; working = 0;
} }
#ifdef ECP5DDRPHY #ifdef ECP5DDRPHY
@ -598,9 +645,14 @@ static void read_level(int module)
cdelay(15); cdelay(15);
working = 1; working = 1;
for(p=0;p<DFII_NPHASES;p++) { for(p=0;p<DFII_NPHASES;p++) {
if(MMPTR(sdram_dfii_pix_rddata_addr[p]+DFII_ADDR_SHIFT*(NBMODULES-module-1)) != prs[DFII_PIX_DATA_SIZE*p+(NBMODULES-module-1)]) /* read back test pattern */
working = 0; for(i=0;i<DFII_PIX_DATA_SIZE;i++)
if(MMPTR(sdram_dfii_pix_rddata_addr[p]+DFII_ADDR_SHIFT*(2*NBMODULES-module-1)) != prs[DFII_PIX_DATA_SIZE*p+2*NBMODULES-module-1]) tst[i] = csr_dw_ntoh(MMPTR(sdram_dfii_pix_rddata_addr[p]+DFII_ADDR_SHIFT*i));
prs_bytes = (unsigned char *)&(prs[p][0]);
tst_bytes = (unsigned char *)&(tst[0]);
/* verify bytes matching current 'module' */
if (prs_bytes[ NBMODULES-1-module] != tst_bytes[ NBMODULES-1-module] ||
prs_bytes[2*NBMODULES-1-module] != tst_bytes[2*NBMODULES-1-module])
working = 0; working = 0;
} }
#ifdef ECP5DDRPHY #ifdef ECP5DDRPHY