X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=litex%2Fsoc%2Fsoftware%2Fbios%2Fsdram.c;h=4f2bc81099519370f14a2e031674befd3a3dfea6;hb=f9bc98ed4ce5b9383d06d910af4b53cc2ebb9d3c;hp=e826d52f03ebfd6ba2fc9538aa17779a28db49d1;hpb=bda196fbc8417b84e9668fb4ff6a46853ba07d4c;p=litex.git diff --git a/litex/soc/software/bios/sdram.c b/litex/soc/software/bios/sdram.c index e826d52f..4f2bc810 100644 --- a/litex/soc/software/bios/sdram.c +++ b/litex/soc/software/bios/sdram.c @@ -1,23 +1,51 @@ +// This file is Copyright (c) 2013-2014 Sebastien Bourdeauducq +// This file is Copyright (c) 2013-2019 Florent Kermarrec +// This file is Copyright (c) 2018 Chris Ballance +// This file is Copyright (c) 2018 Dolu1990 +// This file is Copyright (c) 2019 Gabriel L. Somlo +// This file is Copyright (c) 2018 Jean-François Nguyen +// This file is Copyright (c) 2018 Sergiusz Bazanski +// This file is Copyright (c) 2018 Tim 'mithro' Ansell +// License: BSD + #include -#ifdef CSR_SDRAM_BASE #include #include +#ifdef CSR_SDRAM_BASE #include +#endif #include #include #include #include "sdram.h" -static void cdelay(int i) +// FIXME(hack): If we don't have main ram, just target the sram instead. +#ifndef MAIN_RAM_BASE +#define MAIN_RAM_BASE SRAM_BASE +#endif + +__attribute__((unused)) static void cdelay(int i) { while(i > 0) { #if defined (__lm32__) __asm__ volatile("nop"); #elif defined (__or1k__) __asm__ volatile("l.nop"); +#elif defined (__picorv32__) + __asm__ volatile("nop"); +#elif defined (__vexriscv__) + __asm__ volatile("nop"); +#elif defined (__minerva__) + __asm__ volatile("nop"); +#elif defined (__rocket__) + __asm__ volatile("nop"); +#elif defined (__powerpc__) + __asm__ volatile("nop"); +#elif defined (__microwatt__) + __asm__ volatile("nop"); #else #error Unsupported architecture #endif @@ -25,6 +53,14 @@ static void cdelay(int i) } } +#ifdef CSR_SDRAM_BASE + +#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 + void sdrsw(void) { sdram_dfii_control_write(DFII_CONTROL_CKE|DFII_CONTROL_ODT|DFII_CONTROL_RESET_N); @@ -66,18 +102,22 @@ void sdrrdbuf(int dq) { int i, p; int first_byte, step; + unsigned char buf[DFII_PIX_DATA_BYTES]; if(dq < 0) { first_byte = 0; step = 1; } else { - first_byte = DFII_PIX_DATA_SIZE/2 - 1 - dq; - step = DFII_PIX_DATA_SIZE/2; + first_byte = DFII_PIX_DATA_BYTES/2 - 1 - dq; + step = DFII_PIX_DATA_BYTES/2; } - for(p=0;p\n"); @@ -132,49 +173,52 @@ void sdrrderr(char *count) return; } - for(i=0;i\n"); + printf("sdrwr
\n"); return; } addr = strtoul(startaddr, &c, 0); @@ -183,9 +227,12 @@ void sdrwr(char *startaddr) return; } - for(p=0;p= ERR_DDRPHY_DELAY) - break; - ddrphy_wdly_dq_inc_write(1); - ddrphy_wdly_dqs_inc_write(1); + for(i=0;i= ERR_DDRPHY_DELAY) - break; - ddrphy_wdly_dq_inc_write(1); - ddrphy_wdly_dqs_inc_write(1); - - ddrphy_wlevel_strobe_write(1); + csr_rd_buf_uint8(sdram_dfii_pix_rddata_addr[0], + buf, DFII_PIX_DATA_BYTES); + if (buf[NBMODULES-1-i] != 0) + one_count++; + else + zero_count++; + } + if (one_count > zero_count) + taps_scan[j] = 1; + else + taps_scan[j] = 0; + if (show) + printf("%d", taps_scan[j]); + write_delay_inc(i); cdelay(10); - dq = MMPTR(dq_address); } + printf("|"); + + /* find longer 1 window and set delay at the 0/1 transition */ + one_window_active = 0; + one_window_start = 0; + one_window_count = 0; + one_window_best_start = 0; + one_window_best_count = 0; + delays[i] = -1; + for(j=0;j one_window_best_count) { + one_window_best_start = one_window_start; + one_window_best_count = one_window_count; + } + } + } else { + if (taps_scan[j]) { + one_window_active = 1; + one_window_start = j; + } + } + } + delays[i] = one_window_best_start; + + /* configure write delay */ + write_delay_rst(i); + for(j=0; j=0;i--) { - printf("%2d%c ", delay[i], high_skew[i] ? '*' : ' '); - if(delay[i] >= ERR_DDRPHY_DELAY) + for(i=NBMODULES-1;i>=0;i--) { + if(delays[i] < 0) ok = 0; } - if(ok) - printf("completed\n"); - else - printf("failed\n"); - return ok; } -static void read_bitslip(int *delay, int *high_skew) +#endif /* CSR_DDRPHY_WLEVEL_EN_ADDR */ + +static void read_delay_rst(int module) { + /* sel module */ + ddrphy_dly_sel_write(1 << module); + + /* rst delay */ + ddrphy_rdly_dq_rst_write(1); + + /* unsel module */ + ddrphy_dly_sel_write(0); + +#ifdef ECP5DDRPHY + /* Sync all DQSBUFM's, By toggling all dly_sel (DQSBUFM.PAUSE) lines. */ + ddrphy_dly_sel_write(0xFF); + ddrphy_dly_sel_write(0); +#endif +} + +static void read_delay_inc(int module) { + /* sel module */ + ddrphy_dly_sel_write(1 << module); + + /* inc delay */ + ddrphy_rdly_dq_inc_write(1); + + /* unsel module */ + ddrphy_dly_sel_write(0); + +#ifdef ECP5DDRPHY + /* Sync all DQSBUFM's, By toggling all dly_sel (DQSBUFM.PAUSE) lines. */ + ddrphy_dly_sel_write(0xFF); + ddrphy_dly_sel_write(0); +#endif +} + +static void read_bitslip_rst(char m) { - int bitslip_thr; - int i; + /* sel module */ + ddrphy_dly_sel_write(1 << m); - bitslip_thr = 0x7fffffff; - for(i=0;i=0;i--) - if(delay[i] > bitslip_thr) { - ddrphy_dly_sel_write(1 << i); - /* 7-series SERDES in DDR mode needs 3 pulses for 1 bitslip */ - ddrphy_rdly_dq_bitslip_write(1); - ddrphy_rdly_dq_bitslip_write(1); - ddrphy_rdly_dq_bitslip_write(1); - printf("%d ", i); + /* inc delay */ + ddrphy_rdly_dq_bitslip_rst_write(1); + + /* unsel module */ + ddrphy_dly_sel_write(0); +} + + +static void read_bitslip_inc(char m) +{ + /* sel module */ + ddrphy_dly_sel_write(1 << m); + + /* inc delay */ + ddrphy_rdly_dq_bitslip_write(1); + + /* unsel module */ + ddrphy_dly_sel_write(0); +} + +static int read_level_scan(int module, int bitslip) +{ + unsigned int prv; + unsigned char prs[DFII_NPHASES][DFII_PIX_DATA_BYTES]; + unsigned char tst[DFII_PIX_DATA_BYTES]; + int p, i; + int score; + + /* Generate pseudo-random sequence */ + prv = 42; + for(p=0;p> module) & 0x1) != 1) + working = 0; +#endif + if (show) + printf("%d", working); + score += working; + read_delay_inc(module); + } + printf("| "); + + /* Precharge */ + sdram_dfii_pi0_address_write(0); + sdram_dfii_pi0_baddress_write(0); + command_p0(DFII_COMMAND_RAS|DFII_COMMAND_WE|DFII_COMMAND_CS); + cdelay(15); + + return score; } -static void read_delays(void) +static void read_level(int module) { unsigned int prv; - unsigned char prs[DFII_NPHASES*DFII_PIX_DATA_SIZE]; - int p, i, j; + unsigned char prs[DFII_NPHASES][DFII_PIX_DATA_BYTES]; + unsigned char tst[DFII_PIX_DATA_BYTES]; + int p, i; int working; int delay, delay_min, delay_max; - printf("Read delays: "); + printf("delays: "); /* Generate pseudo-random sequence */ prv = 42; - for(i=0;i= ERR_DDRPHY_DELAY) - break; - ddrphy_rdly_dq_inc_write(1); + /* Find smallest working delay */ + delay = 0; + read_delay_rst(module); + while(1) { +#ifdef ECP5DDRPHY + ddrphy_burstdet_clr_write(1); +#endif + command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS|DFII_COMMAND_RDDATA); + cdelay(15); + working = 1; + for(p=0;p> module) & 0x1) != 1) + working = 0; +#endif + if(working) + break; delay++; - ddrphy_rdly_dq_inc_write(1); + if(delay >= ERR_DDRPHY_DELAY) + break; + read_delay_inc(module); + } + delay_min = delay; - /* Find largest working delay */ - while(1) { - command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS|DFII_COMMAND_RDDATA); - cdelay(15); - working = 1; - for(p=0;p= ERR_DDRPHY_DELAY) - break; - ddrphy_rdly_dq_inc_write(1); + /* Get a bit further into the working zone */ +#ifdef USDDRPHY + for(i=0;i<16;i++) { + delay += 1; + read_delay_inc(module); + } +#else + delay++; + read_delay_inc(module); +#endif + + /* Find largest working delay */ + while(1) { +#ifdef ECP5DDRPHY + ddrphy_burstdet_clr_write(1); +#endif + command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS|DFII_COMMAND_RDDATA); + cdelay(15); + working = 1; + for(p=0;p> module) & 0x1) != 1) + working = 0; +#endif + if(!working) + break; + delay++; + if(delay >= ERR_DDRPHY_DELAY) + break; + read_delay_inc(module); + } + delay_max = delay; - printf("%d:%02d-%02d ", DFII_PIX_DATA_SIZE/2-i-1, delay_min, delay_max); + if (delay_min >= ERR_DDRPHY_DELAY) + printf("-"); + else + printf("%02d+-%02d", (delay_min+delay_max)/2, (delay_max-delay_min)/2); - /* Set delay to the middle */ - ddrphy_rdly_dq_rst_write(1); - for(j=0;j<(delay_min+delay_max)/2;j++) - ddrphy_rdly_dq_inc_write(1); - } + /* Set delay to the middle */ + read_delay_rst(module); + for(i=0;i<(delay_min+delay_max)/2;i++) + read_delay_inc(module); /* Precharge */ sdram_dfii_pi0_address_write(0); sdram_dfii_pi0_baddress_write(0); command_p0(DFII_COMMAND_RAS|DFII_COMMAND_WE|DFII_COMMAND_CS); cdelay(15); - - printf("completed\n"); } - -int sdrlevel(void) -{ - int delay[DFII_PIX_DATA_SIZE/2]; - int high_skew[DFII_PIX_DATA_SIZE/2]; - - if(!write_level(delay, high_skew)) - return 0; - read_bitslip(delay, high_skew); - read_delays(); - - return 1; -} - #endif /* CSR_DDRPHY_BASE */ +#endif /* CSR_SDRAM_BASE */ + static unsigned int seed_to_data_32(unsigned int seed, int random) { if (random) @@ -446,10 +699,13 @@ static unsigned short seed_to_data_16(unsigned short seed, int random) #define MEMTEST_BUS_SIZE (512) #endif +//#define MEMTEST_BUS_DEBUG + static int memtest_bus(void) { volatile unsigned int *array = (unsigned int *)MAIN_RAM_BASE; int i, errors; + unsigned int rdata; errors = 0; @@ -457,20 +713,34 @@ static int memtest_bus(void) array[i] = ONEZERO; } flush_cpu_dcache(); +#ifdef CONFIG_L2_SIZE flush_l2_cache(); +#endif for(i=0;i best_score) { + best_bitslip = bitslip; + best_score = score; + } + /* exit */ + if (bitslip == ERR_DDRPHY_BITSLIP-1) + break; + /* increment bitslip */ + read_bitslip_inc(module); + } + + /* select best read window */ + printf("best: m%d, b%d ", module, best_bitslip); + read_bitslip_rst(module); + for (bitslip=0; bitslip