software: create liblitedram and move sdram init/test code to it.
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Mon, 18 May 2020 20:39:59 +0000 (22:39 +0200)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Mon, 18 May 2020 20:42:23 +0000 (22:42 +0200)
litex/soc/integration/builder.py
litex/soc/software/bios/Makefile
litex/soc/software/bios/lfsr.h [deleted file]
litex/soc/software/bios/sdram.c [deleted file]
litex/soc/software/bios/sdram.h [deleted file]
litex/soc/software/common.mak
litex/soc/software/liblitedram/Makefile [new file with mode: 0644]
litex/soc/software/liblitedram/lfsr.h [new file with mode: 0644]
litex/soc/software/liblitedram/sdram.c [new file with mode: 0644]
litex/soc/software/liblitedram/sdram.h [new file with mode: 0644]

index 79c6b95d39e1a1b2486e29060ccad6da988d2a55..64dca9d61fdb69b2e15f90e025b5e366edac744c 100644 (file)
@@ -25,6 +25,7 @@ __all__ = ["soc_software_packages", "soc_directory",
 soc_software_packages = [
     "libcompiler_rt",
     "libbase",
+    "liblitedram",
     "libliteeth",
     "bios"
 ]
index 24d33a504ac26380785ed1a7a3e51839344928ba..73d9ed0a2327e127002db02109045fad2d5bac0e 100755 (executable)
@@ -11,7 +11,6 @@ CFLAGS += -DTFTP_SERVER_PORT=$(TFTP_SERVER_PORT)
 endif
 
 OBJECTS = isr.o                        \
-         sdram.o                       \
          sdcard.o                      \
          main.o                        \
          boot-helper.o         \
@@ -59,15 +58,20 @@ endif
 bios.elf: $(BIOS_DIRECTORY)/linker.ld $(OBJECTS)
 
 
-%.elf: ../libbase/crt0-ctr.o ../libliteeth/libliteeth.a ../libbase/libbase-nofloat.a ../libcompiler_rt/libcompiler_rt.a
+%.elf: ../libbase/crt0-ctr.o \
+       ../libcompiler_rt/libcompiler_rt.a \
+       ../libbase/libbase-nofloat.a \
+       ../liblitedram/liblitedram.a \
+       ../libliteeth/libliteeth.a
        $(LD) $(LDFLAGS) -T $(BIOS_DIRECTORY)/linker.ld -N -o $@ \
                ../libbase/crt0-ctr.o \
                $(OBJECTS) \
-               -L../libliteeth \
-               -L../libbase \
                -L../libcompiler_rt \
+               -L../libbase \
+               -L../liblitedram \
+               -L../libliteeth \
                $(BP_LIBS) \
-               -lliteeth -lbase-nofloat -lcompiler_rt \
+               -lcompiler_rt -lbase-nofloat -llitedram -lliteeth \
                $(BP_FLAGS)
 
 ifneq ($(OS),Windows_NT)
diff --git a/litex/soc/software/bios/lfsr.h b/litex/soc/software/bios/lfsr.h
deleted file mode 100644 (file)
index 50dfccf..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-#include <limits.h>
-
-/*
- * Copyright (C) 2020, Anton Blanchard <anton@linux.ibm.com>, IBM
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * 1. Redistributions of source code must retain the above copyright notice, this
- *    list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- *    this list of conditions and the following disclaimer in the documentation
- *    and/or other materials provided with the distribution.
-
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
- * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
- * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*
- * Galois LFSR
- *
- * Polynomials verified with https://bitbucket.org/gallen/mlpolygen/
- */
-static inline unsigned long lfsr(unsigned long bits, unsigned long prev)
-{
-       static const unsigned long lfsr_taps[] = {
-               0x0,
-               0x0,
-               0x3,
-               0x6,
-               0xc,
-               0x14,
-               0x30,
-               0x60,
-               0xb8,
-               0x110,
-               0x240,
-               0x500,
-               0x829,
-               0x100d,
-               0x2015,
-               0x6000,
-               0xd008,
-               0x12000,
-               0x20400,
-               0x40023,
-               0x90000,
-               0x140000,
-               0x300000,
-               0x420000,
-               0xe10000,
-               0x1200000,
-               0x2000023,
-               0x4000013,
-               0x9000000,
-               0x14000000,
-               0x20000029,
-               0x48000000,
-               0x80200003,
-#if __WORDSIZE == 64
-               0x100080000,
-               0x204000003,
-               0x500000000,
-               0x801000000,
-               0x100000001f,
-               0x2000000031,
-               0x4400000000,
-               0xa000140000,
-               0x12000000000,
-               0x300000c0000,
-               0x63000000000,
-               0xc0000030000,
-               0x1b0000000000,
-               0x300003000000,
-               0x420000000000,
-               0xc00000180000,
-               0x1008000000000,
-               0x3000000c00000,
-               0x6000c00000000,
-               0x9000000000000,
-               0x18003000000000,
-               0x30000000030000,
-               0x40000040000000,
-               0xc0000600000000,
-               0x102000000000000,
-               0x200004000000000,
-               0x600003000000000,
-               0xc00000000000000,
-               0x1800300000000000,
-               0x3000000000000030,
-               0x6000000000000000,
-               0x800000000000000d
-#endif
-       };
-       unsigned long lsb = prev & 1;
-
-       prev >>= 1;
-       prev ^= (-lsb) & lfsr_taps[bits];
-
-       return prev;
-}
diff --git a/litex/soc/software/bios/sdram.c b/litex/soc/software/bios/sdram.c
deleted file mode 100644 (file)
index 81b169c..0000000
+++ /dev/null
@@ -1,1066 +0,0 @@
-// This file is Copyright (c) 2013-2014 Sebastien Bourdeauducq <sb@m-labs.hk>
-// This file is Copyright (c) 2013-2020 Florent Kermarrec <florent@enjoy-digital.fr>
-// This file is Copyright (c) 2018 Chris Ballance <chris.ballance@physics.ox.ac.uk>
-// This file is Copyright (c) 2018 Dolu1990 <charles.papon.90@gmail.com>
-// This file is Copyright (c) 2019 Gabriel L. Somlo <gsomlo@gmail.com>
-// This file is Copyright (c) 2018 Jean-François Nguyen <jf@lambdaconcept.fr>
-// This file is Copyright (c) 2018 Sergiusz Bazanski <q3k@q3k.org>
-// This file is Copyright (c) 2018 Tim 'mithro' Ansell <me@mith.ro>
-// License: BSD
-
-#include <generated/csr.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#ifdef CSR_SDRAM_BASE
-#include <generated/sdram_phy.h>
-#endif
-#include <generated/mem.h>
-#include <hw/flags.h>
-#include <system.h>
-
-#include "sdram.h"
-#include "lfsr.h"
-
-// 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) {
-               __asm__ volatile(CONFIG_CPU_NOP);
-               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);
-       printf("SDRAM now under software control\n");
-}
-
-void sdrhw(void)
-{
-       sdram_dfii_control_write(DFII_CONTROL_SEL);
-       printf("SDRAM now under hardware control\n");
-}
-
-void sdrrow(unsigned int row)
-{
-       if(row == 0) {
-               sdram_dfii_pi0_address_write(0x0000);
-               sdram_dfii_pi0_baddress_write(0);
-               command_p0(DFII_COMMAND_RAS|DFII_COMMAND_WE|DFII_COMMAND_CS);
-               cdelay(15);
-       } else {
-               sdram_dfii_pi0_address_write(row);
-               sdram_dfii_pi0_baddress_write(0);
-               command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CS);
-               cdelay(15);
-       }
-}
-
-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_BYTES/2 - 1 - dq;
-               step = DFII_PIX_DATA_BYTES/2;
-       }
-
-       for(p=0;p<SDRAM_PHY_PHASES;p++) {
-               csr_rd_buf_uint8(sdram_dfii_pix_rddata_addr[p],
-                                buf, DFII_PIX_DATA_BYTES);
-               for(i=first_byte;i<DFII_PIX_DATA_BYTES;i+=step)
-                       printf("%02x", buf[i]);
-       }
-       printf("\n");
-}
-
-void sdrrd(unsigned int addr, int dq)
-{
-       sdram_dfii_pird_address_write(addr);
-       sdram_dfii_pird_baddress_write(0);
-       command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS|DFII_COMMAND_RDDATA);
-       cdelay(15);
-       sdrrdbuf(dq);
-}
-
-void sdrrderr(int count)
-{
-       int addr;
-       int i, j, p;
-       unsigned char prev_data[SDRAM_PHY_PHASES][DFII_PIX_DATA_BYTES];
-       unsigned char errs[SDRAM_PHY_PHASES][DFII_PIX_DATA_BYTES];
-       unsigned char new_data[DFII_PIX_DATA_BYTES];
-
-       for(p=0;p<SDRAM_PHY_PHASES;p++)
-               for(i=0;i<DFII_PIX_DATA_BYTES;i++)
-                       errs[p][i] = 0;
-
-       for(addr=0;addr<16;addr++) {
-               sdram_dfii_pird_address_write(addr*8);
-               sdram_dfii_pird_baddress_write(0);
-               command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS|DFII_COMMAND_RDDATA);
-               cdelay(15);
-               for(p=0;p<SDRAM_PHY_PHASES;p++)
-                       csr_rd_buf_uint8(sdram_dfii_pix_rddata_addr[p],
-                                        prev_data[p], DFII_PIX_DATA_BYTES);
-
-               for(j=0;j<count;j++) {
-                       command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS|DFII_COMMAND_RDDATA);
-                       cdelay(15);
-                       for(p=0;p<SDRAM_PHY_PHASES;p++) {
-                               csr_rd_buf_uint8(sdram_dfii_pix_rddata_addr[p],
-                                                new_data, DFII_PIX_DATA_BYTES);
-                               for(i=0;i<DFII_PIX_DATA_BYTES;i++) {
-                                       errs[p][i] |= prev_data[p][i] ^ new_data[i];
-                                       prev_data[p][i] = new_data[i];
-                               }
-                       }
-               }
-       }
-
-       for(p=0;p<SDRAM_PHY_PHASES;p++)
-               for(i=0;i<DFII_PIX_DATA_BYTES;i++)
-                       printf("%02x", errs[p][i]);
-       printf("\n");
-       for(p=0;p<SDRAM_PHY_PHASES;p++)
-               for(i=0;i<DFII_PIX_DATA_BYTES;i++)
-                       printf("%2x", DFII_PIX_DATA_BYTES/2 - 1 - (i % (DFII_PIX_DATA_BYTES/2)));
-       printf("\n");
-}
-
-void sdrwr(unsigned int addr)
-{
-       int i, p;
-       unsigned char buf[DFII_PIX_DATA_BYTES];
-
-       for(p=0;p<SDRAM_PHY_PHASES;p++) {
-               for(i=0;i<DFII_PIX_DATA_BYTES;i++)
-                       buf[i] = 0x10*p + i;
-               csr_wr_buf_uint8(sdram_dfii_pix_wrdata_addr[p],
-                                buf, DFII_PIX_DATA_BYTES);
-       }
-
-       sdram_dfii_piwr_address_write(addr);
-       sdram_dfii_piwr_baddress_write(0);
-       command_pwr(DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS|DFII_COMMAND_WRDATA);
-}
-
-#ifdef CSR_DDRPHY_BASE
-
-#if defined(DDRPHY_CMD_DELAY)
-void ddrphy_cdly(unsigned int delay) {
-       printf("Setting clk/cmd delay to %d taps\n", delay);
-#if CSR_DDRPHY_EN_VTC_ADDR
-       ddrphy_en_vtc_write(0);
-#endif
-       ddrphy_cdly_rst_write(1);
-       while (delay > 0) {
-               ddrphy_cdly_inc_write(1);
-               cdelay(1000);
-               delay--;
-       }
-#if CSR_DDRPHY_EN_VTC_ADDR
-       ddrphy_en_vtc_write(1);
-#endif
-}
-#endif
-
-#ifdef SDRAM_PHY_WRITE_LEVELING_CAPABLE
-void sdrwlon(void)
-{
-       sdram_dfii_pi0_address_write(DDRX_MR1 | (1 << 7));
-       sdram_dfii_pi0_baddress_write(1);
-       command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS);
-
-#ifdef SDRAM_PHY_DDR4_RDIMM
-       sdram_dfii_pi0_address_write((DDRX_MR1 | (1 << 7)) ^ 0x2BF8) ;
-       sdram_dfii_pi0_baddress_write(1 ^ 0xF);
-       command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS);
-#endif
-
-       ddrphy_wlevel_en_write(1);
-}
-
-void sdrwloff(void)
-{
-       sdram_dfii_pi0_address_write(DDRX_MR1);
-       sdram_dfii_pi0_baddress_write(1);
-       command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS);
-
-#ifdef SDRAM_PHY_DDR4_RDIMM
-       sdram_dfii_pi0_address_write(DDRX_MR1 ^ 0x2BF8);
-       sdram_dfii_pi0_baddress_write(1 ^ 0xF);
-       command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS);
-#endif
-
-       ddrphy_wlevel_en_write(0);
-}
-
-static void write_delay_rst(int module) {
-#ifdef SDRAM_PHY_WRITE_LEVELING_REINIT
-       int i;
-#endif
-
-       /* sel module */
-       ddrphy_dly_sel_write(1 << module);
-
-       /* rst delay */
-       ddrphy_wdly_dq_rst_write(1);
-       ddrphy_wdly_dqs_rst_write(1);
-#ifdef SDRAM_PHY_WRITE_LEVELING_REINIT
-       for(i=0; i<ddrphy_half_sys8x_taps_read(); i++)
-               ddrphy_wdly_dqs_inc_write(1);
-#endif
-
-       /* unsel module */
-       ddrphy_dly_sel_write(0);
-}
-
-static void write_delay_inc(int module) {
-       /* sel module */
-       ddrphy_dly_sel_write(1 << module);
-
-       /* inc delay */
-       ddrphy_wdly_dq_inc_write(1);
-       ddrphy_wdly_dqs_inc_write(1);
-
-       /* unsel module */
-       ddrphy_dly_sel_write(0);
-}
-
-static int write_level_scan(int *delays, int loops, int show)
-{
-       int i, j, k;
-
-       int err_ddrphy_wdly;
-
-       unsigned char taps_scan[SDRAM_PHY_DELAYS];
-
-       int one_window_active;
-       int one_window_start, one_window_best_start;
-       int one_window_count, one_window_best_count;
-
-       unsigned char buf[DFII_PIX_DATA_BYTES];
-
-       int ok;
-
-       err_ddrphy_wdly = SDRAM_PHY_DELAYS - ddrphy_half_sys8x_taps_read();
-
-       sdrwlon();
-       cdelay(100);
-       for(i=0;i<SDRAM_PHY_MODULES;i++) {
-               if (show)
-                       printf("m%d: |", i);
-
-               /* rst delay */
-               write_delay_rst(i);
-
-               /* scan write delay taps */
-               for(j=0;j<err_ddrphy_wdly;j++) {
-                       int zero_count = 0;
-                       int one_count = 0;
-                       int show_iter = show;
-#if SDRAM_PHY_DELAYS > 32
-                       show_iter = (j%16 == 0) && show;
-#endif
-                       for (k=0; k<loops; k++) {
-                               ddrphy_wlevel_strobe_write(1);
-                               cdelay(10);
-                               csr_rd_buf_uint8(sdram_dfii_pix_rddata_addr[0],
-                                                buf, DFII_PIX_DATA_BYTES);
-                               if (buf[SDRAM_PHY_MODULES-1-i] != 0)
-                                       one_count++;
-                               else
-                                       zero_count++;
-                       }
-                       if (one_count > zero_count)
-                               taps_scan[j] = 1;
-                       else
-                               taps_scan[j] = 0;
-                       if (show_iter)
-                               printf("%d", taps_scan[j]);
-                       write_delay_inc(i);
-                       cdelay(10);
-               }
-               if (show)
-                       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 = -1;
-               delays[i] = -1;
-               for(j=0;j<err_ddrphy_wdly;j++) {
-                       if (one_window_active) {
-                               if ((taps_scan[j] == 0) | (j == err_ddrphy_wdly - 1)) {
-                                       one_window_active = 0;
-                                       one_window_count = j - one_window_start;
-                                       if (one_window_count > 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;
-                               }
-                       }
-               }
-               /* succeed only if the start of a 1s window has been found */
-               if (one_window_best_count > 0 && one_window_best_start > 0) {
-                       delays[i] = one_window_best_start;
-
-                       /* configure write delay */
-                       write_delay_rst(i);
-                       for(j=0; j<delays[i]; j++)
-                               write_delay_inc(i);
-               }
-               if (show)
-                       printf(" delay: %02d\n", delays[i]);
-       }
-
-       sdrwloff();
-
-       ok = 1;
-       for(i=SDRAM_PHY_MODULES-1;i>=0;i--) {
-               if(delays[i] < 0)
-                       ok = 0;
-       }
-
-       return ok;
-}
-
-static void write_level_cdly_range(unsigned int *best_error, int *best_cdly,
-               int cdly_start, int cdly_stop, int cdly_step)
-{
-       int cdly;
-       int cdly_actual = 0;
-       int delays[SDRAM_PHY_MODULES];
-
-       /* scan through the range */
-       ddrphy_cdly_rst_write(1);
-       for (cdly = cdly_start; cdly < cdly_stop; cdly += cdly_step) {
-               /* increment cdly to current value */
-               while (cdly_actual < cdly) {
-                       ddrphy_cdly_inc_write(1);
-                       cdelay(10);
-                       cdly_actual++;
-               }
-
-               /* write level using this delay */
-               if (write_level_scan(delays, 8, 0)) {
-                       /* use the mean of delays for error calulation */
-                       int delay_mean = 0;
-                       for (int i=0; i < SDRAM_PHY_MODULES; ++i) {
-                               delay_mean += delays[i];
-                       }
-                       delay_mean /= SDRAM_PHY_MODULES;
-
-                       /* we want it to be at the start */
-                       int ideal_delay = 4*SDRAM_PHY_DELAYS/32;
-                       int error = ideal_delay - delay_mean;
-                       if (error < 0)
-                               error *= -1;
-
-                       if (error < *best_error) {
-                               *best_cdly = cdly;
-                               *best_error = error;
-                       }
-                       printf("1");
-               } else {
-                       printf("0");
-               }
-       }
-}
-
-int write_level(void)
-{
-       int delays[SDRAM_PHY_MODULES];
-       unsigned int best_error = ~0u;
-       int best_cdly = -1;
-       int cdly_range_start;
-       int cdly_range_end;
-       int cdly_range_step;
-
-       printf("Command/Clk scan:\n");
-
-       /* Center write leveling by varying cdly. Searching through all possible
-        * values is slow, but we can use a simple optimization method of iterativly
-        * scanning smaller ranges with decreasing step */
-       cdly_range_start = 0;
-       cdly_range_end = SDRAM_PHY_DELAYS;
-       if (SDRAM_PHY_DELAYS > 32)
-               cdly_range_step = SDRAM_PHY_DELAYS/8;
-       else
-               cdly_range_step = 1;
-       while (cdly_range_step > 0) {
-               printf("|");
-               write_level_cdly_range(&best_error, &best_cdly,
-                               cdly_range_start, cdly_range_end, cdly_range_step);
-
-               /* small optimization - stop if we have zero error */
-               if (best_error == 0)
-                       break;
-
-               /* use best result as the middle of next range */
-               cdly_range_start = best_cdly - cdly_range_step;
-               cdly_range_end = best_cdly + cdly_range_step + 1;
-               if (cdly_range_start < 0)
-                       cdly_range_start = 0;
-               if (cdly_range_end > 512)
-                       cdly_range_end = 512;
-
-               cdly_range_step /= 4;
-       }
-       printf("| best: %d\n", best_cdly);
-
-       /* if we found any working delay then set it */
-       if (best_cdly >= 0) {
-               ddrphy_cdly_rst_write(1);
-               for (int i = 0; i < best_cdly; ++i) {
-                       ddrphy_cdly_inc_write(1);
-                       cdelay(10);
-               }
-       }
-
-       printf("Data scan:\n");
-
-       /* re-run write leveling the final time */
-       if (!write_level_scan(delays, 128, 1))
-               return 0;
-
-       return best_cdly >= 0;
-}
-
-
-#endif /*  SDRAM_PHY_WRITE_LEVELING_CAPABLE */
-
-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 SDRAM_PHY_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 SDRAM_PHY_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)
-{
-       /* sel module */
-       ddrphy_dly_sel_write(1 << m);
-
-       /* 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[SDRAM_PHY_PHASES][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<SDRAM_PHY_PHASES;p++)
-               for(i=0;i<DFII_PIX_DATA_BYTES;i++) {
-                       prv = lfsr(32, prv);
-                       prs[p][i] = prv;
-               }
-
-       /* Activate */
-       sdram_dfii_pi0_address_write(0);
-       sdram_dfii_pi0_baddress_write(0);
-       command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CS);
-       cdelay(15);
-
-       /* Write test pattern */
-       for(p=0;p<SDRAM_PHY_PHASES;p++)
-               csr_wr_buf_uint8(sdram_dfii_pix_wrdata_addr[p],
-                                prs[p], DFII_PIX_DATA_BYTES);
-       sdram_dfii_piwr_address_write(0);
-       sdram_dfii_piwr_baddress_write(0);
-       command_pwr(DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS|DFII_COMMAND_WRDATA);
-
-       /* Calibrate each DQ in turn */
-       sdram_dfii_pird_address_write(0);
-       sdram_dfii_pird_baddress_write(0);
-       score = 0;
-
-       printf("m%d, b%02d: |", module, bitslip);
-       read_delay_rst(module);
-       for(i=0;i<SDRAM_PHY_DELAYS;i++) {
-               int working = 1;
-               int show = 1;
-#if SDRAM_PHY_DELAYS > 32
-               show = (i%16 == 0);
-#endif
-#ifdef SDRAM_PHY_ECP5DDRPHY
-               ddrphy_burstdet_clr_write(1);
-#endif
-               command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS|DFII_COMMAND_RDDATA);
-               cdelay(15);
-               for(p=0;p<SDRAM_PHY_PHASES;p++) {
-                       /* read back test pattern */
-                       csr_rd_buf_uint8(sdram_dfii_pix_rddata_addr[p],
-                                        tst, DFII_PIX_DATA_BYTES);
-                       /* verify bytes matching current 'module' */
-                       if (prs[p][  SDRAM_PHY_MODULES-1-module] != tst[  SDRAM_PHY_MODULES-1-module] ||
-                           prs[p][2*SDRAM_PHY_MODULES-1-module] != tst[2*SDRAM_PHY_MODULES-1-module])
-                               working = 0;
-               }
-#ifdef SDRAM_PHY_ECP5DDRPHY
-               if (((ddrphy_burstdet_seen_read() >> 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_level(int module)
-{
-       unsigned int prv;
-       unsigned char prs[SDRAM_PHY_PHASES][DFII_PIX_DATA_BYTES];
-       unsigned char tst[DFII_PIX_DATA_BYTES];
-       int p, i;
-       int working;
-       int delay, delay_min, delay_max;
-
-       printf("delays: ");
-
-       /* Generate pseudo-random sequence */
-       prv = 42;
-       for(p=0;p<SDRAM_PHY_PHASES;p++)
-               for(i=0;i<DFII_PIX_DATA_BYTES;i++) {
-                       prv = lfsr(32, prv);
-                       prs[p][i] = prv;
-               }
-
-       /* Activate */
-       sdram_dfii_pi0_address_write(0);
-       sdram_dfii_pi0_baddress_write(0);
-       command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CS);
-       cdelay(15);
-
-       /* Write test pattern */
-       for(p=0;p<SDRAM_PHY_PHASES;p++)
-               csr_wr_buf_uint8(sdram_dfii_pix_wrdata_addr[p],
-                                prs[p], DFII_PIX_DATA_BYTES);
-       sdram_dfii_piwr_address_write(0);
-       sdram_dfii_piwr_baddress_write(0);
-       command_pwr(DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS|DFII_COMMAND_WRDATA);
-
-       /* Calibrate each DQ in turn */
-       sdram_dfii_pird_address_write(0);
-       sdram_dfii_pird_baddress_write(0);
-
-       /* Find smallest working delay */
-       delay = 0;
-       read_delay_rst(module);
-       while(1) {
-#ifdef SDRAM_PHY_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<SDRAM_PHY_PHASES;p++) {
-                       /* read back test pattern */
-                       csr_rd_buf_uint8(sdram_dfii_pix_rddata_addr[p],
-                                        tst, DFII_PIX_DATA_BYTES);
-                       /* verify bytes matching current 'module' */
-                       if (prs[p][  SDRAM_PHY_MODULES-1-module] != tst[  SDRAM_PHY_MODULES-1-module] ||
-                           prs[p][2*SDRAM_PHY_MODULES-1-module] != tst[2*SDRAM_PHY_MODULES-1-module])
-                               working = 0;
-               }
-#ifdef SDRAM_PHY_ECP5DDRPHY
-               if (((ddrphy_burstdet_seen_read() >> module) & 0x1) != 1)
-                       working = 0;
-#endif
-               if(working)
-                       break;
-               delay++;
-               if(delay >= SDRAM_PHY_DELAYS)
-                       break;
-               read_delay_inc(module);
-       }
-       delay_min = delay;
-
-       /* Get a bit further into the working zone */
-#if SDRAM_PHY_DELAYS > 32
-       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 SDRAM_PHY_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<SDRAM_PHY_PHASES;p++) {
-                       /* read back test pattern */
-                       csr_rd_buf_uint8(sdram_dfii_pix_rddata_addr[p],
-                                        tst, DFII_PIX_DATA_BYTES);
-                       /* verify bytes matching current 'module' */
-                       if (prs[p][  SDRAM_PHY_MODULES-1-module] != tst[  SDRAM_PHY_MODULES-1-module] ||
-                           prs[p][2*SDRAM_PHY_MODULES-1-module] != tst[2*SDRAM_PHY_MODULES-1-module])
-                               working = 0;
-               }
-#ifdef SDRAM_PHY_ECP5DDRPHY
-               if (((ddrphy_burstdet_seen_read() >> module) & 0x1) != 1)
-                       working = 0;
-#endif
-               if(!working)
-                       break;
-               delay++;
-               if(delay >= SDRAM_PHY_DELAYS)
-                       break;
-               read_delay_inc(module);
-       }
-       delay_max = delay;
-
-       if (delay_min >= SDRAM_PHY_DELAYS)
-               printf("-");
-       else
-               printf("%02d+-%02d", (delay_min+delay_max)/2, (delay_max-delay_min)/2);
-
-       /* 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);
-}
-#endif /* CSR_DDRPHY_BASE */
-
-#endif /* CSR_SDRAM_BASE */
-
-static unsigned int seed_to_data_32(unsigned int seed, int random)
-{
-       if (random)
-               return lfsr(32, seed);
-       else
-               return seed + 1;
-}
-
-static unsigned short seed_to_data_16(unsigned short seed, int random)
-{
-       if (random)
-               return lfsr(16, seed);
-       else
-               return seed + 1;
-}
-
-#define ONEZERO 0xAAAAAAAA
-#define ZEROONE 0x55555555
-
-#ifndef MEMTEST_BUS_SIZE
-#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;
-
-       for(i=0;i<MEMTEST_BUS_SIZE/4;i++) {
-               array[i] = ONEZERO;
-       }
-       flush_cpu_dcache();
-#ifdef CONFIG_L2_SIZE
-       flush_l2_cache();
-#endif
-       for(i=0;i<MEMTEST_BUS_SIZE/4;i++) {
-               rdata = array[i];
-               if(rdata != ONEZERO) {
-                       errors++;
-#ifdef MEMTEST_BUS_DEBUG
-                       printf("[bus: 0x%0x]: 0x%08x vs 0x%08x\n", i, rdata, ONEZERO);
-#endif
-               }
-       }
-
-       for(i=0;i<MEMTEST_BUS_SIZE/4;i++) {
-               array[i] = ZEROONE;
-       }
-       flush_cpu_dcache();
-#ifdef CONFIG_L2_SIZE
-       flush_l2_cache();
-#endif
-       for(i=0;i<MEMTEST_BUS_SIZE/4;i++) {
-               rdata = array[i];
-               if(rdata != ZEROONE) {
-                       errors++;
-#ifdef MEMTEST_BUS_DEBUG
-                       printf("[bus 0x%0x]: 0x%08x vs 0x%08x\n", i, rdata, ZEROONE);
-#endif
-               }
-       }
-
-       return errors;
-}
-
-#ifndef MEMTEST_DATA_SIZE
-#define MEMTEST_DATA_SIZE (2*1024*1024)
-#endif
-#define MEMTEST_DATA_RANDOM 1
-
-//#define MEMTEST_DATA_DEBUG
-
-static int memtest_data(void)
-{
-       volatile unsigned int *array = (unsigned int *)MAIN_RAM_BASE;
-       int i, errors;
-       unsigned int seed_32;
-       unsigned int rdata;
-
-       errors = 0;
-       seed_32 = 1;
-
-       for(i=0;i<MEMTEST_DATA_SIZE/4;i++) {
-               seed_32 = seed_to_data_32(seed_32, MEMTEST_DATA_RANDOM);
-               array[i] = seed_32;
-       }
-
-       seed_32 = 1;
-       flush_cpu_dcache();
-#ifdef CONFIG_L2_SIZE
-       flush_l2_cache();
-#endif
-       for(i=0;i<MEMTEST_DATA_SIZE/4;i++) {
-               seed_32 = seed_to_data_32(seed_32, MEMTEST_DATA_RANDOM);
-               rdata = array[i];
-               if(rdata != seed_32) {
-                       errors++;
-#ifdef MEMTEST_DATA_DEBUG
-                       printf("[data 0x%0x]: 0x%08x vs 0x%08x\n", i, rdata, seed_32);
-#endif
-               }
-       }
-
-       return errors;
-}
-#ifndef MEMTEST_ADDR_SIZE
-#define MEMTEST_ADDR_SIZE (32*1024)
-#endif
-#define MEMTEST_ADDR_RANDOM 0
-
-//#define MEMTEST_ADDR_DEBUG
-
-static int memtest_addr(void)
-{
-       volatile unsigned int *array = (unsigned int *)MAIN_RAM_BASE;
-       int i, errors;
-       unsigned short seed_16;
-       unsigned short rdata;
-
-       errors = 0;
-       seed_16 = 1;
-
-       for(i=0;i<MEMTEST_ADDR_SIZE/4;i++) {
-               seed_16 = seed_to_data_16(seed_16, MEMTEST_ADDR_RANDOM);
-               array[(unsigned int) seed_16] = i;
-       }
-
-       seed_16 = 1;
-       flush_cpu_dcache();
-#ifdef CONFIG_L2_SIZE
-       flush_l2_cache();
-#endif
-       for(i=0;i<MEMTEST_ADDR_SIZE/4;i++) {
-               seed_16 = seed_to_data_16(seed_16, MEMTEST_ADDR_RANDOM);
-               rdata = array[(unsigned int) seed_16];
-               if(rdata != i) {
-                       errors++;
-#ifdef MEMTEST_ADDR_DEBUG
-                       printf("[addr 0x%0x]: 0x%08x vs 0x%08x\n", i, rdata, i);
-#endif
-               }
-       }
-
-       return errors;
-}
-
-static void memspeed(void)
-{
-       volatile unsigned int *array = (unsigned int *)MAIN_RAM_BASE;
-       int i;
-       unsigned int start, end;
-       unsigned long write_speed;
-       unsigned long read_speed;
-       __attribute__((unused)) unsigned int data;
-
-       /* init timer */
-       timer0_en_write(0);
-       timer0_reload_write(0);
-       timer0_load_write(0xffffffff);
-       timer0_en_write(1);
-
-       /* write speed */
-       timer0_update_value_write(1);
-       start = timer0_value_read();
-       for(i=0;i<MEMTEST_DATA_SIZE/4;i++) {
-               array[i] = i;
-       }
-       timer0_update_value_write(1);
-       end = timer0_value_read();
-       write_speed = (8*MEMTEST_DATA_SIZE*(CONFIG_CLOCK_FREQUENCY/1000000))/(start - end);
-
-       /* flush CPU and L2 caches */
-       flush_cpu_dcache();
-#ifdef CONFIG_L2_SIZE
-       flush_l2_cache();
-#endif
-
-       /* read speed */
-       timer0_en_write(1);
-       timer0_update_value_write(1);
-       start = timer0_value_read();
-       for(i=0;i<MEMTEST_DATA_SIZE/4;i++) {
-               data = array[i];
-       }
-       timer0_update_value_write(1);
-       end = timer0_value_read();
-       read_speed = (8*MEMTEST_DATA_SIZE*(CONFIG_CLOCK_FREQUENCY/1000000))/(start - end);
-
-       printf("Memspeed Writes: %ldMbps Reads: %ldMbps\n", write_speed, read_speed);
-}
-
-int memtest(void)
-{
-       int bus_errors, data_errors, addr_errors;
-
-       bus_errors = memtest_bus();
-       if(bus_errors != 0)
-               printf("Memtest bus failed: %d/%d errors\n", bus_errors, 2*128);
-
-       data_errors = memtest_data();
-       if(data_errors != 0)
-               printf("Memtest data failed: %d/%d errors\n", data_errors, MEMTEST_DATA_SIZE/4);
-
-       addr_errors = memtest_addr();
-       if(addr_errors != 0)
-               printf("Memtest addr failed: %d/%d errors\n", addr_errors, MEMTEST_ADDR_SIZE/4);
-
-       if(bus_errors + data_errors + addr_errors != 0)
-               return 0;
-       else {
-               printf("Memtest OK\n");
-               memspeed();
-               return 1;
-       }
-}
-
-#ifdef CSR_SDRAM_BASE
-
-#if defined(SDRAM_PHY_WRITE_LEVELING_CAPABLE) || defined(SDRAM_PHY_READ_LEVELING_CAPABLE)
-
-static void read_leveling(void)
-{
-       int module;
-       int bitslip;
-       int score;
-       int best_score;
-       int best_bitslip;
-
-       for(module=0; module<SDRAM_PHY_MODULES; module++) {
-               /* scan possible read windows */
-               best_score = 0;
-               best_bitslip = 0;
-               for(bitslip=0; bitslip<SDRAM_PHY_BITSLIPS; bitslip++) {
-                       /* compute score */
-                       score = read_level_scan(module, bitslip);
-                       read_level(module);
-                       printf("\n");
-                       if (score > best_score) {
-                               best_bitslip = bitslip;
-                               best_score = score;
-                       }
-                       /* exit */
-                       if (bitslip == SDRAM_PHY_BITSLIPS-1)
-                               break;
-                       /* increment bitslip */
-                       read_bitslip_inc(module);
-               }
-
-               /* select best read window */
-               printf("best: m%d, b%02d ", module, best_bitslip);
-               read_bitslip_rst(module);
-               for (bitslip=0; bitslip<best_bitslip; bitslip++)
-                       read_bitslip_inc(module);
-
-               /* re-do leveling on best read window*/
-               read_level(module);
-               printf("\n");
-       }
-}
-
-int _write_level_cdly_scan = 1;
-
-int sdrlevel(void)
-{
-       int module;
-       sdrsw();
-
-       for(module=0; module<SDRAM_PHY_MODULES; module++) {
-#ifdef SDRAM_PHY_WRITE_LEVELING_CAPABLE
-               write_delay_rst(module);
-#endif
-               read_delay_rst(module);
-               read_bitslip_rst(module);
-       }
-
-#ifdef SDRAM_PHY_WRITE_LEVELING_CAPABLE
-       printf("Write leveling:\n");
-       if (_write_level_cdly_scan) {
-               write_level();
-       } else {
-               /* use only the current cdly */
-               int delays[SDRAM_PHY_MODULES];
-               write_level_scan(delays, 128, 1);
-       }
-#endif
-
-#ifdef SDRAM_PHY_READ_LEVELING_CAPABLE
-       printf("Read leveling:\n");
-       read_leveling();
-#endif
-
-       return 1;
-}
-#endif
-
-int sdrinit(void)
-{
-       printf("Initializing SDRAM...\n");
-
-#ifdef CSR_DDRCTRL_BASE
-       ddrctrl_init_done_write(0);
-       ddrctrl_init_error_write(0);
-#endif
-
-       init_sequence();
-#ifdef CSR_DDRPHY_BASE
-#ifdef DDRPHY_CMD_DELAY
-       ddrphy_cdly(DDRPHY_CMD_DELAY);
-#endif
-#if CSR_DDRPHY_EN_VTC_ADDR
-       ddrphy_en_vtc_write(0);
-#endif
-#if defined(SDRAM_PHY_WRITE_LEVELING_CAPABLE) || defined(SDRAM_PHY_READ_LEVELING_CAPABLE)
-       sdrlevel();
-#endif
-#if CSR_DDRPHY_EN_VTC_ADDR
-       ddrphy_en_vtc_write(1);
-#endif
-#endif
-       sdrhw();
-       if(!memtest()) {
-#ifdef CSR_DDRCTRL_BASE
-               ddrctrl_init_done_write(1);
-               ddrctrl_init_error_write(1);
-#endif
-               return 0;
-       }
-#ifdef CSR_DDRCTRL_BASE
-       ddrctrl_init_done_write(1);
-#endif
-
-       return 1;
-}
-
-#endif
diff --git a/litex/soc/software/bios/sdram.h b/litex/soc/software/bios/sdram.h
deleted file mode 100644 (file)
index 21433c0..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef __SDRAM_H
-#define __SDRAM_H
-
-#include <generated/csr.h>
-
-void sdrsw(void);
-void sdrhw(void);
-void sdrrow(unsigned int row);
-void sdrrdbuf(int dq);
-void sdrrd(unsigned int addr, int dq);
-void sdrrderr(int count);
-void sdrwr(unsigned int addr);
-
-void sdrwlon(void);
-void sdrwloff(void);
-int write_level(void);
-
-int sdrlevel(void);
-
-int memtest_silent(void);
-int memtest(void);
-int sdrinit(void);
-
-#if defined(DDRPHY_CMD_DELAY) || defined(USDDRPHY_DEBUG)
-void ddrphy_cdly(unsigned int delay);
-#endif
-
-#endif /* __SDRAM_H */
index fb97fc4803e775bf224e5b0fd6364500a46c0e74..808915315d47ba420873cb3a068855ca747f6136 100644 (file)
@@ -50,6 +50,7 @@ INCLUDES = -I$(SOC_DIRECTORY)/software/include/base \
            -I$(SOC_DIRECTORY)/common \
            -I$(BUILDINC_DIRECTORY) \
            -I$(CPU_DIRECTORY) \
+           -I$(SOC_DIRECTORY)/software/liblitedram \
            -I$(SOC_DIRECTORY)/software/libliteeth
 COMMONFLAGS = $(DEPFLAGS) -Os $(CPUFLAGS) -g3 -fomit-frame-pointer -Wall -fno-builtin -nostdinc $(INCLUDES)
 CFLAGS = $(COMMONFLAGS) -fexceptions -Wstrict-prototypes -Wold-style-definition -Wmissing-prototypes
diff --git a/litex/soc/software/liblitedram/Makefile b/litex/soc/software/liblitedram/Makefile
new file mode 100644 (file)
index 0000000..0702632
--- /dev/null
@@ -0,0 +1,23 @@
+include ../include/generated/variables.mak
+include $(SOC_DIRECTORY)/software/common.mak
+
+OBJECTS=sdram.o
+
+all: liblitedram.a
+
+liblitedram.a: $(OBJECTS)
+       $(AR) crs liblitedram.a $(OBJECTS)
+
+# pull in dependency info for *existing* .o files
+-include $(OBJECTS:.o=.d)
+
+%.o: $(LIBLITEDRAM_DIRECTORY)/%.c
+       $(compile)
+
+%.o: %.S
+       $(assemble)
+
+.PHONY: all clean
+
+clean:
+       $(RM) $(OBJECTS) liblitedram.a .*~ *~
diff --git a/litex/soc/software/liblitedram/lfsr.h b/litex/soc/software/liblitedram/lfsr.h
new file mode 100644 (file)
index 0000000..50dfccf
--- /dev/null
@@ -0,0 +1,109 @@
+#include <limits.h>
+
+/*
+ * Copyright (C) 2020, Anton Blanchard <anton@linux.ibm.com>, IBM
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Galois LFSR
+ *
+ * Polynomials verified with https://bitbucket.org/gallen/mlpolygen/
+ */
+static inline unsigned long lfsr(unsigned long bits, unsigned long prev)
+{
+       static const unsigned long lfsr_taps[] = {
+               0x0,
+               0x0,
+               0x3,
+               0x6,
+               0xc,
+               0x14,
+               0x30,
+               0x60,
+               0xb8,
+               0x110,
+               0x240,
+               0x500,
+               0x829,
+               0x100d,
+               0x2015,
+               0x6000,
+               0xd008,
+               0x12000,
+               0x20400,
+               0x40023,
+               0x90000,
+               0x140000,
+               0x300000,
+               0x420000,
+               0xe10000,
+               0x1200000,
+               0x2000023,
+               0x4000013,
+               0x9000000,
+               0x14000000,
+               0x20000029,
+               0x48000000,
+               0x80200003,
+#if __WORDSIZE == 64
+               0x100080000,
+               0x204000003,
+               0x500000000,
+               0x801000000,
+               0x100000001f,
+               0x2000000031,
+               0x4400000000,
+               0xa000140000,
+               0x12000000000,
+               0x300000c0000,
+               0x63000000000,
+               0xc0000030000,
+               0x1b0000000000,
+               0x300003000000,
+               0x420000000000,
+               0xc00000180000,
+               0x1008000000000,
+               0x3000000c00000,
+               0x6000c00000000,
+               0x9000000000000,
+               0x18003000000000,
+               0x30000000030000,
+               0x40000040000000,
+               0xc0000600000000,
+               0x102000000000000,
+               0x200004000000000,
+               0x600003000000000,
+               0xc00000000000000,
+               0x1800300000000000,
+               0x3000000000000030,
+               0x6000000000000000,
+               0x800000000000000d
+#endif
+       };
+       unsigned long lsb = prev & 1;
+
+       prev >>= 1;
+       prev ^= (-lsb) & lfsr_taps[bits];
+
+       return prev;
+}
diff --git a/litex/soc/software/liblitedram/sdram.c b/litex/soc/software/liblitedram/sdram.c
new file mode 100644 (file)
index 0000000..81b169c
--- /dev/null
@@ -0,0 +1,1066 @@
+// This file is Copyright (c) 2013-2014 Sebastien Bourdeauducq <sb@m-labs.hk>
+// This file is Copyright (c) 2013-2020 Florent Kermarrec <florent@enjoy-digital.fr>
+// This file is Copyright (c) 2018 Chris Ballance <chris.ballance@physics.ox.ac.uk>
+// This file is Copyright (c) 2018 Dolu1990 <charles.papon.90@gmail.com>
+// This file is Copyright (c) 2019 Gabriel L. Somlo <gsomlo@gmail.com>
+// This file is Copyright (c) 2018 Jean-François Nguyen <jf@lambdaconcept.fr>
+// This file is Copyright (c) 2018 Sergiusz Bazanski <q3k@q3k.org>
+// This file is Copyright (c) 2018 Tim 'mithro' Ansell <me@mith.ro>
+// License: BSD
+
+#include <generated/csr.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef CSR_SDRAM_BASE
+#include <generated/sdram_phy.h>
+#endif
+#include <generated/mem.h>
+#include <hw/flags.h>
+#include <system.h>
+
+#include "sdram.h"
+#include "lfsr.h"
+
+// 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) {
+               __asm__ volatile(CONFIG_CPU_NOP);
+               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);
+       printf("SDRAM now under software control\n");
+}
+
+void sdrhw(void)
+{
+       sdram_dfii_control_write(DFII_CONTROL_SEL);
+       printf("SDRAM now under hardware control\n");
+}
+
+void sdrrow(unsigned int row)
+{
+       if(row == 0) {
+               sdram_dfii_pi0_address_write(0x0000);
+               sdram_dfii_pi0_baddress_write(0);
+               command_p0(DFII_COMMAND_RAS|DFII_COMMAND_WE|DFII_COMMAND_CS);
+               cdelay(15);
+       } else {
+               sdram_dfii_pi0_address_write(row);
+               sdram_dfii_pi0_baddress_write(0);
+               command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CS);
+               cdelay(15);
+       }
+}
+
+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_BYTES/2 - 1 - dq;
+               step = DFII_PIX_DATA_BYTES/2;
+       }
+
+       for(p=0;p<SDRAM_PHY_PHASES;p++) {
+               csr_rd_buf_uint8(sdram_dfii_pix_rddata_addr[p],
+                                buf, DFII_PIX_DATA_BYTES);
+               for(i=first_byte;i<DFII_PIX_DATA_BYTES;i+=step)
+                       printf("%02x", buf[i]);
+       }
+       printf("\n");
+}
+
+void sdrrd(unsigned int addr, int dq)
+{
+       sdram_dfii_pird_address_write(addr);
+       sdram_dfii_pird_baddress_write(0);
+       command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS|DFII_COMMAND_RDDATA);
+       cdelay(15);
+       sdrrdbuf(dq);
+}
+
+void sdrrderr(int count)
+{
+       int addr;
+       int i, j, p;
+       unsigned char prev_data[SDRAM_PHY_PHASES][DFII_PIX_DATA_BYTES];
+       unsigned char errs[SDRAM_PHY_PHASES][DFII_PIX_DATA_BYTES];
+       unsigned char new_data[DFII_PIX_DATA_BYTES];
+
+       for(p=0;p<SDRAM_PHY_PHASES;p++)
+               for(i=0;i<DFII_PIX_DATA_BYTES;i++)
+                       errs[p][i] = 0;
+
+       for(addr=0;addr<16;addr++) {
+               sdram_dfii_pird_address_write(addr*8);
+               sdram_dfii_pird_baddress_write(0);
+               command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS|DFII_COMMAND_RDDATA);
+               cdelay(15);
+               for(p=0;p<SDRAM_PHY_PHASES;p++)
+                       csr_rd_buf_uint8(sdram_dfii_pix_rddata_addr[p],
+                                        prev_data[p], DFII_PIX_DATA_BYTES);
+
+               for(j=0;j<count;j++) {
+                       command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS|DFII_COMMAND_RDDATA);
+                       cdelay(15);
+                       for(p=0;p<SDRAM_PHY_PHASES;p++) {
+                               csr_rd_buf_uint8(sdram_dfii_pix_rddata_addr[p],
+                                                new_data, DFII_PIX_DATA_BYTES);
+                               for(i=0;i<DFII_PIX_DATA_BYTES;i++) {
+                                       errs[p][i] |= prev_data[p][i] ^ new_data[i];
+                                       prev_data[p][i] = new_data[i];
+                               }
+                       }
+               }
+       }
+
+       for(p=0;p<SDRAM_PHY_PHASES;p++)
+               for(i=0;i<DFII_PIX_DATA_BYTES;i++)
+                       printf("%02x", errs[p][i]);
+       printf("\n");
+       for(p=0;p<SDRAM_PHY_PHASES;p++)
+               for(i=0;i<DFII_PIX_DATA_BYTES;i++)
+                       printf("%2x", DFII_PIX_DATA_BYTES/2 - 1 - (i % (DFII_PIX_DATA_BYTES/2)));
+       printf("\n");
+}
+
+void sdrwr(unsigned int addr)
+{
+       int i, p;
+       unsigned char buf[DFII_PIX_DATA_BYTES];
+
+       for(p=0;p<SDRAM_PHY_PHASES;p++) {
+               for(i=0;i<DFII_PIX_DATA_BYTES;i++)
+                       buf[i] = 0x10*p + i;
+               csr_wr_buf_uint8(sdram_dfii_pix_wrdata_addr[p],
+                                buf, DFII_PIX_DATA_BYTES);
+       }
+
+       sdram_dfii_piwr_address_write(addr);
+       sdram_dfii_piwr_baddress_write(0);
+       command_pwr(DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS|DFII_COMMAND_WRDATA);
+}
+
+#ifdef CSR_DDRPHY_BASE
+
+#if defined(DDRPHY_CMD_DELAY)
+void ddrphy_cdly(unsigned int delay) {
+       printf("Setting clk/cmd delay to %d taps\n", delay);
+#if CSR_DDRPHY_EN_VTC_ADDR
+       ddrphy_en_vtc_write(0);
+#endif
+       ddrphy_cdly_rst_write(1);
+       while (delay > 0) {
+               ddrphy_cdly_inc_write(1);
+               cdelay(1000);
+               delay--;
+       }
+#if CSR_DDRPHY_EN_VTC_ADDR
+       ddrphy_en_vtc_write(1);
+#endif
+}
+#endif
+
+#ifdef SDRAM_PHY_WRITE_LEVELING_CAPABLE
+void sdrwlon(void)
+{
+       sdram_dfii_pi0_address_write(DDRX_MR1 | (1 << 7));
+       sdram_dfii_pi0_baddress_write(1);
+       command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS);
+
+#ifdef SDRAM_PHY_DDR4_RDIMM
+       sdram_dfii_pi0_address_write((DDRX_MR1 | (1 << 7)) ^ 0x2BF8) ;
+       sdram_dfii_pi0_baddress_write(1 ^ 0xF);
+       command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS);
+#endif
+
+       ddrphy_wlevel_en_write(1);
+}
+
+void sdrwloff(void)
+{
+       sdram_dfii_pi0_address_write(DDRX_MR1);
+       sdram_dfii_pi0_baddress_write(1);
+       command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS);
+
+#ifdef SDRAM_PHY_DDR4_RDIMM
+       sdram_dfii_pi0_address_write(DDRX_MR1 ^ 0x2BF8);
+       sdram_dfii_pi0_baddress_write(1 ^ 0xF);
+       command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS);
+#endif
+
+       ddrphy_wlevel_en_write(0);
+}
+
+static void write_delay_rst(int module) {
+#ifdef SDRAM_PHY_WRITE_LEVELING_REINIT
+       int i;
+#endif
+
+       /* sel module */
+       ddrphy_dly_sel_write(1 << module);
+
+       /* rst delay */
+       ddrphy_wdly_dq_rst_write(1);
+       ddrphy_wdly_dqs_rst_write(1);
+#ifdef SDRAM_PHY_WRITE_LEVELING_REINIT
+       for(i=0; i<ddrphy_half_sys8x_taps_read(); i++)
+               ddrphy_wdly_dqs_inc_write(1);
+#endif
+
+       /* unsel module */
+       ddrphy_dly_sel_write(0);
+}
+
+static void write_delay_inc(int module) {
+       /* sel module */
+       ddrphy_dly_sel_write(1 << module);
+
+       /* inc delay */
+       ddrphy_wdly_dq_inc_write(1);
+       ddrphy_wdly_dqs_inc_write(1);
+
+       /* unsel module */
+       ddrphy_dly_sel_write(0);
+}
+
+static int write_level_scan(int *delays, int loops, int show)
+{
+       int i, j, k;
+
+       int err_ddrphy_wdly;
+
+       unsigned char taps_scan[SDRAM_PHY_DELAYS];
+
+       int one_window_active;
+       int one_window_start, one_window_best_start;
+       int one_window_count, one_window_best_count;
+
+       unsigned char buf[DFII_PIX_DATA_BYTES];
+
+       int ok;
+
+       err_ddrphy_wdly = SDRAM_PHY_DELAYS - ddrphy_half_sys8x_taps_read();
+
+       sdrwlon();
+       cdelay(100);
+       for(i=0;i<SDRAM_PHY_MODULES;i++) {
+               if (show)
+                       printf("m%d: |", i);
+
+               /* rst delay */
+               write_delay_rst(i);
+
+               /* scan write delay taps */
+               for(j=0;j<err_ddrphy_wdly;j++) {
+                       int zero_count = 0;
+                       int one_count = 0;
+                       int show_iter = show;
+#if SDRAM_PHY_DELAYS > 32
+                       show_iter = (j%16 == 0) && show;
+#endif
+                       for (k=0; k<loops; k++) {
+                               ddrphy_wlevel_strobe_write(1);
+                               cdelay(10);
+                               csr_rd_buf_uint8(sdram_dfii_pix_rddata_addr[0],
+                                                buf, DFII_PIX_DATA_BYTES);
+                               if (buf[SDRAM_PHY_MODULES-1-i] != 0)
+                                       one_count++;
+                               else
+                                       zero_count++;
+                       }
+                       if (one_count > zero_count)
+                               taps_scan[j] = 1;
+                       else
+                               taps_scan[j] = 0;
+                       if (show_iter)
+                               printf("%d", taps_scan[j]);
+                       write_delay_inc(i);
+                       cdelay(10);
+               }
+               if (show)
+                       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 = -1;
+               delays[i] = -1;
+               for(j=0;j<err_ddrphy_wdly;j++) {
+                       if (one_window_active) {
+                               if ((taps_scan[j] == 0) | (j == err_ddrphy_wdly - 1)) {
+                                       one_window_active = 0;
+                                       one_window_count = j - one_window_start;
+                                       if (one_window_count > 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;
+                               }
+                       }
+               }
+               /* succeed only if the start of a 1s window has been found */
+               if (one_window_best_count > 0 && one_window_best_start > 0) {
+                       delays[i] = one_window_best_start;
+
+                       /* configure write delay */
+                       write_delay_rst(i);
+                       for(j=0; j<delays[i]; j++)
+                               write_delay_inc(i);
+               }
+               if (show)
+                       printf(" delay: %02d\n", delays[i]);
+       }
+
+       sdrwloff();
+
+       ok = 1;
+       for(i=SDRAM_PHY_MODULES-1;i>=0;i--) {
+               if(delays[i] < 0)
+                       ok = 0;
+       }
+
+       return ok;
+}
+
+static void write_level_cdly_range(unsigned int *best_error, int *best_cdly,
+               int cdly_start, int cdly_stop, int cdly_step)
+{
+       int cdly;
+       int cdly_actual = 0;
+       int delays[SDRAM_PHY_MODULES];
+
+       /* scan through the range */
+       ddrphy_cdly_rst_write(1);
+       for (cdly = cdly_start; cdly < cdly_stop; cdly += cdly_step) {
+               /* increment cdly to current value */
+               while (cdly_actual < cdly) {
+                       ddrphy_cdly_inc_write(1);
+                       cdelay(10);
+                       cdly_actual++;
+               }
+
+               /* write level using this delay */
+               if (write_level_scan(delays, 8, 0)) {
+                       /* use the mean of delays for error calulation */
+                       int delay_mean = 0;
+                       for (int i=0; i < SDRAM_PHY_MODULES; ++i) {
+                               delay_mean += delays[i];
+                       }
+                       delay_mean /= SDRAM_PHY_MODULES;
+
+                       /* we want it to be at the start */
+                       int ideal_delay = 4*SDRAM_PHY_DELAYS/32;
+                       int error = ideal_delay - delay_mean;
+                       if (error < 0)
+                               error *= -1;
+
+                       if (error < *best_error) {
+                               *best_cdly = cdly;
+                               *best_error = error;
+                       }
+                       printf("1");
+               } else {
+                       printf("0");
+               }
+       }
+}
+
+int write_level(void)
+{
+       int delays[SDRAM_PHY_MODULES];
+       unsigned int best_error = ~0u;
+       int best_cdly = -1;
+       int cdly_range_start;
+       int cdly_range_end;
+       int cdly_range_step;
+
+       printf("Command/Clk scan:\n");
+
+       /* Center write leveling by varying cdly. Searching through all possible
+        * values is slow, but we can use a simple optimization method of iterativly
+        * scanning smaller ranges with decreasing step */
+       cdly_range_start = 0;
+       cdly_range_end = SDRAM_PHY_DELAYS;
+       if (SDRAM_PHY_DELAYS > 32)
+               cdly_range_step = SDRAM_PHY_DELAYS/8;
+       else
+               cdly_range_step = 1;
+       while (cdly_range_step > 0) {
+               printf("|");
+               write_level_cdly_range(&best_error, &best_cdly,
+                               cdly_range_start, cdly_range_end, cdly_range_step);
+
+               /* small optimization - stop if we have zero error */
+               if (best_error == 0)
+                       break;
+
+               /* use best result as the middle of next range */
+               cdly_range_start = best_cdly - cdly_range_step;
+               cdly_range_end = best_cdly + cdly_range_step + 1;
+               if (cdly_range_start < 0)
+                       cdly_range_start = 0;
+               if (cdly_range_end > 512)
+                       cdly_range_end = 512;
+
+               cdly_range_step /= 4;
+       }
+       printf("| best: %d\n", best_cdly);
+
+       /* if we found any working delay then set it */
+       if (best_cdly >= 0) {
+               ddrphy_cdly_rst_write(1);
+               for (int i = 0; i < best_cdly; ++i) {
+                       ddrphy_cdly_inc_write(1);
+                       cdelay(10);
+               }
+       }
+
+       printf("Data scan:\n");
+
+       /* re-run write leveling the final time */
+       if (!write_level_scan(delays, 128, 1))
+               return 0;
+
+       return best_cdly >= 0;
+}
+
+
+#endif /*  SDRAM_PHY_WRITE_LEVELING_CAPABLE */
+
+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 SDRAM_PHY_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 SDRAM_PHY_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)
+{
+       /* sel module */
+       ddrphy_dly_sel_write(1 << m);
+
+       /* 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[SDRAM_PHY_PHASES][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<SDRAM_PHY_PHASES;p++)
+               for(i=0;i<DFII_PIX_DATA_BYTES;i++) {
+                       prv = lfsr(32, prv);
+                       prs[p][i] = prv;
+               }
+
+       /* Activate */
+       sdram_dfii_pi0_address_write(0);
+       sdram_dfii_pi0_baddress_write(0);
+       command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CS);
+       cdelay(15);
+
+       /* Write test pattern */
+       for(p=0;p<SDRAM_PHY_PHASES;p++)
+               csr_wr_buf_uint8(sdram_dfii_pix_wrdata_addr[p],
+                                prs[p], DFII_PIX_DATA_BYTES);
+       sdram_dfii_piwr_address_write(0);
+       sdram_dfii_piwr_baddress_write(0);
+       command_pwr(DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS|DFII_COMMAND_WRDATA);
+
+       /* Calibrate each DQ in turn */
+       sdram_dfii_pird_address_write(0);
+       sdram_dfii_pird_baddress_write(0);
+       score = 0;
+
+       printf("m%d, b%02d: |", module, bitslip);
+       read_delay_rst(module);
+       for(i=0;i<SDRAM_PHY_DELAYS;i++) {
+               int working = 1;
+               int show = 1;
+#if SDRAM_PHY_DELAYS > 32
+               show = (i%16 == 0);
+#endif
+#ifdef SDRAM_PHY_ECP5DDRPHY
+               ddrphy_burstdet_clr_write(1);
+#endif
+               command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS|DFII_COMMAND_RDDATA);
+               cdelay(15);
+               for(p=0;p<SDRAM_PHY_PHASES;p++) {
+                       /* read back test pattern */
+                       csr_rd_buf_uint8(sdram_dfii_pix_rddata_addr[p],
+                                        tst, DFII_PIX_DATA_BYTES);
+                       /* verify bytes matching current 'module' */
+                       if (prs[p][  SDRAM_PHY_MODULES-1-module] != tst[  SDRAM_PHY_MODULES-1-module] ||
+                           prs[p][2*SDRAM_PHY_MODULES-1-module] != tst[2*SDRAM_PHY_MODULES-1-module])
+                               working = 0;
+               }
+#ifdef SDRAM_PHY_ECP5DDRPHY
+               if (((ddrphy_burstdet_seen_read() >> 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_level(int module)
+{
+       unsigned int prv;
+       unsigned char prs[SDRAM_PHY_PHASES][DFII_PIX_DATA_BYTES];
+       unsigned char tst[DFII_PIX_DATA_BYTES];
+       int p, i;
+       int working;
+       int delay, delay_min, delay_max;
+
+       printf("delays: ");
+
+       /* Generate pseudo-random sequence */
+       prv = 42;
+       for(p=0;p<SDRAM_PHY_PHASES;p++)
+               for(i=0;i<DFII_PIX_DATA_BYTES;i++) {
+                       prv = lfsr(32, prv);
+                       prs[p][i] = prv;
+               }
+
+       /* Activate */
+       sdram_dfii_pi0_address_write(0);
+       sdram_dfii_pi0_baddress_write(0);
+       command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CS);
+       cdelay(15);
+
+       /* Write test pattern */
+       for(p=0;p<SDRAM_PHY_PHASES;p++)
+               csr_wr_buf_uint8(sdram_dfii_pix_wrdata_addr[p],
+                                prs[p], DFII_PIX_DATA_BYTES);
+       sdram_dfii_piwr_address_write(0);
+       sdram_dfii_piwr_baddress_write(0);
+       command_pwr(DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS|DFII_COMMAND_WRDATA);
+
+       /* Calibrate each DQ in turn */
+       sdram_dfii_pird_address_write(0);
+       sdram_dfii_pird_baddress_write(0);
+
+       /* Find smallest working delay */
+       delay = 0;
+       read_delay_rst(module);
+       while(1) {
+#ifdef SDRAM_PHY_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<SDRAM_PHY_PHASES;p++) {
+                       /* read back test pattern */
+                       csr_rd_buf_uint8(sdram_dfii_pix_rddata_addr[p],
+                                        tst, DFII_PIX_DATA_BYTES);
+                       /* verify bytes matching current 'module' */
+                       if (prs[p][  SDRAM_PHY_MODULES-1-module] != tst[  SDRAM_PHY_MODULES-1-module] ||
+                           prs[p][2*SDRAM_PHY_MODULES-1-module] != tst[2*SDRAM_PHY_MODULES-1-module])
+                               working = 0;
+               }
+#ifdef SDRAM_PHY_ECP5DDRPHY
+               if (((ddrphy_burstdet_seen_read() >> module) & 0x1) != 1)
+                       working = 0;
+#endif
+               if(working)
+                       break;
+               delay++;
+               if(delay >= SDRAM_PHY_DELAYS)
+                       break;
+               read_delay_inc(module);
+       }
+       delay_min = delay;
+
+       /* Get a bit further into the working zone */
+#if SDRAM_PHY_DELAYS > 32
+       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 SDRAM_PHY_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<SDRAM_PHY_PHASES;p++) {
+                       /* read back test pattern */
+                       csr_rd_buf_uint8(sdram_dfii_pix_rddata_addr[p],
+                                        tst, DFII_PIX_DATA_BYTES);
+                       /* verify bytes matching current 'module' */
+                       if (prs[p][  SDRAM_PHY_MODULES-1-module] != tst[  SDRAM_PHY_MODULES-1-module] ||
+                           prs[p][2*SDRAM_PHY_MODULES-1-module] != tst[2*SDRAM_PHY_MODULES-1-module])
+                               working = 0;
+               }
+#ifdef SDRAM_PHY_ECP5DDRPHY
+               if (((ddrphy_burstdet_seen_read() >> module) & 0x1) != 1)
+                       working = 0;
+#endif
+               if(!working)
+                       break;
+               delay++;
+               if(delay >= SDRAM_PHY_DELAYS)
+                       break;
+               read_delay_inc(module);
+       }
+       delay_max = delay;
+
+       if (delay_min >= SDRAM_PHY_DELAYS)
+               printf("-");
+       else
+               printf("%02d+-%02d", (delay_min+delay_max)/2, (delay_max-delay_min)/2);
+
+       /* 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);
+}
+#endif /* CSR_DDRPHY_BASE */
+
+#endif /* CSR_SDRAM_BASE */
+
+static unsigned int seed_to_data_32(unsigned int seed, int random)
+{
+       if (random)
+               return lfsr(32, seed);
+       else
+               return seed + 1;
+}
+
+static unsigned short seed_to_data_16(unsigned short seed, int random)
+{
+       if (random)
+               return lfsr(16, seed);
+       else
+               return seed + 1;
+}
+
+#define ONEZERO 0xAAAAAAAA
+#define ZEROONE 0x55555555
+
+#ifndef MEMTEST_BUS_SIZE
+#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;
+
+       for(i=0;i<MEMTEST_BUS_SIZE/4;i++) {
+               array[i] = ONEZERO;
+       }
+       flush_cpu_dcache();
+#ifdef CONFIG_L2_SIZE
+       flush_l2_cache();
+#endif
+       for(i=0;i<MEMTEST_BUS_SIZE/4;i++) {
+               rdata = array[i];
+               if(rdata != ONEZERO) {
+                       errors++;
+#ifdef MEMTEST_BUS_DEBUG
+                       printf("[bus: 0x%0x]: 0x%08x vs 0x%08x\n", i, rdata, ONEZERO);
+#endif
+               }
+       }
+
+       for(i=0;i<MEMTEST_BUS_SIZE/4;i++) {
+               array[i] = ZEROONE;
+       }
+       flush_cpu_dcache();
+#ifdef CONFIG_L2_SIZE
+       flush_l2_cache();
+#endif
+       for(i=0;i<MEMTEST_BUS_SIZE/4;i++) {
+               rdata = array[i];
+               if(rdata != ZEROONE) {
+                       errors++;
+#ifdef MEMTEST_BUS_DEBUG
+                       printf("[bus 0x%0x]: 0x%08x vs 0x%08x\n", i, rdata, ZEROONE);
+#endif
+               }
+       }
+
+       return errors;
+}
+
+#ifndef MEMTEST_DATA_SIZE
+#define MEMTEST_DATA_SIZE (2*1024*1024)
+#endif
+#define MEMTEST_DATA_RANDOM 1
+
+//#define MEMTEST_DATA_DEBUG
+
+static int memtest_data(void)
+{
+       volatile unsigned int *array = (unsigned int *)MAIN_RAM_BASE;
+       int i, errors;
+       unsigned int seed_32;
+       unsigned int rdata;
+
+       errors = 0;
+       seed_32 = 1;
+
+       for(i=0;i<MEMTEST_DATA_SIZE/4;i++) {
+               seed_32 = seed_to_data_32(seed_32, MEMTEST_DATA_RANDOM);
+               array[i] = seed_32;
+       }
+
+       seed_32 = 1;
+       flush_cpu_dcache();
+#ifdef CONFIG_L2_SIZE
+       flush_l2_cache();
+#endif
+       for(i=0;i<MEMTEST_DATA_SIZE/4;i++) {
+               seed_32 = seed_to_data_32(seed_32, MEMTEST_DATA_RANDOM);
+               rdata = array[i];
+               if(rdata != seed_32) {
+                       errors++;
+#ifdef MEMTEST_DATA_DEBUG
+                       printf("[data 0x%0x]: 0x%08x vs 0x%08x\n", i, rdata, seed_32);
+#endif
+               }
+       }
+
+       return errors;
+}
+#ifndef MEMTEST_ADDR_SIZE
+#define MEMTEST_ADDR_SIZE (32*1024)
+#endif
+#define MEMTEST_ADDR_RANDOM 0
+
+//#define MEMTEST_ADDR_DEBUG
+
+static int memtest_addr(void)
+{
+       volatile unsigned int *array = (unsigned int *)MAIN_RAM_BASE;
+       int i, errors;
+       unsigned short seed_16;
+       unsigned short rdata;
+
+       errors = 0;
+       seed_16 = 1;
+
+       for(i=0;i<MEMTEST_ADDR_SIZE/4;i++) {
+               seed_16 = seed_to_data_16(seed_16, MEMTEST_ADDR_RANDOM);
+               array[(unsigned int) seed_16] = i;
+       }
+
+       seed_16 = 1;
+       flush_cpu_dcache();
+#ifdef CONFIG_L2_SIZE
+       flush_l2_cache();
+#endif
+       for(i=0;i<MEMTEST_ADDR_SIZE/4;i++) {
+               seed_16 = seed_to_data_16(seed_16, MEMTEST_ADDR_RANDOM);
+               rdata = array[(unsigned int) seed_16];
+               if(rdata != i) {
+                       errors++;
+#ifdef MEMTEST_ADDR_DEBUG
+                       printf("[addr 0x%0x]: 0x%08x vs 0x%08x\n", i, rdata, i);
+#endif
+               }
+       }
+
+       return errors;
+}
+
+static void memspeed(void)
+{
+       volatile unsigned int *array = (unsigned int *)MAIN_RAM_BASE;
+       int i;
+       unsigned int start, end;
+       unsigned long write_speed;
+       unsigned long read_speed;
+       __attribute__((unused)) unsigned int data;
+
+       /* init timer */
+       timer0_en_write(0);
+       timer0_reload_write(0);
+       timer0_load_write(0xffffffff);
+       timer0_en_write(1);
+
+       /* write speed */
+       timer0_update_value_write(1);
+       start = timer0_value_read();
+       for(i=0;i<MEMTEST_DATA_SIZE/4;i++) {
+               array[i] = i;
+       }
+       timer0_update_value_write(1);
+       end = timer0_value_read();
+       write_speed = (8*MEMTEST_DATA_SIZE*(CONFIG_CLOCK_FREQUENCY/1000000))/(start - end);
+
+       /* flush CPU and L2 caches */
+       flush_cpu_dcache();
+#ifdef CONFIG_L2_SIZE
+       flush_l2_cache();
+#endif
+
+       /* read speed */
+       timer0_en_write(1);
+       timer0_update_value_write(1);
+       start = timer0_value_read();
+       for(i=0;i<MEMTEST_DATA_SIZE/4;i++) {
+               data = array[i];
+       }
+       timer0_update_value_write(1);
+       end = timer0_value_read();
+       read_speed = (8*MEMTEST_DATA_SIZE*(CONFIG_CLOCK_FREQUENCY/1000000))/(start - end);
+
+       printf("Memspeed Writes: %ldMbps Reads: %ldMbps\n", write_speed, read_speed);
+}
+
+int memtest(void)
+{
+       int bus_errors, data_errors, addr_errors;
+
+       bus_errors = memtest_bus();
+       if(bus_errors != 0)
+               printf("Memtest bus failed: %d/%d errors\n", bus_errors, 2*128);
+
+       data_errors = memtest_data();
+       if(data_errors != 0)
+               printf("Memtest data failed: %d/%d errors\n", data_errors, MEMTEST_DATA_SIZE/4);
+
+       addr_errors = memtest_addr();
+       if(addr_errors != 0)
+               printf("Memtest addr failed: %d/%d errors\n", addr_errors, MEMTEST_ADDR_SIZE/4);
+
+       if(bus_errors + data_errors + addr_errors != 0)
+               return 0;
+       else {
+               printf("Memtest OK\n");
+               memspeed();
+               return 1;
+       }
+}
+
+#ifdef CSR_SDRAM_BASE
+
+#if defined(SDRAM_PHY_WRITE_LEVELING_CAPABLE) || defined(SDRAM_PHY_READ_LEVELING_CAPABLE)
+
+static void read_leveling(void)
+{
+       int module;
+       int bitslip;
+       int score;
+       int best_score;
+       int best_bitslip;
+
+       for(module=0; module<SDRAM_PHY_MODULES; module++) {
+               /* scan possible read windows */
+               best_score = 0;
+               best_bitslip = 0;
+               for(bitslip=0; bitslip<SDRAM_PHY_BITSLIPS; bitslip++) {
+                       /* compute score */
+                       score = read_level_scan(module, bitslip);
+                       read_level(module);
+                       printf("\n");
+                       if (score > best_score) {
+                               best_bitslip = bitslip;
+                               best_score = score;
+                       }
+                       /* exit */
+                       if (bitslip == SDRAM_PHY_BITSLIPS-1)
+                               break;
+                       /* increment bitslip */
+                       read_bitslip_inc(module);
+               }
+
+               /* select best read window */
+               printf("best: m%d, b%02d ", module, best_bitslip);
+               read_bitslip_rst(module);
+               for (bitslip=0; bitslip<best_bitslip; bitslip++)
+                       read_bitslip_inc(module);
+
+               /* re-do leveling on best read window*/
+               read_level(module);
+               printf("\n");
+       }
+}
+
+int _write_level_cdly_scan = 1;
+
+int sdrlevel(void)
+{
+       int module;
+       sdrsw();
+
+       for(module=0; module<SDRAM_PHY_MODULES; module++) {
+#ifdef SDRAM_PHY_WRITE_LEVELING_CAPABLE
+               write_delay_rst(module);
+#endif
+               read_delay_rst(module);
+               read_bitslip_rst(module);
+       }
+
+#ifdef SDRAM_PHY_WRITE_LEVELING_CAPABLE
+       printf("Write leveling:\n");
+       if (_write_level_cdly_scan) {
+               write_level();
+       } else {
+               /* use only the current cdly */
+               int delays[SDRAM_PHY_MODULES];
+               write_level_scan(delays, 128, 1);
+       }
+#endif
+
+#ifdef SDRAM_PHY_READ_LEVELING_CAPABLE
+       printf("Read leveling:\n");
+       read_leveling();
+#endif
+
+       return 1;
+}
+#endif
+
+int sdrinit(void)
+{
+       printf("Initializing SDRAM...\n");
+
+#ifdef CSR_DDRCTRL_BASE
+       ddrctrl_init_done_write(0);
+       ddrctrl_init_error_write(0);
+#endif
+
+       init_sequence();
+#ifdef CSR_DDRPHY_BASE
+#ifdef DDRPHY_CMD_DELAY
+       ddrphy_cdly(DDRPHY_CMD_DELAY);
+#endif
+#if CSR_DDRPHY_EN_VTC_ADDR
+       ddrphy_en_vtc_write(0);
+#endif
+#if defined(SDRAM_PHY_WRITE_LEVELING_CAPABLE) || defined(SDRAM_PHY_READ_LEVELING_CAPABLE)
+       sdrlevel();
+#endif
+#if CSR_DDRPHY_EN_VTC_ADDR
+       ddrphy_en_vtc_write(1);
+#endif
+#endif
+       sdrhw();
+       if(!memtest()) {
+#ifdef CSR_DDRCTRL_BASE
+               ddrctrl_init_done_write(1);
+               ddrctrl_init_error_write(1);
+#endif
+               return 0;
+       }
+#ifdef CSR_DDRCTRL_BASE
+       ddrctrl_init_done_write(1);
+#endif
+
+       return 1;
+}
+
+#endif
diff --git a/litex/soc/software/liblitedram/sdram.h b/litex/soc/software/liblitedram/sdram.h
new file mode 100644 (file)
index 0000000..21433c0
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef __SDRAM_H
+#define __SDRAM_H
+
+#include <generated/csr.h>
+
+void sdrsw(void);
+void sdrhw(void);
+void sdrrow(unsigned int row);
+void sdrrdbuf(int dq);
+void sdrrd(unsigned int addr, int dq);
+void sdrrderr(int count);
+void sdrwr(unsigned int addr);
+
+void sdrwlon(void);
+void sdrwloff(void);
+int write_level(void);
+
+int sdrlevel(void);
+
+int memtest_silent(void);
+int memtest(void);
+int sdrinit(void);
+
+#if defined(DDRPHY_CMD_DELAY) || defined(USDDRPHY_DEBUG)
+void ddrphy_cdly(unsigned int delay);
+#endif
+
+#endif /* __SDRAM_H */