summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile13
-rw-r--r--arch/arm/dts/socfpga.dtsi4
-rw-r--r--arch/arm/dts/socfpga_arria5_socdk.dts8
-rw-r--r--arch/arm/dts/socfpga_cyclone5_socdk.dts4
-rw-r--r--arch/arm/dts/socfpga_cyclone5_socrates.dts6
-rw-r--r--arch/arm/mach-socfpga/Makefile4
-rw-r--r--arch/arm/mach-socfpga/clock_manager.c28
-rw-r--r--arch/arm/mach-socfpga/include/mach/clock_manager.h12
-rw-r--r--arch/arm/mach-socfpga/include/mach/reset_manager.h60
-rw-r--r--arch/arm/mach-socfpga/include/mach/scan_manager.h75
-rw-r--r--arch/arm/mach-socfpga/include/mach/sdram.h441
-rw-r--r--arch/arm/mach-socfpga/include/mach/system_manager.h7
-rw-r--r--arch/arm/mach-socfpga/misc.c184
-rw-r--r--arch/arm/mach-socfpga/reset_manager.c99
-rw-r--r--arch/arm/mach-socfpga/scan_manager.c335
-rw-r--r--arch/arm/mach-socfpga/spl.c220
-rw-r--r--arch/arm/mach-socfpga/system_manager.c16
-rw-r--r--arch/arm/mach-socfpga/u-boot-spl.lds45
-rw-r--r--board/altera/socfpga/Makefile5
-rw-r--r--board/altera/socfpga/qts/iocsr_config.c (renamed from board/altera/socfpga/iocsr_config.c)0
-rw-r--r--board/altera/socfpga/qts/iocsr_config.h (renamed from board/altera/socfpga/iocsr_config.h)0
-rw-r--r--board/altera/socfpga/qts/pinmux_config.c (renamed from board/altera/socfpga/pinmux_config.c)0
-rw-r--r--board/altera/socfpga/qts/pinmux_config.h (renamed from board/altera/socfpga/pinmux_config.h)0
-rw-r--r--board/altera/socfpga/qts/pll_config.h (renamed from board/altera/socfpga/pll_config.h)0
-rw-r--r--board/altera/socfpga/qts/sdram_config.h100
-rw-r--r--board/altera/socfpga/qts/sequencer_auto.h128
-rw-r--r--board/altera/socfpga/qts/sequencer_auto_ac_init.h84
-rw-r--r--board/altera/socfpga/qts/sequencer_auto_inst_init.h268
-rw-r--r--board/altera/socfpga/qts/sequencer_defines.h122
-rw-r--r--board/altera/socfpga/wrap_iocsr_config.c41
-rw-r--r--board/altera/socfpga/wrap_pinmux_config.c35
-rw-r--r--board/altera/socfpga/wrap_pll_config.c144
-rw-r--r--board/altera/socfpga/wrap_sdram_config.c316
-rw-r--r--configs/socfpga_arria5_defconfig10
-rw-r--r--configs/socfpga_cyclone5_defconfig11
-rw-r--r--configs/socfpga_socrates_defconfig12
-rw-r--r--drivers/ddr/altera/Makefile11
-rw-r--r--drivers/ddr/altera/sdram.c535
-rw-r--r--drivers/ddr/altera/sequencer.c3783
-rw-r--r--drivers/ddr/altera/sequencer.h227
-rw-r--r--drivers/fpga/socfpga.c3
-rw-r--r--drivers/net/designware.c3
-rw-r--r--include/configs/socfpga_arria5.h7
-rw-r--r--include/configs/socfpga_common.h63
-rw-r--r--include/configs/socfpga_cyclone5.h7
-rw-r--r--include/fdtdec.h1
-rw-r--r--lib/fdtdec.c1
-rw-r--r--scripts/Makefile.spl11
48 files changed, 6913 insertions, 576 deletions
diff --git a/Makefile b/Makefile
index bb0ba9f8a22..ad51e60ca1b 100644
--- a/Makefile
+++ b/Makefile
@@ -649,6 +649,7 @@ libs-y += drivers/power/ \
libs-y += drivers/spi/
libs-$(CONFIG_FMAN_ENET) += drivers/net/fm/
libs-$(CONFIG_SYS_FSL_DDR) += drivers/ddr/fsl/
+libs-$(CONFIG_ALTERA_SDRAM) += drivers/ddr/altera/
libs-y += drivers/serial/
libs-y += drivers/usb/dwc3/
libs-y += drivers/usb/emul/
@@ -1019,6 +1020,15 @@ u-boot-nand.gph: u-boot.bin FORCE
$(call if_changed,mkimage)
@dd if=/dev/zero bs=8 count=1 2>/dev/null >> $@
+ifneq ($(CONFIG_ARCH_SOCFPGA),)
+quiet_cmd_socboot = SOCBOOT $@
+cmd_socboot = cat spl/u-boot-spl-dtb.sfp spl/u-boot-spl-dtb.sfp \
+ spl/u-boot-spl-dtb.sfp spl/u-boot-spl-dtb.sfp \
+ u-boot-dtb.img > $@ || rm -f $@
+u-boot-with-spl-dtb.sfp: spl/u-boot-spl-dtb.sfp u-boot-dtb.img FORCE
+ $(call if_changed,socboot)
+endif
+
# x86 uses a large ROM. We fill it with 0xff, put the 16-bit stuff (including
# reset vector) at the top, Intel ME descriptor at the bottom, and U-Boot in
# the middle.
@@ -1297,6 +1307,9 @@ spl/u-boot-spl: tools prepare $(if $(CONFIG_OF_SEPARATE),dts/dt.dtb)
spl/sunxi-spl.bin: spl/u-boot-spl
@:
+spl/u-boot-spl-dtb.sfp: spl/u-boot-spl
+ @:
+
tpl/u-boot-tpl.bin: tools prepare
$(Q)$(MAKE) obj=tpl -f $(srctree)/scripts/Makefile.spl all
diff --git a/arch/arm/dts/socfpga.dtsi b/arch/arm/dts/socfpga.dtsi
index 9b1242025dc..e17e9f4a3ca 100644
--- a/arch/arm/dts/socfpga.dtsi
+++ b/arch/arm/dts/socfpga.dtsi
@@ -20,6 +20,10 @@
timer1 = &timer1;
timer2 = &timer2;
timer3 = &timer3;
+ spi0 = &qspi;
+ spi1 = &spi0;
+ spi2 = &spi1;
+ mmc = &mmc;
};
cpus {
diff --git a/arch/arm/dts/socfpga_arria5_socdk.dts b/arch/arm/dts/socfpga_arria5_socdk.dts
index 1b868978728..f2b5963f594 100644
--- a/arch/arm/dts/socfpga_arria5_socdk.dts
+++ b/arch/arm/dts/socfpga_arria5_socdk.dts
@@ -22,13 +22,9 @@
aliases {
/* this allow the ethaddr uboot environmnet variable contents
- * to be added to the gmac1 device tree blob.
- */
+ * to be added to the gmac1 device tree blob.
+ */
ethernet0 = &gmac1;
-
- spi0 = "/spi@ff705000"; /* QSPI */
- spi1 = "/spi@fff00000";
- spi2 = "/spi@fff01000";
};
regulator_3_3v: 3-3-v-regulator {
diff --git a/arch/arm/dts/socfpga_cyclone5_socdk.dts b/arch/arm/dts/socfpga_cyclone5_socdk.dts
index 0b300b92be0..9650eb08777 100644
--- a/arch/arm/dts/socfpga_cyclone5_socdk.dts
+++ b/arch/arm/dts/socfpga_cyclone5_socdk.dts
@@ -25,10 +25,6 @@
* to be added to the gmac1 device tree blob.
*/
ethernet0 = &gmac1;
-
- spi0 = "/spi@ff705000"; /* QSPI */
- spi1 = "/spi@fff00000";
- spi2 = "/spi@fff01000";
};
regulator_3_3v: 3-3-v-regulator {
diff --git a/arch/arm/dts/socfpga_cyclone5_socrates.dts b/arch/arm/dts/socfpga_cyclone5_socrates.dts
index ea30483e52f..00b1830485a 100644
--- a/arch/arm/dts/socfpga_cyclone5_socrates.dts
+++ b/arch/arm/dts/socfpga_cyclone5_socrates.dts
@@ -14,12 +14,6 @@
bootargs = "console=ttyS0,115200";
};
- aliases {
- spi0 = "/spi@ff705000"; /* QSPI */
- spi1 = "/spi@fff00000";
- spi2 = "/spi@fff01000";
- };
-
memory {
name = "memory";
device_type = "memory";
diff --git a/arch/arm/mach-socfpga/Makefile b/arch/arm/mach-socfpga/Makefile
index 7524ef90e49..8a745c9b1e8 100644
--- a/arch/arm/mach-socfpga/Makefile
+++ b/arch/arm/mach-socfpga/Makefile
@@ -8,5 +8,5 @@
#
obj-y += misc.o timer.o reset_manager.o system_manager.o clock_manager.o \
- fpga_manager.o
-obj-$(CONFIG_SPL_BUILD) += spl.o freeze_controller.o scan_manager.o
+ fpga_manager.o scan_manager.o
+obj-$(CONFIG_SPL_BUILD) += spl.o freeze_controller.o
diff --git a/arch/arm/mach-socfpga/clock_manager.c b/arch/arm/mach-socfpga/clock_manager.c
index fa3b93a2572..1341df4361d 100644
--- a/arch/arm/mach-socfpga/clock_manager.c
+++ b/arch/arm/mach-socfpga/clock_manager.c
@@ -88,7 +88,7 @@ static void cm_write_with_phase(uint32_t value,
* Ungate clocks
*/
-void cm_basic_init(const cm_config_t *cfg)
+void cm_basic_init(const struct cm_config * const cfg)
{
uint32_t start, timeout;
@@ -336,7 +336,7 @@ static unsigned int cm_get_main_vco_clk_hz(void)
/* get the main VCO clock */
reg = readl(&clock_manager_base->main_pll.vco);
- clock = CONFIG_HPS_CLK_OSC1_HZ;
+ clock = cm_get_osc_clk_hz(1);
clock /= ((reg & CLKMGR_MAINPLLGRP_VCO_DENOM_MASK) >>
CLKMGR_MAINPLLGRP_VCO_DENOM_OFFSET) + 1;
clock *= ((reg & CLKMGR_MAINPLLGRP_VCO_NUMER_MASK) >>
@@ -354,11 +354,11 @@ static unsigned int cm_get_per_vco_clk_hz(void)
reg = (reg & CLKMGR_PERPLLGRP_VCO_SSRC_MASK) >>
CLKMGR_PERPLLGRP_VCO_SSRC_OFFSET;
if (reg == CLKMGR_VCO_SSRC_EOSC1)
- clock = CONFIG_HPS_CLK_OSC1_HZ;
+ clock = cm_get_osc_clk_hz(1);
else if (reg == CLKMGR_VCO_SSRC_EOSC2)
- clock = CONFIG_HPS_CLK_OSC2_HZ;
+ clock = cm_get_osc_clk_hz(2);
else if (reg == CLKMGR_VCO_SSRC_F2S)
- clock = CONFIG_HPS_CLK_F2S_PER_REF_HZ;
+ clock = cm_get_f2s_per_ref_clk_hz();
/* get the PER VCO clock */
reg = readl(&clock_manager_base->per_pll.vco);
@@ -393,11 +393,11 @@ unsigned long cm_get_sdram_clk_hz(void)
reg = (reg & CLKMGR_SDRPLLGRP_VCO_SSRC_MASK) >>
CLKMGR_SDRPLLGRP_VCO_SSRC_OFFSET;
if (reg == CLKMGR_VCO_SSRC_EOSC1)
- clock = CONFIG_HPS_CLK_OSC1_HZ;
+ clock = cm_get_osc_clk_hz(1);
else if (reg == CLKMGR_VCO_SSRC_EOSC2)
- clock = CONFIG_HPS_CLK_OSC2_HZ;
+ clock = cm_get_osc_clk_hz(2);
else if (reg == CLKMGR_VCO_SSRC_F2S)
- clock = CONFIG_HPS_CLK_F2S_SDR_REF_HZ;
+ clock = cm_get_f2s_sdr_ref_clk_hz();
/* get the SDRAM VCO clock */
reg = readl(&clock_manager_base->sdr_pll.vco);
@@ -459,7 +459,7 @@ unsigned int cm_get_mmc_controller_clk_hz(void)
CLKMGR_PERPLLGRP_SRC_SDMMC_OFFSET;
if (reg == CLKMGR_SDMMC_CLK_SRC_F2S) {
- clock = CONFIG_HPS_CLK_F2S_PER_REF_HZ;
+ clock = cm_get_f2s_per_ref_clk_hz();
} else if (reg == CLKMGR_SDMMC_CLK_SRC_MAIN) {
clock = cm_get_main_vco_clk_hz();
@@ -489,7 +489,7 @@ unsigned int cm_get_qspi_controller_clk_hz(void)
CLKMGR_PERPLLGRP_SRC_QSPI_OFFSET;
if (reg == CLKMGR_QSPI_CLK_SRC_F2S) {
- clock = CONFIG_HPS_CLK_F2S_PER_REF_HZ;
+ clock = cm_get_f2s_per_ref_clk_hz();
} else if (reg == CLKMGR_QSPI_CLK_SRC_MAIN) {
clock = cm_get_main_vco_clk_hz();
@@ -524,10 +524,10 @@ static void cm_print_clock_quick_summary(void)
{
printf("MPU %10ld kHz\n", cm_get_mpu_clk_hz() / 1000);
printf("DDR %10ld kHz\n", cm_get_sdram_clk_hz() / 1000);
- printf("EOSC1 %8d kHz\n", CONFIG_HPS_CLK_OSC1_HZ / 1000);
- printf("EOSC2 %8d kHz\n", CONFIG_HPS_CLK_OSC2_HZ / 1000);
- printf("F2S_SDR_REF %8d kHz\n", CONFIG_HPS_CLK_F2S_SDR_REF_HZ / 1000);
- printf("F2S_PER_REF %8d kHz\n", CONFIG_HPS_CLK_F2S_PER_REF_HZ / 1000);
+ printf("EOSC1 %8d kHz\n", cm_get_osc_clk_hz(1) / 1000);
+ printf("EOSC2 %8d kHz\n", cm_get_osc_clk_hz(2) / 1000);
+ printf("F2S_SDR_REF %8d kHz\n", cm_get_f2s_sdr_ref_clk_hz() / 1000);
+ printf("F2S_PER_REF %8d kHz\n", cm_get_f2s_per_ref_clk_hz() / 1000);
printf("MMC %8d kHz\n", cm_get_mmc_controller_clk_hz() / 1000);
printf("QSPI %8d kHz\n", cm_get_qspi_controller_clk_hz() / 1000);
printf("UART %8d kHz\n", cm_get_l4_sp_clk_hz() / 1000);
diff --git a/arch/arm/mach-socfpga/include/mach/clock_manager.h b/arch/arm/mach-socfpga/include/mach/clock_manager.h
index 54497261802..2675951a3e2 100644
--- a/arch/arm/mach-socfpga/include/mach/clock_manager.h
+++ b/arch/arm/mach-socfpga/include/mach/clock_manager.h
@@ -15,9 +15,15 @@ unsigned int cm_get_l4_sp_clk_hz(void);
unsigned int cm_get_mmc_controller_clk_hz(void);
unsigned int cm_get_qspi_controller_clk_hz(void);
unsigned int cm_get_spi_controller_clk_hz(void);
+const unsigned int cm_get_osc_clk_hz(const int osc);
+const unsigned int cm_get_f2s_per_ref_clk_hz(void);
+const unsigned int cm_get_f2s_sdr_ref_clk_hz(void);
+
+/* Clock configuration accessors */
+const struct cm_config * const cm_get_default_config(void);
#endif
-typedef struct {
+struct cm_config {
/* main group */
uint32_t main_vco_base;
uint32_t mpuclk;
@@ -49,9 +55,9 @@ typedef struct {
uint32_t ddr2xdqsclk;
uint32_t ddrdqclk;
uint32_t s2fuser2clk;
-} cm_config_t;
+};
-extern void cm_basic_init(const cm_config_t *cfg);
+void cm_basic_init(const struct cm_config * const cfg);
struct socfpga_clock_manager_main_pll {
u32 vco;
diff --git a/arch/arm/mach-socfpga/include/mach/reset_manager.h b/arch/arm/mach-socfpga/include/mach/reset_manager.h
index d63a2850912..8e59578f374 100644
--- a/arch/arm/mach-socfpga/include/mach/reset_manager.h
+++ b/arch/arm/mach-socfpga/include/mach/reset_manager.h
@@ -12,12 +12,8 @@ void reset_deassert_peripherals_handoff(void);
void socfpga_bridges_reset(int enable);
-void socfpga_emac_reset(int enable);
-void socfpga_watchdog_reset(void);
-void socfpga_spim_enable(void);
-void socfpga_uart0_enable(void);
-void socfpga_sdram_enable(void);
-void socfpga_osc1timer_enable(void);
+void socfpga_per_reset(u32 reset, int set);
+void socfpga_per_reset_all(void);
struct socfpga_reset_manager {
u32 status;
@@ -28,6 +24,8 @@ struct socfpga_reset_manager {
u32 per_mod_reset;
u32 per2_mod_reset;
u32 brg_mod_reset;
+ u32 misc_mod_reset;
+ u32 tstscratch;
};
#if defined(CONFIG_SOCFPGA_VIRTUAL_TARGET)
@@ -36,13 +34,47 @@ struct socfpga_reset_manager {
#define RSTMGR_CTRL_SWWARMRSTREQ_LSB 1
#endif
-#define RSTMGR_PERMODRST_EMAC0_LSB 0
-#define RSTMGR_PERMODRST_EMAC1_LSB 1
-#define RSTMGR_PERMODRST_L4WD0_LSB 6
-#define RSTMGR_PERMODRST_OSC1TIMER0_LSB 8
-#define RSTMGR_PERMODRST_UART0_LSB 16
-#define RSTMGR_PERMODRST_SPIM0_LSB 18
-#define RSTMGR_PERMODRST_SPIM1_LSB 19
-#define RSTMGR_PERMODRST_SDR_LSB 29
+/*
+ * Define a reset identifier, from which a permodrst bank ID
+ * and reset ID can be extracted using the subsequent macros
+ * RSTMGR_RESET() and RSTMGR_BANK().
+ */
+#define RSTMGR_BANK_OFFSET 8
+#define RSTMGR_BANK_MASK 0x7
+#define RSTMGR_RESET_OFFSET 0
+#define RSTMGR_RESET_MASK 0x1f
+#define RSTMGR_DEFINE(_bank, _offset) \
+ ((_bank) << RSTMGR_BANK_OFFSET) | ((_offset) << RSTMGR_RESET_OFFSET)
+
+/* Extract reset ID from the reset identifier. */
+#define RSTMGR_RESET(_reset) \
+ (((_reset) >> RSTMGR_RESET_OFFSET) & RSTMGR_RESET_MASK)
+
+/* Extract bank ID from the reset identifier. */
+#define RSTMGR_BANK(_reset) \
+ (((_reset) >> RSTMGR_BANK_OFFSET) & RSTMGR_BANK_MASK)
+
+/*
+ * SocFPGA Cyclone V/Arria V reset IDs, bank mapping is as follows:
+ * 0 ... mpumodrst
+ * 1 ... permodrst
+ * 2 ... per2modrst
+ * 3 ... brgmodrst
+ * 4 ... miscmodrst
+ */
+#define RSTMGR_EMAC0 RSTMGR_DEFINE(1, 0)
+#define RSTMGR_EMAC1 RSTMGR_DEFINE(1, 1)
+#define RSTMGR_L4WD0 RSTMGR_DEFINE(1, 6)
+#define RSTMGR_OSC1TIMER0 RSTMGR_DEFINE(1, 8)
+#define RSTMGR_UART0 RSTMGR_DEFINE(1, 16)
+#define RSTMGR_SPIM0 RSTMGR_DEFINE(1, 18)
+#define RSTMGR_SPIM1 RSTMGR_DEFINE(1, 19)
+#define RSTMGR_QSPI RSTMGR_DEFINE(0, 5)
+#define RSTMGR_SDMMC RSTMGR_DEFINE(0, 22)
+#define RSTMGR_DMA RSTMGR_DEFINE(0, 28)
+#define RSTMGR_SDR RSTMGR_DEFINE(1, 29)
+
+/* Create a human-readable reference to SoCFPGA reset. */
+#define SOCFPGA_RESET(_name) RSTMGR_##_name
#endif /* _RESET_MANAGER_H_ */
diff --git a/arch/arm/mach-socfpga/include/mach/scan_manager.h b/arch/arm/mach-socfpga/include/mach/scan_manager.h
index 1155fd3decc..5ca68435575 100644
--- a/arch/arm/mach-socfpga/include/mach/scan_manager.h
+++ b/arch/arm/mach-socfpga/include/mach/scan_manager.h
@@ -17,77 +17,10 @@ struct socfpga_scan_manager {
u32 fifo_quad_byte;
};
-/*
- * Shift count to get number of IO scan chain data in granularity
- * of 128-bit ( N / 128 )
- */
-#define IO_SCAN_CHAIN_128BIT_SHIFT 7
-
-/*
- * Mask to get residual IO scan chain data in
- * granularity of 128-bit ( N mod 128 )
- */
-#define IO_SCAN_CHAIN_128BIT_MASK 0x7F
-
-/*
- * Shift count to get number of IO scan chain
- * data in granularity of 32-bit ( N / 32 )
- */
-#define IO_SCAN_CHAIN_32BIT_SHIFT 5
-
-/*
- * Mask to get residual IO scan chain data in
- * granularity of 32-bit ( N mod 32 )
- */
-#define IO_SCAN_CHAIN_32BIT_MASK 0x1F
-
-/* Byte mask */
-#define IO_SCAN_CHAIN_BYTE_MASK 0xFF
-
-/* 24-bits (3 bytes) IO scan chain payload definition */
-#define IO_SCAN_CHAIN_PAYLOAD_24BIT 24
-
-/*
- * Maximum length of TDI_TDO packet payload is 128 bits,
- * represented by (length - 1) in TDI_TDO header
- */
-#define TDI_TDO_MAX_PAYLOAD 127
-
-/* TDI_TDO packet header for IO scan chain program */
-#define TDI_TDO_HEADER_FIRST_BYTE 0x80
-
-/* Position of second command byte for TDI_TDO packet */
-#define TDI_TDO_HEADER_SECOND_BYTE_SHIFT 8
-
-/*
- * Maximum polling loop to wait for IO scan chain engine
- * becomes idle to prevent infinite loop
- */
-#define SCAN_MAX_DELAY 100
-
-#define SCANMGR_STAT_ACTIVE_GET(x) (((x) & 0x80000000) >> 31)
-#define SCANMGR_STAT_WFIFOCNT_GET(x) (((x) & 0x70000000) >> 28)
-
-/*
- * Program HPS IO Scan Chain
- * io_scan_chain_id - IO scan chain ID
- * io_scan_chain_len_in_bits - IO scan chain length in bits
- * iocsr_scan_chain - IO scan chain table
- */
-uint32_t scan_mgr_io_scan_chain_prg(
- uint32_t io_scan_chain_id,
- uint32_t io_scan_chain_len_in_bits,
- const uint32_t *iocsr_scan_chain);
-
-extern const uint32_t iocsr_scan_chain0_table[
- ((CONFIG_HPS_IOCSR_SCANCHAIN0_LENGTH / 32) + 1)];
-extern const uint32_t iocsr_scan_chain1_table[
- ((CONFIG_HPS_IOCSR_SCANCHAIN1_LENGTH / 32) + 1)];
-extern const uint32_t iocsr_scan_chain2_table[
- ((CONFIG_HPS_IOCSR_SCANCHAIN2_LENGTH / 32) + 1)];
-extern const uint32_t iocsr_scan_chain3_table[
- ((CONFIG_HPS_IOCSR_SCANCHAIN3_LENGTH / 32) + 1)];
-
int scan_mgr_configure_iocsr(void);
+u32 scan_mgr_get_fpga_id(void);
+int iocsr_get_config_table(const unsigned int chain_id,
+ const unsigned long **table,
+ unsigned int *table_len);
#endif /* _SCAN_MANAGER_H_ */
diff --git a/arch/arm/mach-socfpga/include/mach/sdram.h b/arch/arm/mach-socfpga/include/mach/sdram.h
index 4f6489dff67..f12bb846613 100644
--- a/arch/arm/mach-socfpga/include/mach/sdram.h
+++ b/arch/arm/mach-socfpga/include/mach/sdram.h
@@ -1,19 +1,436 @@
/*
- * Copyright (C) 2015 Marek Vasut <marex@denx.de>
- *
- * FIXME: This file contains temporary stub functions and is here
- * only until these functions are properly merged into
- * mainline.
+ * Copyright Altera Corporation (C) 2014-2015
*
* SPDX-License-Identifier: GPL-2.0+
*/
+#ifndef _SDRAM_H_
+#define _SDRAM_H_
+
+#ifndef __ASSEMBLY__
+
+unsigned long sdram_calculate_size(void);
+int sdram_mmr_init_full(unsigned int sdr_phy_reg);
+int sdram_calibration_full(void);
+
+const struct socfpga_sdram_config *socfpga_get_sdram_config(void);
+
+void socfpga_get_seq_ac_init(const u32 **init, unsigned int *nelem);
+void socfpga_get_seq_inst_init(const u32 **init, unsigned int *nelem);
+const struct socfpga_sdram_rw_mgr_config *socfpga_get_sdram_rwmgr_config(void);
+const struct socfpga_sdram_io_config *socfpga_get_sdram_io_config(void);
+const struct socfpga_sdram_misc_config *socfpga_get_sdram_misc_config(void);
+
+#define SDR_CTRLGRP_ADDRESS (SOCFPGA_SDR_ADDRESS | 0x5000)
+
+struct socfpga_sdr_ctrl {
+ u32 ctrl_cfg;
+ u32 dram_timing1;
+ u32 dram_timing2;
+ u32 dram_timing3;
+ u32 dram_timing4; /* 0x10 */
+ u32 lowpwr_timing;
+ u32 dram_odt;
+ u32 __padding0[4];
+ u32 dram_addrw; /* 0x2c */
+ u32 dram_if_width; /* 0x30 */
+ u32 dram_dev_width;
+ u32 dram_sts;
+ u32 dram_intr;
+ u32 sbe_count; /* 0x40 */
+ u32 dbe_count;
+ u32 err_addr;
+ u32 drop_count;
+ u32 drop_addr; /* 0x50 */
+ u32 lowpwr_eq;
+ u32 lowpwr_ack;
+ u32 static_cfg;
+ u32 ctrl_width; /* 0x60 */
+ u32 cport_width;
+ u32 cport_wmap;
+ u32 cport_rmap;
+ u32 rfifo_cmap; /* 0x70 */
+ u32 wfifo_cmap;
+ u32 cport_rdwr;
+ u32 port_cfg;
+ u32 fpgaport_rst; /* 0x80 */
+ u32 __padding1;
+ u32 fifo_cfg;
+ u32 protport_default;
+ u32 prot_rule_addr; /* 0x90 */
+ u32 prot_rule_id;
+ u32 prot_rule_data;
+ u32 prot_rule_rdwr;
+ u32 __padding2[3];
+ u32 mp_priority; /* 0xac */
+ u32 mp_weight0; /* 0xb0 */
+ u32 mp_weight1;
+ u32 mp_weight2;
+ u32 mp_weight3;
+ u32 mp_pacing0; /* 0xc0 */
+ u32 mp_pacing1;
+ u32 mp_pacing2;
+ u32 mp_pacing3;
+ u32 mp_threshold0; /* 0xd0 */
+ u32 mp_threshold1;
+ u32 mp_threshold2;
+ u32 __padding3[29];
+ u32 phy_ctrl0; /* 0x150 */
+ u32 phy_ctrl1;
+ u32 phy_ctrl2;
+};
+
+/* SDRAM configuration structure for the SPL. */
+struct socfpga_sdram_config {
+ u32 ctrl_cfg;
+ u32 dram_timing1;
+ u32 dram_timing2;
+ u32 dram_timing3;
+ u32 dram_timing4;
+ u32 lowpwr_timing;
+ u32 dram_odt;
+ u32 dram_addrw;
+ u32 dram_if_width;
+ u32 dram_dev_width;
+ u32 dram_intr;
+ u32 lowpwr_eq;
+ u32 static_cfg;
+ u32 ctrl_width;
+ u32 cport_width;
+ u32 cport_wmap;
+ u32 cport_rmap;
+ u32 rfifo_cmap;
+ u32 wfifo_cmap;
+ u32 cport_rdwr;
+ u32 port_cfg;
+ u32 fpgaport_rst;
+ u32 fifo_cfg;
+ u32 mp_priority;
+ u32 mp_weight0;
+ u32 mp_weight1;
+ u32 mp_weight2;
+ u32 mp_weight3;
+ u32 mp_pacing0;
+ u32 mp_pacing1;
+ u32 mp_pacing2;
+ u32 mp_pacing3;
+ u32 mp_threshold0;
+ u32 mp_threshold1;
+ u32 mp_threshold2;
+ u32 phy_ctrl0;
+};
+
+struct socfpga_sdram_rw_mgr_config {
+ u8 activate_0_and_1;
+ u8 activate_0_and_1_wait1;
+ u8 activate_0_and_1_wait2;
+ u8 activate_1;
+ u8 clear_dqs_enable;
+ u8 guaranteed_read;
+ u8 guaranteed_read_cont;
+ u8 guaranteed_write;
+ u8 guaranteed_write_wait0;
+ u8 guaranteed_write_wait1;
+ u8 guaranteed_write_wait2;
+ u8 guaranteed_write_wait3;
+ u8 idle;
+ u8 idle_loop1;
+ u8 idle_loop2;
+ u8 init_reset_0_cke_0;
+ u8 init_reset_1_cke_0;
+ u8 lfsr_wr_rd_bank_0;
+ u8 lfsr_wr_rd_bank_0_data;
+ u8 lfsr_wr_rd_bank_0_dqs;
+ u8 lfsr_wr_rd_bank_0_nop;
+ u8 lfsr_wr_rd_bank_0_wait;
+ u8 lfsr_wr_rd_bank_0_wl_1;
+ u8 lfsr_wr_rd_dm_bank_0;
+ u8 lfsr_wr_rd_dm_bank_0_data;
+ u8 lfsr_wr_rd_dm_bank_0_dqs;
+ u8 lfsr_wr_rd_dm_bank_0_nop;
+ u8 lfsr_wr_rd_dm_bank_0_wait;
+ u8 lfsr_wr_rd_dm_bank_0_wl_1;
+ u8 mrs0_dll_reset;
+ u8 mrs0_dll_reset_mirr;
+ u8 mrs0_user;
+ u8 mrs0_user_mirr;
+ u8 mrs1;
+ u8 mrs1_mirr;
+ u8 mrs2;
+ u8 mrs2_mirr;
+ u8 mrs3;
+ u8 mrs3_mirr;
+ u8 precharge_all;
+ u8 read_b2b;
+ u8 read_b2b_wait1;
+ u8 read_b2b_wait2;
+ u8 refresh_all;
+ u8 rreturn;
+ u8 sgle_read;
+ u8 zqcl;
+
+ u8 true_mem_data_mask_width;
+ u8 mem_address_mirroring;
+ u8 mem_data_mask_width;
+ u8 mem_data_width;
+ u8 mem_dq_per_read_dqs;
+ u8 mem_dq_per_write_dqs;
+ u8 mem_if_read_dqs_width;
+ u8 mem_if_write_dqs_width;
+ u8 mem_number_of_cs_per_dimm;
+ u8 mem_number_of_ranks;
+ u8 mem_virtual_groups_per_read_dqs;
+ u8 mem_virtual_groups_per_write_dqs;
+};
+
+struct socfpga_sdram_io_config {
+ u16 delay_per_opa_tap;
+ u8 delay_per_dchain_tap;
+ u8 delay_per_dqs_en_dchain_tap;
+ u8 dll_chain_length;
+ u8 dqdqs_out_phase_max;
+ u8 dqs_en_delay_max;
+ u8 dqs_en_delay_offset;
+ u8 dqs_en_phase_max;
+ u8 dqs_in_delay_max;
+ u8 dqs_in_reserve;
+ u8 dqs_out_reserve;
+ u8 io_in_delay_max;
+ u8 io_out1_delay_max;
+ u8 io_out2_delay_max;
+ u8 shift_dqs_en_when_shift_dqs;
+};
+
+struct socfpga_sdram_misc_config {
+ u32 reg_file_init_seq_signature;
+ u8 afi_rate_ratio;
+ u8 calib_lfifo_offset;
+ u8 calib_vfifo_offset;
+ u8 enable_super_quick_calibration;
+ u8 max_latency_count_width;
+ u8 read_valid_fifo_size;
+ u8 tinit_cntr0_val;
+ u8 tinit_cntr1_val;
+ u8 tinit_cntr2_val;
+ u8 treset_cntr0_val;
+ u8 treset_cntr1_val;
+ u8 treset_cntr2_val;
+};
-#ifndef __ARCH_SDRAM_H__
-#define __ARCH_SDRAM_H__
+#define SDR_CTRLGRP_CTRLCFG_NODMPINS_LSB 23
+#define SDR_CTRLGRP_CTRLCFG_NODMPINS_MASK 0x00800000
+#define SDR_CTRLGRP_CTRLCFG_DQSTRKEN_LSB 22
+#define SDR_CTRLGRP_CTRLCFG_DQSTRKEN_MASK 0x00400000
+#define SDR_CTRLGRP_CTRLCFG_STARVELIMIT_LSB 16
+#define SDR_CTRLGRP_CTRLCFG_STARVELIMIT_MASK 0x003f0000
+#define SDR_CTRLGRP_CTRLCFG_REORDEREN_LSB 15
+#define SDR_CTRLGRP_CTRLCFG_REORDEREN_MASK 0x00008000
+#define SDR_CTRLGRP_CTRLCFG_ECCCORREN_LSB 11
+#define SDR_CTRLGRP_CTRLCFG_ECCCORREN_MASK 0x00000800
+#define SDR_CTRLGRP_CTRLCFG_ECCEN_LSB 10
+#define SDR_CTRLGRP_CTRLCFG_ECCEN_MASK 0x00000400
+#define SDR_CTRLGRP_CTRLCFG_ADDRORDER_LSB 8
+#define SDR_CTRLGRP_CTRLCFG_ADDRORDER_MASK 0x00000300
+#define SDR_CTRLGRP_CTRLCFG_MEMBL_LSB 3
+#define SDR_CTRLGRP_CTRLCFG_MEMBL_MASK 0x000000f8
+#define SDR_CTRLGRP_CTRLCFG_MEMTYPE_LSB 0
+#define SDR_CTRLGRP_CTRLCFG_MEMTYPE_MASK 0x00000007
+/* Register template: sdr::ctrlgrp::dramtiming1 */
+#define SDR_CTRLGRP_DRAMTIMING1_TRFC_LSB 24
+#define SDR_CTRLGRP_DRAMTIMING1_TRFC_MASK 0xff000000
+#define SDR_CTRLGRP_DRAMTIMING1_TFAW_LSB 18
+#define SDR_CTRLGRP_DRAMTIMING1_TFAW_MASK 0x00fc0000
+#define SDR_CTRLGRP_DRAMTIMING1_TRRD_LSB 14
+#define SDR_CTRLGRP_DRAMTIMING1_TRRD_MASK 0x0003c000
+#define SDR_CTRLGRP_DRAMTIMING1_TCL_LSB 9
+#define SDR_CTRLGRP_DRAMTIMING1_TCL_MASK 0x00003e00
+#define SDR_CTRLGRP_DRAMTIMING1_TAL_LSB 4
+#define SDR_CTRLGRP_DRAMTIMING1_TAL_MASK 0x000001f0
+#define SDR_CTRLGRP_DRAMTIMING1_TCWL_LSB 0
+#define SDR_CTRLGRP_DRAMTIMING1_TCWL_MASK 0x0000000f
+/* Register template: sdr::ctrlgrp::dramtiming2 */
+#define SDR_CTRLGRP_DRAMTIMING2_TWTR_LSB 25
+#define SDR_CTRLGRP_DRAMTIMING2_TWTR_MASK 0x1e000000
+#define SDR_CTRLGRP_DRAMTIMING2_TWR_LSB 21
+#define SDR_CTRLGRP_DRAMTIMING2_TWR_MASK 0x01e00000
+#define SDR_CTRLGRP_DRAMTIMING2_TRP_LSB 17
+#define SDR_CTRLGRP_DRAMTIMING2_TRP_MASK 0x001e0000
+#define SDR_CTRLGRP_DRAMTIMING2_TRCD_LSB 13
+#define SDR_CTRLGRP_DRAMTIMING2_TRCD_MASK 0x0001e000
+#define SDR_CTRLGRP_DRAMTIMING2_TREFI_LSB 0
+#define SDR_CTRLGRP_DRAMTIMING2_TREFI_MASK 0x00001fff
+/* Register template: sdr::ctrlgrp::dramtiming3 */
+#define SDR_CTRLGRP_DRAMTIMING3_TCCD_LSB 19
+#define SDR_CTRLGRP_DRAMTIMING3_TCCD_MASK 0x00780000
+#define SDR_CTRLGRP_DRAMTIMING3_TMRD_LSB 15
+#define SDR_CTRLGRP_DRAMTIMING3_TMRD_MASK 0x00078000
+#define SDR_CTRLGRP_DRAMTIMING3_TRC_LSB 9
+#define SDR_CTRLGRP_DRAMTIMING3_TRC_MASK 0x00007e00
+#define SDR_CTRLGRP_DRAMTIMING3_TRAS_LSB 4
+#define SDR_CTRLGRP_DRAMTIMING3_TRAS_MASK 0x000001f0
+#define SDR_CTRLGRP_DRAMTIMING3_TRTP_LSB 0
+#define SDR_CTRLGRP_DRAMTIMING3_TRTP_MASK 0x0000000f
+/* Register template: sdr::ctrlgrp::dramtiming4 */
+#define SDR_CTRLGRP_DRAMTIMING4_MINPWRSAVECYCLES_LSB 20
+#define SDR_CTRLGRP_DRAMTIMING4_MINPWRSAVECYCLES_MASK 0x00f00000
+#define SDR_CTRLGRP_DRAMTIMING4_PWRDOWNEXIT_LSB 10
+#define SDR_CTRLGRP_DRAMTIMING4_PWRDOWNEXIT_MASK 0x000ffc00
+#define SDR_CTRLGRP_DRAMTIMING4_SELFRFSHEXIT_LSB 0
+#define SDR_CTRLGRP_DRAMTIMING4_SELFRFSHEXIT_MASK 0x000003ff
+/* Register template: sdr::ctrlgrp::lowpwrtiming */
+#define SDR_CTRLGRP_LOWPWRTIMING_CLKDISABLECYCLES_LSB 16
+#define SDR_CTRLGRP_LOWPWRTIMING_CLKDISABLECYCLES_MASK 0x000f0000
+#define SDR_CTRLGRP_LOWPWRTIMING_AUTOPDCYCLES_LSB 0
+#define SDR_CTRLGRP_LOWPWRTIMING_AUTOPDCYCLES_MASK 0x0000ffff
+/* Register template: sdr::ctrlgrp::dramaddrw */
+#define SDR_CTRLGRP_DRAMADDRW_CSBITS_LSB 13
+#define SDR_CTRLGRP_DRAMADDRW_CSBITS_MASK 0x0000e000
+#define SDR_CTRLGRP_DRAMADDRW_BANKBITS_LSB 10
+#define SDR_CTRLGRP_DRAMADDRW_BANKBITS_MASK 0x00001c00
+#define SDR_CTRLGRP_DRAMADDRW_ROWBITS_LSB 5
+#define SDR_CTRLGRP_DRAMADDRW_ROWBITS_MASK 0x000003e0
+#define SDR_CTRLGRP_DRAMADDRW_COLBITS_LSB 0
+#define SDR_CTRLGRP_DRAMADDRW_COLBITS_MASK 0x0000001f
+/* Register template: sdr::ctrlgrp::dramifwidth */
+#define SDR_CTRLGRP_DRAMIFWIDTH_IFWIDTH_LSB 0
+#define SDR_CTRLGRP_DRAMIFWIDTH_IFWIDTH_MASK 0x000000ff
+/* Register template: sdr::ctrlgrp::dramdevwidth */
+#define SDR_CTRLGRP_DRAMDEVWIDTH_DEVWIDTH_LSB 0
+#define SDR_CTRLGRP_DRAMDEVWIDTH_DEVWIDTH_MASK 0x0000000f
+/* Register template: sdr::ctrlgrp::dramintr */
+#define SDR_CTRLGRP_DRAMINTR_INTREN_LSB 0
+#define SDR_CTRLGRP_DRAMINTR_INTREN_MASK 0x00000001
+#define SDR_CTRLGRP_LOWPWREQ_SELFRFSHMASK_LSB 4
+#define SDR_CTRLGRP_LOWPWREQ_SELFRFSHMASK_MASK 0x00000030
+/* Register template: sdr::ctrlgrp::staticcfg */
+#define SDR_CTRLGRP_STATICCFG_APPLYCFG_LSB 3
+#define SDR_CTRLGRP_STATICCFG_APPLYCFG_MASK 0x00000008
+#define SDR_CTRLGRP_STATICCFG_USEECCASDATA_LSB 2
+#define SDR_CTRLGRP_STATICCFG_USEECCASDATA_MASK 0x00000004
+#define SDR_CTRLGRP_STATICCFG_MEMBL_LSB 0
+#define SDR_CTRLGRP_STATICCFG_MEMBL_MASK 0x00000003
+/* Register template: sdr::ctrlgrp::ctrlwidth */
+#define SDR_CTRLGRP_CTRLWIDTH_CTRLWIDTH_LSB 0
+#define SDR_CTRLGRP_CTRLWIDTH_CTRLWIDTH_MASK 0x00000003
+/* Register template: sdr::ctrlgrp::cportwidth */
+#define SDR_CTRLGRP_CPORTWIDTH_CMDPORTWIDTH_LSB 0
+#define SDR_CTRLGRP_CPORTWIDTH_CMDPORTWIDTH_MASK 0x000fffff
+/* Register template: sdr::ctrlgrp::cportwmap */
+#define SDR_CTRLGRP_CPORTWMAP_CPORTWFIFOMAP_LSB 0
+#define SDR_CTRLGRP_CPORTWMAP_CPORTWFIFOMAP_MASK 0x3fffffff
+/* Register template: sdr::ctrlgrp::cportrmap */
+#define SDR_CTRLGRP_CPORTRMAP_CPORTRFIFOMAP_LSB 0
+#define SDR_CTRLGRP_CPORTRMAP_CPORTRFIFOMAP_MASK 0x3fffffff
+/* Register template: sdr::ctrlgrp::rfifocmap */
+#define SDR_CTRLGRP_RFIFOCMAP_RFIFOCPORTMAP_LSB 0
+#define SDR_CTRLGRP_RFIFOCMAP_RFIFOCPORTMAP_MASK 0x00ffffff
+/* Register template: sdr::ctrlgrp::wfifocmap */
+#define SDR_CTRLGRP_WFIFOCMAP_WFIFOCPORTMAP_LSB 0
+#define SDR_CTRLGRP_WFIFOCMAP_WFIFOCPORTMAP_MASK 0x00ffffff
+/* Register template: sdr::ctrlgrp::cportrdwr */
+#define SDR_CTRLGRP_CPORTRDWR_CPORTRDWR_LSB 0
+#define SDR_CTRLGRP_CPORTRDWR_CPORTRDWR_MASK 0x000fffff
+/* Register template: sdr::ctrlgrp::portcfg */
+#define SDR_CTRLGRP_PORTCFG_AUTOPCHEN_LSB 10
+#define SDR_CTRLGRP_PORTCFG_AUTOPCHEN_MASK 0x000ffc00
+#define SDR_CTRLGRP_PORTCFG_PORTPROTOCOL_LSB 0
+#define SDR_CTRLGRP_PORTCFG_PORTPROTOCOL_MASK 0x000003ff
+/* Register template: sdr::ctrlgrp::fifocfg */
+#define SDR_CTRLGRP_FIFOCFG_INCSYNC_LSB 10
+#define SDR_CTRLGRP_FIFOCFG_INCSYNC_MASK 0x00000400
+#define SDR_CTRLGRP_FIFOCFG_SYNCMODE_LSB 0
+#define SDR_CTRLGRP_FIFOCFG_SYNCMODE_MASK 0x000003ff
+/* Register template: sdr::ctrlgrp::mppriority */
+#define SDR_CTRLGRP_MPPRIORITY_USERPRIORITY_LSB 0
+#define SDR_CTRLGRP_MPPRIORITY_USERPRIORITY_MASK 0x3fffffff
+/* Register template: sdr::ctrlgrp::mpweight::mpweight_0 */
+#define SDR_CTRLGRP_MPWEIGHT_MPWEIGHT_0_STATICWEIGHT_31_0_LSB 0
+#define SDR_CTRLGRP_MPWEIGHT_MPWEIGHT_0_STATICWEIGHT_31_0_MASK 0xffffffff
+/* Register template: sdr::ctrlgrp::mpweight::mpweight_1 */
+#define SDR_CTRLGRP_MPWEIGHT_MPWEIGHT_1_SUMOFWEIGHTS_13_0_LSB 18
+#define SDR_CTRLGRP_MPWEIGHT_MPWEIGHT_1_SUMOFWEIGHTS_13_0_MASK 0xfffc0000
+#define SDR_CTRLGRP_MPWEIGHT_MPWEIGHT_1_STATICWEIGHT_49_32_LSB 0
+#define SDR_CTRLGRP_MPWEIGHT_MPWEIGHT_1_STATICWEIGHT_49_32_MASK 0x0003ffff
+/* Register template: sdr::ctrlgrp::mpweight::mpweight_2 */
+#define SDR_CTRLGRP_MPWEIGHT_MPWEIGHT_2_SUMOFWEIGHTS_45_14_LSB 0
+#define SDR_CTRLGRP_MPWEIGHT_MPWEIGHT_2_SUMOFWEIGHTS_45_14_MASK 0xffffffff
+/* Register template: sdr::ctrlgrp::mpweight::mpweight_3 */
+#define SDR_CTRLGRP_MPWEIGHT_MPWEIGHT_3_SUMOFWEIGHTS_63_46_LSB 0
+#define SDR_CTRLGRP_MPWEIGHT_MPWEIGHT_3_SUMOFWEIGHTS_63_46_MASK 0x0003ffff
+/* Register template: sdr::ctrlgrp::mppacing::mppacing_0 */
+#define SDR_CTRLGRP_MPPACING_MPPACING_0_THRESHOLD1_31_0_LSB 0
+#define SDR_CTRLGRP_MPPACING_MPPACING_0_THRESHOLD1_31_0_MASK 0xffffffff
+/* Register template: sdr::ctrlgrp::mppacing::mppacing_1 */
+#define SDR_CTRLGRP_MPPACING_MPPACING_1_THRESHOLD2_3_0_LSB 28
+#define SDR_CTRLGRP_MPPACING_MPPACING_1_THRESHOLD2_3_0_MASK 0xf0000000
+#define SDR_CTRLGRP_MPPACING_MPPACING_1_THRESHOLD1_59_32_LSB 0
+#define SDR_CTRLGRP_MPPACING_MPPACING_1_THRESHOLD1_59_32_MASK 0x0fffffff
+/* Register template: sdr::ctrlgrp::mppacing::mppacing_2 */
+#define SDR_CTRLGRP_MPPACING_MPPACING_2_THRESHOLD2_35_4_LSB 0
+#define SDR_CTRLGRP_MPPACING_MPPACING_2_THRESHOLD2_35_4_MASK 0xffffffff
+/* Register template: sdr::ctrlgrp::mppacing::mppacing_3 */
+#define SDR_CTRLGRP_MPPACING_MPPACING_3_THRESHOLD2_59_36_LSB 0
+#define SDR_CTRLGRP_MPPACING_MPPACING_3_THRESHOLD2_59_36_MASK 0x00ffffff
+/* Register template: sdr::ctrlgrp::mpthresholdrst::mpthresholdrst_0 */
+#define \
+SDR_CTRLGRP_MPTHRESHOLDRST_0_THRESHOLDRSTCYCLES_31_0_LSB 0
+#define \
+SDR_CTRLGRP_MPTHRESHOLDRST_0_THRESHOLDRSTCYCLES_31_0_MASK \
+0xffffffff
+/* Register template: sdr::ctrlgrp::mpthresholdrst::mpthresholdrst_1 */
+#define \
+SDR_CTRLGRP_MPTHRESHOLDRST_1_THRESHOLDRSTCYCLES_63_32_LSB 0
+#define \
+SDR_CTRLGRP_MPTHRESHOLDRST_1_THRESHOLDRSTCYCLES_63_32_MASK \
+0xffffffff
+/* Register template: sdr::ctrlgrp::mpthresholdrst::mpthresholdrst_2 */
+#define \
+SDR_CTRLGRP_MPTHRESHOLDRST_2_THRESHOLDRSTCYCLES_79_64_LSB 0
+#define \
+SDR_CTRLGRP_MPTHRESHOLDRST_2_THRESHOLDRSTCYCLES_79_64_MASK \
+0x0000ffff
+/* Register template: sdr::ctrlgrp::remappriority */
+#define SDR_CTRLGRP_REMAPPRIORITY_PRIORITYREMAP_LSB 0
+#define SDR_CTRLGRP_REMAPPRIORITY_PRIORITYREMAP_MASK 0x000000ff
+/* Register template: sdr::ctrlgrp::phyctrl::phyctrl_0 */
+#define SDR_CTRLGRP_PHYCTRL_PHYCTRL_0_SAMPLECOUNT_19_0_LSB 12
+#define SDR_CTRLGRP_PHYCTRL_PHYCTRL_0_SAMPLECOUNT_19_0_WIDTH 20
+#define SDR_CTRLGRP_PHYCTRL_PHYCTRL_0_SAMPLECOUNT_19_0_SET(x) \
+ (((x) << 12) & 0xfffff000)
+#define SDR_CTRLGRP_PHYCTRL_PHYCTRL_0_ADDLATSEL_SET(x) \
+ (((x) << 10) & 0x00000c00)
+#define SDR_CTRLGRP_PHYCTRL_PHYCTRL_0_DQSLOGICDELAYEN_SET(x) \
+ (((x) << 6) & 0x000000c0)
+#define SDR_CTRLGRP_PHYCTRL_PHYCTRL_0_RESETDELAYEN_SET(x) \
+ (((x) << 8) & 0x00000100)
+#define SDR_CTRLGRP_PHYCTRL_PHYCTRL_0_LPDDRDIS_SET(x) \
+ (((x) << 9) & 0x00000200)
+#define SDR_CTRLGRP_PHYCTRL_PHYCTRL_0_DQSDELAYEN_SET(x) \
+ (((x) << 4) & 0x00000030)
+#define SDR_CTRLGRP_PHYCTRL_PHYCTRL_0_DQDELAYEN_SET(x) \
+ (((x) << 2) & 0x0000000c)
+#define SDR_CTRLGRP_PHYCTRL_PHYCTRL_0_ACDELAYEN_SET(x) \
+ (((x) << 0) & 0x00000003)
+/* Register template: sdr::ctrlgrp::phyctrl::phyctrl_1 */
+#define SDR_CTRLGRP_PHYCTRL_PHYCTRL_1_LONGIDLESAMPLECOUNT_19_0_WIDTH 20
+#define SDR_CTRLGRP_PHYCTRL_PHYCTRL_1_LONGIDLESAMPLECOUNT_19_0_SET(x) \
+ (((x) << 12) & 0xfffff000)
+#define SDR_CTRLGRP_PHYCTRL_PHYCTRL_1_SAMPLECOUNT_31_20_SET(x) \
+ (((x) << 0) & 0x00000fff)
+/* Register template: sdr::ctrlgrp::phyctrl::phyctrl_2 */
+#define SDR_CTRLGRP_PHYCTRL_PHYCTRL_2_LONGIDLESAMPLECOUNT_31_20_SET(x) \
+ (((x) << 0) & 0x00000fff)
+/* Register template: sdr::ctrlgrp::dramodt */
+#define SDR_CTRLGRP_DRAMODT_READ_LSB 4
+#define SDR_CTRLGRP_DRAMODT_READ_MASK 0x000000f0
+#define SDR_CTRLGRP_DRAMODT_WRITE_LSB 0
+#define SDR_CTRLGRP_DRAMODT_WRITE_MASK 0x0000000f
+/* Field instance: sdr::ctrlgrp::dramsts */
+#define SDR_CTRLGRP_DRAMSTS_DBEERR_MASK 0x00000008
+#define SDR_CTRLGRP_DRAMSTS_SBEERR_MASK 0x00000004
-/* function declaration */
-inline unsigned long sdram_calculate_size(void) { return 0; }
-inline unsigned sdram_mmr_init_full(unsigned int sdr_phy_reg) { return 0; }
-inline int sdram_calibration_full(void) { return 0; }
+/* SDRAM width macro for configuration with ECC */
+#define SDRAM_WIDTH_32BIT_WITH_ECC 40
+#define SDRAM_WIDTH_16BIT_WITH_ECC 24
-#endif /* __ARCH_SDRAM_H__ */
+#endif
+#endif /* _SDRAM_H_ */
diff --git a/arch/arm/mach-socfpga/include/mach/system_manager.h b/arch/arm/mach-socfpga/include/mach/system_manager.h
index 51d98157783..46af30b640e 100644
--- a/arch/arm/mach-socfpga/include/mach/system_manager.h
+++ b/arch/arm/mach-socfpga/include/mach/system_manager.h
@@ -10,11 +10,10 @@
#ifndef __ASSEMBLY__
void sysmgr_pinmux_init(void);
-void sysmgr_enable_warmrstcfgio(void);
-
-/* declaration for handoff table type */
-extern unsigned long sys_mgr_init_table[CONFIG_HPS_PINMUX_NUM];
+void sysmgr_config_warmrstcfgio(int enable);
+void sysmgr_get_pinmux_table(const unsigned long **table,
+ unsigned int *table_len);
#endif
struct socfpga_system_manager {
diff --git a/arch/arm/mach-socfpga/misc.c b/arch/arm/mach-socfpga/misc.c
index 0f8b4d095d4..6128d54b188 100644
--- a/arch/arm/mach-socfpga/misc.c
+++ b/arch/arm/mach-socfpga/misc.c
@@ -6,17 +6,23 @@
#include <common.h>
#include <asm/io.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <libfdt.h>
#include <altera.h>
#include <miiphy.h>
#include <netdev.h>
#include <watchdog.h>
#include <asm/arch/reset_manager.h>
+#include <asm/arch/scan_manager.h>
#include <asm/arch/system_manager.h>
#include <asm/arch/dwmmc.h>
#include <asm/arch/nic301.h>
#include <asm/arch/scu.h>
#include <asm/pl310.h>
+#include <dt-bindings/reset/altr,rst-mgr.h>
+
DECLARE_GLOBAL_DATA_PTR;
static struct pl310_regs *const pl310 =
@@ -50,23 +56,20 @@ void enable_caches(void)
* DesignWare Ethernet initialization
*/
#ifdef CONFIG_ETH_DESIGNWARE
-int cpu_eth_init(bd_t *bis)
+static void dwmac_deassert_reset(const unsigned int of_reset_id)
{
-#if CONFIG_EMAC_BASE == SOCFPGA_EMAC0_ADDRESS
- const int physhift = SYSMGR_EMACGRP_CTRL_PHYSEL0_LSB;
-#elif CONFIG_EMAC_BASE == SOCFPGA_EMAC1_ADDRESS
- const int physhift = SYSMGR_EMACGRP_CTRL_PHYSEL1_LSB;
-#else
-#error "Incorrect CONFIG_EMAC_BASE value!"
-#endif
-
- /* Initialize EMAC. This needs to be done at least once per boot. */
-
- /*
- * Putting the EMAC controller to reset when configuring the PHY
- * interface select at System Manager
- */
- socfpga_emac_reset(1);
+ u32 physhift, reset;
+
+ if (of_reset_id == EMAC0_RESET) {
+ physhift = SYSMGR_EMACGRP_CTRL_PHYSEL0_LSB;
+ reset = SOCFPGA_RESET(EMAC0);
+ } else if (of_reset_id == EMAC1_RESET) {
+ physhift = SYSMGR_EMACGRP_CTRL_PHYSEL1_LSB;
+ reset = SOCFPGA_RESET(EMAC1);
+ } else {
+ printf("GMAC: Invalid reset ID (%i)!\n", of_reset_id);
+ return;
+ }
/* Clearing emac0 PHY interface select to 0 */
clrbits_le32(&sysmgr_regs->emacgrp_ctrl,
@@ -77,11 +80,41 @@ int cpu_eth_init(bd_t *bis)
SYSMGR_EMACGRP_CTRL_PHYSEL_ENUM_RGMII << physhift);
/* Release the EMAC controller from reset */
- socfpga_emac_reset(0);
+ socfpga_per_reset(reset, 0);
+}
+
+int cpu_eth_init(bd_t *bis)
+{
+ const void *fdt = gd->fdt_blob;
+ struct fdtdec_phandle_args args;
+ int nodes[2]; /* Max. two GMACs */
+ int ret, count;
+ int i, node;
+
+ /* Put both GMACs into RESET state. */
+ socfpga_per_reset(SOCFPGA_RESET(EMAC0), 1);
+ socfpga_per_reset(SOCFPGA_RESET(EMAC1), 1);
+
+ count = fdtdec_find_aliases_for_id(fdt, "ethernet",
+ COMPAT_ALTERA_SOCFPGA_DWMAC,
+ nodes, ARRAY_SIZE(nodes));
+ for (i = 0; i < count; i++) {
+ node = nodes[i];
+ if (node <= 0)
+ continue;
+
+ ret = fdtdec_parse_phandle_with_args(fdt, node, "resets",
+ "#reset-cells", 1, 0,
+ &args);
+ if (ret || (args.args_count != 1)) {
+ debug("GMAC%i: Failed to parse DT 'resets'!\n", i);
+ continue;
+ }
+
+ dwmac_deassert_reset(args.args[0]);
+ }
- /* initialize and register the emac */
- return designware_initialize(CONFIG_EMAC_BASE,
- CONFIG_PHY_INTERFACE_MODE);
+ return 0;
}
#endif
@@ -92,18 +125,110 @@ int cpu_eth_init(bd_t *bis)
*/
int cpu_mmc_init(bd_t *bis)
{
+/*
+ * FIXME: Temporarily define CONFIG_HPS_SDMMC_BUSWIDTH to prevent breakage
+ * due to missing patches in u-boot/master . The upcoming patch will
+ * switch this to OF probing, so this whole block will go away.
+ */
+#define CONFIG_HPS_SDMMC_BUSWIDTH 8
return socfpga_dwmmc_init(SOCFPGA_SDMMC_ADDRESS,
CONFIG_HPS_SDMMC_BUSWIDTH, 0);
}
#endif
-#if defined(CONFIG_DISPLAY_CPUINFO)
+struct {
+ const char *mode;
+ const char *name;
+} bsel_str[] = {
+ { "rsvd", "Reserved", },
+ { "fpga", "FPGA (HPS2FPGA Bridge)", },
+ { "nand", "NAND Flash (1.8V)", },
+ { "nand", "NAND Flash (3.0V)", },
+ { "sd", "SD/MMC External Transceiver (1.8V)", },
+ { "sd", "SD/MMC Internal Transceiver (3.0V)", },
+ { "qspi", "QSPI Flash (1.8V)", },
+ { "qspi", "QSPI Flash (3.0V)", },
+};
+
+static const struct {
+ const u16 pn;
+ const char *name;
+ const char *var;
+} const socfpga_fpga_model[] = {
+ /* Cyclone V E */
+ { 0x2b15, "Cyclone V, E/A2", "cv_e_a2" },
+ { 0x2b05, "Cyclone V, E/A4", "cv_e_a4" },
+ { 0x2b22, "Cyclone V, E/A5", "cv_e_a5" },
+ { 0x2b13, "Cyclone V, E/A7", "cv_e_a7" },
+ { 0x2b14, "Cyclone V, E/A9", "cv_e_a9" },
+ /* Cyclone V GX/GT */
+ { 0x2b01, "Cyclone V, GX/C3", "cv_gx_c3" },
+ { 0x2b12, "Cyclone V, GX/C4", "cv_gx_c4" },
+ { 0x2b02, "Cyclone V, GX/C5 or GT/D5", "cv_gx_c5" },
+ { 0x2b03, "Cyclone V, GX/C7 or GT/D7", "cv_gx_c7" },
+ { 0x2b04, "Cyclone V, GX/C9 or GT/D9", "cv_gx_c9" },
+ /* Cyclone V SE/SX/ST */
+ { 0x2d11, "Cyclone V, SE/A2 or SX/C2", "cv_se_a2" },
+ { 0x2d01, "Cyclone V, SE/A4 or SX/C4", "cv_se_a4" },
+ { 0x2d12, "Cyclone V, SE/A5 or SX/C5 or ST/D5", "cv_se_a5" },
+ { 0x2d02, "Cyclone V, SE/A6 or SX/C6 or ST/D6", "cv_se_a6" },
+ /* Arria V */
+ { 0x2d03, "Arria V, D5", "av_d5" },
+};
+
+static int socfpga_fpga_id(const bool print_id)
+{
+ const u32 altera_mi = 0x6e;
+ const u32 id = scan_mgr_get_fpga_id();
+
+ const u32 lsb = id & 0x00000001;
+ const u32 mi = (id >> 1) & 0x000007ff;
+ const u32 pn = (id >> 12) & 0x0000ffff;
+ const u32 version = (id >> 28) & 0x0000000f;
+ int i;
+
+ if ((mi != altera_mi) || (lsb != 1)) {
+ printf("FPGA: Not Altera chip ID\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(socfpga_fpga_model); i++)
+ if (pn == socfpga_fpga_model[i].pn)
+ break;
+
+ if (i == ARRAY_SIZE(socfpga_fpga_model)) {
+ printf("FPGA: Unknown Altera chip, ID 0x%08x\n", id);
+ return -EINVAL;
+ }
+
+ if (print_id)
+ printf("FPGA: Altera %s, version 0x%01x\n",
+ socfpga_fpga_model[i].name, version);
+ return i;
+}
+
/*
* Print CPU information
*/
+#if defined(CONFIG_DISPLAY_CPUINFO)
int print_cpuinfo(void)
{
+ const u32 bsel = readl(&sysmgr_regs->bootinfo) & 0x7;
puts("CPU: Altera SoCFPGA Platform\n");
+ socfpga_fpga_id(1);
+ printf("BOOT: %s\n", bsel_str[bsel].name);
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_ARCH_MISC_INIT
+int arch_misc_init(void)
+{
+ const u32 bsel = readl(&sysmgr_regs->bootinfo) & 0x7;
+ const int fpga_id = socfpga_fpga_id(0);
+ setenv("bootmode", bsel_str[bsel].mode);
+ if (fpga_id >= 0)
+ setenv("fpgatype", socfpga_fpga_model[fpga_id].var);
return 0;
}
#endif
@@ -164,8 +289,10 @@ int arch_cpu_init(void)
* If the HW watchdog is NOT enabled, make sure it is not running,
* for example because it was enabled in the preloader. This might
* trigger a watchdog-triggered reboot of Linux kernel later.
+ * Toggle watchdog reset, so watchdog in not running state.
*/
- socfpga_watchdog_reset();
+ socfpga_per_reset(SOCFPGA_RESET(L4WD0), 1);
+ socfpga_per_reset(SOCFPGA_RESET(L4WD0), 0);
#endif
return 0;
@@ -189,6 +316,16 @@ static uint32_t iswgrp_handoff[8];
int arch_early_init_r(void)
{
int i;
+
+ /*
+ * Write magic value into magic register to unlock support for
+ * issuing warm reset. The ancient kernel code expects this
+ * value to be written into the register by the bootloader, so
+ * to support that old code, we write it here instead of in the
+ * reset_cpu() function just before reseting the CPU.
+ */
+ writel(0xae9efebc, &sysmgr_regs->romcodegrp_warmramgrp_enable);
+
for (i = 0; i < 8; i++) /* Cache initial SW setting regs */
iswgrp_handoff[i] = readl(&sysmgr_regs->iswgrp_handoff[i]);
@@ -215,7 +352,8 @@ int arch_early_init_r(void)
#ifdef CONFIG_DESIGNWARE_SPI
/* Get Designware SPI controller out of reset */
- socfpga_spim_enable();
+ socfpga_per_reset(SOCFPGA_RESET(SPIM0), 0);
+ socfpga_per_reset(SOCFPGA_RESET(SPIM1), 0);
#endif
return 0;
diff --git a/arch/arm/mach-socfpga/reset_manager.c b/arch/arm/mach-socfpga/reset_manager.c
index 45b352bdfc0..1186358a71a 100644
--- a/arch/arm/mach-socfpga/reset_manager.c
+++ b/arch/arm/mach-socfpga/reset_manager.c
@@ -15,16 +15,41 @@ DECLARE_GLOBAL_DATA_PTR;
static const struct socfpga_reset_manager *reset_manager_base =
(void *)SOCFPGA_RSTMGR_ADDRESS;
-/* Toggle reset signal to watchdog (WDT is disabled after this operation!) */
-void socfpga_watchdog_reset(void)
+/* Assert or de-assert SoCFPGA reset manager reset. */
+void socfpga_per_reset(u32 reset, int set)
{
- /* assert reset for watchdog */
- setbits_le32(&reset_manager_base->per_mod_reset,
- 1 << RSTMGR_PERMODRST_L4WD0_LSB);
+ const void *reg;
+
+ if (RSTMGR_BANK(reset) == 0)
+ reg = &reset_manager_base->mpu_mod_reset;
+ else if (RSTMGR_BANK(reset) == 1)
+ reg = &reset_manager_base->per_mod_reset;
+ else if (RSTMGR_BANK(reset) == 2)
+ reg = &reset_manager_base->per2_mod_reset;
+ else if (RSTMGR_BANK(reset) == 3)
+ reg = &reset_manager_base->brg_mod_reset;
+ else if (RSTMGR_BANK(reset) == 4)
+ reg = &reset_manager_base->misc_mod_reset;
+ else /* Invalid reset register, do nothing */
+ return;
+
+ if (set)
+ setbits_le32(reg, 1 << RSTMGR_RESET(reset));
+ else
+ clrbits_le32(reg, 1 << RSTMGR_RESET(reset));
+}
+
+/*
+ * Assert reset on every peripheral but L4WD0.
+ * Watchdog must be kept intact to prevent glitches
+ * and/or hangs.
+ */
+void socfpga_per_reset_all(void)
+{
+ const u32 l4wd0 = 1 << RSTMGR_RESET(SOCFPGA_RESET(L4WD0));
- /* deassert watchdog from reset (watchdog in not running state) */
- clrbits_le32(&reset_manager_base->per_mod_reset,
- 1 << RSTMGR_PERMODRST_L4WD0_LSB);
+ writel(~l4wd0, &reset_manager_base->per_mod_reset);
+ writel(0xffffffff, &reset_manager_base->per2_mod_reset);
}
/*
@@ -73,10 +98,10 @@ void socfpga_bridges_reset(int enable)
writel(0xffffffff, &reset_manager_base->brg_mod_reset);
} else {
/* Check signal from FPGA. */
- if (fpgamgr_poll_fpga_ready()) {
- /* FPGA not ready. Wait for watchdog timeout. */
- printf("%s: fpga not ready, hanging.\n", __func__);
- hang();
+ if (!fpgamgr_test_fpga_ready()) {
+ /* FPGA not ready, do nothing. */
+ printf("%s: FPGA not ready, aborting.\n", __func__);
+ return;
}
/* brdmodrst */
@@ -87,53 +112,3 @@ void socfpga_bridges_reset(int enable)
}
}
#endif
-
-/* Change the reset state for EMAC 0 and EMAC 1 */
-void socfpga_emac_reset(int enable)
-{
- const void *reset = &reset_manager_base->per_mod_reset;
-
- if (enable) {
- setbits_le32(reset, 1 << RSTMGR_PERMODRST_EMAC0_LSB);
- setbits_le32(reset, 1 << RSTMGR_PERMODRST_EMAC1_LSB);
- } else {
-#if (CONFIG_EMAC_BASE == SOCFPGA_EMAC0_ADDRESS)
- clrbits_le32(reset, 1 << RSTMGR_PERMODRST_EMAC0_LSB);
-#elif (CONFIG_EMAC_BASE == SOCFPGA_EMAC1_ADDRESS)
- clrbits_le32(reset, 1 << RSTMGR_PERMODRST_EMAC1_LSB);
-#endif
- }
-}
-
-/* SPI Master enable (its held in reset by the preloader) */
-void socfpga_spim_enable(void)
-{
- const void *reset = &reset_manager_base->per_mod_reset;
-
- clrbits_le32(reset, (1 << RSTMGR_PERMODRST_SPIM0_LSB) |
- (1 << RSTMGR_PERMODRST_SPIM1_LSB));
-}
-
-/* Bring UART0 out of reset. */
-void socfpga_uart0_enable(void)
-{
- const void *reset = &reset_manager_base->per_mod_reset;
-
- clrbits_le32(reset, 1 << RSTMGR_PERMODRST_UART0_LSB);
-}
-
-/* Bring SDRAM controller out of reset. */
-void socfpga_sdram_enable(void)
-{
- const void *reset = &reset_manager_base->per_mod_reset;
-
- clrbits_le32(reset, 1 << RSTMGR_PERMODRST_SDR_LSB);
-}
-
-/* Bring OSC1 timer out of reset. */
-void socfpga_osc1timer_enable(void)
-{
- const void *reset = &reset_manager_base->per_mod_reset;
-
- clrbits_le32(reset, 1 << RSTMGR_PERMODRST_OSC1TIMER0_LSB);
-}
diff --git a/arch/arm/mach-socfpga/scan_manager.c b/arch/arm/mach-socfpga/scan_manager.c
index a820b1b1bfc..566b33f2b6a 100644
--- a/arch/arm/mach-socfpga/scan_manager.c
+++ b/arch/arm/mach-socfpga/scan_manager.c
@@ -5,9 +5,28 @@
*/
#include <common.h>
+#include <errno.h>
#include <asm/io.h>
#include <asm/arch/freeze_controller.h>
#include <asm/arch/scan_manager.h>
+#include <asm/arch/system_manager.h>
+
+/*
+ * Maximum polling loop to wait for IO scan chain engine becomes idle
+ * to prevent infinite loop. It is important that this is NOT changed
+ * to delay using timer functions, since at the time this function is
+ * called, timer might not yet be inited.
+ */
+#define SCANMGR_MAX_DELAY 100
+
+/*
+ * Maximum length of TDI_TDO packet payload is 128 bits,
+ * represented by (length - 1) in TDI_TDO header.
+ */
+#define TDI_TDO_MAX_PAYLOAD 127
+
+#define SCANMGR_STAT_ACTIVE (1 << 31)
+#define SCANMGR_STAT_WFIFOCNT_MASK 0x70000000
DECLARE_GLOBAL_DATA_PTR;
@@ -15,41 +34,122 @@ static const struct socfpga_scan_manager *scan_manager_base =
(void *)(SOCFPGA_SCANMGR_ADDRESS);
static const struct socfpga_freeze_controller *freeze_controller_base =
(void *)(SOCFPGA_SYSMGR_ADDRESS + SYSMGR_FRZCTRL_ADDRESS);
+static struct socfpga_system_manager *sys_mgr_base =
+ (struct socfpga_system_manager *)SOCFPGA_SYSMGR_ADDRESS;
-/*
+/**
+ * scan_chain_engine_is_idle() - Check if the JTAG scan chain is idle
+ * @max_iter: Maximum number of iterations to wait for idle
+ *
* Function to check IO scan chain engine status and wait if the engine is
* is active. Poll the IO scan chain engine till maximum iteration reached.
*/
-static inline uint32_t scan_chain_engine_is_idle(uint32_t max_iter)
+static u32 scan_chain_engine_is_idle(u32 max_iter)
{
- uint32_t scanmgr_status;
-
- scanmgr_status = readl(&scan_manager_base->stat);
+ const u32 mask = SCANMGR_STAT_ACTIVE | SCANMGR_STAT_WFIFOCNT_MASK;
+ u32 status;
- /* Poll the engine until the scan engine is inactive */
- while (SCANMGR_STAT_ACTIVE_GET(scanmgr_status) ||
- (SCANMGR_STAT_WFIFOCNT_GET(scanmgr_status) > 0)) {
- max_iter--;
- if (max_iter > 0)
- scanmgr_status = readl(&scan_manager_base->stat);
- else
+ /* Poll the engine until the scan engine is inactive. */
+ do {
+ status = readl(&scan_manager_base->stat);
+ if (!(status & mask))
return 0;
+ } while (max_iter--);
+
+ return -ETIMEDOUT;
+}
+
+#define JTAG_BP_INSN (1 << 0)
+#define JTAG_BP_TMS (1 << 1)
+#define JTAG_BP_PAYLOAD (1 << 2)
+#define JTAG_BP_2BYTE (1 << 3)
+#define JTAG_BP_4BYTE (1 << 4)
+
+/**
+ * scan_mgr_jtag_io() - Access the JTAG chain
+ * @flags: Control flags, used to configure the action on the JTAG
+ * @iarg: Instruction argument
+ * @parg: Payload argument or data
+ *
+ * Perform I/O on the JTAG chain
+ */
+static void scan_mgr_jtag_io(const u32 flags, const u8 iarg, const u32 parg)
+{
+ u32 data = parg;
+
+ if (flags & JTAG_BP_INSN) { /* JTAG instruction */
+ /*
+ * The SCC JTAG register is LSB first, so make
+ * space for the instruction at the LSB.
+ */
+ data <<= 8;
+ if (flags & JTAG_BP_TMS) {
+ data |= (0 << 7); /* TMS instruction. */
+ data |= iarg & 0x3f; /* TMS arg is 6 bits. */
+ if (flags & JTAG_BP_PAYLOAD)
+ data |= (1 << 6);
+ } else {
+ data |= (1 << 7); /* TDI/TDO instruction. */
+ data |= iarg & 0xf; /* TDI/TDO arg is 4 bits. */
+ if (flags & JTAG_BP_PAYLOAD)
+ data |= (1 << 4);
+ }
+ }
+
+ if (flags & JTAG_BP_4BYTE)
+ writel(data, &scan_manager_base->fifo_quad_byte);
+ else if (flags & JTAG_BP_2BYTE)
+ writel(data & 0xffff, &scan_manager_base->fifo_double_byte);
+ else
+ writel(data & 0xff, &scan_manager_base->fifo_single_byte);
+}
+
+/**
+ * scan_mgr_jtag_insn_data() - Send JTAG instruction and data
+ * @iarg: Instruction argument
+ * @data: Associated data
+ * @dlen: Length of data in bits
+ *
+ * This function is used when programming the IO chains to submit the
+ * instruction followed by variable length payload.
+ */
+static int
+scan_mgr_jtag_insn_data(const u8 iarg, const unsigned long *data,
+ const unsigned int dlen)
+{
+ int i, j;
+
+ scan_mgr_jtag_io(JTAG_BP_INSN | JTAG_BP_2BYTE, iarg, dlen - 1);
+
+ /* 32 bits or more remain */
+ for (i = 0; i < dlen / 32; i++)
+ scan_mgr_jtag_io(JTAG_BP_4BYTE, 0x0, data[i]);
+
+ if ((dlen % 32) > 24) { /* 31...24 bits remain */
+ scan_mgr_jtag_io(JTAG_BP_4BYTE, 0x0, data[i]);
+ } else if (dlen % 32) { /* 24...1 bit remain */
+ for (j = 0; j < dlen % 32; j += 8)
+ scan_mgr_jtag_io(0, 0x0, data[i] >> j);
}
- return 1;
+
+ return scan_chain_engine_is_idle(SCANMGR_MAX_DELAY);
}
-/* Program HPS IO Scan Chain */
-uint32_t scan_mgr_io_scan_chain_prg(
- uint32_t io_scan_chain_id,
- uint32_t io_scan_chain_len_in_bits,
- const uint32_t *iocsr_scan_chain)
+/**
+ * scan_mgr_io_scan_chain_prg() - Program HPS IO Scan Chain
+ * @io_scan_chain_id: IO scan chain ID
+ */
+static int scan_mgr_io_scan_chain_prg(const unsigned int io_scan_chain_id)
{
- uint16_t tdi_tdo_header;
- uint32_t io_program_iter;
- uint32_t io_scan_chain_data_residual;
- uint32_t residual;
- uint32_t i;
- uint32_t index = 0;
+ u32 io_scan_chain_len_in_bits;
+ const unsigned long *iocsr_scan_chain;
+ unsigned int rem, idx = 0;
+ int ret;
+
+ ret = iocsr_get_config_table(io_scan_chain_id, &iocsr_scan_chain,
+ &io_scan_chain_len_in_bits);
+ if (ret)
+ return 1;
/*
* De-assert reinit if the IO scan chain is intended for HIO. In
@@ -63,8 +163,9 @@ uint32_t scan_mgr_io_scan_chain_prg(
* Check if the scan chain engine is inactive and the
* WFIFO is empty before enabling the IO scan chain
*/
- if (!scan_chain_engine_is_idle(SCAN_MAX_DELAY))
- return 1;
+ ret = scan_chain_engine_is_idle(SCANMGR_MAX_DELAY);
+ if (ret)
+ return ret;
/*
* Enable IO Scan chain based on scan chain id
@@ -72,114 +173,18 @@ uint32_t scan_mgr_io_scan_chain_prg(
*/
setbits_le32(&scan_manager_base->en, 1 << io_scan_chain_id);
- /*
- * Calculate number of iteration needed for full 128-bit (4 x32-bits)
- * bits shifting. Each TDI_TDO packet can shift in maximum 128-bits
- */
- io_program_iter = io_scan_chain_len_in_bits >>
- IO_SCAN_CHAIN_128BIT_SHIFT;
- io_scan_chain_data_residual = io_scan_chain_len_in_bits &
- IO_SCAN_CHAIN_128BIT_MASK;
-
- /* Construct TDI_TDO packet for 128-bit IO scan chain (2 bytes) */
- tdi_tdo_header = TDI_TDO_HEADER_FIRST_BYTE |
- (TDI_TDO_MAX_PAYLOAD << TDI_TDO_HEADER_SECOND_BYTE_SHIFT);
-
- /* Program IO scan chain in 128-bit iteration */
- for (i = 0; i < io_program_iter; i++) {
- /* write TDI_TDO packet header to scan manager */
- writel(tdi_tdo_header, &scan_manager_base->fifo_double_byte);
-
- /* calculate array index. Multiply by 4 as write 4 x 32bits */
- index = i * 4;
-
- /* write 4 successive 32-bit IO scan chain data into WFIFO */
- writel(iocsr_scan_chain[index],
- &scan_manager_base->fifo_quad_byte);
- writel(iocsr_scan_chain[index + 1],
- &scan_manager_base->fifo_quad_byte);
- writel(iocsr_scan_chain[index + 2],
- &scan_manager_base->fifo_quad_byte);
- writel(iocsr_scan_chain[index + 3],
- &scan_manager_base->fifo_quad_byte);
-
- /*
- * Check if the scan chain engine has completed the
- * IO scan chain data shifting
- */
- if (!scan_chain_engine_is_idle(SCAN_MAX_DELAY))
- goto error;
- }
-
- /* Calculate array index for final TDI_TDO packet */
- index = io_program_iter * 4;
-
- /* Final TDI_TDO packet if any */
- if (io_scan_chain_data_residual) {
- /*
- * Calculate number of quad bytes FIFO write
- * needed for the final TDI_TDO packet
- */
- io_program_iter = io_scan_chain_data_residual >>
- IO_SCAN_CHAIN_32BIT_SHIFT;
-
- /*
- * Construct TDI_TDO packet for remaining IO
- * scan chain (2 bytes)
- */
- tdi_tdo_header = TDI_TDO_HEADER_FIRST_BYTE |
- ((io_scan_chain_data_residual - 1) <<
- TDI_TDO_HEADER_SECOND_BYTE_SHIFT);
-
- /*
- * Program the last part of IO scan chain write TDI_TDO packet
- * header (2 bytes) to scan manager
- */
- writel(tdi_tdo_header, &scan_manager_base->fifo_double_byte);
-
- for (i = 0; i < io_program_iter; i++) {
- /*
- * write remaining scan chain data into scan
- * manager WFIFO with 4 bytes write
- */
- writel(iocsr_scan_chain[index + i],
- &scan_manager_base->fifo_quad_byte);
- }
-
- index += io_program_iter;
- residual = io_scan_chain_data_residual &
- IO_SCAN_CHAIN_32BIT_MASK;
-
- if (IO_SCAN_CHAIN_PAYLOAD_24BIT < residual) {
- /*
- * write the last 4B scan chain data
- * into scan manager WFIFO
- */
- writel(iocsr_scan_chain[index],
- &scan_manager_base->fifo_quad_byte);
- } else {
- /*
- * write the remaining 1 - 3 bytes scan chain
- * data into scan manager WFIFO byte by byte
- * to prevent JTAG engine shifting unused data
- * from the FIFO and mistaken the data as a
- * valid command (even though unused bits are
- * set to 0, but just to prevent hardware
- * glitch)
- */
- for (i = 0; i < residual; i += 8) {
- writel(((iocsr_scan_chain[index] >> i)
- & IO_SCAN_CHAIN_BYTE_MASK),
- &scan_manager_base->fifo_single_byte);
- }
- }
+ /* Program IO scan chain. */
+ while (io_scan_chain_len_in_bits) {
+ if (io_scan_chain_len_in_bits > 128)
+ rem = 128;
+ else
+ rem = io_scan_chain_len_in_bits;
- /*
- * Check if the scan chain engine has completed the
- * IO scan chain data shifting
- */
- if (!scan_chain_engine_is_idle(SCAN_MAX_DELAY))
+ ret = scan_mgr_jtag_insn_data(0x0, &iocsr_scan_chain[idx], rem);
+ if (ret)
goto error;
+ io_scan_chain_len_in_bits -= rem;
+ idx += 4;
}
/* Disable IO Scan chain when configuration done*/
@@ -189,7 +194,7 @@ uint32_t scan_mgr_io_scan_chain_prg(
error:
/* Disable IO Scan chain when error detected */
clrbits_le32(&scan_manager_base->en, 1 << io_scan_chain_id);
- return 1;
+ return ret;
}
int scan_mgr_configure_iocsr(void)
@@ -197,13 +202,61 @@ int scan_mgr_configure_iocsr(void)
int status = 0;
/* configure the IOCSR through scan chain */
- status |= scan_mgr_io_scan_chain_prg(0,
- CONFIG_HPS_IOCSR_SCANCHAIN0_LENGTH, iocsr_scan_chain0_table);
- status |= scan_mgr_io_scan_chain_prg(1,
- CONFIG_HPS_IOCSR_SCANCHAIN1_LENGTH, iocsr_scan_chain1_table);
- status |= scan_mgr_io_scan_chain_prg(2,
- CONFIG_HPS_IOCSR_SCANCHAIN2_LENGTH, iocsr_scan_chain2_table);
- status |= scan_mgr_io_scan_chain_prg(3,
- CONFIG_HPS_IOCSR_SCANCHAIN3_LENGTH, iocsr_scan_chain3_table);
+ status |= scan_mgr_io_scan_chain_prg(0);
+ status |= scan_mgr_io_scan_chain_prg(1);
+ status |= scan_mgr_io_scan_chain_prg(2);
+ status |= scan_mgr_io_scan_chain_prg(3);
return status;
}
+
+/**
+ * scan_mgr_get_fpga_id() - Obtain FPGA JTAG ID
+ *
+ * This function obtains JTAG ID from the FPGA TAP controller.
+ */
+u32 scan_mgr_get_fpga_id(void)
+{
+ const unsigned long data = 0;
+ u32 id = 0xffffffff;
+ int ret;
+
+ /* Enable HPS to talk to JTAG in the FPGA through the System Manager */
+ writel(0x1, &sys_mgr_base->scanmgrgrp_ctrl);
+
+ /* Enable port 7 */
+ writel(0x80, &scan_manager_base->en);
+ /* write to CSW to make s2f_ntrst reset */
+ writel(0x02, &scan_manager_base->stat);
+
+ /* Add a pause */
+ mdelay(1);
+
+ /* write 0x00 to CSW to clear the s2f_ntrst */
+ writel(0, &scan_manager_base->stat);
+
+ /*
+ * Go to Test-Logic-Reset state.
+ * This sets TAP controller into IDCODE mode.
+ */
+ scan_mgr_jtag_io(JTAG_BP_INSN | JTAG_BP_TMS, 0x1f | (1 << 5), 0x0);
+
+ /* Go to Run-Test/Idle -> DR-Scan -> Capture-DR -> Shift-DR state. */
+ scan_mgr_jtag_io(JTAG_BP_INSN | JTAG_BP_TMS, 0x02 | (1 << 4), 0x0);
+
+ /*
+ * Push 4 bytes of data through TDI->DR->TDO.
+ *
+ * Length of TDI data is 32bits (length - 1) and they are only
+ * zeroes as we care only for TDO data.
+ */
+ ret = scan_mgr_jtag_insn_data(0x4, &data, 32);
+ /* Read 32 bit from captured JTAG data. */
+ if (!ret)
+ id = readl(&scan_manager_base->fifo_quad_byte);
+
+ /* Disable all port */
+ writel(0, &scan_manager_base->en);
+ writel(0, &sys_mgr_base->scanmgrgrp_ctrl);
+
+ return id;
+}
diff --git a/arch/arm/mach-socfpga/spl.c b/arch/arm/mach-socfpga/spl.c
index f9946584521..13ec24bc169 100644
--- a/arch/arm/mach-socfpga/spl.c
+++ b/arch/arm/mach-socfpga/spl.c
@@ -17,42 +17,74 @@
#include <asm/arch/clock_manager.h>
#include <asm/arch/scan_manager.h>
#include <asm/arch/sdram.h>
+#include <asm/arch/scu.h>
+#include <asm/arch/nic301.h>
DECLARE_GLOBAL_DATA_PTR;
static struct pl310_regs *const pl310 =
(struct pl310_regs *)CONFIG_SYS_PL310_BASE;
+static struct scu_registers *scu_regs =
+ (struct scu_registers *)SOCFPGA_MPUSCU_ADDRESS;
+static struct nic301_registers *nic301_regs =
+ (struct nic301_registers *)SOCFPGA_L3REGS_ADDRESS;
+static struct socfpga_system_manager *sysmgr_regs =
+ (struct socfpga_system_manager *)SOCFPGA_SYSMGR_ADDRESS;
-#define MAIN_VCO_BASE ( \
- (CONFIG_HPS_MAINPLLGRP_VCO_DENOM << \
- CLKMGR_MAINPLLGRP_VCO_DENOM_OFFSET) | \
- (CONFIG_HPS_MAINPLLGRP_VCO_NUMER << \
- CLKMGR_MAINPLLGRP_VCO_NUMER_OFFSET) \
- )
-
-#define PERI_VCO_BASE ( \
- (CONFIG_HPS_PERPLLGRP_VCO_PSRC << \
- CLKMGR_PERPLLGRP_VCO_PSRC_OFFSET) | \
- (CONFIG_HPS_PERPLLGRP_VCO_DENOM << \
- CLKMGR_PERPLLGRP_VCO_DENOM_OFFSET) | \
- (CONFIG_HPS_PERPLLGRP_VCO_NUMER << \
- CLKMGR_PERPLLGRP_VCO_NUMER_OFFSET) \
- )
-
-#define SDR_VCO_BASE ( \
- (CONFIG_HPS_SDRPLLGRP_VCO_SSRC << \
- CLKMGR_SDRPLLGRP_VCO_SSRC_OFFSET) | \
- (CONFIG_HPS_SDRPLLGRP_VCO_DENOM << \
- CLKMGR_SDRPLLGRP_VCO_DENOM_OFFSET) | \
- (CONFIG_HPS_SDRPLLGRP_VCO_NUMER << \
- CLKMGR_SDRPLLGRP_VCO_NUMER_OFFSET) \
- )
+u32 spl_boot_device(void)
+{
+ const u32 bsel = readl(&sysmgr_regs->bootinfo);
+
+ switch (bsel & 0x7) {
+ case 0x1: /* FPGA (HPS2FPGA Bridge) */
+ return BOOT_DEVICE_RAM;
+ case 0x2: /* NAND Flash (1.8V) */
+ case 0x3: /* NAND Flash (3.0V) */
+ return BOOT_DEVICE_NAND;
+ case 0x4: /* SD/MMC External Transceiver (1.8V) */
+ case 0x5: /* SD/MMC Internal Transceiver (3.0V) */
+ socfpga_per_reset(SOCFPGA_RESET(SDMMC), 0);
+ socfpga_per_reset(SOCFPGA_RESET(DMA), 0);
+ return BOOT_DEVICE_MMC1;
+ case 0x6: /* QSPI Flash (1.8V) */
+ case 0x7: /* QSPI Flash (3.0V) */
+ socfpga_per_reset(SOCFPGA_RESET(QSPI), 0);
+ return BOOT_DEVICE_SPI;
+ default:
+ printf("Invalid boot device (bsel=%08x)!\n", bsel);
+ hang();
+ }
+}
+
+#ifdef CONFIG_SPL_MMC_SUPPORT
+u32 spl_boot_mode(void)
+{
+#if defined(CONFIG_SPL_FAT_SUPPORT) || defined(CONFIG_SPL_EXT_SUPPORT)
+ return MMCSD_MODE_FS;
+#else
+ return MMCSD_MODE_RAW;
+#endif
+}
+#endif
+
+static void socfpga_nic301_slave_ns(void)
+{
+ writel(0x1, &nic301_regs->lwhps2fpgaregs);
+ writel(0x1, &nic301_regs->hps2fpgaregs);
+ writel(0x1, &nic301_regs->acp);
+ writel(0x1, &nic301_regs->rom);
+ writel(0x1, &nic301_regs->ocram);
+ writel(0x1, &nic301_regs->sdrdata);
+}
void board_init_f(ulong dummy)
{
- struct socfpga_system_manager *sysmgr_regs =
- (struct socfpga_system_manager *)SOCFPGA_SYSMGR_ADDRESS;
+#ifndef CONFIG_SOCFPGA_VIRTUAL_TARGET
+ const struct cm_config *cm_default_cfg = cm_get_default_config();
+#endif
+ unsigned long sdram_size;
unsigned long reg;
+
/*
* First C code to run. Clear fake OCRAM ECC first as SBE
* and DBE might triggered during power on
@@ -67,137 +99,54 @@ void board_init_f(ulong dummy)
memset(__bss_start, 0, __bss_end - __bss_start);
- /* Remap SDRAM to 0x0 */
- writel(0x1, &pl310->pl310_addr_filter_start);
+ socfpga_nic301_slave_ns();
- board_init_r(NULL, 0);
-}
+ /* Configure ARM MPU SNSAC register. */
+ setbits_le32(&scu_regs->sacr, 0xfff);
-u32 spl_boot_device(void)
-{
- return BOOT_DEVICE_RAM;
-}
+ /* Remap SDRAM to 0x0 */
+ writel(0x1, &nic301_regs->remap); /* remap.mpuzero */
+ writel(0x1, &pl310->pl310_addr_filter_start);
-/*
- * Board initialization after bss clearance
- */
-void spl_board_init(void)
-{
- unsigned long sdram_size;
#ifndef CONFIG_SOCFPGA_VIRTUAL_TARGET
- cm_config_t cm_default_cfg = {
- /* main group */
- MAIN_VCO_BASE,
- (CONFIG_HPS_MAINPLLGRP_MPUCLK_CNT <<
- CLKMGR_MAINPLLGRP_MPUCLK_CNT_OFFSET),
- (CONFIG_HPS_MAINPLLGRP_MAINCLK_CNT <<
- CLKMGR_MAINPLLGRP_MAINCLK_CNT_OFFSET),
- (CONFIG_HPS_MAINPLLGRP_DBGATCLK_CNT <<
- CLKMGR_MAINPLLGRP_DBGATCLK_CNT_OFFSET),
- (CONFIG_HPS_MAINPLLGRP_MAINQSPICLK_CNT <<
- CLKMGR_MAINPLLGRP_MAINQSPICLK_CNT_OFFSET),
- (CONFIG_HPS_MAINPLLGRP_MAINNANDSDMMCCLK_CNT <<
- CLKMGR_PERPLLGRP_PERNANDSDMMCCLK_CNT_OFFSET),
- (CONFIG_HPS_MAINPLLGRP_CFGS2FUSER0CLK_CNT <<
- CLKMGR_MAINPLLGRP_CFGS2FUSER0CLK_CNT_OFFSET),
- (CONFIG_HPS_MAINPLLGRP_MAINDIV_L3MPCLK <<
- CLKMGR_MAINPLLGRP_MAINDIV_L3MPCLK_OFFSET) |
- (CONFIG_HPS_MAINPLLGRP_MAINDIV_L3SPCLK <<
- CLKMGR_MAINPLLGRP_MAINDIV_L3SPCLK_OFFSET) |
- (CONFIG_HPS_MAINPLLGRP_MAINDIV_L4MPCLK <<
- CLKMGR_MAINPLLGRP_MAINDIV_L4MPCLK_OFFSET) |
- (CONFIG_HPS_MAINPLLGRP_MAINDIV_L4SPCLK <<
- CLKMGR_MAINPLLGRP_MAINDIV_L4SPCLK_OFFSET),
- (CONFIG_HPS_MAINPLLGRP_DBGDIV_DBGATCLK <<
- CLKMGR_MAINPLLGRP_DBGDIV_DBGATCLK_OFFSET) |
- (CONFIG_HPS_MAINPLLGRP_DBGDIV_DBGCLK <<
- CLKMGR_MAINPLLGRP_DBGDIV_DBGCLK_OFFSET),
- (CONFIG_HPS_MAINPLLGRP_TRACEDIV_TRACECLK <<
- CLKMGR_MAINPLLGRP_TRACEDIV_TRACECLK_OFFSET),
- (CONFIG_HPS_MAINPLLGRP_L4SRC_L4MP <<
- CLKMGR_MAINPLLGRP_L4SRC_L4MP_OFFSET) |
- (CONFIG_HPS_MAINPLLGRP_L4SRC_L4SP <<
- CLKMGR_MAINPLLGRP_L4SRC_L4SP_OFFSET),
-
- /* peripheral group */
- PERI_VCO_BASE,
- (CONFIG_HPS_PERPLLGRP_EMAC0CLK_CNT <<
- CLKMGR_PERPLLGRP_EMAC0CLK_CNT_OFFSET),
- (CONFIG_HPS_PERPLLGRP_EMAC1CLK_CNT <<
- CLKMGR_PERPLLGRP_EMAC1CLK_CNT_OFFSET),
- (CONFIG_HPS_PERPLLGRP_PERQSPICLK_CNT <<
- CLKMGR_PERPLLGRP_PERQSPICLK_CNT_OFFSET),
- (CONFIG_HPS_PERPLLGRP_PERNANDSDMMCCLK_CNT <<
- CLKMGR_PERPLLGRP_PERNANDSDMMCCLK_CNT_OFFSET),
- (CONFIG_HPS_PERPLLGRP_PERBASECLK_CNT <<
- CLKMGR_PERPLLGRP_PERBASECLK_CNT_OFFSET),
- (CONFIG_HPS_PERPLLGRP_S2FUSER1CLK_CNT <<
- CLKMGR_PERPLLGRP_S2FUSER1CLK_CNT_OFFSET),
- (CONFIG_HPS_PERPLLGRP_DIV_USBCLK <<
- CLKMGR_PERPLLGRP_DIV_USBCLK_OFFSET) |
- (CONFIG_HPS_PERPLLGRP_DIV_SPIMCLK <<
- CLKMGR_PERPLLGRP_DIV_SPIMCLK_OFFSET) |
- (CONFIG_HPS_PERPLLGRP_DIV_CAN0CLK <<
- CLKMGR_PERPLLGRP_DIV_CAN0CLK_OFFSET) |
- (CONFIG_HPS_PERPLLGRP_DIV_CAN1CLK <<
- CLKMGR_PERPLLGRP_DIV_CAN1CLK_OFFSET),
- (CONFIG_HPS_PERPLLGRP_GPIODIV_GPIODBCLK <<
- CLKMGR_PERPLLGRP_GPIODIV_GPIODBCLK_OFFSET),
- (CONFIG_HPS_PERPLLGRP_SRC_QSPI <<
- CLKMGR_PERPLLGRP_SRC_QSPI_OFFSET) |
- (CONFIG_HPS_PERPLLGRP_SRC_NAND <<
- CLKMGR_PERPLLGRP_SRC_NAND_OFFSET) |
- (CONFIG_HPS_PERPLLGRP_SRC_SDMMC <<
- CLKMGR_PERPLLGRP_SRC_SDMMC_OFFSET),
-
- /* sdram pll group */
- SDR_VCO_BASE,
- (CONFIG_HPS_SDRPLLGRP_DDRDQSCLK_PHASE <<
- CLKMGR_SDRPLLGRP_DDRDQSCLK_PHASE_OFFSET) |
- (CONFIG_HPS_SDRPLLGRP_DDRDQSCLK_CNT <<
- CLKMGR_SDRPLLGRP_DDRDQSCLK_CNT_OFFSET),
- (CONFIG_HPS_SDRPLLGRP_DDR2XDQSCLK_PHASE <<
- CLKMGR_SDRPLLGRP_DDR2XDQSCLK_PHASE_OFFSET) |
- (CONFIG_HPS_SDRPLLGRP_DDR2XDQSCLK_CNT <<
- CLKMGR_SDRPLLGRP_DDR2XDQSCLK_CNT_OFFSET),
- (CONFIG_HPS_SDRPLLGRP_DDRDQCLK_PHASE <<
- CLKMGR_SDRPLLGRP_DDRDQCLK_PHASE_OFFSET) |
- (CONFIG_HPS_SDRPLLGRP_DDRDQCLK_CNT <<
- CLKMGR_SDRPLLGRP_DDRDQCLK_CNT_OFFSET),
- (CONFIG_HPS_SDRPLLGRP_S2FUSER2CLK_PHASE <<
- CLKMGR_SDRPLLGRP_S2FUSER2CLK_PHASE_OFFSET) |
- (CONFIG_HPS_SDRPLLGRP_S2FUSER2CLK_CNT <<
- CLKMGR_SDRPLLGRP_S2FUSER2CLK_CNT_OFFSET),
-
- };
-
debug("Freezing all I/O banks\n");
/* freeze all IO banks */
sys_mgr_frzctrl_freeze_req();
- socfpga_sdram_enable();
- socfpga_uart0_enable();
- socfpga_osc1timer_enable();
+ /* Put everything into reset but L4WD0. */
+ socfpga_per_reset_all();
+ /* Put FPGA bridges into reset too. */
+ socfpga_bridges_reset(1);
+
+ socfpga_per_reset(SOCFPGA_RESET(SDR), 0);
+ socfpga_per_reset(SOCFPGA_RESET(UART0), 0);
+ socfpga_per_reset(SOCFPGA_RESET(OSC1TIMER0), 0);
timer_init();
debug("Reconfigure Clock Manager\n");
/* reconfigure the PLLs */
- cm_basic_init(&cm_default_cfg);
+ cm_basic_init(cm_default_cfg);
/* Enable bootrom to configure IOs. */
- sysmgr_enable_warmrstcfgio();
+ sysmgr_config_warmrstcfgio(1);
/* configure the IOCSR / IO buffer settings */
if (scan_mgr_configure_iocsr())
hang();
+ sysmgr_config_warmrstcfgio(0);
+
/* configure the pin muxing through system manager */
+ sysmgr_config_warmrstcfgio(1);
sysmgr_pinmux_init();
+ sysmgr_config_warmrstcfgio(0);
+
#endif /* CONFIG_SOCFPGA_VIRTUAL_TARGET */
- /* de-assert reset for peripherals and bridges based on handoff */
+ /* De-assert reset for peripherals and bridges based on handoff */
reset_deassert_peripherals_handoff();
+ socfpga_bridges_reset(0);
debug("Unfreezing/Thaw all I/O banks\n");
/* unfreeze / thaw all IO banks */
@@ -226,4 +175,11 @@ void spl_board_init(void)
puts("SDRAM size check failed!\n");
hang();
}
+
+ socfpga_bridges_reset(1);
+
+ /* Configure simple malloc base pointer into RAM. */
+ gd->malloc_base = CONFIG_SYS_TEXT_BASE + (1024 * 1024);
+
+ board_init_r(NULL, 0);
}
diff --git a/arch/arm/mach-socfpga/system_manager.c b/arch/arm/mach-socfpga/system_manager.c
index 8126e0d43cf..744ec326b49 100644
--- a/arch/arm/mach-socfpga/system_manager.c
+++ b/arch/arm/mach-socfpga/system_manager.c
@@ -57,9 +57,13 @@ static void populate_sysmgr_fpgaintf_module(void)
void sysmgr_pinmux_init(void)
{
uint32_t regs = (uint32_t)&sysmgr_regs->emacio[0];
+ const unsigned long *sys_mgr_init_table;
+ unsigned int len;
int i;
- for (i = 0; i < ARRAY_SIZE(sys_mgr_init_table); i++) {
+ sysmgr_get_pinmux_table(&sys_mgr_init_table, &len);
+
+ for (i = 0; i < len; i++) {
writel(sys_mgr_init_table[i], regs);
regs += sizeof(regs);
}
@@ -70,8 +74,12 @@ void sysmgr_pinmux_init(void)
/*
* This bit allows the bootrom to configure the IOs after a warm reset.
*/
-void sysmgr_enable_warmrstcfgio(void)
+void sysmgr_config_warmrstcfgio(int enable)
{
- setbits_le32(&sysmgr_regs->romcodegrp_ctrl,
- SYSMGR_ROMCODEGRP_CTRL_WARMRSTCFGIO);
+ if (enable)
+ setbits_le32(&sysmgr_regs->romcodegrp_ctrl,
+ SYSMGR_ROMCODEGRP_CTRL_WARMRSTCFGIO);
+ else
+ clrbits_le32(&sysmgr_regs->romcodegrp_ctrl,
+ SYSMGR_ROMCODEGRP_CTRL_WARMRSTCFGIO);
}
diff --git a/arch/arm/mach-socfpga/u-boot-spl.lds b/arch/arm/mach-socfpga/u-boot-spl.lds
deleted file mode 100644
index 569fa418f46..00000000000
--- a/arch/arm/mach-socfpga/u-boot-spl.lds
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2012 Altera Corporation <www.altera.com>
- *
- * SPDX-License-Identifier: GPL-2.0+
- */
-
-MEMORY { .sdram : ORIGIN = (0), LENGTH = (0xffffffff) }
-
-OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
-OUTPUT_ARCH(arm)
-ENTRY(_start)
-SECTIONS
-{
- . = 0x00000000;
-
- . = ALIGN(4);
- .text :
- {
- *(.vectors)
- arch/arm/cpu/armv7/start.o (.text*)
- *(.text*)
- } >.sdram
-
- . = ALIGN(4);
- .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } >.sdram
-
- . = ALIGN(4);
- .data : { *(SORT_BY_ALIGNMENT(.data*)) } >.sdram
-
- . = ALIGN(4);
- __image_copy_end = .;
-
- .end :
- {
- *(.__end)
- }
-
- .bss : {
- . = ALIGN(4);
- __bss_start = .;
- *(.bss*)
- . = ALIGN(4);
- __bss_end = .;
- } >.sdram
-}
diff --git a/board/altera/socfpga/Makefile b/board/altera/socfpga/Makefile
index c867f73ff7e..5a15c716106 100644
--- a/board/altera/socfpga/Makefile
+++ b/board/altera/socfpga/Makefile
@@ -6,5 +6,6 @@
# SPDX-License-Identifier: GPL-2.0+
#
-obj-y := socfpga.o
-obj-$(CONFIG_SPL_BUILD) += pinmux_config.o iocsr_config.o
+obj-y := socfpga.o wrap_pll_config.o
+obj-$(CONFIG_SPL_BUILD) += wrap_iocsr_config.o wrap_pinmux_config.o \
+ wrap_sdram_config.o
diff --git a/board/altera/socfpga/iocsr_config.c b/board/altera/socfpga/qts/iocsr_config.c
index 3b202b5b687..3b202b5b687 100644
--- a/board/altera/socfpga/iocsr_config.c
+++ b/board/altera/socfpga/qts/iocsr_config.c
diff --git a/board/altera/socfpga/iocsr_config.h b/board/altera/socfpga/qts/iocsr_config.h
index d1c9b0d36a0..d1c9b0d36a0 100644
--- a/board/altera/socfpga/iocsr_config.h
+++ b/board/altera/socfpga/qts/iocsr_config.h
diff --git a/board/altera/socfpga/pinmux_config.c b/board/altera/socfpga/qts/pinmux_config.c
index 7e7a18484fd..7e7a18484fd 100644
--- a/board/altera/socfpga/pinmux_config.c
+++ b/board/altera/socfpga/qts/pinmux_config.c
diff --git a/board/altera/socfpga/pinmux_config.h b/board/altera/socfpga/qts/pinmux_config.h
index 21fabb0b2b4..21fabb0b2b4 100644
--- a/board/altera/socfpga/pinmux_config.h
+++ b/board/altera/socfpga/qts/pinmux_config.h
diff --git a/board/altera/socfpga/pll_config.h b/board/altera/socfpga/qts/pll_config.h
index 7cd25df6145..7cd25df6145 100644
--- a/board/altera/socfpga/pll_config.h
+++ b/board/altera/socfpga/qts/pll_config.h
diff --git a/board/altera/socfpga/qts/sdram_config.h b/board/altera/socfpga/qts/sdram_config.h
new file mode 100644
index 00000000000..f6d51ca8efb
--- /dev/null
+++ b/board/altera/socfpga/qts/sdram_config.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright Altera Corporation (C) 2012-2015
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+/* This file is autogenerated from tools provided by Altera.*/
+#ifndef __SDRAM_CONFIG_H
+#define __SDRAM_CONFIG_H
+
+#define CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_MEMTYPE 2
+#define CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_MEMBL 8
+#define CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_ADDRORDER 0
+#define CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_ECCEN 1
+#define CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_ECCCORREN 1
+#define CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_REORDEREN 1
+#define CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_STARVELIMIT 10
+#define CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_DQSTRKEN 0
+#define CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_NODMPINS 0
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING1_TCWL 6
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING1_AL 0
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING1_TCL 7
+#ifdef CONFIG_SOCFPGA_ARRIA5
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING1_TRRD 4
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING1_TFAW 19
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING1_TRFC 139
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TREFI 4160
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TRCD 8
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TRP 8
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TWR 8
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TWTR 4
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING3_TRTP 4
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING3_TRAS 19
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING3_TRC 26
+#else
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING1_TRRD 3
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING1_TFAW 14
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING1_TRFC 104
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TREFI 3120
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TRCD 6
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TRP 6
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TWR 6
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TWTR 4
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING3_TRTP 3
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING3_TRAS 14
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING3_TRC 20
+#endif /* CONFIG_SOCFPGA_ARRIA5 */
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING3_TMRD 4
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING3_TCCD 4
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING4_SELFRFSHEXIT 512
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING4_PWRDOWNEXIT 3
+#define CONFIG_HPS_SDR_CTRLCFG_LOWPWRTIMING_AUTOPDCYCLES 0
+#define CONFIG_HPS_SDR_CTRLCFG_LOWPWRTIMING_CLKDISABLECYCLES 8
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMADDRW_COLBITS 10
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMADDRW_ROWBITS 15
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMADDRW_BANKBITS 3
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMADDRW_CSBITS 1
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMIFWIDTH_IFWIDTH 40
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMDEVWIDTH_DEVWIDTH 8
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMINTR_INTREN 0
+#define CONFIG_HPS_SDR_CTRLCFG_LOWPWREQ_SELFRFSHMASK 3
+#define CONFIG_HPS_SDR_CTRLCFG_STATICCFG_MEMBL 2
+#define CONFIG_HPS_SDR_CTRLCFG_STATICCFG_USEECCASDATA 0
+#define CONFIG_HPS_SDR_CTRLCFG_CTRLWIDTH_CTRLWIDTH 2
+#define CONFIG_HPS_SDR_CTRLCFG_PORTCFG_AUTOPCHEN 0
+#define CONFIG_HPS_SDR_CTRLCFG_FIFOCFG_SYNCMODE 0
+#define CONFIG_HPS_SDR_CTRLCFG_FIFOCFG_INCSYNC 0
+#define CONFIG_HPS_SDR_CTRLCFG_MPPRIORITY_USERPRIORITY 0x3FFD1088
+#define CONFIG_HPS_SDR_CTRLCFG_MPWIEIGHT_0_STATICWEIGHT_31_0 0x21084210
+#define CONFIG_HPS_SDR_CTRLCFG_MPWIEIGHT_1_STATICWEIGHT_49_32 0x1EF84
+#define CONFIG_HPS_SDR_CTRLCFG_MPWIEIGHT_1_SUMOFWEIGHT_13_0 0x2020
+#define CONFIG_HPS_SDR_CTRLCFG_MPWIEIGHT_2_SUMOFWEIGHT_45_14 0x0
+#define CONFIG_HPS_SDR_CTRLCFG_MPWIEIGHT_3_SUMOFWEIGHT_63_46 0xF800
+#define CONFIG_HPS_SDR_CTRLCFG_PHYCTRL_PHYCTRL_0 0x200
+
+#define CONFIG_HPS_SDR_CTRLCFG_CPORTWIDTH_CPORTWIDTH 0x44555
+#define CONFIG_HPS_SDR_CTRLCFG_CPORTWMAP_CPORTWMAP 0x2C011000
+#define CONFIG_HPS_SDR_CTRLCFG_CPORTRMAP_CPORTRMAP 0xB00088
+#define CONFIG_HPS_SDR_CTRLCFG_RFIFOCMAP_RFIFOCMAP 0x760210
+#define CONFIG_HPS_SDR_CTRLCFG_WFIFOCMAP_WFIFOCMAP 0x980543
+#define CONFIG_HPS_SDR_CTRLCFG_CPORTRDWR_CPORTRDWR 0x5A56A
+#define CONFIG_HPS_SDR_CTRLCFG_MPPACING_0_THRESHOLD1_31_0 0x20820820
+#define CONFIG_HPS_SDR_CTRLCFG_MPPACING_1_THRESHOLD1_59_32 0x8208208
+#define CONFIG_HPS_SDR_CTRLCFG_MPPACING_1_THRESHOLD2_3_0 0
+#define CONFIG_HPS_SDR_CTRLCFG_MPPACING_2_THRESHOLD2_35_4 0x41041041
+#define CONFIG_HPS_SDR_CTRLCFG_MPPACING_3_THRESHOLD2_59_36 0x410410
+#define CONFIG_HPS_SDR_CTRLCFG_MPTHRESHOLDRST_0_THRESHOLDRSTCYCLES_31_0 \
+0x01010101
+#define CONFIG_HPS_SDR_CTRLCFG_MPTHRESHOLDRST_1_THRESHOLDRSTCYCLES_63_32 \
+0x01010101
+#define CONFIG_HPS_SDR_CTRLCFG_MPTHRESHOLDRST_2_THRESHOLDRSTCYCLES_79_64 \
+0x0101
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMODT_READ 0
+#define CONFIG_HPS_SDR_CTRLCFG_DRAMODT_WRITE 1
+#define CONFIG_HPS_SDR_CTRLCFG_FPGAPORTRST_READ_PORT_USED 0
+#define CONFIG_HPS_SDR_CTRLCFG_FPGAPORTRST_WRITE_PORT_USED 0
+#define CONFIG_HPS_SDR_CTRLCFG_FPGAPORTRST_COMMAND_PORT_USED 0
+#define CONFIG_HPS_SDR_CTRLCFG_FPGAPORTRST 0
+
+#endif /*#ifndef__SDRAM_CONFIG_H*/
diff --git a/board/altera/socfpga/qts/sequencer_auto.h b/board/altera/socfpga/qts/sequencer_auto.h
new file mode 100644
index 00000000000..0c5d83bbdff
--- /dev/null
+++ b/board/altera/socfpga/qts/sequencer_auto.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright Altera Corporation (C) 2012-2015
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+
+#define RW_MGR_READ_B2B_WAIT2 0x6A
+#define RW_MGR_LFSR_WR_RD_BANK_0_WAIT 0x31
+#define RW_MGR_REFRESH_ALL 0x14
+#define RW_MGR_ZQCL 0x06
+#define RW_MGR_LFSR_WR_RD_BANK_0_NOP 0x22
+#define RW_MGR_LFSR_WR_RD_BANK_0_DQS 0x23
+#define RW_MGR_ACTIVATE_0_AND_1 0x0D
+#define RW_MGR_MRS2_MIRR 0x0A
+#define RW_MGR_INIT_RESET_0_CKE_0 0x6E
+#define RW_MGR_LFSR_WR_RD_DM_BANK_0_WAIT 0x45
+#define RW_MGR_ACTIVATE_1 0x0F
+#define RW_MGR_MRS2 0x04
+#define RW_MGR_LFSR_WR_RD_DM_BANK_0_WL_1 0x34
+#define RW_MGR_MRS1 0x03
+#ifdef CONFIG_SOCFPGA_ARRIA5
+/* The if..else... is not required if generated by tools */
+#define RW_MGR_IDLE_LOOP1 0x7A
+#else
+#define RW_MGR_IDLE_LOOP1 0x7C
+#endif /* CONFIG_SOCFPGA_ARRIA5 */
+#define RW_MGR_GUARANTEED_WRITE_WAIT2 0x18
+#define RW_MGR_MRS3 0x05
+#ifdef CONFIG_SOCFPGA_ARRIA5
+/* The if..else... is not required if generated by tools */
+#define RW_MGR_IDLE_LOOP2 0x79
+#else
+#define RW_MGR_IDLE_LOOP2 0x7B
+#endif /* CONFIG_SOCFPGA_ARRIA5 */
+#define RW_MGR_GUARANTEED_WRITE_WAIT1 0x1E
+#define RW_MGR_LFSR_WR_RD_BANK_0_DATA 0x24
+#define RW_MGR_GUARANTEED_WRITE_WAIT3 0x1C
+#ifdef CONFIG_SOCFPGA_ARRIA5
+/* The if..else... is not required if generated by tools */
+#define RW_MGR_RDIMM_CMD 0x78
+#else
+#define RW_MGR_RDIMM_CMD 0x7A
+#endif /* CONFIG_SOCFPGA_ARRIA5 */
+#define RW_MGR_LFSR_WR_RD_DM_BANK_0_NOP 0x36
+#define RW_MGR_GUARANTEED_WRITE_WAIT0 0x1A
+#define RW_MGR_LFSR_WR_RD_DM_BANK_0_DATA 0x38
+#define RW_MGR_GUARANTEED_READ_CONT 0x53
+#define RW_MGR_MRS3_MIRR 0x0B
+#define RW_MGR_IDLE 0x00
+#define RW_MGR_READ_B2B 0x58
+#define RW_MGR_INIT_RESET_0_CKE_0_inloop 0x6F
+#define RW_MGR_LFSR_WR_RD_DM_BANK_0_DQS 0x37
+#define RW_MGR_GUARANTEED_WRITE 0x17
+#define RW_MGR_PRECHARGE_ALL 0x12
+#define RW_MGR_INIT_RESET_1_CKE_0_inloop_1 0x74
+#ifdef CONFIG_SOCFPGA_ARRIA5
+/* The if..else... is not required if generated by tools */
+#define RW_MGR_SGLE_READ 0x7C
+#else
+#define RW_MGR_SGLE_READ 0x7E
+#endif /* CONFIG_SOCFPGA_ARRIA5 */
+#define RW_MGR_MRS0_USER_MIRR 0x0C
+#define RW_MGR_RETURN 0x01
+#define RW_MGR_LFSR_WR_RD_DM_BANK_0 0x35
+#define RW_MGR_MRS0_USER 0x07
+#define RW_MGR_GUARANTEED_READ 0x4B
+#define RW_MGR_MRS0_DLL_RESET_MIRR 0x08
+#define RW_MGR_INIT_RESET_1_CKE_0 0x73
+#define RW_MGR_ACTIVATE_0_AND_1_WAIT2 0x10
+#define RW_MGR_LFSR_WR_RD_BANK_0_WL_1 0x20
+#define RW_MGR_MRS0_DLL_RESET 0x02
+#define RW_MGR_ACTIVATE_0_AND_1_WAIT1 0x0E
+#define RW_MGR_LFSR_WR_RD_BANK_0 0x21
+#define RW_MGR_CLEAR_DQS_ENABLE 0x48
+#define RW_MGR_MRS1_MIRR 0x09
+#define RW_MGR_READ_B2B_WAIT1 0x60
+#define RW_MGR_CONTENT_READ_B2B_WAIT2 0x00C680
+#define RW_MGR_CONTENT_LFSR_WR_RD_BANK_0_WAIT 0x00A680
+#define RW_MGR_CONTENT_REFRESH_ALL 0x000980
+#define RW_MGR_CONTENT_ZQCL 0x008380
+#define RW_MGR_CONTENT_LFSR_WR_RD_BANK_0_NOP 0x00E700
+#define RW_MGR_CONTENT_LFSR_WR_RD_BANK_0_DQS 0x000C00
+#define RW_MGR_CONTENT_ACTIVATE_0_AND_1 0x000800
+#define RW_MGR_CONTENT_MRS2_MIRR 0x008580
+#define RW_MGR_CONTENT_INIT_RESET_0_CKE_0 0x000000
+#define RW_MGR_CONTENT_LFSR_WR_RD_DM_BANK_0_WAIT 0x00A680
+#define RW_MGR_CONTENT_ACTIVATE_1 0x000880
+#define RW_MGR_CONTENT_MRS2 0x008280
+#define RW_MGR_CONTENT_LFSR_WR_RD_DM_BANK_0_WL_1 0x00CE00
+#define RW_MGR_CONTENT_MRS1 0x008200
+#define RW_MGR_CONTENT_IDLE_LOOP1 0x00A680
+#define RW_MGR_CONTENT_GUARANTEED_WRITE_WAIT2 0x00CCE8
+#define RW_MGR_CONTENT_MRS3 0x008300
+#define RW_MGR_CONTENT_IDLE_LOOP2 0x008680
+#define RW_MGR_CONTENT_GUARANTEED_WRITE_WAIT1 0x00AC88
+#define RW_MGR_CONTENT_LFSR_WR_RD_BANK_0_DATA 0x020CE0
+#define RW_MGR_CONTENT_GUARANTEED_WRITE_WAIT3 0x00EC88
+#define RW_MGR_CONTENT_RDIMM_CMD 0x009180
+#define RW_MGR_CONTENT_LFSR_WR_RD_DM_BANK_0_NOP 0x00E700
+#define RW_MGR_CONTENT_GUARANTEED_WRITE_WAIT0 0x008CE8
+#define RW_MGR_CONTENT_LFSR_WR_RD_DM_BANK_0_DATA 0x030CE0
+#define RW_MGR_CONTENT_GUARANTEED_READ_CONT 0x001168
+#define RW_MGR_CONTENT_MRS3_MIRR 0x008600
+#define RW_MGR_CONTENT_IDLE 0x080000
+#define RW_MGR_CONTENT_READ_B2B 0x040E88
+#define RW_MGR_CONTENT_INIT_RESET_0_CKE_0_inloop 0x000000
+#define RW_MGR_CONTENT_LFSR_WR_RD_DM_BANK_0_DQS 0x000C00
+#define RW_MGR_CONTENT_GUARANTEED_WRITE 0x000B68
+#define RW_MGR_CONTENT_PRECHARGE_ALL 0x000900
+#define RW_MGR_CONTENT_INIT_RESET_1_CKE_0_inloop_1 0x000080
+#define RW_MGR_CONTENT_SGLE_READ 0x040F08
+#define RW_MGR_CONTENT_MRS0_USER_MIRR 0x008400
+#define RW_MGR_CONTENT_RETURN 0x080680
+#define RW_MGR_CONTENT_LFSR_WR_RD_DM_BANK_0 0x00CD80
+#define RW_MGR_CONTENT_MRS0_USER 0x008100
+#define RW_MGR_CONTENT_GUARANTEED_READ 0x001168
+#define RW_MGR_CONTENT_MRS0_DLL_RESET_MIRR 0x008480
+#define RW_MGR_CONTENT_INIT_RESET_1_CKE_0 0x000080
+#define RW_MGR_CONTENT_ACTIVATE_0_AND_1_WAIT2 0x00A680
+#define RW_MGR_CONTENT_LFSR_WR_RD_BANK_0_WL_1 0x00CE00
+#define RW_MGR_CONTENT_MRS0_DLL_RESET 0x008180
+#define RW_MGR_CONTENT_ACTIVATE_0_AND_1_WAIT1 0x008680
+#define RW_MGR_CONTENT_LFSR_WR_RD_BANK_0 0x00CD80
+#define RW_MGR_CONTENT_CLEAR_DQS_ENABLE 0x001158
+#define RW_MGR_CONTENT_MRS1_MIRR 0x008500
+#define RW_MGR_CONTENT_READ_B2B_WAIT1 0x00A680
+
diff --git a/board/altera/socfpga/qts/sequencer_auto_ac_init.h b/board/altera/socfpga/qts/sequencer_auto_ac_init.h
new file mode 100644
index 00000000000..c46421b2120
--- /dev/null
+++ b/board/altera/socfpga/qts/sequencer_auto_ac_init.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright Altera Corporation (C) 2012-2015
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+const uint32_t ac_rom_init[] = {
+#ifdef CONFIG_SOCFPGA_ARRIA5
+/* The if..else... is not required if generated by tools */
+ 0x20700000,
+ 0x20780000,
+ 0x10080831,
+ 0x10080930,
+ 0x10090004,
+ 0x100a0008,
+ 0x100b0000,
+ 0x10380400,
+ 0x10080849,
+ 0x100808c8,
+ 0x100a0004,
+ 0x10090010,
+ 0x100b0000,
+ 0x30780000,
+ 0x38780000,
+ 0x30780000,
+ 0x10680000,
+ 0x106b0000,
+ 0x10280400,
+ 0x10480000,
+ 0x1c980000,
+ 0x1c9b0000,
+ 0x1c980008,
+ 0x1c9b0008,
+ 0x38f80000,
+ 0x3cf80000,
+ 0x38780000,
+ 0x18180000,
+ 0x18980000,
+ 0x13580000,
+ 0x135b0000,
+ 0x13580008,
+ 0x135b0008,
+ 0x33780000,
+ 0x10580008,
+ 0x10780000
+#else
+ 0x20700000,
+ 0x20780000,
+ 0x10080431,
+ 0x10080530,
+ 0x10090004,
+ 0x100a0008,
+ 0x100b0000,
+ 0x10380400,
+ 0x10080449,
+ 0x100804c8,
+ 0x100a0004,
+ 0x10090010,
+ 0x100b0000,
+ 0x30780000,
+ 0x38780000,
+ 0x30780000,
+ 0x10680000,
+ 0x106b0000,
+ 0x10280400,
+ 0x10480000,
+ 0x1c980000,
+ 0x1c9b0000,
+ 0x1c980008,
+ 0x1c9b0008,
+ 0x38f80000,
+ 0x3cf80000,
+ 0x38780000,
+ 0x18180000,
+ 0x18980000,
+ 0x13580000,
+ 0x135b0000,
+ 0x13580008,
+ 0x135b0008,
+ 0x33780000,
+ 0x10580008,
+ 0x10780000
+#endif /* CONFIG_SOCFPGA_ARRIA5 */
+};
diff --git a/board/altera/socfpga/qts/sequencer_auto_inst_init.h b/board/altera/socfpga/qts/sequencer_auto_inst_init.h
new file mode 100644
index 00000000000..ad0395b4961
--- /dev/null
+++ b/board/altera/socfpga/qts/sequencer_auto_inst_init.h
@@ -0,0 +1,268 @@
+/*
+ * Copyright Altera Corporation (C) 2012-2015
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifdef CONFIG_SOCFPGA_ARRIA5
+/* The if..else... is not required if generated by tools */
+const u32 inst_rom_init[] = {
+ 0x80000,
+ 0x80680,
+ 0x8180,
+ 0x8200,
+ 0x8280,
+ 0x8300,
+ 0x8380,
+ 0x8100,
+ 0x8480,
+ 0x8500,
+ 0x8580,
+ 0x8600,
+ 0x8400,
+ 0x800,
+ 0x8680,
+ 0x880,
+ 0xa680,
+ 0x80680,
+ 0x900,
+ 0x80680,
+ 0x980,
+ 0x8680,
+ 0x80680,
+ 0xb68,
+ 0xcce8,
+ 0xae8,
+ 0x8ce8,
+ 0xb88,
+ 0xec88,
+ 0xa08,
+ 0xac88,
+ 0x80680,
+ 0xce00,
+ 0xcd80,
+ 0xe700,
+ 0xc00,
+ 0x20ce0,
+ 0x20ce0,
+ 0x20ce0,
+ 0x20ce0,
+ 0xd00,
+ 0x680,
+ 0x680,
+ 0x680,
+ 0x680,
+ 0x60e80,
+ 0x61080,
+ 0x61080,
+ 0x61080,
+ 0xa680,
+ 0x8680,
+ 0x80680,
+ 0xce00,
+ 0xcd80,
+ 0xe700,
+ 0xc00,
+ 0x30ce0,
+ 0x30ce0,
+ 0x30ce0,
+ 0x30ce0,
+ 0xd00,
+ 0x680,
+ 0x680,
+ 0x680,
+ 0x680,
+ 0x70e80,
+ 0x71080,
+ 0x71080,
+ 0x71080,
+ 0xa680,
+ 0x8680,
+ 0x80680,
+ 0x1158,
+ 0x6d8,
+ 0x80680,
+ 0x1168,
+ 0x7e8,
+ 0x7e8,
+ 0x87e8,
+ 0x40fe8,
+ 0x410e8,
+ 0x410e8,
+ 0x410e8,
+ 0x1168,
+ 0x7e8,
+ 0x7e8,
+ 0xa7e8,
+ 0x80680,
+ 0x40e88,
+ 0x41088,
+ 0x41088,
+ 0x41088,
+ 0x40f68,
+ 0x410e8,
+ 0x410e8,
+ 0x410e8,
+ 0xa680,
+ 0x40fe8,
+ 0x410e8,
+ 0x410e8,
+ 0x410e8,
+ 0x41008,
+ 0x41088,
+ 0x41088,
+ 0x41088,
+ 0x1100,
+ 0xc680,
+ 0x8680,
+ 0xe680,
+ 0x80680,
+ 0x0,
+ 0x8000,
+ 0xa000,
+ 0xc000,
+ 0x80000,
+ 0x80,
+ 0x8080,
+ 0xa080,
+ 0xc080,
+ 0x80080,
+ 0x9180,
+ 0x8680,
+ 0xa680,
+ 0x80680,
+ 0x40f08,
+ 0x80680
+};
+#else
+const u32 inst_rom_init[] = {
+ 0x80000,
+ 0x80680,
+ 0x8180,
+ 0x8200,
+ 0x8280,
+ 0x8300,
+ 0x8380,
+ 0x8100,
+ 0x8480,
+ 0x8500,
+ 0x8580,
+ 0x8600,
+ 0x8400,
+ 0x800,
+ 0x8680,
+ 0x880,
+ 0xa680,
+ 0x80680,
+ 0x900,
+ 0x80680,
+ 0x980,
+ 0x8680,
+ 0x80680,
+ 0xb68,
+ 0xcce8,
+ 0xae8,
+ 0x8ce8,
+ 0xb88,
+ 0xec88,
+ 0xa08,
+ 0xac88,
+ 0x80680,
+ 0xce00,
+ 0xcd80,
+ 0xe700,
+ 0xc00,
+ 0x20ce0,
+ 0x20ce0,
+ 0x20ce0,
+ 0x20ce0,
+ 0xd00,
+ 0x680,
+ 0x680,
+ 0x680,
+ 0x680,
+ 0x60e80,
+ 0x61080,
+ 0x61080,
+ 0x61080,
+ 0xa680,
+ 0x8680,
+ 0x80680,
+ 0xce00,
+ 0xcd80,
+ 0xe700,
+ 0xc00,
+ 0x30ce0,
+ 0x30ce0,
+ 0x30ce0,
+ 0x30ce0,
+ 0xd00,
+ 0x680,
+ 0x680,
+ 0x680,
+ 0x680,
+ 0x70e80,
+ 0x71080,
+ 0x71080,
+ 0x71080,
+ 0xa680,
+ 0x8680,
+ 0x80680,
+ 0x1158,
+ 0x6d8,
+ 0x80680,
+ 0x1168,
+ 0x7e8,
+ 0x7e8,
+ 0x87e8,
+ 0x40fe8,
+ 0x410e8,
+ 0x410e8,
+ 0x410e8,
+ 0x1168,
+ 0x7e8,
+ 0x7e8,
+ 0xa7e8,
+ 0x80680,
+ 0x40e88,
+ 0x41088,
+ 0x41088,
+ 0x41088,
+ 0x40f68,
+ 0x410e8,
+ 0x410e8,
+ 0x410e8,
+ 0xa680,
+ 0x40fe8,
+ 0x410e8,
+ 0x410e8,
+ 0x410e8,
+ 0x41008,
+ 0x41088,
+ 0x41088,
+ 0x41088,
+ 0x1100,
+ 0xc680,
+ 0x8680,
+ 0xe680,
+ 0x80680,
+ 0x0,
+ 0x0,
+ 0xa000,
+ 0x8000,
+ 0x80000,
+ 0x80,
+ 0x80,
+ 0x80,
+ 0x80,
+ 0xa080,
+ 0x8080,
+ 0x80080,
+ 0x9180,
+ 0x8680,
+ 0xa680,
+ 0x80680,
+ 0x40f08,
+ 0x80680
+};
+#endif /* CONFIG_SOCFPGA_ARRIA5 */
diff --git a/board/altera/socfpga/qts/sequencer_defines.h b/board/altera/socfpga/qts/sequencer_defines.h
new file mode 100644
index 00000000000..bfe5b2719fd
--- /dev/null
+++ b/board/altera/socfpga/qts/sequencer_defines.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright Altera Corporation (C) 2012-2015
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _SEQUENCER_DEFINES_H_
+#define _SEQUENCER_DEFINES_H_
+
+#define AC_ROM_MR1_MIRR 0000000000100
+#define AC_ROM_MR1_OCD_ENABLE
+#define AC_ROM_MR2_MIRR 0000000010000
+#define AC_ROM_MR3_MIRR 0000000000000
+#define AC_ROM_MR0_CALIB
+#ifdef CONFIG_SOCFPGA_ARRIA5
+/* The if..else... is not required if generated by tools */
+#define AC_ROM_MR0_DLL_RESET_MIRR 0100011001000
+#define AC_ROM_MR0_DLL_RESET 0100100110000
+#define AC_ROM_MR0_MIRR 0100001001001
+#define AC_ROM_MR0 0100000110001
+#else
+#define AC_ROM_MR0_DLL_RESET_MIRR 0010011001000
+#define AC_ROM_MR0_DLL_RESET 0010100110000
+#define AC_ROM_MR0_MIRR 0010001001001
+#define AC_ROM_MR0 0010000110001
+#endif /* CONFIG_SOCFPGA_ARRIA5 */
+#define AC_ROM_MR1 0000000000100
+#define AC_ROM_MR2 0000000001000
+#define AC_ROM_MR3 0000000000000
+#ifdef CONFIG_SOCFPGA_ARRIA5
+/* The if..else... is not required if generated by tools */
+#define AFI_CLK_FREQ 534
+#else
+#define AFI_CLK_FREQ 401
+#endif /* CONFIG_SOCFPGA_ARRIA5 */
+#define AFI_RATE_RATIO 1
+#define AVL_CLK_FREQ 67
+#define BFM_MODE 0
+#define BURST2 0
+#ifdef CONFIG_SOCFPGA_ARRIA5
+/* The if..else... is not required if generated by tools */
+#define CALIB_LFIFO_OFFSET 8
+#define CALIB_VFIFO_OFFSET 6
+#else
+#define CALIB_LFIFO_OFFSET 7
+#define CALIB_VFIFO_OFFSET 5
+#endif /* CONFIG_SOCFPGA_ARRIA5 */
+#define ENABLE_EXPORT_SEQ_DEBUG_BRIDGE 0
+#define ENABLE_SUPER_QUICK_CALIBRATION 0
+#define GUARANTEED_READ_BRINGUP_TEST 0
+#define HARD_PHY 1
+#define HARD_VFIFO 1
+#define HPS_HW 1
+#define HR_DDIO_OUT_HAS_THREE_REGS 0
+#define IO_DELAY_PER_DCHAIN_TAP 25
+#define IO_DELAY_PER_DQS_EN_DCHAIN_TAP 25
+#ifdef CONFIG_SOCFPGA_ARRIA5
+/* The if..else... is not required if generated by tools */
+#define IO_DELAY_PER_OPA_TAP 234
+#else
+#define IO_DELAY_PER_OPA_TAP 312
+#endif /* CONFIG_SOCFPGA_ARRIA5 */
+#define IO_DLL_CHAIN_LENGTH 8
+#define IO_DM_OUT_RESERVE 0
+#define IO_DQDQS_OUT_PHASE_MAX 0
+#ifdef CONFIG_SOCFPGA_ARRIA5
+/* The if..else... is not required if generated by tools */
+#define IO_DQS_EN_DELAY_MAX 15
+#define IO_DQS_EN_DELAY_OFFSET 16
+#else
+#define IO_DQS_EN_DELAY_MAX 31
+#define IO_DQS_EN_DELAY_OFFSET 0
+#endif /* CONFIG_SOCFPGA_ARRIA5 */
+#define IO_DQS_EN_PHASE_MAX 7
+#define IO_DQS_IN_DELAY_MAX 31
+#define IO_DQS_IN_RESERVE 4
+#define IO_DQS_OUT_RESERVE 6
+#define IO_DQ_OUT_RESERVE 0
+#define IO_IO_IN_DELAY_MAX 31
+#define IO_IO_OUT1_DELAY_MAX 31
+#define IO_IO_OUT2_DELAY_MAX 0
+#define IO_SHIFT_DQS_EN_WHEN_SHIFT_DQS 0
+#define MARGIN_VARIATION_TEST 0
+#define MAX_LATENCY_COUNT_WIDTH 5
+#define MEM_ADDR_WIDTH 13
+#define READ_VALID_FIFO_SIZE 16
+#ifdef CONFIG_SOCFPGA_ARRIA5
+/* The if..else... is not required if generated by tools */
+#define REG_FILE_INIT_SEQ_SIGNATURE 0x5555048c
+#else
+#define REG_FILE_INIT_SEQ_SIGNATURE 0x55550483
+#endif /* CONFIG_SOCFPGA_ARRIA5 */
+#define RW_MGR_MEM_ADDRESS_MIRRORING 0
+#define RW_MGR_MEM_ADDRESS_WIDTH 15
+#define RW_MGR_MEM_BANK_WIDTH 3
+#define RW_MGR_MEM_CHIP_SELECT_WIDTH 1
+#define RW_MGR_MEM_CLK_EN_WIDTH 1
+#define RW_MGR_MEM_CONTROL_WIDTH 1
+#define RW_MGR_MEM_DATA_MASK_WIDTH 5
+#define RW_MGR_MEM_DATA_WIDTH 40
+#define RW_MGR_MEM_DQ_PER_READ_DQS 8
+#define RW_MGR_MEM_DQ_PER_WRITE_DQS 8
+#define RW_MGR_MEM_IF_READ_DQS_WIDTH 5
+#define RW_MGR_MEM_IF_WRITE_DQS_WIDTH 5
+#define RW_MGR_MEM_NUMBER_OF_CS_PER_DIMM 1
+#define RW_MGR_MEM_NUMBER_OF_RANKS 1
+#define RW_MGR_MEM_ODT_WIDTH 1
+#define RW_MGR_MEM_VIRTUAL_GROUPS_PER_READ_DQS 1
+#define RW_MGR_MEM_VIRTUAL_GROUPS_PER_WRITE_DQS 1
+#define RW_MGR_MR0_BL 1
+#define RW_MGR_MR0_CAS_LATENCY 3
+#define RW_MGR_TRUE_MEM_DATA_MASK_WIDTH 5
+#define RW_MGR_WRITE_TO_DEBUG_READ 1.0
+#define SKEW_CALIBRATION 0
+#define TINIT_CNTR1_VAL 32
+#define TINIT_CNTR2_VAL 32
+#define TINIT_CNTR0_VAL 132
+#define TRESET_CNTR1_VAL 99
+#define TRESET_CNTR2_VAL 10
+#define TRESET_CNTR0_VAL 132
+
+#endif /* _SEQUENCER_DEFINES_H_ */
diff --git a/board/altera/socfpga/wrap_iocsr_config.c b/board/altera/socfpga/wrap_iocsr_config.c
new file mode 100644
index 00000000000..49e922823f3
--- /dev/null
+++ b/board/altera/socfpga/wrap_iocsr_config.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015 Marek Vasut <marex@denx.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <asm/arch/clock_manager.h>
+/*
+ * Yes, dear reader, we're including a C file here, this is no mistake :-)
+ */
+#include "qts/iocsr_config.c"
+
+int iocsr_get_config_table(const unsigned int chain_id,
+ const unsigned long **table,
+ unsigned int *table_len)
+{
+ switch (chain_id) {
+ case 0:
+ *table = iocsr_scan_chain0_table;
+ *table_len = CONFIG_HPS_IOCSR_SCANCHAIN0_LENGTH;
+ break;
+ case 1:
+ *table = iocsr_scan_chain1_table;
+ *table_len = CONFIG_HPS_IOCSR_SCANCHAIN1_LENGTH;
+ break;
+ case 2:
+ *table = iocsr_scan_chain2_table;
+ *table_len = CONFIG_HPS_IOCSR_SCANCHAIN2_LENGTH;
+ break;
+ case 3:
+ *table = iocsr_scan_chain3_table;
+ *table_len = CONFIG_HPS_IOCSR_SCANCHAIN3_LENGTH;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/board/altera/socfpga/wrap_pinmux_config.c b/board/altera/socfpga/wrap_pinmux_config.c
new file mode 100644
index 00000000000..b33e2cab824
--- /dev/null
+++ b/board/altera/socfpga/wrap_pinmux_config.c
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 Marek Vasut <marex@denx.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+/*
+ * Yes, dear reader, we're including a C file here, this is no mistake.
+ * But this time around, we do even more perverse hacking here to be
+ * compatible with QTS headers and obtain reasonably nice results too.
+ *
+ * First, we define _PRELOADER_PINMUX_CONFIG_H_, which will neutralise
+ * the pinmux_config.h inclusion in pinmux_config.c . Since we are
+ * probing everything from DT, we do NOT want those macros from the
+ * pinmux_config.h to ooze into our build system, anywhere, ever. So
+ * we nip it at the bud.
+ *
+ * Next, pinmux_config.c needs CONFIG_HPS_PINMUX_NUM and uses it to
+ * specify sized array explicitly. Instead, we want to use ARRAY_SIZE
+ * to figure out the size of the array, so define this macro as an
+ * empty one, so that the preprocessor optimizes things such that the
+ * arrays are not sized by default.
+ */
+#define _PRELOADER_PINMUX_CONFIG_H_
+#define CONFIG_HPS_PINMUX_NUM
+#include "qts/pinmux_config.c"
+
+void sysmgr_get_pinmux_table(const unsigned long **table,
+ unsigned int *table_len)
+{
+ *table = sys_mgr_init_table;
+ *table_len = ARRAY_SIZE(sys_mgr_init_table);
+}
diff --git a/board/altera/socfpga/wrap_pll_config.c b/board/altera/socfpga/wrap_pll_config.c
new file mode 100644
index 00000000000..8dbff68f5cc
--- /dev/null
+++ b/board/altera/socfpga/wrap_pll_config.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2015 Marek Vasut <marex@denx.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/arch/clock_manager.h>
+#include "qts/pll_config.h"
+
+#define MAIN_VCO_BASE ( \
+ (CONFIG_HPS_MAINPLLGRP_VCO_DENOM << \
+ CLKMGR_MAINPLLGRP_VCO_DENOM_OFFSET) | \
+ (CONFIG_HPS_MAINPLLGRP_VCO_NUMER << \
+ CLKMGR_MAINPLLGRP_VCO_NUMER_OFFSET) \
+ )
+
+#define PERI_VCO_BASE ( \
+ (CONFIG_HPS_PERPLLGRP_VCO_PSRC << \
+ CLKMGR_PERPLLGRP_VCO_PSRC_OFFSET) | \
+ (CONFIG_HPS_PERPLLGRP_VCO_DENOM << \
+ CLKMGR_PERPLLGRP_VCO_DENOM_OFFSET) | \
+ (CONFIG_HPS_PERPLLGRP_VCO_NUMER << \
+ CLKMGR_PERPLLGRP_VCO_NUMER_OFFSET) \
+ )
+
+#define SDR_VCO_BASE ( \
+ (CONFIG_HPS_SDRPLLGRP_VCO_SSRC << \
+ CLKMGR_SDRPLLGRP_VCO_SSRC_OFFSET) | \
+ (CONFIG_HPS_SDRPLLGRP_VCO_DENOM << \
+ CLKMGR_SDRPLLGRP_VCO_DENOM_OFFSET) | \
+ (CONFIG_HPS_SDRPLLGRP_VCO_NUMER << \
+ CLKMGR_SDRPLLGRP_VCO_NUMER_OFFSET) \
+ )
+
+static const struct cm_config cm_default_cfg = {
+ /* main group */
+ MAIN_VCO_BASE,
+ (CONFIG_HPS_MAINPLLGRP_MPUCLK_CNT <<
+ CLKMGR_MAINPLLGRP_MPUCLK_CNT_OFFSET),
+ (CONFIG_HPS_MAINPLLGRP_MAINCLK_CNT <<
+ CLKMGR_MAINPLLGRP_MAINCLK_CNT_OFFSET),
+ (CONFIG_HPS_MAINPLLGRP_DBGATCLK_CNT <<
+ CLKMGR_MAINPLLGRP_DBGATCLK_CNT_OFFSET),
+ (CONFIG_HPS_MAINPLLGRP_MAINQSPICLK_CNT <<
+ CLKMGR_MAINPLLGRP_MAINQSPICLK_CNT_OFFSET),
+ (CONFIG_HPS_MAINPLLGRP_MAINNANDSDMMCCLK_CNT <<
+ CLKMGR_PERPLLGRP_PERNANDSDMMCCLK_CNT_OFFSET),
+ (CONFIG_HPS_MAINPLLGRP_CFGS2FUSER0CLK_CNT <<
+ CLKMGR_MAINPLLGRP_CFGS2FUSER0CLK_CNT_OFFSET),
+ (CONFIG_HPS_MAINPLLGRP_MAINDIV_L3MPCLK <<
+ CLKMGR_MAINPLLGRP_MAINDIV_L3MPCLK_OFFSET) |
+ (CONFIG_HPS_MAINPLLGRP_MAINDIV_L3SPCLK <<
+ CLKMGR_MAINPLLGRP_MAINDIV_L3SPCLK_OFFSET) |
+ (CONFIG_HPS_MAINPLLGRP_MAINDIV_L4MPCLK <<
+ CLKMGR_MAINPLLGRP_MAINDIV_L4MPCLK_OFFSET) |
+ (CONFIG_HPS_MAINPLLGRP_MAINDIV_L4SPCLK <<
+ CLKMGR_MAINPLLGRP_MAINDIV_L4SPCLK_OFFSET),
+ (CONFIG_HPS_MAINPLLGRP_DBGDIV_DBGATCLK <<
+ CLKMGR_MAINPLLGRP_DBGDIV_DBGATCLK_OFFSET) |
+ (CONFIG_HPS_MAINPLLGRP_DBGDIV_DBGCLK <<
+ CLKMGR_MAINPLLGRP_DBGDIV_DBGCLK_OFFSET),
+ (CONFIG_HPS_MAINPLLGRP_TRACEDIV_TRACECLK <<
+ CLKMGR_MAINPLLGRP_TRACEDIV_TRACECLK_OFFSET),
+ (CONFIG_HPS_MAINPLLGRP_L4SRC_L4MP <<
+ CLKMGR_MAINPLLGRP_L4SRC_L4MP_OFFSET) |
+ (CONFIG_HPS_MAINPLLGRP_L4SRC_L4SP <<
+ CLKMGR_MAINPLLGRP_L4SRC_L4SP_OFFSET),
+
+ /* peripheral group */
+ PERI_VCO_BASE,
+ (CONFIG_HPS_PERPLLGRP_EMAC0CLK_CNT <<
+ CLKMGR_PERPLLGRP_EMAC0CLK_CNT_OFFSET),
+ (CONFIG_HPS_PERPLLGRP_EMAC1CLK_CNT <<
+ CLKMGR_PERPLLGRP_EMAC1CLK_CNT_OFFSET),
+ (CONFIG_HPS_PERPLLGRP_PERQSPICLK_CNT <<
+ CLKMGR_PERPLLGRP_PERQSPICLK_CNT_OFFSET),
+ (CONFIG_HPS_PERPLLGRP_PERNANDSDMMCCLK_CNT <<
+ CLKMGR_PERPLLGRP_PERNANDSDMMCCLK_CNT_OFFSET),
+ (CONFIG_HPS_PERPLLGRP_PERBASECLK_CNT <<
+ CLKMGR_PERPLLGRP_PERBASECLK_CNT_OFFSET),
+ (CONFIG_HPS_PERPLLGRP_S2FUSER1CLK_CNT <<
+ CLKMGR_PERPLLGRP_S2FUSER1CLK_CNT_OFFSET),
+ (CONFIG_HPS_PERPLLGRP_DIV_USBCLK <<
+ CLKMGR_PERPLLGRP_DIV_USBCLK_OFFSET) |
+ (CONFIG_HPS_PERPLLGRP_DIV_SPIMCLK <<
+ CLKMGR_PERPLLGRP_DIV_SPIMCLK_OFFSET) |
+ (CONFIG_HPS_PERPLLGRP_DIV_CAN0CLK <<
+ CLKMGR_PERPLLGRP_DIV_CAN0CLK_OFFSET) |
+ (CONFIG_HPS_PERPLLGRP_DIV_CAN1CLK <<
+ CLKMGR_PERPLLGRP_DIV_CAN1CLK_OFFSET),
+ (CONFIG_HPS_PERPLLGRP_GPIODIV_GPIODBCLK <<
+ CLKMGR_PERPLLGRP_GPIODIV_GPIODBCLK_OFFSET),
+ (CONFIG_HPS_PERPLLGRP_SRC_QSPI <<
+ CLKMGR_PERPLLGRP_SRC_QSPI_OFFSET) |
+ (CONFIG_HPS_PERPLLGRP_SRC_NAND <<
+ CLKMGR_PERPLLGRP_SRC_NAND_OFFSET) |
+ (CONFIG_HPS_PERPLLGRP_SRC_SDMMC <<
+ CLKMGR_PERPLLGRP_SRC_SDMMC_OFFSET),
+
+ /* sdram pll group */
+ SDR_VCO_BASE,
+ (CONFIG_HPS_SDRPLLGRP_DDRDQSCLK_PHASE <<
+ CLKMGR_SDRPLLGRP_DDRDQSCLK_PHASE_OFFSET) |
+ (CONFIG_HPS_SDRPLLGRP_DDRDQSCLK_CNT <<
+ CLKMGR_SDRPLLGRP_DDRDQSCLK_CNT_OFFSET),
+ (CONFIG_HPS_SDRPLLGRP_DDR2XDQSCLK_PHASE <<
+ CLKMGR_SDRPLLGRP_DDR2XDQSCLK_PHASE_OFFSET) |
+ (CONFIG_HPS_SDRPLLGRP_DDR2XDQSCLK_CNT <<
+ CLKMGR_SDRPLLGRP_DDR2XDQSCLK_CNT_OFFSET),
+ (CONFIG_HPS_SDRPLLGRP_DDRDQCLK_PHASE <<
+ CLKMGR_SDRPLLGRP_DDRDQCLK_PHASE_OFFSET) |
+ (CONFIG_HPS_SDRPLLGRP_DDRDQCLK_CNT <<
+ CLKMGR_SDRPLLGRP_DDRDQCLK_CNT_OFFSET),
+ (CONFIG_HPS_SDRPLLGRP_S2FUSER2CLK_PHASE <<
+ CLKMGR_SDRPLLGRP_S2FUSER2CLK_PHASE_OFFSET) |
+ (CONFIG_HPS_SDRPLLGRP_S2FUSER2CLK_CNT <<
+ CLKMGR_SDRPLLGRP_S2FUSER2CLK_CNT_OFFSET),
+};
+
+const struct cm_config * const cm_get_default_config(void)
+{
+ return &cm_default_cfg;
+}
+
+const unsigned int cm_get_osc_clk_hz(const int osc)
+{
+ if (osc == 1)
+ return CONFIG_HPS_CLK_OSC1_HZ;
+ else if (osc == 2)
+ return CONFIG_HPS_CLK_OSC2_HZ;
+ else
+ return 0;
+}
+
+const unsigned int cm_get_f2s_per_ref_clk_hz(void)
+{
+ return CONFIG_HPS_CLK_F2S_PER_REF_HZ;
+}
+
+const unsigned int cm_get_f2s_sdr_ref_clk_hz(void)
+{
+ return CONFIG_HPS_CLK_F2S_SDR_REF_HZ;
+}
diff --git a/board/altera/socfpga/wrap_sdram_config.c b/board/altera/socfpga/wrap_sdram_config.c
new file mode 100644
index 00000000000..cd97cc509f3
--- /dev/null
+++ b/board/altera/socfpga/wrap_sdram_config.c
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2015 Marek Vasut <marex@denx.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <asm/arch/sdram.h>
+/* QTS output file. */
+#include "qts/sdram_config.h"
+
+#include "qts/sequencer_auto_ac_init.h"
+#include "qts/sequencer_auto_inst_init.h"
+#include "qts/sequencer_auto.h"
+#include "qts/sequencer_defines.h"
+
+static const struct socfpga_sdram_config sdram_config = {
+ .ctrl_cfg =
+ (CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_MEMTYPE <<
+ SDR_CTRLGRP_CTRLCFG_MEMTYPE_LSB) |
+ (CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_MEMBL <<
+ SDR_CTRLGRP_CTRLCFG_MEMBL_LSB) |
+ (CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_ADDRORDER <<
+ SDR_CTRLGRP_CTRLCFG_ADDRORDER_LSB) |
+ (CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_ECCEN <<
+ SDR_CTRLGRP_CTRLCFG_ECCEN_LSB) |
+ (CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_ECCCORREN <<
+ SDR_CTRLGRP_CTRLCFG_ECCCORREN_LSB) |
+ (CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_REORDEREN <<
+ SDR_CTRLGRP_CTRLCFG_REORDEREN_LSB) |
+ (CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_STARVELIMIT <<
+ SDR_CTRLGRP_CTRLCFG_STARVELIMIT_LSB) |
+ (CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_DQSTRKEN <<
+ SDR_CTRLGRP_CTRLCFG_DQSTRKEN_LSB) |
+ (CONFIG_HPS_SDR_CTRLCFG_CTRLCFG_NODMPINS <<
+ SDR_CTRLGRP_CTRLCFG_NODMPINS_LSB),
+ .dram_timing1 =
+ (CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING1_TCWL <<
+ SDR_CTRLGRP_DRAMTIMING1_TCWL_LSB) |
+ (CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING1_AL <<
+ SDR_CTRLGRP_DRAMTIMING1_TAL_LSB) |
+ (CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING1_TCL <<
+ SDR_CTRLGRP_DRAMTIMING1_TCL_LSB) |
+ (CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING1_TRRD <<
+ SDR_CTRLGRP_DRAMTIMING1_TRRD_LSB) |
+ (CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING1_TFAW <<
+ SDR_CTRLGRP_DRAMTIMING1_TFAW_LSB) |
+ (CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING1_TRFC <<
+ SDR_CTRLGRP_DRAMTIMING1_TRFC_LSB),
+ .dram_timing2 =
+ (CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TREFI <<
+ SDR_CTRLGRP_DRAMTIMING2_TREFI_LSB) |
+ (CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TRCD <<
+ SDR_CTRLGRP_DRAMTIMING2_TRCD_LSB) |
+ (CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TRP <<
+ SDR_CTRLGRP_DRAMTIMING2_TRP_LSB) |
+ (CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TWR <<
+ SDR_CTRLGRP_DRAMTIMING2_TWR_LSB) |
+ (CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING2_IF_TWTR <<
+ SDR_CTRLGRP_DRAMTIMING2_TWTR_LSB),
+ .dram_timing3 =
+ (CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING3_TRTP <<
+ SDR_CTRLGRP_DRAMTIMING3_TRTP_LSB) |
+ (CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING3_TRAS <<
+ SDR_CTRLGRP_DRAMTIMING3_TRAS_LSB) |
+ (CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING3_TRC <<
+ SDR_CTRLGRP_DRAMTIMING3_TRC_LSB) |
+ (CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING3_TMRD <<
+ SDR_CTRLGRP_DRAMTIMING3_TMRD_LSB) |
+ (CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING3_TCCD <<
+ SDR_CTRLGRP_DRAMTIMING3_TCCD_LSB),
+ .dram_timing4 =
+ (CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING4_SELFRFSHEXIT <<
+ SDR_CTRLGRP_DRAMTIMING4_SELFRFSHEXIT_LSB) |
+ (CONFIG_HPS_SDR_CTRLCFG_DRAMTIMING4_PWRDOWNEXIT <<
+ SDR_CTRLGRP_DRAMTIMING4_PWRDOWNEXIT_LSB),
+ .lowpwr_timing =
+ (CONFIG_HPS_SDR_CTRLCFG_LOWPWRTIMING_AUTOPDCYCLES <<
+ SDR_CTRLGRP_LOWPWRTIMING_AUTOPDCYCLES_LSB) |
+ (CONFIG_HPS_SDR_CTRLCFG_LOWPWRTIMING_CLKDISABLECYCLES <<
+ SDR_CTRLGRP_LOWPWRTIMING_CLKDISABLECYCLES_LSB),
+ .dram_odt =
+ (CONFIG_HPS_SDR_CTRLCFG_DRAMODT_READ <<
+ SDR_CTRLGRP_DRAMODT_READ_LSB) |
+ (CONFIG_HPS_SDR_CTRLCFG_DRAMODT_WRITE <<
+ SDR_CTRLGRP_DRAMODT_WRITE_LSB),
+ .dram_addrw =
+ (CONFIG_HPS_SDR_CTRLCFG_DRAMADDRW_COLBITS <<
+ SDR_CTRLGRP_DRAMADDRW_COLBITS_LSB) |
+ (CONFIG_HPS_SDR_CTRLCFG_DRAMADDRW_ROWBITS <<
+ SDR_CTRLGRP_DRAMADDRW_ROWBITS_LSB) |
+ (CONFIG_HPS_SDR_CTRLCFG_DRAMADDRW_BANKBITS <<
+ SDR_CTRLGRP_DRAMADDRW_BANKBITS_LSB) |
+ ((CONFIG_HPS_SDR_CTRLCFG_DRAMADDRW_CSBITS - 1) <<
+ SDR_CTRLGRP_DRAMADDRW_CSBITS_LSB),
+ .dram_if_width =
+ (CONFIG_HPS_SDR_CTRLCFG_DRAMIFWIDTH_IFWIDTH <<
+ SDR_CTRLGRP_DRAMIFWIDTH_IFWIDTH_LSB),
+ .dram_dev_width =
+ (CONFIG_HPS_SDR_CTRLCFG_DRAMDEVWIDTH_DEVWIDTH <<
+ SDR_CTRLGRP_DRAMDEVWIDTH_DEVWIDTH_LSB),
+ .dram_intr =
+ (CONFIG_HPS_SDR_CTRLCFG_DRAMINTR_INTREN <<
+ SDR_CTRLGRP_DRAMINTR_INTREN_LSB),
+ .lowpwr_eq =
+ (CONFIG_HPS_SDR_CTRLCFG_LOWPWREQ_SELFRFSHMASK <<
+ SDR_CTRLGRP_LOWPWREQ_SELFRFSHMASK_LSB),
+ .static_cfg =
+ (CONFIG_HPS_SDR_CTRLCFG_STATICCFG_MEMBL <<
+ SDR_CTRLGRP_STATICCFG_MEMBL_LSB) |
+ (CONFIG_HPS_SDR_CTRLCFG_STATICCFG_USEECCASDATA <<
+ SDR_CTRLGRP_STATICCFG_USEECCASDATA_LSB),
+ .ctrl_width =
+ (CONFIG_HPS_SDR_CTRLCFG_CTRLWIDTH_CTRLWIDTH <<
+ SDR_CTRLGRP_CTRLWIDTH_CTRLWIDTH_LSB),
+ .cport_width =
+ (CONFIG_HPS_SDR_CTRLCFG_CPORTWIDTH_CPORTWIDTH <<
+ SDR_CTRLGRP_CPORTWIDTH_CMDPORTWIDTH_LSB),
+ .cport_wmap =
+ (CONFIG_HPS_SDR_CTRLCFG_CPORTWMAP_CPORTWMAP <<
+ SDR_CTRLGRP_CPORTWMAP_CPORTWFIFOMAP_LSB),
+ .cport_rmap =
+ (CONFIG_HPS_SDR_CTRLCFG_CPORTRMAP_CPORTRMAP <<
+ SDR_CTRLGRP_CPORTRMAP_CPORTRFIFOMAP_LSB),
+ .rfifo_cmap =
+ (CONFIG_HPS_SDR_CTRLCFG_RFIFOCMAP_RFIFOCMAP <<
+ SDR_CTRLGRP_RFIFOCMAP_RFIFOCPORTMAP_LSB),
+ .wfifo_cmap =
+ (CONFIG_HPS_SDR_CTRLCFG_WFIFOCMAP_WFIFOCMAP <<
+ SDR_CTRLGRP_WFIFOCMAP_WFIFOCPORTMAP_LSB),
+ .cport_rdwr =
+ (CONFIG_HPS_SDR_CTRLCFG_CPORTRDWR_CPORTRDWR <<
+ SDR_CTRLGRP_CPORTRDWR_CPORTRDWR_LSB),
+ .port_cfg =
+ (CONFIG_HPS_SDR_CTRLCFG_PORTCFG_AUTOPCHEN <<
+ SDR_CTRLGRP_PORTCFG_AUTOPCHEN_LSB),
+ .fpgaport_rst = CONFIG_HPS_SDR_CTRLCFG_FPGAPORTRST,
+ .fifo_cfg =
+ (CONFIG_HPS_SDR_CTRLCFG_FIFOCFG_SYNCMODE <<
+ SDR_CTRLGRP_FIFOCFG_SYNCMODE_LSB) |
+ (CONFIG_HPS_SDR_CTRLCFG_FIFOCFG_INCSYNC <<
+ SDR_CTRLGRP_FIFOCFG_INCSYNC_LSB),
+ .mp_priority =
+ (CONFIG_HPS_SDR_CTRLCFG_MPPRIORITY_USERPRIORITY <<
+ SDR_CTRLGRP_MPPRIORITY_USERPRIORITY_LSB),
+ .mp_weight0 =
+ (CONFIG_HPS_SDR_CTRLCFG_MPWIEIGHT_0_STATICWEIGHT_31_0 <<
+ SDR_CTRLGRP_MPWEIGHT_MPWEIGHT_0_STATICWEIGHT_31_0_LSB),
+ .mp_weight1 =
+ (CONFIG_HPS_SDR_CTRLCFG_MPWIEIGHT_1_STATICWEIGHT_49_32 <<
+ SDR_CTRLGRP_MPWEIGHT_MPWEIGHT_1_STATICWEIGHT_49_32_LSB) |
+ (CONFIG_HPS_SDR_CTRLCFG_MPWIEIGHT_1_SUMOFWEIGHT_13_0 <<
+ SDR_CTRLGRP_MPWEIGHT_MPWEIGHT_1_SUMOFWEIGHTS_13_0_LSB),
+ .mp_weight2 =
+ (CONFIG_HPS_SDR_CTRLCFG_MPWIEIGHT_2_SUMOFWEIGHT_45_14 <<
+ SDR_CTRLGRP_MPWEIGHT_MPWEIGHT_2_SUMOFWEIGHTS_45_14_LSB),
+ .mp_weight3 =
+ (CONFIG_HPS_SDR_CTRLCFG_MPWIEIGHT_3_SUMOFWEIGHT_63_46 <<
+ SDR_CTRLGRP_MPWEIGHT_MPWEIGHT_3_SUMOFWEIGHTS_63_46_LSB),
+ .mp_pacing0 =
+ (CONFIG_HPS_SDR_CTRLCFG_MPPACING_0_THRESHOLD1_31_0 <<
+ SDR_CTRLGRP_MPPACING_MPPACING_0_THRESHOLD1_31_0_LSB),
+ .mp_pacing1 =
+ (CONFIG_HPS_SDR_CTRLCFG_MPPACING_1_THRESHOLD1_59_32 <<
+ SDR_CTRLGRP_MPPACING_MPPACING_1_THRESHOLD1_59_32_LSB) |
+ (CONFIG_HPS_SDR_CTRLCFG_MPPACING_1_THRESHOLD2_3_0 <<
+ SDR_CTRLGRP_MPPACING_MPPACING_1_THRESHOLD2_3_0_LSB),
+ .mp_pacing2 =
+ (CONFIG_HPS_SDR_CTRLCFG_MPPACING_2_THRESHOLD2_35_4 <<
+ SDR_CTRLGRP_MPPACING_MPPACING_2_THRESHOLD2_35_4_LSB),
+ .mp_pacing3 =
+ (CONFIG_HPS_SDR_CTRLCFG_MPPACING_3_THRESHOLD2_59_36 <<
+ SDR_CTRLGRP_MPPACING_MPPACING_3_THRESHOLD2_59_36_LSB),
+ .mp_threshold0 =
+ (CONFIG_HPS_SDR_CTRLCFG_MPTHRESHOLDRST_0_THRESHOLDRSTCYCLES_31_0 <<
+ SDR_CTRLGRP_MPTHRESHOLDRST_0_THRESHOLDRSTCYCLES_31_0_LSB),
+ .mp_threshold1 =
+ (CONFIG_HPS_SDR_CTRLCFG_MPTHRESHOLDRST_1_THRESHOLDRSTCYCLES_63_32 <<
+ SDR_CTRLGRP_MPTHRESHOLDRST_1_THRESHOLDRSTCYCLES_63_32_LSB),
+ .mp_threshold2 =
+ (CONFIG_HPS_SDR_CTRLCFG_MPTHRESHOLDRST_2_THRESHOLDRSTCYCLES_79_64 <<
+ SDR_CTRLGRP_MPTHRESHOLDRST_2_THRESHOLDRSTCYCLES_79_64_LSB),
+ .phy_ctrl0 = CONFIG_HPS_SDR_CTRLCFG_PHYCTRL_PHYCTRL_0,
+};
+
+static const struct socfpga_sdram_rw_mgr_config rw_mgr_config = {
+ .activate_0_and_1 = RW_MGR_ACTIVATE_0_AND_1,
+ .activate_0_and_1_wait1 = RW_MGR_ACTIVATE_0_AND_1_WAIT1,
+ .activate_0_and_1_wait2 = RW_MGR_ACTIVATE_0_AND_1_WAIT2,
+ .activate_1 = RW_MGR_ACTIVATE_1,
+ .clear_dqs_enable = RW_MGR_CLEAR_DQS_ENABLE,
+ .guaranteed_read = RW_MGR_GUARANTEED_READ,
+ .guaranteed_read_cont = RW_MGR_GUARANTEED_READ_CONT,
+ .guaranteed_write = RW_MGR_GUARANTEED_WRITE,
+ .guaranteed_write_wait0 = RW_MGR_GUARANTEED_WRITE_WAIT0,
+ .guaranteed_write_wait1 = RW_MGR_GUARANTEED_WRITE_WAIT1,
+ .guaranteed_write_wait2 = RW_MGR_GUARANTEED_WRITE_WAIT2,
+ .guaranteed_write_wait3 = RW_MGR_GUARANTEED_WRITE_WAIT3,
+ .idle = RW_MGR_IDLE,
+ .idle_loop1 = RW_MGR_IDLE_LOOP1,
+ .idle_loop2 = RW_MGR_IDLE_LOOP2,
+ .init_reset_0_cke_0 = RW_MGR_INIT_RESET_0_CKE_0,
+ .init_reset_1_cke_0 = RW_MGR_INIT_RESET_1_CKE_0,
+ .lfsr_wr_rd_bank_0 = RW_MGR_LFSR_WR_RD_BANK_0,
+ .lfsr_wr_rd_bank_0_data = RW_MGR_LFSR_WR_RD_BANK_0_DATA,
+ .lfsr_wr_rd_bank_0_dqs = RW_MGR_LFSR_WR_RD_BANK_0_DQS,
+ .lfsr_wr_rd_bank_0_nop = RW_MGR_LFSR_WR_RD_BANK_0_NOP,
+ .lfsr_wr_rd_bank_0_wait = RW_MGR_LFSR_WR_RD_BANK_0_WAIT,
+ .lfsr_wr_rd_bank_0_wl_1 = RW_MGR_LFSR_WR_RD_BANK_0_WL_1,
+ .lfsr_wr_rd_dm_bank_0 = RW_MGR_LFSR_WR_RD_DM_BANK_0,
+ .lfsr_wr_rd_dm_bank_0_data = RW_MGR_LFSR_WR_RD_DM_BANK_0_DATA,
+ .lfsr_wr_rd_dm_bank_0_dqs = RW_MGR_LFSR_WR_RD_DM_BANK_0_DQS,
+ .lfsr_wr_rd_dm_bank_0_nop = RW_MGR_LFSR_WR_RD_DM_BANK_0_NOP,
+ .lfsr_wr_rd_dm_bank_0_wait = RW_MGR_LFSR_WR_RD_DM_BANK_0_WAIT,
+ .lfsr_wr_rd_dm_bank_0_wl_1 = RW_MGR_LFSR_WR_RD_DM_BANK_0_WL_1,
+ .mrs0_dll_reset = RW_MGR_MRS0_DLL_RESET,
+ .mrs0_dll_reset_mirr = RW_MGR_MRS0_DLL_RESET_MIRR,
+ .mrs0_user = RW_MGR_MRS0_USER,
+ .mrs0_user_mirr = RW_MGR_MRS0_USER_MIRR,
+ .mrs1 = RW_MGR_MRS1,
+ .mrs1_mirr = RW_MGR_MRS1_MIRR,
+ .mrs2 = RW_MGR_MRS2,
+ .mrs2_mirr = RW_MGR_MRS2_MIRR,
+ .mrs3 = RW_MGR_MRS3,
+ .mrs3_mirr = RW_MGR_MRS3_MIRR,
+ .precharge_all = RW_MGR_PRECHARGE_ALL,
+ .read_b2b = RW_MGR_READ_B2B,
+ .read_b2b_wait1 = RW_MGR_READ_B2B_WAIT1,
+ .read_b2b_wait2 = RW_MGR_READ_B2B_WAIT2,
+ .refresh_all = RW_MGR_REFRESH_ALL,
+ .rreturn = RW_MGR_RETURN,
+ .sgle_read = RW_MGR_SGLE_READ,
+ .zqcl = RW_MGR_ZQCL,
+
+ .true_mem_data_mask_width = RW_MGR_TRUE_MEM_DATA_MASK_WIDTH,
+ .mem_address_mirroring = RW_MGR_MEM_ADDRESS_MIRRORING,
+ .mem_data_mask_width = RW_MGR_MEM_DATA_MASK_WIDTH,
+ .mem_data_width = RW_MGR_MEM_DATA_WIDTH,
+ .mem_dq_per_read_dqs = RW_MGR_MEM_DQ_PER_READ_DQS,
+ .mem_dq_per_write_dqs = RW_MGR_MEM_DQ_PER_WRITE_DQS,
+ .mem_if_read_dqs_width = RW_MGR_MEM_IF_READ_DQS_WIDTH,
+ .mem_if_write_dqs_width = RW_MGR_MEM_IF_WRITE_DQS_WIDTH,
+ .mem_number_of_cs_per_dimm = RW_MGR_MEM_NUMBER_OF_CS_PER_DIMM,
+ .mem_number_of_ranks = RW_MGR_MEM_NUMBER_OF_RANKS,
+ .mem_virtual_groups_per_read_dqs =
+ RW_MGR_MEM_VIRTUAL_GROUPS_PER_READ_DQS,
+ .mem_virtual_groups_per_write_dqs =
+ RW_MGR_MEM_VIRTUAL_GROUPS_PER_WRITE_DQS,
+};
+
+struct socfpga_sdram_io_config io_config = {
+ .delay_per_dchain_tap = IO_DELAY_PER_DCHAIN_TAP,
+ .delay_per_dqs_en_dchain_tap = IO_DELAY_PER_DQS_EN_DCHAIN_TAP,
+ .delay_per_opa_tap = IO_DELAY_PER_OPA_TAP,
+ .dll_chain_length = IO_DLL_CHAIN_LENGTH,
+ .dqdqs_out_phase_max = IO_DQDQS_OUT_PHASE_MAX,
+ .dqs_en_delay_max = IO_DQS_EN_DELAY_MAX,
+ .dqs_en_delay_offset = IO_DQS_EN_DELAY_OFFSET,
+ .dqs_en_phase_max = IO_DQS_EN_PHASE_MAX,
+ .dqs_in_delay_max = IO_DQS_IN_DELAY_MAX,
+ .dqs_in_reserve = IO_DQS_IN_RESERVE,
+ .dqs_out_reserve = IO_DQS_OUT_RESERVE,
+ .io_in_delay_max = IO_IO_IN_DELAY_MAX,
+ .io_out1_delay_max = IO_IO_OUT1_DELAY_MAX,
+ .io_out2_delay_max = IO_IO_OUT2_DELAY_MAX,
+ .shift_dqs_en_when_shift_dqs = IO_SHIFT_DQS_EN_WHEN_SHIFT_DQS,
+};
+
+struct socfpga_sdram_misc_config misc_config = {
+ .afi_rate_ratio = AFI_RATE_RATIO,
+ .calib_lfifo_offset = CALIB_LFIFO_OFFSET,
+ .calib_vfifo_offset = CALIB_VFIFO_OFFSET,
+ .enable_super_quick_calibration = ENABLE_SUPER_QUICK_CALIBRATION,
+ .max_latency_count_width = MAX_LATENCY_COUNT_WIDTH,
+ .read_valid_fifo_size = READ_VALID_FIFO_SIZE,
+ .reg_file_init_seq_signature = REG_FILE_INIT_SEQ_SIGNATURE,
+ .tinit_cntr0_val = TINIT_CNTR0_VAL,
+ .tinit_cntr1_val = TINIT_CNTR1_VAL,
+ .tinit_cntr2_val = TINIT_CNTR2_VAL,
+ .treset_cntr0_val = TRESET_CNTR0_VAL,
+ .treset_cntr1_val = TRESET_CNTR1_VAL,
+ .treset_cntr2_val = TRESET_CNTR2_VAL,
+};
+
+const struct socfpga_sdram_config *socfpga_get_sdram_config(void)
+{
+ return &sdram_config;
+}
+
+void socfpga_get_seq_ac_init(const u32 **init, unsigned int *nelem)
+{
+ *init = ac_rom_init;
+ *nelem = ARRAY_SIZE(ac_rom_init);
+}
+
+void socfpga_get_seq_inst_init(const u32 **init, unsigned int *nelem)
+{
+ *init = inst_rom_init;
+ *nelem = ARRAY_SIZE(inst_rom_init);
+}
+
+const struct socfpga_sdram_rw_mgr_config *socfpga_get_sdram_rwmgr_config(void)
+{
+ return &rw_mgr_config;
+}
+
+const struct socfpga_sdram_io_config *socfpga_get_sdram_io_config(void)
+{
+ return &io_config;
+}
+
+const struct socfpga_sdram_misc_config *socfpga_get_sdram_misc_config(void)
+{
+ return &misc_config;
+}
diff --git a/configs/socfpga_arria5_defconfig b/configs/socfpga_arria5_defconfig
index 4ba4b8c5f26..4d1cd21c151 100644
--- a/configs/socfpga_arria5_defconfig
+++ b/configs/socfpga_arria5_defconfig
@@ -7,3 +7,13 @@ CONFIG_SPL=y
# CONFIG_CMD_FLASH is not set
CONFIG_OF_CONTROL=y
CONFIG_SPI_FLASH=y
+CONFIG_SPL_DM=y
+CONFIG_SPL_MMC_SUPPORT=y
+CONFIG_DM_SEQ_ALIAS=y
+CONFIG_SPL_SIMPLE_BUS=y
+CONFIG_DM_SPI=y
+CONFIG_DM_SPI_FLASH=y
+CONFIG_SPL_SPI_SUPPORT=y
+CONFIG_SPL_STACK_R=y
+CONFIG_SPL_STACK_R_ADDR=0x00800000
+CONFIG_SYS_MALLOC_F_LEN=0x2000
diff --git a/configs/socfpga_cyclone5_defconfig b/configs/socfpga_cyclone5_defconfig
index e101f767122..ae3a1dea911 100644
--- a/configs/socfpga_cyclone5_defconfig
+++ b/configs/socfpga_cyclone5_defconfig
@@ -7,5 +7,16 @@ CONFIG_SPL=y
# CONFIG_CMD_FLASH is not set
CONFIG_OF_CONTROL=y
CONFIG_SPI_FLASH=y
+CONFIG_DM_ETH=y
CONFIG_NETDEVICES=y
CONFIG_ETH_DESIGNWARE=y
+CONFIG_SPL_DM=y
+CONFIG_SPL_MMC_SUPPORT=y
+CONFIG_DM_SEQ_ALIAS=y
+CONFIG_SPL_SIMPLE_BUS=y
+CONFIG_DM_SPI=y
+CONFIG_DM_SPI_FLASH=y
+CONFIG_SPL_SPI_SUPPORT=y
+CONFIG_SPL_STACK_R=y
+CONFIG_SPL_STACK_R_ADDR=0x00800000
+CONFIG_SYS_MALLOC_F_LEN=0x2000
diff --git a/configs/socfpga_socrates_defconfig b/configs/socfpga_socrates_defconfig
index 63dda73dd21..71d47116791 100644
--- a/configs/socfpga_socrates_defconfig
+++ b/configs/socfpga_socrates_defconfig
@@ -6,7 +6,17 @@ CONFIG_SPL=y
# CONFIG_CMD_IMLS is not set
# CONFIG_CMD_FLASH is not set
CONFIG_OF_CONTROL=y
-CONFIG_SPL_DISABLE_OF_CONTROL=y
CONFIG_SPI_FLASH=y
+CONFIG_DM_ETH=y
CONFIG_NETDEVICES=y
CONFIG_ETH_DESIGNWARE=y
+CONFIG_SPL_DM=y
+CONFIG_SPL_MMC_SUPPORT=y
+CONFIG_DM_SEQ_ALIAS=y
+CONFIG_SPL_SIMPLE_BUS=y
+CONFIG_DM_SPI=y
+CONFIG_DM_SPI_FLASH=y
+CONFIG_SPL_SPI_SUPPORT=y
+CONFIG_SPL_STACK_R=y
+CONFIG_SPL_STACK_R_ADDR=0x00800000
+CONFIG_SYS_MALLOC_F_LEN=0x2000
diff --git a/drivers/ddr/altera/Makefile b/drivers/ddr/altera/Makefile
new file mode 100644
index 00000000000..1ca705856d2
--- /dev/null
+++ b/drivers/ddr/altera/Makefile
@@ -0,0 +1,11 @@
+#
+# (C) Copyright 2000-2003
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# (C) Copyright 2010, Thomas Chou <thomas@wytron.com.tw>
+# Copyright (C) 2014 Altera Corporation <www.altera.com>
+#
+# SPDX-License-Identifier: GPL-2.0+
+#
+
+obj-$(CONFIG_ALTERA_SDRAM) += sdram.o sequencer.o
diff --git a/drivers/ddr/altera/sdram.c b/drivers/ddr/altera/sdram.c
new file mode 100644
index 00000000000..1ed2883d1b8
--- /dev/null
+++ b/drivers/ddr/altera/sdram.c
@@ -0,0 +1,535 @@
+/*
+ * Copyright Altera Corporation (C) 2014-2015
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+#include <common.h>
+#include <errno.h>
+#include <div64.h>
+#include <watchdog.h>
+#include <asm/arch/fpga_manager.h>
+#include <asm/arch/sdram.h>
+#include <asm/arch/system_manager.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct sdram_prot_rule {
+ u32 sdram_start; /* SDRAM start address */
+ u32 sdram_end; /* SDRAM end address */
+ u32 rule; /* SDRAM protection rule number: 0-19 */
+ int valid; /* Rule valid or not? 1 - valid, 0 not*/
+
+ u32 security;
+ u32 portmask;
+ u32 result;
+ u32 lo_prot_id;
+ u32 hi_prot_id;
+};
+
+static struct socfpga_system_manager *sysmgr_regs =
+ (struct socfpga_system_manager *)SOCFPGA_SYSMGR_ADDRESS;
+static struct socfpga_sdr_ctrl *sdr_ctrl =
+ (struct socfpga_sdr_ctrl *)SDR_CTRLGRP_ADDRESS;
+
+/**
+ * get_errata_rows() - Up the number of DRAM rows to cover entire address space
+ * @cfg: SDRAM controller configuration data
+ *
+ * SDRAM Failure happens when accessing non-existent memory. Artificially
+ * increase the number of rows so that the memory controller thinks it has
+ * 4GB of RAM. This function returns such amount of rows.
+ */
+static int get_errata_rows(const struct socfpga_sdram_config *cfg)
+{
+ /* Define constant for 4G memory - used for SDRAM errata workaround */
+#define MEMSIZE_4G (4ULL * 1024ULL * 1024ULL * 1024ULL)
+ const unsigned long long memsize = MEMSIZE_4G;
+ const unsigned int cs =
+ ((cfg->dram_addrw & SDR_CTRLGRP_DRAMADDRW_CSBITS_MASK) >>
+ SDR_CTRLGRP_DRAMADDRW_CSBITS_LSB) + 1;
+ const unsigned int rows =
+ (cfg->dram_addrw & SDR_CTRLGRP_DRAMADDRW_ROWBITS_MASK) >>
+ SDR_CTRLGRP_DRAMADDRW_ROWBITS_LSB;
+ const unsigned int banks =
+ (cfg->dram_addrw & SDR_CTRLGRP_DRAMADDRW_BANKBITS_MASK) >>
+ SDR_CTRLGRP_DRAMADDRW_BANKBITS_LSB;
+ const unsigned int cols =
+ (cfg->dram_addrw & SDR_CTRLGRP_DRAMADDRW_COLBITS_MASK) >>
+ SDR_CTRLGRP_DRAMADDRW_COLBITS_LSB;
+ const unsigned int width = 8;
+
+ unsigned long long newrows;
+ int bits, inewrowslog2;
+
+ debug("workaround rows - memsize %lld\n", memsize);
+ debug("workaround rows - cs %d\n", cs);
+ debug("workaround rows - width %d\n", width);
+ debug("workaround rows - rows %d\n", rows);
+ debug("workaround rows - banks %d\n", banks);
+ debug("workaround rows - cols %d\n", cols);
+
+ newrows = lldiv(memsize, cs * (width / 8));
+ debug("rows workaround - term1 %lld\n", newrows);
+
+ newrows = lldiv(newrows, (1 << banks) * (1 << cols));
+ debug("rows workaround - term2 %lld\n", newrows);
+
+ /*
+ * Compute the hamming weight - same as number of bits set.
+ * Need to see if result is ordinal power of 2 before
+ * attempting log2 of result.
+ */
+ bits = generic_hweight32(newrows);
+
+ debug("rows workaround - bits %d\n", bits);
+
+ if (bits != 1) {
+ printf("SDRAM workaround failed, bits set %d\n", bits);
+ return rows;
+ }
+
+ if (newrows > UINT_MAX) {
+ printf("SDRAM workaround rangecheck failed, %lld\n", newrows);
+ return rows;
+ }
+
+ inewrowslog2 = __ilog2(newrows);
+
+ debug("rows workaround - ilog2 %d, %lld\n", inewrowslog2, newrows);
+
+ if (inewrowslog2 == -1) {
+ printf("SDRAM workaround failed, newrows %lld\n", newrows);
+ return rows;
+ }
+
+ return inewrowslog2;
+}
+
+/* SDRAM protection rules vary from 0-19, a total of 20 rules. */
+static void sdram_set_rule(struct sdram_prot_rule *prule)
+{
+ u32 lo_addr_bits;
+ u32 hi_addr_bits;
+ int ruleno = prule->rule;
+
+ /* Select the rule */
+ writel(ruleno, &sdr_ctrl->prot_rule_rdwr);
+
+ /* Obtain the address bits */
+ lo_addr_bits = prule->sdram_start >> 20ULL;
+ hi_addr_bits = prule->sdram_end >> 20ULL;
+
+ debug("sdram set rule start %x, %d\n", lo_addr_bits,
+ prule->sdram_start);
+ debug("sdram set rule end %x, %d\n", hi_addr_bits,
+ prule->sdram_end);
+
+ /* Set rule addresses */
+ writel(lo_addr_bits | (hi_addr_bits << 12), &sdr_ctrl->prot_rule_addr);
+
+ /* Set rule protection ids */
+ writel(prule->lo_prot_id | (prule->hi_prot_id << 12),
+ &sdr_ctrl->prot_rule_id);
+
+ /* Set the rule data */
+ writel(prule->security | (prule->valid << 2) |
+ (prule->portmask << 3) | (prule->result << 13),
+ &sdr_ctrl->prot_rule_data);
+
+ /* write the rule */
+ writel(ruleno | (1 << 5), &sdr_ctrl->prot_rule_rdwr);
+
+ /* Set rule number to 0 by default */
+ writel(0, &sdr_ctrl->prot_rule_rdwr);
+}
+
+static void sdram_get_rule(struct sdram_prot_rule *prule)
+{
+ u32 addr;
+ u32 id;
+ u32 data;
+ int ruleno = prule->rule;
+
+ /* Read the rule */
+ writel(ruleno, &sdr_ctrl->prot_rule_rdwr);
+ writel(ruleno | (1 << 6), &sdr_ctrl->prot_rule_rdwr);
+
+ /* Get the addresses */
+ addr = readl(&sdr_ctrl->prot_rule_addr);
+ prule->sdram_start = (addr & 0xFFF) << 20;
+ prule->sdram_end = ((addr >> 12) & 0xFFF) << 20;
+
+ /* Get the configured protection IDs */
+ id = readl(&sdr_ctrl->prot_rule_id);
+ prule->lo_prot_id = id & 0xFFF;
+ prule->hi_prot_id = (id >> 12) & 0xFFF;
+
+ /* Get protection data */
+ data = readl(&sdr_ctrl->prot_rule_data);
+
+ prule->security = data & 0x3;
+ prule->valid = (data >> 2) & 0x1;
+ prule->portmask = (data >> 3) & 0x3FF;
+ prule->result = (data >> 13) & 0x1;
+}
+
+static void
+sdram_set_protection_config(const u32 sdram_start, const u32 sdram_end)
+{
+ struct sdram_prot_rule rule;
+ int rules;
+
+ /* Start with accepting all SDRAM transaction */
+ writel(0x0, &sdr_ctrl->protport_default);
+
+ /* Clear all protection rules for warm boot case */
+ memset(&rule, 0, sizeof(rule));
+
+ for (rules = 0; rules < 20; rules++) {
+ rule.rule = rules;
+ sdram_set_rule(&rule);
+ }
+
+ /* new rule: accept SDRAM */
+ rule.sdram_start = sdram_start;
+ rule.sdram_end = sdram_end;
+ rule.lo_prot_id = 0x0;
+ rule.hi_prot_id = 0xFFF;
+ rule.portmask = 0x3FF;
+ rule.security = 0x3;
+ rule.result = 0;
+ rule.valid = 1;
+ rule.rule = 0;
+
+ /* set new rule */
+ sdram_set_rule(&rule);
+
+ /* default rule: reject everything */
+ writel(0x3ff, &sdr_ctrl->protport_default);
+}
+
+static void sdram_dump_protection_config(void)
+{
+ struct sdram_prot_rule rule;
+ int rules;
+
+ debug("SDRAM Prot rule, default %x\n",
+ readl(&sdr_ctrl->protport_default));
+
+ for (rules = 0; rules < 20; rules++) {
+ sdram_get_rule(&rule);
+ debug("Rule %d, rules ...\n", rules);
+ debug(" sdram start %x\n", rule.sdram_start);
+ debug(" sdram end %x\n", rule.sdram_end);
+ debug(" low prot id %d, hi prot id %d\n",
+ rule.lo_prot_id,
+ rule.hi_prot_id);
+ debug(" portmask %x\n", rule.portmask);
+ debug(" security %d\n", rule.security);
+ debug(" result %d\n", rule.result);
+ debug(" valid %d\n", rule.valid);
+ }
+}
+
+/**
+ * sdram_write_verify() - write to register and verify the write.
+ * @addr: Register address
+ * @val: Value to be written and verified
+ *
+ * This function writes to a register, reads back the value and compares
+ * the result with the written value to check if the data match.
+ */
+static unsigned sdram_write_verify(const u32 *addr, const u32 val)
+{
+ u32 rval;
+
+ debug(" Write - Address 0x%p Data 0x%08x\n", addr, val);
+ writel(val, addr);
+
+ debug(" Read and verify...");
+ rval = readl(addr);
+ if (rval != val) {
+ debug("FAIL - Address 0x%p Expected 0x%08x Data 0x%08x\n",
+ addr, val, rval);
+ return -EINVAL;
+ }
+
+ debug("correct!\n");
+ return 0;
+}
+
+/**
+ * sdr_get_ctrlcfg() - Get the value of DRAM CTRLCFG register
+ * @cfg: SDRAM controller configuration data
+ *
+ * Return the value of DRAM CTRLCFG register.
+ */
+static u32 sdr_get_ctrlcfg(const struct socfpga_sdram_config *cfg)
+{
+ const u32 csbits =
+ ((cfg->dram_addrw & SDR_CTRLGRP_DRAMADDRW_CSBITS_MASK) >>
+ SDR_CTRLGRP_DRAMADDRW_CSBITS_LSB) + 1;
+ u32 addrorder =
+ (cfg->ctrl_cfg & SDR_CTRLGRP_CTRLCFG_ADDRORDER_MASK) >>
+ SDR_CTRLGRP_CTRLCFG_ADDRORDER_LSB;
+
+ u32 ctrl_cfg = cfg->ctrl_cfg;
+
+ /*
+ * SDRAM Failure When Accessing Non-Existent Memory
+ * Set the addrorder field of the SDRAM control register
+ * based on the CSBITs setting.
+ */
+ if (csbits == 1) {
+ if (addrorder != 0)
+ debug("INFO: Changing address order to 0 (chip, row, bank, column)\n");
+ addrorder = 0;
+ } else if (csbits == 2) {
+ if (addrorder != 2)
+ debug("INFO: Changing address order to 2 (row, chip, bank, column)\n");
+ addrorder = 2;
+ }
+
+ ctrl_cfg &= ~SDR_CTRLGRP_CTRLCFG_ADDRORDER_MASK;
+ ctrl_cfg |= addrorder << SDR_CTRLGRP_CTRLCFG_ADDRORDER_LSB;
+
+ return ctrl_cfg;
+}
+
+/**
+ * sdr_get_addr_rw() - Get the value of DRAM ADDRW register
+ * @cfg: SDRAM controller configuration data
+ *
+ * Return the value of DRAM ADDRW register.
+ */
+static u32 sdr_get_addr_rw(const struct socfpga_sdram_config *cfg)
+{
+ /*
+ * SDRAM Failure When Accessing Non-Existent Memory
+ * Set SDR_CTRLGRP_DRAMADDRW_CSBITS_LSB to
+ * log2(number of chip select bits). Since there's only
+ * 1 or 2 chip selects, log2(1) => 0, and log2(2) => 1,
+ * which is the same as "chip selects" - 1.
+ */
+ const int rows = get_errata_rows(cfg);
+ u32 dram_addrw = cfg->dram_addrw & ~SDR_CTRLGRP_DRAMADDRW_ROWBITS_MASK;
+
+ return dram_addrw | (rows << SDR_CTRLGRP_DRAMADDRW_ROWBITS_LSB);
+}
+
+/**
+ * sdr_load_regs() - Load SDRAM controller registers
+ * @cfg: SDRAM controller configuration data
+ *
+ * This function loads the register values into the SDRAM controller block.
+ */
+static void sdr_load_regs(const struct socfpga_sdram_config *cfg)
+{
+ const u32 ctrl_cfg = sdr_get_ctrlcfg(cfg);
+ const u32 dram_addrw = sdr_get_addr_rw(cfg);
+
+ debug("\nConfiguring CTRLCFG\n");
+ writel(ctrl_cfg, &sdr_ctrl->ctrl_cfg);
+
+ debug("Configuring DRAMTIMING1\n");
+ writel(cfg->dram_timing1, &sdr_ctrl->dram_timing1);
+
+ debug("Configuring DRAMTIMING2\n");
+ writel(cfg->dram_timing2, &sdr_ctrl->dram_timing2);
+
+ debug("Configuring DRAMTIMING3\n");
+ writel(cfg->dram_timing3, &sdr_ctrl->dram_timing3);
+
+ debug("Configuring DRAMTIMING4\n");
+ writel(cfg->dram_timing4, &sdr_ctrl->dram_timing4);
+
+ debug("Configuring LOWPWRTIMING\n");
+ writel(cfg->lowpwr_timing, &sdr_ctrl->lowpwr_timing);
+
+ debug("Configuring DRAMADDRW\n");
+ writel(dram_addrw, &sdr_ctrl->dram_addrw);
+
+ debug("Configuring DRAMIFWIDTH\n");
+ writel(cfg->dram_if_width, &sdr_ctrl->dram_if_width);
+
+ debug("Configuring DRAMDEVWIDTH\n");
+ writel(cfg->dram_dev_width, &sdr_ctrl->dram_dev_width);
+
+ debug("Configuring LOWPWREQ\n");
+ writel(cfg->lowpwr_eq, &sdr_ctrl->lowpwr_eq);
+
+ debug("Configuring DRAMINTR\n");
+ writel(cfg->dram_intr, &sdr_ctrl->dram_intr);
+
+ debug("Configuring STATICCFG\n");
+ writel(cfg->static_cfg, &sdr_ctrl->static_cfg);
+
+ debug("Configuring CTRLWIDTH\n");
+ writel(cfg->ctrl_width, &sdr_ctrl->ctrl_width);
+
+ debug("Configuring PORTCFG\n");
+ writel(cfg->port_cfg, &sdr_ctrl->port_cfg);
+
+ debug("Configuring FIFOCFG\n");
+ writel(cfg->fifo_cfg, &sdr_ctrl->fifo_cfg);
+
+ debug("Configuring MPPRIORITY\n");
+ writel(cfg->mp_priority, &sdr_ctrl->mp_priority);
+
+ debug("Configuring MPWEIGHT_MPWEIGHT_0\n");
+ writel(cfg->mp_weight0, &sdr_ctrl->mp_weight0);
+ writel(cfg->mp_weight1, &sdr_ctrl->mp_weight1);
+ writel(cfg->mp_weight2, &sdr_ctrl->mp_weight2);
+ writel(cfg->mp_weight3, &sdr_ctrl->mp_weight3);
+
+ debug("Configuring MPPACING_MPPACING_0\n");
+ writel(cfg->mp_pacing0, &sdr_ctrl->mp_pacing0);
+ writel(cfg->mp_pacing1, &sdr_ctrl->mp_pacing1);
+ writel(cfg->mp_pacing2, &sdr_ctrl->mp_pacing2);
+ writel(cfg->mp_pacing3, &sdr_ctrl->mp_pacing3);
+
+ debug("Configuring MPTHRESHOLDRST_MPTHRESHOLDRST_0\n");
+ writel(cfg->mp_threshold0, &sdr_ctrl->mp_threshold0);
+ writel(cfg->mp_threshold1, &sdr_ctrl->mp_threshold1);
+ writel(cfg->mp_threshold2, &sdr_ctrl->mp_threshold2);
+
+ debug("Configuring PHYCTRL_PHYCTRL_0\n");
+ writel(cfg->phy_ctrl0, &sdr_ctrl->phy_ctrl0);
+
+ debug("Configuring CPORTWIDTH\n");
+ writel(cfg->cport_width, &sdr_ctrl->cport_width);
+
+ debug("Configuring CPORTWMAP\n");
+ writel(cfg->cport_wmap, &sdr_ctrl->cport_wmap);
+
+ debug("Configuring CPORTRMAP\n");
+ writel(cfg->cport_rmap, &sdr_ctrl->cport_rmap);
+
+ debug("Configuring RFIFOCMAP\n");
+ writel(cfg->rfifo_cmap, &sdr_ctrl->rfifo_cmap);
+
+ debug("Configuring WFIFOCMAP\n");
+ writel(cfg->wfifo_cmap, &sdr_ctrl->wfifo_cmap);
+
+ debug("Configuring CPORTRDWR\n");
+ writel(cfg->cport_rdwr, &sdr_ctrl->cport_rdwr);
+
+ debug("Configuring DRAMODT\n");
+ writel(cfg->dram_odt, &sdr_ctrl->dram_odt);
+}
+
+/**
+ * sdram_mmr_init_full() - Function to initialize SDRAM MMR
+ * @sdr_phy_reg: Value of the PHY control register 0
+ *
+ * Initialize the SDRAM MMR.
+ */
+int sdram_mmr_init_full(unsigned int sdr_phy_reg)
+{
+ const struct socfpga_sdram_config *cfg = socfpga_get_sdram_config();
+ const unsigned int rows =
+ (cfg->dram_addrw & SDR_CTRLGRP_DRAMADDRW_ROWBITS_MASK) >>
+ SDR_CTRLGRP_DRAMADDRW_ROWBITS_LSB;
+ int ret;
+
+ writel(rows, &sysmgr_regs->iswgrp_handoff[4]);
+
+ sdr_load_regs(cfg);
+
+ /* saving this value to SYSMGR.ISWGRP.HANDOFF.FPGA2SDR */
+ writel(cfg->fpgaport_rst, &sysmgr_regs->iswgrp_handoff[3]);
+
+ /* only enable if the FPGA is programmed */
+ if (fpgamgr_test_fpga_ready()) {
+ ret = sdram_write_verify(&sdr_ctrl->fpgaport_rst,
+ cfg->fpgaport_rst);
+ if (ret)
+ return ret;
+ }
+
+ /* Restore the SDR PHY Register if valid */
+ if (sdr_phy_reg != 0xffffffff)
+ writel(sdr_phy_reg, &sdr_ctrl->phy_ctrl0);
+
+ /* Final step - apply configuration changes */
+ debug("Configuring STATICCFG\n");
+ clrsetbits_le32(&sdr_ctrl->static_cfg,
+ SDR_CTRLGRP_STATICCFG_APPLYCFG_MASK,
+ 1 << SDR_CTRLGRP_STATICCFG_APPLYCFG_LSB);
+
+ sdram_set_protection_config(0, sdram_calculate_size() - 1);
+
+ sdram_dump_protection_config();
+
+ return 0;
+}
+
+/**
+ * sdram_calculate_size() - Calculate SDRAM size
+ *
+ * Calculate SDRAM device size based on SDRAM controller parameters.
+ * Size is specified in bytes.
+ */
+unsigned long sdram_calculate_size(void)
+{
+ unsigned long temp;
+ unsigned long row, bank, col, cs, width;
+ const struct socfpga_sdram_config *cfg = socfpga_get_sdram_config();
+ const unsigned int csbits =
+ ((cfg->dram_addrw & SDR_CTRLGRP_DRAMADDRW_CSBITS_MASK) >>
+ SDR_CTRLGRP_DRAMADDRW_CSBITS_LSB) + 1;
+ const unsigned int rowbits =
+ (cfg->dram_addrw & SDR_CTRLGRP_DRAMADDRW_ROWBITS_MASK) >>
+ SDR_CTRLGRP_DRAMADDRW_ROWBITS_LSB;
+
+ temp = readl(&sdr_ctrl->dram_addrw);
+ col = (temp & SDR_CTRLGRP_DRAMADDRW_COLBITS_MASK) >>
+ SDR_CTRLGRP_DRAMADDRW_COLBITS_LSB;
+
+ /*
+ * SDRAM Failure When Accessing Non-Existent Memory
+ * Use ROWBITS from Quartus/QSys to calculate SDRAM size
+ * since the FB specifies we modify ROWBITs to work around SDRAM
+ * controller issue.
+ */
+ row = readl(&sysmgr_regs->iswgrp_handoff[4]);
+ if (row == 0)
+ row = rowbits;
+ /*
+ * If the stored handoff value for rows is greater than
+ * the field width in the sdr.dramaddrw register then
+ * something is very wrong. Revert to using the the #define
+ * value handed off by the SOCEDS tool chain instead of
+ * using a broken value.
+ */
+ if (row > 31)
+ row = rowbits;
+
+ bank = (temp & SDR_CTRLGRP_DRAMADDRW_BANKBITS_MASK) >>
+ SDR_CTRLGRP_DRAMADDRW_BANKBITS_LSB;
+
+ /*
+ * SDRAM Failure When Accessing Non-Existent Memory
+ * Use CSBITs from Quartus/QSys to calculate SDRAM size
+ * since the FB specifies we modify CSBITs to work around SDRAM
+ * controller issue.
+ */
+ cs = csbits;
+
+ width = readl(&sdr_ctrl->dram_if_width);
+
+ /* ECC would not be calculated as its not addressible */
+ if (width == SDRAM_WIDTH_32BIT_WITH_ECC)
+ width = 32;
+ if (width == SDRAM_WIDTH_16BIT_WITH_ECC)
+ width = 16;
+
+ /* calculate the SDRAM size base on this info */
+ temp = 1 << (row + bank + col);
+ temp = temp * cs * (width / 8);
+
+ debug("%s returns %ld\n", __func__, temp);
+
+ return temp;
+}
diff --git a/drivers/ddr/altera/sequencer.c b/drivers/ddr/altera/sequencer.c
new file mode 100644
index 00000000000..2bd01092eed
--- /dev/null
+++ b/drivers/ddr/altera/sequencer.c
@@ -0,0 +1,3783 @@
+/*
+ * Copyright Altera Corporation (C) 2012-2015
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/sdram.h>
+#include <errno.h>
+#include "sequencer.h"
+
+static struct socfpga_sdr_rw_load_manager *sdr_rw_load_mgr_regs =
+ (struct socfpga_sdr_rw_load_manager *)
+ (SDR_PHYGRP_RWMGRGRP_ADDRESS | 0x800);
+static struct socfpga_sdr_rw_load_jump_manager *sdr_rw_load_jump_mgr_regs =
+ (struct socfpga_sdr_rw_load_jump_manager *)
+ (SDR_PHYGRP_RWMGRGRP_ADDRESS | 0xC00);
+static struct socfpga_sdr_reg_file *sdr_reg_file =
+ (struct socfpga_sdr_reg_file *)SDR_PHYGRP_REGFILEGRP_ADDRESS;
+static struct socfpga_sdr_scc_mgr *sdr_scc_mgr =
+ (struct socfpga_sdr_scc_mgr *)
+ (SDR_PHYGRP_SCCGRP_ADDRESS | 0xe00);
+static struct socfpga_phy_mgr_cmd *phy_mgr_cmd =
+ (struct socfpga_phy_mgr_cmd *)SDR_PHYGRP_PHYMGRGRP_ADDRESS;
+static struct socfpga_phy_mgr_cfg *phy_mgr_cfg =
+ (struct socfpga_phy_mgr_cfg *)
+ (SDR_PHYGRP_PHYMGRGRP_ADDRESS | 0x40);
+static struct socfpga_data_mgr *data_mgr =
+ (struct socfpga_data_mgr *)SDR_PHYGRP_DATAMGRGRP_ADDRESS;
+static struct socfpga_sdr_ctrl *sdr_ctrl =
+ (struct socfpga_sdr_ctrl *)SDR_CTRLGRP_ADDRESS;
+
+const struct socfpga_sdram_rw_mgr_config *rwcfg;
+const struct socfpga_sdram_io_config *iocfg;
+const struct socfpga_sdram_misc_config *misccfg;
+
+#define DELTA_D 1
+
+/*
+ * In order to reduce ROM size, most of the selectable calibration steps are
+ * decided at compile time based on the user's calibration mode selection,
+ * as captured by the STATIC_CALIB_STEPS selection below.
+ *
+ * However, to support simulation-time selection of fast simulation mode, where
+ * we skip everything except the bare minimum, we need a few of the steps to
+ * be dynamic. In those cases, we either use the DYNAMIC_CALIB_STEPS for the
+ * check, which is based on the rtl-supplied value, or we dynamically compute
+ * the value to use based on the dynamically-chosen calibration mode
+ */
+
+#define DLEVEL 0
+#define STATIC_IN_RTL_SIM 0
+#define STATIC_SKIP_DELAY_LOOPS 0
+
+#define STATIC_CALIB_STEPS (STATIC_IN_RTL_SIM | CALIB_SKIP_FULL_TEST | \
+ STATIC_SKIP_DELAY_LOOPS)
+
+/* calibration steps requested by the rtl */
+u16 dyn_calib_steps;
+
+/*
+ * To make CALIB_SKIP_DELAY_LOOPS a dynamic conditional option
+ * instead of static, we use boolean logic to select between
+ * non-skip and skip values
+ *
+ * The mask is set to include all bits when not-skipping, but is
+ * zero when skipping
+ */
+
+u16 skip_delay_mask; /* mask off bits when skipping/not-skipping */
+
+#define SKIP_DELAY_LOOP_VALUE_OR_ZERO(non_skip_value) \
+ ((non_skip_value) & skip_delay_mask)
+
+struct gbl_type *gbl;
+struct param_type *param;
+
+static void set_failing_group_stage(u32 group, u32 stage,
+ u32 substage)
+{
+ /*
+ * Only set the global stage if there was not been any other
+ * failing group
+ */
+ if (gbl->error_stage == CAL_STAGE_NIL) {
+ gbl->error_substage = substage;
+ gbl->error_stage = stage;
+ gbl->error_group = group;
+ }
+}
+
+static void reg_file_set_group(u16 set_group)
+{
+ clrsetbits_le32(&sdr_reg_file->cur_stage, 0xffff0000, set_group << 16);
+}
+
+static void reg_file_set_stage(u8 set_stage)
+{
+ clrsetbits_le32(&sdr_reg_file->cur_stage, 0xffff, set_stage & 0xff);
+}
+
+static void reg_file_set_sub_stage(u8 set_sub_stage)
+{
+ set_sub_stage &= 0xff;
+ clrsetbits_le32(&sdr_reg_file->cur_stage, 0xff00, set_sub_stage << 8);
+}
+
+/**
+ * phy_mgr_initialize() - Initialize PHY Manager
+ *
+ * Initialize PHY Manager.
+ */
+static void phy_mgr_initialize(void)
+{
+ u32 ratio;
+
+ debug("%s:%d\n", __func__, __LINE__);
+ /* Calibration has control over path to memory */
+ /*
+ * In Hard PHY this is a 2-bit control:
+ * 0: AFI Mux Select
+ * 1: DDIO Mux Select
+ */
+ writel(0x3, &phy_mgr_cfg->mux_sel);
+
+ /* USER memory clock is not stable we begin initialization */
+ writel(0, &phy_mgr_cfg->reset_mem_stbl);
+
+ /* USER calibration status all set to zero */
+ writel(0, &phy_mgr_cfg->cal_status);
+
+ writel(0, &phy_mgr_cfg->cal_debug_info);
+
+ /* Init params only if we do NOT skip calibration. */
+ if ((dyn_calib_steps & CALIB_SKIP_ALL) == CALIB_SKIP_ALL)
+ return;
+
+ ratio = rwcfg->mem_dq_per_read_dqs /
+ rwcfg->mem_virtual_groups_per_read_dqs;
+ param->read_correct_mask_vg = (1 << ratio) - 1;
+ param->write_correct_mask_vg = (1 << ratio) - 1;
+ param->read_correct_mask = (1 << rwcfg->mem_dq_per_read_dqs) - 1;
+ param->write_correct_mask = (1 << rwcfg->mem_dq_per_write_dqs) - 1;
+}
+
+/**
+ * set_rank_and_odt_mask() - Set Rank and ODT mask
+ * @rank: Rank mask
+ * @odt_mode: ODT mode, OFF or READ_WRITE
+ *
+ * Set Rank and ODT mask (On-Die Termination).
+ */
+static void set_rank_and_odt_mask(const u32 rank, const u32 odt_mode)
+{
+ u32 odt_mask_0 = 0;
+ u32 odt_mask_1 = 0;
+ u32 cs_and_odt_mask;
+
+ if (odt_mode == RW_MGR_ODT_MODE_OFF) {
+ odt_mask_0 = 0x0;
+ odt_mask_1 = 0x0;
+ } else { /* RW_MGR_ODT_MODE_READ_WRITE */
+ switch (rwcfg->mem_number_of_ranks) {
+ case 1: /* 1 Rank */
+ /* Read: ODT = 0 ; Write: ODT = 1 */
+ odt_mask_0 = 0x0;
+ odt_mask_1 = 0x1;
+ break;
+ case 2: /* 2 Ranks */
+ if (rwcfg->mem_number_of_cs_per_dimm == 1) {
+ /*
+ * - Dual-Slot , Single-Rank (1 CS per DIMM)
+ * OR
+ * - RDIMM, 4 total CS (2 CS per DIMM, 2 DIMM)
+ *
+ * Since MEM_NUMBER_OF_RANKS is 2, they
+ * are both single rank with 2 CS each
+ * (special for RDIMM).
+ *
+ * Read: Turn on ODT on the opposite rank
+ * Write: Turn on ODT on all ranks
+ */
+ odt_mask_0 = 0x3 & ~(1 << rank);
+ odt_mask_1 = 0x3;
+ } else {
+ /*
+ * - Single-Slot , Dual-Rank (2 CS per DIMM)
+ *
+ * Read: Turn on ODT off on all ranks
+ * Write: Turn on ODT on active rank
+ */
+ odt_mask_0 = 0x0;
+ odt_mask_1 = 0x3 & (1 << rank);
+ }
+ break;
+ case 4: /* 4 Ranks */
+ /* Read:
+ * ----------+-----------------------+
+ * | ODT |
+ * Read From +-----------------------+
+ * Rank | 3 | 2 | 1 | 0 |
+ * ----------+-----+-----+-----+-----+
+ * 0 | 0 | 1 | 0 | 0 |
+ * 1 | 1 | 0 | 0 | 0 |
+ * 2 | 0 | 0 | 0 | 1 |
+ * 3 | 0 | 0 | 1 | 0 |
+ * ----------+-----+-----+-----+-----+
+ *
+ * Write:
+ * ----------+-----------------------+
+ * | ODT |
+ * Write To +-----------------------+
+ * Rank | 3 | 2 | 1 | 0 |
+ * ----------+-----+-----+-----+-----+
+ * 0 | 0 | 1 | 0 | 1 |
+ * 1 | 1 | 0 | 1 | 0 |
+ * 2 | 0 | 1 | 0 | 1 |
+ * 3 | 1 | 0 | 1 | 0 |
+ * ----------+-----+-----+-----+-----+
+ */
+ switch (rank) {
+ case 0:
+ odt_mask_0 = 0x4;
+ odt_mask_1 = 0x5;
+ break;
+ case 1:
+ odt_mask_0 = 0x8;
+ odt_mask_1 = 0xA;
+ break;
+ case 2:
+ odt_mask_0 = 0x1;
+ odt_mask_1 = 0x5;
+ break;
+ case 3:
+ odt_mask_0 = 0x2;
+ odt_mask_1 = 0xA;
+ break;
+ }
+ break;
+ }
+ }
+
+ cs_and_odt_mask = (0xFF & ~(1 << rank)) |
+ ((0xFF & odt_mask_0) << 8) |
+ ((0xFF & odt_mask_1) << 16);
+ writel(cs_and_odt_mask, SDR_PHYGRP_RWMGRGRP_ADDRESS |
+ RW_MGR_SET_CS_AND_ODT_MASK_OFFSET);
+}
+
+/**
+ * scc_mgr_set() - Set SCC Manager register
+ * @off: Base offset in SCC Manager space
+ * @grp: Read/Write group
+ * @val: Value to be set
+ *
+ * This function sets the SCC Manager (Scan Chain Control Manager) register.
+ */
+static void scc_mgr_set(u32 off, u32 grp, u32 val)
+{
+ writel(val, SDR_PHYGRP_SCCGRP_ADDRESS | off | (grp << 2));
+}
+
+/**
+ * scc_mgr_initialize() - Initialize SCC Manager registers
+ *
+ * Initialize SCC Manager registers.
+ */
+static void scc_mgr_initialize(void)
+{
+ /*
+ * Clear register file for HPS. 16 (2^4) is the size of the
+ * full register file in the scc mgr:
+ * RFILE_DEPTH = 1 + log2(MEM_DQ_PER_DQS + 1 + MEM_DM_PER_DQS +
+ * MEM_IF_READ_DQS_WIDTH - 1);
+ */
+ int i;
+
+ for (i = 0; i < 16; i++) {
+ debug_cond(DLEVEL == 1, "%s:%d: Clearing SCC RFILE index %u\n",
+ __func__, __LINE__, i);
+ scc_mgr_set(SCC_MGR_HHP_RFILE_OFFSET, 0, i);
+ }
+}
+
+static void scc_mgr_set_dqdqs_output_phase(u32 write_group, u32 phase)
+{
+ scc_mgr_set(SCC_MGR_DQDQS_OUT_PHASE_OFFSET, write_group, phase);
+}
+
+static void scc_mgr_set_dqs_bus_in_delay(u32 read_group, u32 delay)
+{
+ scc_mgr_set(SCC_MGR_DQS_IN_DELAY_OFFSET, read_group, delay);
+}
+
+static void scc_mgr_set_dqs_en_phase(u32 read_group, u32 phase)
+{
+ scc_mgr_set(SCC_MGR_DQS_EN_PHASE_OFFSET, read_group, phase);
+}
+
+static void scc_mgr_set_dqs_en_delay(u32 read_group, u32 delay)
+{
+ scc_mgr_set(SCC_MGR_DQS_EN_DELAY_OFFSET, read_group, delay);
+}
+
+static void scc_mgr_set_dqs_io_in_delay(u32 delay)
+{
+ scc_mgr_set(SCC_MGR_IO_IN_DELAY_OFFSET, rwcfg->mem_dq_per_write_dqs,
+ delay);
+}
+
+static void scc_mgr_set_dq_in_delay(u32 dq_in_group, u32 delay)
+{
+ scc_mgr_set(SCC_MGR_IO_IN_DELAY_OFFSET, dq_in_group, delay);
+}
+
+static void scc_mgr_set_dq_out1_delay(u32 dq_in_group, u32 delay)
+{
+ scc_mgr_set(SCC_MGR_IO_OUT1_DELAY_OFFSET, dq_in_group, delay);
+}
+
+static void scc_mgr_set_dqs_out1_delay(u32 delay)
+{
+ scc_mgr_set(SCC_MGR_IO_OUT1_DELAY_OFFSET, rwcfg->mem_dq_per_write_dqs,
+ delay);
+}
+
+static void scc_mgr_set_dm_out1_delay(u32 dm, u32 delay)
+{
+ scc_mgr_set(SCC_MGR_IO_OUT1_DELAY_OFFSET,
+ rwcfg->mem_dq_per_write_dqs + 1 + dm,
+ delay);
+}
+
+/* load up dqs config settings */
+static void scc_mgr_load_dqs(u32 dqs)
+{
+ writel(dqs, &sdr_scc_mgr->dqs_ena);
+}
+
+/* load up dqs io config settings */
+static void scc_mgr_load_dqs_io(void)
+{
+ writel(0, &sdr_scc_mgr->dqs_io_ena);
+}
+
+/* load up dq config settings */
+static void scc_mgr_load_dq(u32 dq_in_group)
+{
+ writel(dq_in_group, &sdr_scc_mgr->dq_ena);
+}
+
+/* load up dm config settings */
+static void scc_mgr_load_dm(u32 dm)
+{
+ writel(dm, &sdr_scc_mgr->dm_ena);
+}
+
+/**
+ * scc_mgr_set_all_ranks() - Set SCC Manager register for all ranks
+ * @off: Base offset in SCC Manager space
+ * @grp: Read/Write group
+ * @val: Value to be set
+ * @update: If non-zero, trigger SCC Manager update for all ranks
+ *
+ * This function sets the SCC Manager (Scan Chain Control Manager) register
+ * and optionally triggers the SCC update for all ranks.
+ */
+static void scc_mgr_set_all_ranks(const u32 off, const u32 grp, const u32 val,
+ const int update)
+{
+ u32 r;
+
+ for (r = 0; r < rwcfg->mem_number_of_ranks;
+ r += NUM_RANKS_PER_SHADOW_REG) {
+ scc_mgr_set(off, grp, val);
+
+ if (update || (r == 0)) {
+ writel(grp, &sdr_scc_mgr->dqs_ena);
+ writel(0, &sdr_scc_mgr->update);
+ }
+ }
+}
+
+static void scc_mgr_set_dqs_en_phase_all_ranks(u32 read_group, u32 phase)
+{
+ /*
+ * USER although the h/w doesn't support different phases per
+ * shadow register, for simplicity our scc manager modeling
+ * keeps different phase settings per shadow reg, and it's
+ * important for us to keep them in sync to match h/w.
+ * for efficiency, the scan chain update should occur only
+ * once to sr0.
+ */
+ scc_mgr_set_all_ranks(SCC_MGR_DQS_EN_PHASE_OFFSET,
+ read_group, phase, 0);
+}
+
+static void scc_mgr_set_dqdqs_output_phase_all_ranks(u32 write_group,
+ u32 phase)
+{
+ /*
+ * USER although the h/w doesn't support different phases per
+ * shadow register, for simplicity our scc manager modeling
+ * keeps different phase settings per shadow reg, and it's
+ * important for us to keep them in sync to match h/w.
+ * for efficiency, the scan chain update should occur only
+ * once to sr0.
+ */
+ scc_mgr_set_all_ranks(SCC_MGR_DQDQS_OUT_PHASE_OFFSET,
+ write_group, phase, 0);
+}
+
+static void scc_mgr_set_dqs_en_delay_all_ranks(u32 read_group,
+ u32 delay)
+{
+ /*
+ * In shadow register mode, the T11 settings are stored in
+ * registers in the core, which are updated by the DQS_ENA
+ * signals. Not issuing the SCC_MGR_UPD command allows us to
+ * save lots of rank switching overhead, by calling
+ * select_shadow_regs_for_update with update_scan_chains
+ * set to 0.
+ */
+ scc_mgr_set_all_ranks(SCC_MGR_DQS_EN_DELAY_OFFSET,
+ read_group, delay, 1);
+ writel(0, &sdr_scc_mgr->update);
+}
+
+/**
+ * scc_mgr_set_oct_out1_delay() - Set OCT output delay
+ * @write_group: Write group
+ * @delay: Delay value
+ *
+ * This function sets the OCT output delay in SCC manager.
+ */
+static void scc_mgr_set_oct_out1_delay(const u32 write_group, const u32 delay)
+{
+ const int ratio = rwcfg->mem_if_read_dqs_width /
+ rwcfg->mem_if_write_dqs_width;
+ const int base = write_group * ratio;
+ int i;
+ /*
+ * Load the setting in the SCC manager
+ * Although OCT affects only write data, the OCT delay is controlled
+ * by the DQS logic block which is instantiated once per read group.
+ * For protocols where a write group consists of multiple read groups,
+ * the setting must be set multiple times.
+ */
+ for (i = 0; i < ratio; i++)
+ scc_mgr_set(SCC_MGR_OCT_OUT1_DELAY_OFFSET, base + i, delay);
+}
+
+/**
+ * scc_mgr_set_hhp_extras() - Set HHP extras.
+ *
+ * Load the fixed setting in the SCC manager HHP extras.
+ */
+static void scc_mgr_set_hhp_extras(void)
+{
+ /*
+ * Load the fixed setting in the SCC manager
+ * bits: 0:0 = 1'b1 - DQS bypass
+ * bits: 1:1 = 1'b1 - DQ bypass
+ * bits: 4:2 = 3'b001 - rfifo_mode
+ * bits: 6:5 = 2'b01 - rfifo clock_select
+ * bits: 7:7 = 1'b0 - separate gating from ungating setting
+ * bits: 8:8 = 1'b0 - separate OE from Output delay setting
+ */
+ const u32 value = (0 << 8) | (0 << 7) | (1 << 5) |
+ (1 << 2) | (1 << 1) | (1 << 0);
+ const u32 addr = SDR_PHYGRP_SCCGRP_ADDRESS |
+ SCC_MGR_HHP_GLOBALS_OFFSET |
+ SCC_MGR_HHP_EXTRAS_OFFSET;
+
+ debug_cond(DLEVEL == 1, "%s:%d Setting HHP Extras\n",
+ __func__, __LINE__);
+ writel(value, addr);
+ debug_cond(DLEVEL == 1, "%s:%d Done Setting HHP Extras\n",
+ __func__, __LINE__);
+}
+
+/**
+ * scc_mgr_zero_all() - Zero all DQS config
+ *
+ * Zero all DQS config.
+ */
+static void scc_mgr_zero_all(void)
+{
+ int i, r;
+
+ /*
+ * USER Zero all DQS config settings, across all groups and all
+ * shadow registers
+ */
+ for (r = 0; r < rwcfg->mem_number_of_ranks;
+ r += NUM_RANKS_PER_SHADOW_REG) {
+ for (i = 0; i < rwcfg->mem_if_read_dqs_width; i++) {
+ /*
+ * The phases actually don't exist on a per-rank basis,
+ * but there's no harm updating them several times, so
+ * let's keep the code simple.
+ */
+ scc_mgr_set_dqs_bus_in_delay(i, iocfg->dqs_in_reserve);
+ scc_mgr_set_dqs_en_phase(i, 0);
+ scc_mgr_set_dqs_en_delay(i, 0);
+ }
+
+ for (i = 0; i < rwcfg->mem_if_write_dqs_width; i++) {
+ scc_mgr_set_dqdqs_output_phase(i, 0);
+ /* Arria V/Cyclone V don't have out2. */
+ scc_mgr_set_oct_out1_delay(i, iocfg->dqs_out_reserve);
+ }
+ }
+
+ /* Multicast to all DQS group enables. */
+ writel(0xff, &sdr_scc_mgr->dqs_ena);
+ writel(0, &sdr_scc_mgr->update);
+}
+
+/**
+ * scc_set_bypass_mode() - Set bypass mode and trigger SCC update
+ * @write_group: Write group
+ *
+ * Set bypass mode and trigger SCC update.
+ */
+static void scc_set_bypass_mode(const u32 write_group)
+{
+ /* Multicast to all DQ enables. */
+ writel(0xff, &sdr_scc_mgr->dq_ena);
+ writel(0xff, &sdr_scc_mgr->dm_ena);
+
+ /* Update current DQS IO enable. */
+ writel(0, &sdr_scc_mgr->dqs_io_ena);
+
+ /* Update the DQS logic. */
+ writel(write_group, &sdr_scc_mgr->dqs_ena);
+
+ /* Hit update. */
+ writel(0, &sdr_scc_mgr->update);
+}
+
+/**
+ * scc_mgr_load_dqs_for_write_group() - Load DQS settings for Write Group
+ * @write_group: Write group
+ *
+ * Load DQS settings for Write Group, do not trigger SCC update.
+ */
+static void scc_mgr_load_dqs_for_write_group(const u32 write_group)
+{
+ const int ratio = rwcfg->mem_if_read_dqs_width /
+ rwcfg->mem_if_write_dqs_width;
+ const int base = write_group * ratio;
+ int i;
+ /*
+ * Load the setting in the SCC manager
+ * Although OCT affects only write data, the OCT delay is controlled
+ * by the DQS logic block which is instantiated once per read group.
+ * For protocols where a write group consists of multiple read groups,
+ * the setting must be set multiple times.
+ */
+ for (i = 0; i < ratio; i++)
+ writel(base + i, &sdr_scc_mgr->dqs_ena);
+}
+
+/**
+ * scc_mgr_zero_group() - Zero all configs for a group
+ *
+ * Zero DQ, DM, DQS and OCT configs for a group.
+ */
+static void scc_mgr_zero_group(const u32 write_group, const int out_only)
+{
+ int i, r;
+
+ for (r = 0; r < rwcfg->mem_number_of_ranks;
+ r += NUM_RANKS_PER_SHADOW_REG) {
+ /* Zero all DQ config settings. */
+ for (i = 0; i < rwcfg->mem_dq_per_write_dqs; i++) {
+ scc_mgr_set_dq_out1_delay(i, 0);
+ if (!out_only)
+ scc_mgr_set_dq_in_delay(i, 0);
+ }
+
+ /* Multicast to all DQ enables. */
+ writel(0xff, &sdr_scc_mgr->dq_ena);
+
+ /* Zero all DM config settings. */
+ for (i = 0; i < RW_MGR_NUM_DM_PER_WRITE_GROUP; i++)
+ scc_mgr_set_dm_out1_delay(i, 0);
+
+ /* Multicast to all DM enables. */
+ writel(0xff, &sdr_scc_mgr->dm_ena);
+
+ /* Zero all DQS IO settings. */
+ if (!out_only)
+ scc_mgr_set_dqs_io_in_delay(0);
+
+ /* Arria V/Cyclone V don't have out2. */
+ scc_mgr_set_dqs_out1_delay(iocfg->dqs_out_reserve);
+ scc_mgr_set_oct_out1_delay(write_group, iocfg->dqs_out_reserve);
+ scc_mgr_load_dqs_for_write_group(write_group);
+
+ /* Multicast to all DQS IO enables (only 1 in total). */
+ writel(0, &sdr_scc_mgr->dqs_io_ena);
+
+ /* Hit update to zero everything. */
+ writel(0, &sdr_scc_mgr->update);
+ }
+}
+
+/*
+ * apply and load a particular input delay for the DQ pins in a group
+ * group_bgn is the index of the first dq pin (in the write group)
+ */
+static void scc_mgr_apply_group_dq_in_delay(u32 group_bgn, u32 delay)
+{
+ u32 i, p;
+
+ for (i = 0, p = group_bgn; i < rwcfg->mem_dq_per_read_dqs; i++, p++) {
+ scc_mgr_set_dq_in_delay(p, delay);
+ scc_mgr_load_dq(p);
+ }
+}
+
+/**
+ * scc_mgr_apply_group_dq_out1_delay() - Apply and load an output delay for the DQ pins in a group
+ * @delay: Delay value
+ *
+ * Apply and load a particular output delay for the DQ pins in a group.
+ */
+static void scc_mgr_apply_group_dq_out1_delay(const u32 delay)
+{
+ int i;
+
+ for (i = 0; i < rwcfg->mem_dq_per_write_dqs; i++) {
+ scc_mgr_set_dq_out1_delay(i, delay);
+ scc_mgr_load_dq(i);
+ }
+}
+
+/* apply and load a particular output delay for the DM pins in a group */
+static void scc_mgr_apply_group_dm_out1_delay(u32 delay1)
+{
+ u32 i;
+
+ for (i = 0; i < RW_MGR_NUM_DM_PER_WRITE_GROUP; i++) {
+ scc_mgr_set_dm_out1_delay(i, delay1);
+ scc_mgr_load_dm(i);
+ }
+}
+
+
+/* apply and load delay on both DQS and OCT out1 */
+static void scc_mgr_apply_group_dqs_io_and_oct_out1(u32 write_group,
+ u32 delay)
+{
+ scc_mgr_set_dqs_out1_delay(delay);
+ scc_mgr_load_dqs_io();
+
+ scc_mgr_set_oct_out1_delay(write_group, delay);
+ scc_mgr_load_dqs_for_write_group(write_group);
+}
+
+/**
+ * scc_mgr_apply_group_all_out_delay_add() - Apply a delay to the entire output side: DQ, DM, DQS, OCT
+ * @write_group: Write group
+ * @delay: Delay value
+ *
+ * Apply a delay to the entire output side: DQ, DM, DQS, OCT.
+ */
+static void scc_mgr_apply_group_all_out_delay_add(const u32 write_group,
+ const u32 delay)
+{
+ u32 i, new_delay;
+
+ /* DQ shift */
+ for (i = 0; i < rwcfg->mem_dq_per_write_dqs; i++)
+ scc_mgr_load_dq(i);
+
+ /* DM shift */
+ for (i = 0; i < RW_MGR_NUM_DM_PER_WRITE_GROUP; i++)
+ scc_mgr_load_dm(i);
+
+ /* DQS shift */
+ new_delay = READ_SCC_DQS_IO_OUT2_DELAY + delay;
+ if (new_delay > iocfg->io_out2_delay_max) {
+ debug_cond(DLEVEL == 1,
+ "%s:%d (%u, %u) DQS: %u > %d; adding %u to OUT1\n",
+ __func__, __LINE__, write_group, delay, new_delay,
+ iocfg->io_out2_delay_max,
+ new_delay - iocfg->io_out2_delay_max);
+ new_delay -= iocfg->io_out2_delay_max;
+ scc_mgr_set_dqs_out1_delay(new_delay);
+ }
+
+ scc_mgr_load_dqs_io();
+
+ /* OCT shift */
+ new_delay = READ_SCC_OCT_OUT2_DELAY + delay;
+ if (new_delay > iocfg->io_out2_delay_max) {
+ debug_cond(DLEVEL == 1,
+ "%s:%d (%u, %u) DQS: %u > %d; adding %u to OUT1\n",
+ __func__, __LINE__, write_group, delay,
+ new_delay, iocfg->io_out2_delay_max,
+ new_delay - iocfg->io_out2_delay_max);
+ new_delay -= iocfg->io_out2_delay_max;
+ scc_mgr_set_oct_out1_delay(write_group, new_delay);
+ }
+
+ scc_mgr_load_dqs_for_write_group(write_group);
+}
+
+/**
+ * scc_mgr_apply_group_all_out_delay_add() - Apply a delay to the entire output side to all ranks
+ * @write_group: Write group
+ * @delay: Delay value
+ *
+ * Apply a delay to the entire output side (DQ, DM, DQS, OCT) to all ranks.
+ */
+static void
+scc_mgr_apply_group_all_out_delay_add_all_ranks(const u32 write_group,
+ const u32 delay)
+{
+ int r;
+
+ for (r = 0; r < rwcfg->mem_number_of_ranks;
+ r += NUM_RANKS_PER_SHADOW_REG) {
+ scc_mgr_apply_group_all_out_delay_add(write_group, delay);
+ writel(0, &sdr_scc_mgr->update);
+ }
+}
+
+/**
+ * set_jump_as_return() - Return instruction optimization
+ *
+ * Optimization used to recover some slots in ddr3 inst_rom could be
+ * applied to other protocols if we wanted to
+ */
+static void set_jump_as_return(void)
+{
+ /*
+ * To save space, we replace return with jump to special shared
+ * RETURN instruction so we set the counter to large value so that
+ * we always jump.
+ */
+ writel(0xff, &sdr_rw_load_mgr_regs->load_cntr0);
+ writel(rwcfg->rreturn, &sdr_rw_load_jump_mgr_regs->load_jump_add0);
+}
+
+/**
+ * delay_for_n_mem_clocks() - Delay for N memory clocks
+ * @clocks: Length of the delay
+ *
+ * Delay for N memory clocks.
+ */
+static void delay_for_n_mem_clocks(const u32 clocks)
+{
+ u32 afi_clocks;
+ u16 c_loop;
+ u8 inner;
+ u8 outer;
+
+ debug("%s:%d: clocks=%u ... start\n", __func__, __LINE__, clocks);
+
+ /* Scale (rounding up) to get afi clocks. */
+ afi_clocks = DIV_ROUND_UP(clocks, misccfg->afi_rate_ratio);
+ if (afi_clocks) /* Temporary underflow protection */
+ afi_clocks--;
+
+ /*
+ * Note, we don't bother accounting for being off a little
+ * bit because of a few extra instructions in outer loops.
+ * Note, the loops have a test at the end, and do the test
+ * before the decrement, and so always perform the loop
+ * 1 time more than the counter value
+ */
+ c_loop = afi_clocks >> 16;
+ outer = c_loop ? 0xff : (afi_clocks >> 8);
+ inner = outer ? 0xff : afi_clocks;
+
+ /*
+ * rom instructions are structured as follows:
+ *
+ * IDLE_LOOP2: jnz cntr0, TARGET_A
+ * IDLE_LOOP1: jnz cntr1, TARGET_B
+ * return
+ *
+ * so, when doing nested loops, TARGET_A is set to IDLE_LOOP2, and
+ * TARGET_B is set to IDLE_LOOP2 as well
+ *
+ * if we have no outer loop, though, then we can use IDLE_LOOP1 only,
+ * and set TARGET_B to IDLE_LOOP1 and we skip IDLE_LOOP2 entirely
+ *
+ * a little confusing, but it helps save precious space in the inst_rom
+ * and sequencer rom and keeps the delays more accurate and reduces
+ * overhead
+ */
+ if (afi_clocks < 0x100) {
+ writel(SKIP_DELAY_LOOP_VALUE_OR_ZERO(inner),
+ &sdr_rw_load_mgr_regs->load_cntr1);
+
+ writel(rwcfg->idle_loop1,
+ &sdr_rw_load_jump_mgr_regs->load_jump_add1);
+
+ writel(rwcfg->idle_loop1, SDR_PHYGRP_RWMGRGRP_ADDRESS |
+ RW_MGR_RUN_SINGLE_GROUP_OFFSET);
+ } else {
+ writel(SKIP_DELAY_LOOP_VALUE_OR_ZERO(inner),
+ &sdr_rw_load_mgr_regs->load_cntr0);
+
+ writel(SKIP_DELAY_LOOP_VALUE_OR_ZERO(outer),
+ &sdr_rw_load_mgr_regs->load_cntr1);
+
+ writel(rwcfg->idle_loop2,
+ &sdr_rw_load_jump_mgr_regs->load_jump_add0);
+
+ writel(rwcfg->idle_loop2,
+ &sdr_rw_load_jump_mgr_regs->load_jump_add1);
+
+ do {
+ writel(rwcfg->idle_loop2,
+ SDR_PHYGRP_RWMGRGRP_ADDRESS |
+ RW_MGR_RUN_SINGLE_GROUP_OFFSET);
+ } while (c_loop-- != 0);
+ }
+ debug("%s:%d clocks=%u ... end\n", __func__, __LINE__, clocks);
+}
+
+/**
+ * rw_mgr_mem_init_load_regs() - Load instruction registers
+ * @cntr0: Counter 0 value
+ * @cntr1: Counter 1 value
+ * @cntr2: Counter 2 value
+ * @jump: Jump instruction value
+ *
+ * Load instruction registers.
+ */
+static void rw_mgr_mem_init_load_regs(u32 cntr0, u32 cntr1, u32 cntr2, u32 jump)
+{
+ u32 grpaddr = SDR_PHYGRP_RWMGRGRP_ADDRESS |
+ RW_MGR_RUN_SINGLE_GROUP_OFFSET;
+
+ /* Load counters */
+ writel(SKIP_DELAY_LOOP_VALUE_OR_ZERO(cntr0),
+ &sdr_rw_load_mgr_regs->load_cntr0);
+ writel(SKIP_DELAY_LOOP_VALUE_OR_ZERO(cntr1),
+ &sdr_rw_load_mgr_regs->load_cntr1);
+ writel(SKIP_DELAY_LOOP_VALUE_OR_ZERO(cntr2),
+ &sdr_rw_load_mgr_regs->load_cntr2);
+
+ /* Load jump address */
+ writel(jump, &sdr_rw_load_jump_mgr_regs->load_jump_add0);
+ writel(jump, &sdr_rw_load_jump_mgr_regs->load_jump_add1);
+ writel(jump, &sdr_rw_load_jump_mgr_regs->load_jump_add2);
+
+ /* Execute count instruction */
+ writel(jump, grpaddr);
+}
+
+/**
+ * rw_mgr_mem_load_user() - Load user calibration values
+ * @fin1: Final instruction 1
+ * @fin2: Final instruction 2
+ * @precharge: If 1, precharge the banks at the end
+ *
+ * Load user calibration values and optionally precharge the banks.
+ */
+static void rw_mgr_mem_load_user(const u32 fin1, const u32 fin2,
+ const int precharge)
+{
+ u32 grpaddr = SDR_PHYGRP_RWMGRGRP_ADDRESS |
+ RW_MGR_RUN_SINGLE_GROUP_OFFSET;
+ u32 r;
+
+ for (r = 0; r < rwcfg->mem_number_of_ranks; r++) {
+ /* set rank */
+ set_rank_and_odt_mask(r, RW_MGR_ODT_MODE_OFF);
+
+ /* precharge all banks ... */
+ if (precharge)
+ writel(rwcfg->precharge_all, grpaddr);
+
+ /*
+ * USER Use Mirror-ed commands for odd ranks if address
+ * mirrorring is on
+ */
+ if ((rwcfg->mem_address_mirroring >> r) & 0x1) {
+ set_jump_as_return();
+ writel(rwcfg->mrs2_mirr, grpaddr);
+ delay_for_n_mem_clocks(4);
+ set_jump_as_return();
+ writel(rwcfg->mrs3_mirr, grpaddr);
+ delay_for_n_mem_clocks(4);
+ set_jump_as_return();
+ writel(rwcfg->mrs1_mirr, grpaddr);
+ delay_for_n_mem_clocks(4);
+ set_jump_as_return();
+ writel(fin1, grpaddr);
+ } else {
+ set_jump_as_return();
+ writel(rwcfg->mrs2, grpaddr);
+ delay_for_n_mem_clocks(4);
+ set_jump_as_return();
+ writel(rwcfg->mrs3, grpaddr);
+ delay_for_n_mem_clocks(4);
+ set_jump_as_return();
+ writel(rwcfg->mrs1, grpaddr);
+ set_jump_as_return();
+ writel(fin2, grpaddr);
+ }
+
+ if (precharge)
+ continue;
+
+ set_jump_as_return();
+ writel(rwcfg->zqcl, grpaddr);
+
+ /* tZQinit = tDLLK = 512 ck cycles */
+ delay_for_n_mem_clocks(512);
+ }
+}
+
+/**
+ * rw_mgr_mem_initialize() - Initialize RW Manager
+ *
+ * Initialize RW Manager.
+ */
+static void rw_mgr_mem_initialize(void)
+{
+ debug("%s:%d\n", __func__, __LINE__);
+
+ /* The reset / cke part of initialization is broadcasted to all ranks */
+ writel(RW_MGR_RANK_ALL, SDR_PHYGRP_RWMGRGRP_ADDRESS |
+ RW_MGR_SET_CS_AND_ODT_MASK_OFFSET);
+
+ /*
+ * Here's how you load register for a loop
+ * Counters are located @ 0x800
+ * Jump address are located @ 0xC00
+ * For both, registers 0 to 3 are selected using bits 3 and 2, like
+ * in 0x800, 0x804, 0x808, 0x80C and 0xC00, 0xC04, 0xC08, 0xC0C
+ * I know this ain't pretty, but Avalon bus throws away the 2 least
+ * significant bits
+ */
+
+ /* Start with memory RESET activated */
+
+ /* tINIT = 200us */
+
+ /*
+ * 200us @ 266MHz (3.75 ns) ~ 54000 clock cycles
+ * If a and b are the number of iteration in 2 nested loops
+ * it takes the following number of cycles to complete the operation:
+ * number_of_cycles = ((2 + n) * a + 2) * b
+ * where n is the number of instruction in the inner loop
+ * One possible solution is n = 0 , a = 256 , b = 106 => a = FF,
+ * b = 6A
+ */
+ rw_mgr_mem_init_load_regs(misccfg->tinit_cntr0_val,
+ misccfg->tinit_cntr1_val,
+ misccfg->tinit_cntr2_val,
+ rwcfg->init_reset_0_cke_0);
+
+ /* Indicate that memory is stable. */
+ writel(1, &phy_mgr_cfg->reset_mem_stbl);
+
+ /*
+ * transition the RESET to high
+ * Wait for 500us
+ */
+
+ /*
+ * 500us @ 266MHz (3.75 ns) ~ 134000 clock cycles
+ * If a and b are the number of iteration in 2 nested loops
+ * it takes the following number of cycles to complete the operation
+ * number_of_cycles = ((2 + n) * a + 2) * b
+ * where n is the number of instruction in the inner loop
+ * One possible solution is n = 2 , a = 131 , b = 256 => a = 83,
+ * b = FF
+ */
+ rw_mgr_mem_init_load_regs(misccfg->treset_cntr0_val,
+ misccfg->treset_cntr1_val,
+ misccfg->treset_cntr2_val,
+ rwcfg->init_reset_1_cke_0);
+
+ /* Bring up clock enable. */
+
+ /* tXRP < 250 ck cycles */
+ delay_for_n_mem_clocks(250);
+
+ rw_mgr_mem_load_user(rwcfg->mrs0_dll_reset_mirr, rwcfg->mrs0_dll_reset,
+ 0);
+}
+
+/**
+ * rw_mgr_mem_handoff() - Hand off the memory to user
+ *
+ * At the end of calibration we have to program the user settings in
+ * and hand off the memory to the user.
+ */
+static void rw_mgr_mem_handoff(void)
+{
+ rw_mgr_mem_load_user(rwcfg->mrs0_user_mirr, rwcfg->mrs0_user, 1);
+ /*
+ * Need to wait tMOD (12CK or 15ns) time before issuing other
+ * commands, but we will have plenty of NIOS cycles before actual
+ * handoff so its okay.
+ */
+}
+
+/**
+ * rw_mgr_mem_calibrate_write_test_issue() - Issue write test command
+ * @group: Write Group
+ * @use_dm: Use DM
+ *
+ * Issue write test command. Two variants are provided, one that just tests
+ * a write pattern and another that tests datamask functionality.
+ */
+static void rw_mgr_mem_calibrate_write_test_issue(u32 group,
+ u32 test_dm)
+{
+ const u32 quick_write_mode =
+ (STATIC_CALIB_STEPS & CALIB_SKIP_WRITES) &&
+ misccfg->enable_super_quick_calibration;
+ u32 mcc_instruction;
+ u32 rw_wl_nop_cycles;
+
+ /*
+ * Set counter and jump addresses for the right
+ * number of NOP cycles.
+ * The number of supported NOP cycles can range from -1 to infinity
+ * Three different cases are handled:
+ *
+ * 1. For a number of NOP cycles greater than 0, the RW Mgr looping
+ * mechanism will be used to insert the right number of NOPs
+ *
+ * 2. For a number of NOP cycles equals to 0, the micro-instruction
+ * issuing the write command will jump straight to the
+ * micro-instruction that turns on DQS (for DDRx), or outputs write
+ * data (for RLD), skipping
+ * the NOP micro-instruction all together
+ *
+ * 3. A number of NOP cycles equal to -1 indicates that DQS must be
+ * turned on in the same micro-instruction that issues the write
+ * command. Then we need
+ * to directly jump to the micro-instruction that sends out the data
+ *
+ * NOTE: Implementing this mechanism uses 2 RW Mgr jump-counters
+ * (2 and 3). One jump-counter (0) is used to perform multiple
+ * write-read operations.
+ * one counter left to issue this command in "multiple-group" mode
+ */
+
+ rw_wl_nop_cycles = gbl->rw_wl_nop_cycles;
+
+ if (rw_wl_nop_cycles == -1) {
+ /*
+ * CNTR 2 - We want to execute the special write operation that
+ * turns on DQS right away and then skip directly to the
+ * instruction that sends out the data. We set the counter to a
+ * large number so that the jump is always taken.
+ */
+ writel(0xFF, &sdr_rw_load_mgr_regs->load_cntr2);
+
+ /* CNTR 3 - Not used */
+ if (test_dm) {
+ mcc_instruction = rwcfg->lfsr_wr_rd_dm_bank_0_wl_1;
+ writel(rwcfg->lfsr_wr_rd_dm_bank_0_data,
+ &sdr_rw_load_jump_mgr_regs->load_jump_add2);
+ writel(rwcfg->lfsr_wr_rd_dm_bank_0_nop,
+ &sdr_rw_load_jump_mgr_regs->load_jump_add3);
+ } else {
+ mcc_instruction = rwcfg->lfsr_wr_rd_bank_0_wl_1;
+ writel(rwcfg->lfsr_wr_rd_bank_0_data,
+ &sdr_rw_load_jump_mgr_regs->load_jump_add2);
+ writel(rwcfg->lfsr_wr_rd_bank_0_nop,
+ &sdr_rw_load_jump_mgr_regs->load_jump_add3);
+ }
+ } else if (rw_wl_nop_cycles == 0) {
+ /*
+ * CNTR 2 - We want to skip the NOP operation and go straight
+ * to the DQS enable instruction. We set the counter to a large
+ * number so that the jump is always taken.
+ */
+ writel(0xFF, &sdr_rw_load_mgr_regs->load_cntr2);
+
+ /* CNTR 3 - Not used */
+ if (test_dm) {
+ mcc_instruction = rwcfg->lfsr_wr_rd_dm_bank_0;
+ writel(rwcfg->lfsr_wr_rd_dm_bank_0_dqs,
+ &sdr_rw_load_jump_mgr_regs->load_jump_add2);
+ } else {
+ mcc_instruction = rwcfg->lfsr_wr_rd_bank_0;
+ writel(rwcfg->lfsr_wr_rd_bank_0_dqs,
+ &sdr_rw_load_jump_mgr_regs->load_jump_add2);
+ }
+ } else {
+ /*
+ * CNTR 2 - In this case we want to execute the next instruction
+ * and NOT take the jump. So we set the counter to 0. The jump
+ * address doesn't count.
+ */
+ writel(0x0, &sdr_rw_load_mgr_regs->load_cntr2);
+ writel(0x0, &sdr_rw_load_jump_mgr_regs->load_jump_add2);
+
+ /*
+ * CNTR 3 - Set the nop counter to the number of cycles we
+ * need to loop for, minus 1.
+ */
+ writel(rw_wl_nop_cycles - 1, &sdr_rw_load_mgr_regs->load_cntr3);
+ if (test_dm) {
+ mcc_instruction = rwcfg->lfsr_wr_rd_dm_bank_0;
+ writel(rwcfg->lfsr_wr_rd_dm_bank_0_nop,
+ &sdr_rw_load_jump_mgr_regs->load_jump_add3);
+ } else {
+ mcc_instruction = rwcfg->lfsr_wr_rd_bank_0;
+ writel(rwcfg->lfsr_wr_rd_bank_0_nop,
+ &sdr_rw_load_jump_mgr_regs->load_jump_add3);
+ }
+ }
+
+ writel(0, SDR_PHYGRP_RWMGRGRP_ADDRESS |
+ RW_MGR_RESET_READ_DATAPATH_OFFSET);
+
+ if (quick_write_mode)
+ writel(0x08, &sdr_rw_load_mgr_regs->load_cntr0);
+ else
+ writel(0x40, &sdr_rw_load_mgr_regs->load_cntr0);
+
+ writel(mcc_instruction, &sdr_rw_load_jump_mgr_regs->load_jump_add0);
+
+ /*
+ * CNTR 1 - This is used to ensure enough time elapses
+ * for read data to come back.
+ */
+ writel(0x30, &sdr_rw_load_mgr_regs->load_cntr1);
+
+ if (test_dm) {
+ writel(rwcfg->lfsr_wr_rd_dm_bank_0_wait,
+ &sdr_rw_load_jump_mgr_regs->load_jump_add1);
+ } else {
+ writel(rwcfg->lfsr_wr_rd_bank_0_wait,
+ &sdr_rw_load_jump_mgr_regs->load_jump_add1);
+ }
+
+ writel(mcc_instruction, (SDR_PHYGRP_RWMGRGRP_ADDRESS |
+ RW_MGR_RUN_SINGLE_GROUP_OFFSET) +
+ (group << 2));
+}
+
+/**
+ * rw_mgr_mem_calibrate_write_test() - Test writes, check for single/multiple pass
+ * @rank_bgn: Rank number
+ * @write_group: Write Group
+ * @use_dm: Use DM
+ * @all_correct: All bits must be correct in the mask
+ * @bit_chk: Resulting bit mask after the test
+ * @all_ranks: Test all ranks
+ *
+ * Test writes, can check for a single bit pass or multiple bit pass.
+ */
+static int
+rw_mgr_mem_calibrate_write_test(const u32 rank_bgn, const u32 write_group,
+ const u32 use_dm, const u32 all_correct,
+ u32 *bit_chk, const u32 all_ranks)
+{
+ const u32 rank_end = all_ranks ?
+ rwcfg->mem_number_of_ranks :
+ (rank_bgn + NUM_RANKS_PER_SHADOW_REG);
+ const u32 shift_ratio = rwcfg->mem_dq_per_write_dqs /
+ rwcfg->mem_virtual_groups_per_write_dqs;
+ const u32 correct_mask_vg = param->write_correct_mask_vg;
+
+ u32 tmp_bit_chk, base_rw_mgr;
+ int vg, r;
+
+ *bit_chk = param->write_correct_mask;
+
+ for (r = rank_bgn; r < rank_end; r++) {
+ /* Set rank */
+ set_rank_and_odt_mask(r, RW_MGR_ODT_MODE_READ_WRITE);
+
+ tmp_bit_chk = 0;
+ for (vg = rwcfg->mem_virtual_groups_per_write_dqs - 1;
+ vg >= 0; vg--) {
+ /* Reset the FIFOs to get pointers to known state. */
+ writel(0, &phy_mgr_cmd->fifo_reset);
+
+ rw_mgr_mem_calibrate_write_test_issue(
+ write_group *
+ rwcfg->mem_virtual_groups_per_write_dqs + vg,
+ use_dm);
+
+ base_rw_mgr = readl(SDR_PHYGRP_RWMGRGRP_ADDRESS);
+ tmp_bit_chk <<= shift_ratio;
+ tmp_bit_chk |= (correct_mask_vg & ~(base_rw_mgr));
+ }
+
+ *bit_chk &= tmp_bit_chk;
+ }
+
+ set_rank_and_odt_mask(0, RW_MGR_ODT_MODE_OFF);
+ if (all_correct) {
+ debug_cond(DLEVEL == 2,
+ "write_test(%u,%u,ALL) : %u == %u => %i\n",
+ write_group, use_dm, *bit_chk,
+ param->write_correct_mask,
+ *bit_chk == param->write_correct_mask);
+ return *bit_chk == param->write_correct_mask;
+ } else {
+ set_rank_and_odt_mask(0, RW_MGR_ODT_MODE_OFF);
+ debug_cond(DLEVEL == 2,
+ "write_test(%u,%u,ONE) : %u != %i => %i\n",
+ write_group, use_dm, *bit_chk, 0, *bit_chk != 0);
+ return *bit_chk != 0x00;
+ }
+}
+
+/**
+ * rw_mgr_mem_calibrate_read_test_patterns() - Read back test patterns
+ * @rank_bgn: Rank number
+ * @group: Read/Write Group
+ * @all_ranks: Test all ranks
+ *
+ * Performs a guaranteed read on the patterns we are going to use during a
+ * read test to ensure memory works.
+ */
+static int
+rw_mgr_mem_calibrate_read_test_patterns(const u32 rank_bgn, const u32 group,
+ const u32 all_ranks)
+{
+ const u32 addr = SDR_PHYGRP_RWMGRGRP_ADDRESS |
+ RW_MGR_RUN_SINGLE_GROUP_OFFSET;
+ const u32 addr_offset =
+ (group * rwcfg->mem_virtual_groups_per_read_dqs) << 2;
+ const u32 rank_end = all_ranks ?
+ rwcfg->mem_number_of_ranks :
+ (rank_bgn + NUM_RANKS_PER_SHADOW_REG);
+ const u32 shift_ratio = rwcfg->mem_dq_per_read_dqs /
+ rwcfg->mem_virtual_groups_per_read_dqs;
+ const u32 correct_mask_vg = param->read_correct_mask_vg;
+
+ u32 tmp_bit_chk, base_rw_mgr, bit_chk;
+ int vg, r;
+ int ret = 0;
+
+ bit_chk = param->read_correct_mask;
+
+ for (r = rank_bgn; r < rank_end; r++) {
+ /* Set rank */
+ set_rank_and_odt_mask(r, RW_MGR_ODT_MODE_READ_WRITE);
+
+ /* Load up a constant bursts of read commands */
+ writel(0x20, &sdr_rw_load_mgr_regs->load_cntr0);
+ writel(rwcfg->guaranteed_read,
+ &sdr_rw_load_jump_mgr_regs->load_jump_add0);
+
+ writel(0x20, &sdr_rw_load_mgr_regs->load_cntr1);
+ writel(rwcfg->guaranteed_read_cont,
+ &sdr_rw_load_jump_mgr_regs->load_jump_add1);
+
+ tmp_bit_chk = 0;
+ for (vg = rwcfg->mem_virtual_groups_per_read_dqs - 1;
+ vg >= 0; vg--) {
+ /* Reset the FIFOs to get pointers to known state. */
+ writel(0, &phy_mgr_cmd->fifo_reset);
+ writel(0, SDR_PHYGRP_RWMGRGRP_ADDRESS |
+ RW_MGR_RESET_READ_DATAPATH_OFFSET);
+ writel(rwcfg->guaranteed_read,
+ addr + addr_offset + (vg << 2));
+
+ base_rw_mgr = readl(SDR_PHYGRP_RWMGRGRP_ADDRESS);
+ tmp_bit_chk <<= shift_ratio;
+ tmp_bit_chk |= correct_mask_vg & ~base_rw_mgr;
+ }
+
+ bit_chk &= tmp_bit_chk;
+ }
+
+ writel(rwcfg->clear_dqs_enable, addr + (group << 2));
+
+ set_rank_and_odt_mask(0, RW_MGR_ODT_MODE_OFF);
+
+ if (bit_chk != param->read_correct_mask)
+ ret = -EIO;
+
+ debug_cond(DLEVEL == 1,
+ "%s:%d test_load_patterns(%u,ALL) => (%u == %u) => %i\n",
+ __func__, __LINE__, group, bit_chk,
+ param->read_correct_mask, ret);
+
+ return ret;
+}
+
+/**
+ * rw_mgr_mem_calibrate_read_load_patterns() - Load up the patterns for read test
+ * @rank_bgn: Rank number
+ * @all_ranks: Test all ranks
+ *
+ * Load up the patterns we are going to use during a read test.
+ */
+static void rw_mgr_mem_calibrate_read_load_patterns(const u32 rank_bgn,
+ const int all_ranks)
+{
+ const u32 rank_end = all_ranks ?
+ rwcfg->mem_number_of_ranks :
+ (rank_bgn + NUM_RANKS_PER_SHADOW_REG);
+ u32 r;
+
+ debug("%s:%d\n", __func__, __LINE__);
+
+ for (r = rank_bgn; r < rank_end; r++) {
+ /* set rank */
+ set_rank_and_odt_mask(r, RW_MGR_ODT_MODE_READ_WRITE);
+
+ /* Load up a constant bursts */
+ writel(0x20, &sdr_rw_load_mgr_regs->load_cntr0);
+
+ writel(rwcfg->guaranteed_write_wait0,
+ &sdr_rw_load_jump_mgr_regs->load_jump_add0);
+
+ writel(0x20, &sdr_rw_load_mgr_regs->load_cntr1);
+
+ writel(rwcfg->guaranteed_write_wait1,
+ &sdr_rw_load_jump_mgr_regs->load_jump_add1);
+
+ writel(0x04, &sdr_rw_load_mgr_regs->load_cntr2);
+
+ writel(rwcfg->guaranteed_write_wait2,
+ &sdr_rw_load_jump_mgr_regs->load_jump_add2);
+
+ writel(0x04, &sdr_rw_load_mgr_regs->load_cntr3);
+
+ writel(rwcfg->guaranteed_write_wait3,
+ &sdr_rw_load_jump_mgr_regs->load_jump_add3);
+
+ writel(rwcfg->guaranteed_write, SDR_PHYGRP_RWMGRGRP_ADDRESS |
+ RW_MGR_RUN_SINGLE_GROUP_OFFSET);
+ }
+
+ set_rank_and_odt_mask(0, RW_MGR_ODT_MODE_OFF);
+}
+
+/**
+ * rw_mgr_mem_calibrate_read_test() - Perform READ test on single rank
+ * @rank_bgn: Rank number
+ * @group: Read/Write group
+ * @num_tries: Number of retries of the test
+ * @all_correct: All bits must be correct in the mask
+ * @bit_chk: Resulting bit mask after the test
+ * @all_groups: Test all R/W groups
+ * @all_ranks: Test all ranks
+ *
+ * Try a read and see if it returns correct data back. Test has dummy reads
+ * inserted into the mix used to align DQS enable. Test has more thorough
+ * checks than the regular read test.
+ */
+static int
+rw_mgr_mem_calibrate_read_test(const u32 rank_bgn, const u32 group,
+ const u32 num_tries, const u32 all_correct,
+ u32 *bit_chk,
+ const u32 all_groups, const u32 all_ranks)
+{
+ const u32 rank_end = all_ranks ? rwcfg->mem_number_of_ranks :
+ (rank_bgn + NUM_RANKS_PER_SHADOW_REG);
+ const u32 quick_read_mode =
+ ((STATIC_CALIB_STEPS & CALIB_SKIP_DELAY_SWEEPS) &&
+ misccfg->enable_super_quick_calibration);
+ u32 correct_mask_vg = param->read_correct_mask_vg;
+ u32 tmp_bit_chk;
+ u32 base_rw_mgr;
+ u32 addr;
+
+ int r, vg, ret;
+
+ *bit_chk = param->read_correct_mask;
+
+ for (r = rank_bgn; r < rank_end; r++) {
+ /* set rank */
+ set_rank_and_odt_mask(r, RW_MGR_ODT_MODE_READ_WRITE);
+
+ writel(0x10, &sdr_rw_load_mgr_regs->load_cntr1);
+
+ writel(rwcfg->read_b2b_wait1,
+ &sdr_rw_load_jump_mgr_regs->load_jump_add1);
+
+ writel(0x10, &sdr_rw_load_mgr_regs->load_cntr2);
+ writel(rwcfg->read_b2b_wait2,
+ &sdr_rw_load_jump_mgr_regs->load_jump_add2);
+
+ if (quick_read_mode)
+ writel(0x1, &sdr_rw_load_mgr_regs->load_cntr0);
+ /* need at least two (1+1) reads to capture failures */
+ else if (all_groups)
+ writel(0x06, &sdr_rw_load_mgr_regs->load_cntr0);
+ else
+ writel(0x32, &sdr_rw_load_mgr_regs->load_cntr0);
+
+ writel(rwcfg->read_b2b,
+ &sdr_rw_load_jump_mgr_regs->load_jump_add0);
+ if (all_groups)
+ writel(rwcfg->mem_if_read_dqs_width *
+ rwcfg->mem_virtual_groups_per_read_dqs - 1,
+ &sdr_rw_load_mgr_regs->load_cntr3);
+ else
+ writel(0x0, &sdr_rw_load_mgr_regs->load_cntr3);
+
+ writel(rwcfg->read_b2b,
+ &sdr_rw_load_jump_mgr_regs->load_jump_add3);
+
+ tmp_bit_chk = 0;
+ for (vg = rwcfg->mem_virtual_groups_per_read_dqs - 1; vg >= 0;
+ vg--) {
+ /* Reset the FIFOs to get pointers to known state. */
+ writel(0, &phy_mgr_cmd->fifo_reset);
+ writel(0, SDR_PHYGRP_RWMGRGRP_ADDRESS |
+ RW_MGR_RESET_READ_DATAPATH_OFFSET);
+
+ if (all_groups) {
+ addr = SDR_PHYGRP_RWMGRGRP_ADDRESS |
+ RW_MGR_RUN_ALL_GROUPS_OFFSET;
+ } else {
+ addr = SDR_PHYGRP_RWMGRGRP_ADDRESS |
+ RW_MGR_RUN_SINGLE_GROUP_OFFSET;
+ }
+
+ writel(rwcfg->read_b2b, addr +
+ ((group *
+ rwcfg->mem_virtual_groups_per_read_dqs +
+ vg) << 2));
+
+ base_rw_mgr = readl(SDR_PHYGRP_RWMGRGRP_ADDRESS);
+ tmp_bit_chk <<= rwcfg->mem_dq_per_read_dqs /
+ rwcfg->mem_virtual_groups_per_read_dqs;
+ tmp_bit_chk |= correct_mask_vg & ~(base_rw_mgr);
+ }
+
+ *bit_chk &= tmp_bit_chk;
+ }
+
+ addr = SDR_PHYGRP_RWMGRGRP_ADDRESS | RW_MGR_RUN_SINGLE_GROUP_OFFSET;
+ writel(rwcfg->clear_dqs_enable, addr + (group << 2));
+
+ set_rank_and_odt_mask(0, RW_MGR_ODT_MODE_OFF);
+
+ if (all_correct) {
+ ret = (*bit_chk == param->read_correct_mask);
+ debug_cond(DLEVEL == 2,
+ "%s:%d read_test(%u,ALL,%u) => (%u == %u) => %i\n",
+ __func__, __LINE__, group, all_groups, *bit_chk,
+ param->read_correct_mask, ret);
+ } else {
+ ret = (*bit_chk != 0x00);
+ debug_cond(DLEVEL == 2,
+ "%s:%d read_test(%u,ONE,%u) => (%u != %u) => %i\n",
+ __func__, __LINE__, group, all_groups, *bit_chk,
+ 0, ret);
+ }
+
+ return ret;
+}
+
+/**
+ * rw_mgr_mem_calibrate_read_test_all_ranks() - Perform READ test on all ranks
+ * @grp: Read/Write group
+ * @num_tries: Number of retries of the test
+ * @all_correct: All bits must be correct in the mask
+ * @all_groups: Test all R/W groups
+ *
+ * Perform a READ test across all memory ranks.
+ */
+static int
+rw_mgr_mem_calibrate_read_test_all_ranks(const u32 grp, const u32 num_tries,
+ const u32 all_correct,
+ const u32 all_groups)
+{
+ u32 bit_chk;
+ return rw_mgr_mem_calibrate_read_test(0, grp, num_tries, all_correct,
+ &bit_chk, all_groups, 1);
+}
+
+/**
+ * rw_mgr_incr_vfifo() - Increase VFIFO value
+ * @grp: Read/Write group
+ *
+ * Increase VFIFO value.
+ */
+static void rw_mgr_incr_vfifo(const u32 grp)
+{
+ writel(grp, &phy_mgr_cmd->inc_vfifo_hard_phy);
+}
+
+/**
+ * rw_mgr_decr_vfifo() - Decrease VFIFO value
+ * @grp: Read/Write group
+ *
+ * Decrease VFIFO value.
+ */
+static void rw_mgr_decr_vfifo(const u32 grp)
+{
+ u32 i;
+
+ for (i = 0; i < misccfg->read_valid_fifo_size - 1; i++)
+ rw_mgr_incr_vfifo(grp);
+}
+
+/**
+ * find_vfifo_failing_read() - Push VFIFO to get a failing read
+ * @grp: Read/Write group
+ *
+ * Push VFIFO until a failing read happens.
+ */
+static int find_vfifo_failing_read(const u32 grp)
+{
+ u32 v, ret, fail_cnt = 0;
+
+ for (v = 0; v < misccfg->read_valid_fifo_size; v++) {
+ debug_cond(DLEVEL == 2, "%s:%d: vfifo %u\n",
+ __func__, __LINE__, v);
+ ret = rw_mgr_mem_calibrate_read_test_all_ranks(grp, 1,
+ PASS_ONE_BIT, 0);
+ if (!ret) {
+ fail_cnt++;
+
+ if (fail_cnt == 2)
+ return v;
+ }
+
+ /* Fiddle with FIFO. */
+ rw_mgr_incr_vfifo(grp);
+ }
+
+ /* No failing read found! Something must have gone wrong. */
+ debug_cond(DLEVEL == 2, "%s:%d: vfifo failed\n", __func__, __LINE__);
+ return 0;
+}
+
+/**
+ * sdr_find_phase_delay() - Find DQS enable phase or delay
+ * @working: If 1, look for working phase/delay, if 0, look for non-working
+ * @delay: If 1, look for delay, if 0, look for phase
+ * @grp: Read/Write group
+ * @work: Working window position
+ * @work_inc: Working window increment
+ * @pd: DQS Phase/Delay Iterator
+ *
+ * Find working or non-working DQS enable phase setting.
+ */
+static int sdr_find_phase_delay(int working, int delay, const u32 grp,
+ u32 *work, const u32 work_inc, u32 *pd)
+{
+ const u32 max = delay ? iocfg->dqs_en_delay_max :
+ iocfg->dqs_en_phase_max;
+ u32 ret;
+
+ for (; *pd <= max; (*pd)++) {
+ if (delay)
+ scc_mgr_set_dqs_en_delay_all_ranks(grp, *pd);
+ else
+ scc_mgr_set_dqs_en_phase_all_ranks(grp, *pd);
+
+ ret = rw_mgr_mem_calibrate_read_test_all_ranks(grp, 1,
+ PASS_ONE_BIT, 0);
+ if (!working)
+ ret = !ret;
+
+ if (ret)
+ return 0;
+
+ if (work)
+ *work += work_inc;
+ }
+
+ return -EINVAL;
+}
+/**
+ * sdr_find_phase() - Find DQS enable phase
+ * @working: If 1, look for working phase, if 0, look for non-working phase
+ * @grp: Read/Write group
+ * @work: Working window position
+ * @i: Iterator
+ * @p: DQS Phase Iterator
+ *
+ * Find working or non-working DQS enable phase setting.
+ */
+static int sdr_find_phase(int working, const u32 grp, u32 *work,
+ u32 *i, u32 *p)
+{
+ const u32 end = misccfg->read_valid_fifo_size + (working ? 0 : 1);
+ int ret;
+
+ for (; *i < end; (*i)++) {
+ if (working)
+ *p = 0;
+
+ ret = sdr_find_phase_delay(working, 0, grp, work,
+ iocfg->delay_per_opa_tap, p);
+ if (!ret)
+ return 0;
+
+ if (*p > iocfg->dqs_en_phase_max) {
+ /* Fiddle with FIFO. */
+ rw_mgr_incr_vfifo(grp);
+ if (!working)
+ *p = 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+/**
+ * sdr_working_phase() - Find working DQS enable phase
+ * @grp: Read/Write group
+ * @work_bgn: Working window start position
+ * @d: dtaps output value
+ * @p: DQS Phase Iterator
+ * @i: Iterator
+ *
+ * Find working DQS enable phase setting.
+ */
+static int sdr_working_phase(const u32 grp, u32 *work_bgn, u32 *d,
+ u32 *p, u32 *i)
+{
+ const u32 dtaps_per_ptap = iocfg->delay_per_opa_tap /
+ iocfg->delay_per_dqs_en_dchain_tap;
+ int ret;
+
+ *work_bgn = 0;
+
+ for (*d = 0; *d <= dtaps_per_ptap; (*d)++) {
+ *i = 0;
+ scc_mgr_set_dqs_en_delay_all_ranks(grp, *d);
+ ret = sdr_find_phase(1, grp, work_bgn, i, p);
+ if (!ret)
+ return 0;
+ *work_bgn += iocfg->delay_per_dqs_en_dchain_tap;
+ }
+
+ /* Cannot find working solution */
+ debug_cond(DLEVEL == 2, "%s:%d find_dqs_en_phase: no vfifo/ptap/dtap\n",
+ __func__, __LINE__);
+ return -EINVAL;
+}
+
+/**
+ * sdr_backup_phase() - Find DQS enable backup phase
+ * @grp: Read/Write group
+ * @work_bgn: Working window start position
+ * @p: DQS Phase Iterator
+ *
+ * Find DQS enable backup phase setting.
+ */
+static void sdr_backup_phase(const u32 grp, u32 *work_bgn, u32 *p)
+{
+ u32 tmp_delay, d;
+ int ret;
+
+ /* Special case code for backing up a phase */
+ if (*p == 0) {
+ *p = iocfg->dqs_en_phase_max;
+ rw_mgr_decr_vfifo(grp);
+ } else {
+ (*p)--;
+ }
+ tmp_delay = *work_bgn - iocfg->delay_per_opa_tap;
+ scc_mgr_set_dqs_en_phase_all_ranks(grp, *p);
+
+ for (d = 0; d <= iocfg->dqs_en_delay_max && tmp_delay < *work_bgn;
+ d++) {
+ scc_mgr_set_dqs_en_delay_all_ranks(grp, d);
+
+ ret = rw_mgr_mem_calibrate_read_test_all_ranks(grp, 1,
+ PASS_ONE_BIT, 0);
+ if (ret) {
+ *work_bgn = tmp_delay;
+ break;
+ }
+
+ tmp_delay += iocfg->delay_per_dqs_en_dchain_tap;
+ }
+
+ /* Restore VFIFO to old state before we decremented it (if needed). */
+ (*p)++;
+ if (*p > iocfg->dqs_en_phase_max) {
+ *p = 0;
+ rw_mgr_incr_vfifo(grp);
+ }
+
+ scc_mgr_set_dqs_en_delay_all_ranks(grp, 0);
+}
+
+/**
+ * sdr_nonworking_phase() - Find non-working DQS enable phase
+ * @grp: Read/Write group
+ * @work_end: Working window end position
+ * @p: DQS Phase Iterator
+ * @i: Iterator
+ *
+ * Find non-working DQS enable phase setting.
+ */
+static int sdr_nonworking_phase(const u32 grp, u32 *work_end, u32 *p, u32 *i)
+{
+ int ret;
+
+ (*p)++;
+ *work_end += iocfg->delay_per_opa_tap;
+ if (*p > iocfg->dqs_en_phase_max) {
+ /* Fiddle with FIFO. */
+ *p = 0;
+ rw_mgr_incr_vfifo(grp);
+ }
+
+ ret = sdr_find_phase(0, grp, work_end, i, p);
+ if (ret) {
+ /* Cannot see edge of failing read. */
+ debug_cond(DLEVEL == 2, "%s:%d: end: failed\n",
+ __func__, __LINE__);
+ }
+
+ return ret;
+}
+
+/**
+ * sdr_find_window_center() - Find center of the working DQS window.
+ * @grp: Read/Write group
+ * @work_bgn: First working settings
+ * @work_end: Last working settings
+ *
+ * Find center of the working DQS enable window.
+ */
+static int sdr_find_window_center(const u32 grp, const u32 work_bgn,
+ const u32 work_end)
+{
+ u32 work_mid;
+ int tmp_delay = 0;
+ int i, p, d;
+
+ work_mid = (work_bgn + work_end) / 2;
+
+ debug_cond(DLEVEL == 2, "work_bgn=%d work_end=%d work_mid=%d\n",
+ work_bgn, work_end, work_mid);
+ /* Get the middle delay to be less than a VFIFO delay */
+ tmp_delay = (iocfg->dqs_en_phase_max + 1) * iocfg->delay_per_opa_tap;
+
+ debug_cond(DLEVEL == 2, "vfifo ptap delay %d\n", tmp_delay);
+ work_mid %= tmp_delay;
+ debug_cond(DLEVEL == 2, "new work_mid %d\n", work_mid);
+
+ tmp_delay = rounddown(work_mid, iocfg->delay_per_opa_tap);
+ if (tmp_delay > iocfg->dqs_en_phase_max * iocfg->delay_per_opa_tap)
+ tmp_delay = iocfg->dqs_en_phase_max * iocfg->delay_per_opa_tap;
+ p = tmp_delay / iocfg->delay_per_opa_tap;
+
+ debug_cond(DLEVEL == 2, "new p %d, tmp_delay=%d\n", p, tmp_delay);
+
+ d = DIV_ROUND_UP(work_mid - tmp_delay,
+ iocfg->delay_per_dqs_en_dchain_tap);
+ if (d > iocfg->dqs_en_delay_max)
+ d = iocfg->dqs_en_delay_max;
+ tmp_delay += d * iocfg->delay_per_dqs_en_dchain_tap;
+
+ debug_cond(DLEVEL == 2, "new d %d, tmp_delay=%d\n", d, tmp_delay);
+
+ scc_mgr_set_dqs_en_phase_all_ranks(grp, p);
+ scc_mgr_set_dqs_en_delay_all_ranks(grp, d);
+
+ /*
+ * push vfifo until we can successfully calibrate. We can do this
+ * because the largest possible margin in 1 VFIFO cycle.
+ */
+ for (i = 0; i < misccfg->read_valid_fifo_size; i++) {
+ debug_cond(DLEVEL == 2, "find_dqs_en_phase: center\n");
+ if (rw_mgr_mem_calibrate_read_test_all_ranks(grp, 1,
+ PASS_ONE_BIT,
+ 0)) {
+ debug_cond(DLEVEL == 2,
+ "%s:%d center: found: ptap=%u dtap=%u\n",
+ __func__, __LINE__, p, d);
+ return 0;
+ }
+
+ /* Fiddle with FIFO. */
+ rw_mgr_incr_vfifo(grp);
+ }
+
+ debug_cond(DLEVEL == 2, "%s:%d center: failed.\n",
+ __func__, __LINE__);
+ return -EINVAL;
+}
+
+/**
+ * rw_mgr_mem_calibrate_vfifo_find_dqs_en_phase() - Find a good DQS enable to use
+ * @grp: Read/Write Group
+ *
+ * Find a good DQS enable to use.
+ */
+static int rw_mgr_mem_calibrate_vfifo_find_dqs_en_phase(const u32 grp)
+{
+ u32 d, p, i;
+ u32 dtaps_per_ptap;
+ u32 work_bgn, work_end;
+ u32 found_passing_read, found_failing_read, initial_failing_dtap;
+ int ret;
+
+ debug("%s:%d %u\n", __func__, __LINE__, grp);
+
+ reg_file_set_sub_stage(CAL_SUBSTAGE_VFIFO_CENTER);
+
+ scc_mgr_set_dqs_en_delay_all_ranks(grp, 0);
+ scc_mgr_set_dqs_en_phase_all_ranks(grp, 0);
+
+ /* Step 0: Determine number of delay taps for each phase tap. */
+ dtaps_per_ptap = iocfg->delay_per_opa_tap /
+ iocfg->delay_per_dqs_en_dchain_tap;
+
+ /* Step 1: First push vfifo until we get a failing read. */
+ find_vfifo_failing_read(grp);
+
+ /* Step 2: Find first working phase, increment in ptaps. */
+ work_bgn = 0;
+ ret = sdr_working_phase(grp, &work_bgn, &d, &p, &i);
+ if (ret)
+ return ret;
+
+ work_end = work_bgn;
+
+ /*
+ * If d is 0 then the working window covers a phase tap and we can
+ * follow the old procedure. Otherwise, we've found the beginning
+ * and we need to increment the dtaps until we find the end.
+ */
+ if (d == 0) {
+ /*
+ * Step 3a: If we have room, back off by one and
+ * increment in dtaps.
+ */
+ sdr_backup_phase(grp, &work_bgn, &p);
+
+ /*
+ * Step 4a: go forward from working phase to non working
+ * phase, increment in ptaps.
+ */
+ ret = sdr_nonworking_phase(grp, &work_end, &p, &i);
+ if (ret)
+ return ret;
+
+ /* Step 5a: Back off one from last, increment in dtaps. */
+
+ /* Special case code for backing up a phase */
+ if (p == 0) {
+ p = iocfg->dqs_en_phase_max;
+ rw_mgr_decr_vfifo(grp);
+ } else {
+ p = p - 1;
+ }
+
+ work_end -= iocfg->delay_per_opa_tap;
+ scc_mgr_set_dqs_en_phase_all_ranks(grp, p);
+
+ d = 0;
+
+ debug_cond(DLEVEL == 2, "%s:%d p: ptap=%u\n",
+ __func__, __LINE__, p);
+ }
+
+ /* The dtap increment to find the failing edge is done here. */
+ sdr_find_phase_delay(0, 1, grp, &work_end,
+ iocfg->delay_per_dqs_en_dchain_tap, &d);
+
+ /* Go back to working dtap */
+ if (d != 0)
+ work_end -= iocfg->delay_per_dqs_en_dchain_tap;
+
+ debug_cond(DLEVEL == 2,
+ "%s:%d p/d: ptap=%u dtap=%u end=%u\n",
+ __func__, __LINE__, p, d - 1, work_end);
+
+ if (work_end < work_bgn) {
+ /* nil range */
+ debug_cond(DLEVEL == 2, "%s:%d end-2: failed\n",
+ __func__, __LINE__);
+ return -EINVAL;
+ }
+
+ debug_cond(DLEVEL == 2, "%s:%d found range [%u,%u]\n",
+ __func__, __LINE__, work_bgn, work_end);
+
+ /*
+ * We need to calculate the number of dtaps that equal a ptap.
+ * To do that we'll back up a ptap and re-find the edge of the
+ * window using dtaps
+ */
+ debug_cond(DLEVEL == 2, "%s:%d calculate dtaps_per_ptap for tracking\n",
+ __func__, __LINE__);
+
+ /* Special case code for backing up a phase */
+ if (p == 0) {
+ p = iocfg->dqs_en_phase_max;
+ rw_mgr_decr_vfifo(grp);
+ debug_cond(DLEVEL == 2, "%s:%d backedup cycle/phase: p=%u\n",
+ __func__, __LINE__, p);
+ } else {
+ p = p - 1;
+ debug_cond(DLEVEL == 2, "%s:%d backedup phase only: p=%u",
+ __func__, __LINE__, p);
+ }
+
+ scc_mgr_set_dqs_en_phase_all_ranks(grp, p);
+
+ /*
+ * Increase dtap until we first see a passing read (in case the
+ * window is smaller than a ptap), and then a failing read to
+ * mark the edge of the window again.
+ */
+
+ /* Find a passing read. */
+ debug_cond(DLEVEL == 2, "%s:%d find passing read\n",
+ __func__, __LINE__);
+
+ initial_failing_dtap = d;
+
+ found_passing_read = !sdr_find_phase_delay(1, 1, grp, NULL, 0, &d);
+ if (found_passing_read) {
+ /* Find a failing read. */
+ debug_cond(DLEVEL == 2, "%s:%d find failing read\n",
+ __func__, __LINE__);
+ d++;
+ found_failing_read = !sdr_find_phase_delay(0, 1, grp, NULL, 0,
+ &d);
+ } else {
+ debug_cond(DLEVEL == 1,
+ "%s:%d failed to calculate dtaps per ptap. Fall back on static value\n",
+ __func__, __LINE__);
+ }
+
+ /*
+ * The dynamically calculated dtaps_per_ptap is only valid if we
+ * found a passing/failing read. If we didn't, it means d hit the max
+ * (iocfg->dqs_en_delay_max). Otherwise, dtaps_per_ptap retains its
+ * statically calculated value.
+ */
+ if (found_passing_read && found_failing_read)
+ dtaps_per_ptap = d - initial_failing_dtap;
+
+ writel(dtaps_per_ptap, &sdr_reg_file->dtaps_per_ptap);
+ debug_cond(DLEVEL == 2, "%s:%d dtaps_per_ptap=%u - %u = %u",
+ __func__, __LINE__, d, initial_failing_dtap, dtaps_per_ptap);
+
+ /* Step 6: Find the centre of the window. */
+ ret = sdr_find_window_center(grp, work_bgn, work_end);
+
+ return ret;
+}
+
+/**
+ * search_stop_check() - Check if the detected edge is valid
+ * @write: Perform read (Stage 2) or write (Stage 3) calibration
+ * @d: DQS delay
+ * @rank_bgn: Rank number
+ * @write_group: Write Group
+ * @read_group: Read Group
+ * @bit_chk: Resulting bit mask after the test
+ * @sticky_bit_chk: Resulting sticky bit mask after the test
+ * @use_read_test: Perform read test
+ *
+ * Test if the found edge is valid.
+ */
+static u32 search_stop_check(const int write, const int d, const int rank_bgn,
+ const u32 write_group, const u32 read_group,
+ u32 *bit_chk, u32 *sticky_bit_chk,
+ const u32 use_read_test)
+{
+ const u32 ratio = rwcfg->mem_if_read_dqs_width /
+ rwcfg->mem_if_write_dqs_width;
+ const u32 correct_mask = write ? param->write_correct_mask :
+ param->read_correct_mask;
+ const u32 per_dqs = write ? rwcfg->mem_dq_per_write_dqs :
+ rwcfg->mem_dq_per_read_dqs;
+ u32 ret;
+ /*
+ * Stop searching when the read test doesn't pass AND when
+ * we've seen a passing read on every bit.
+ */
+ if (write) { /* WRITE-ONLY */
+ ret = !rw_mgr_mem_calibrate_write_test(rank_bgn, write_group,
+ 0, PASS_ONE_BIT,
+ bit_chk, 0);
+ } else if (use_read_test) { /* READ-ONLY */
+ ret = !rw_mgr_mem_calibrate_read_test(rank_bgn, read_group,
+ NUM_READ_PB_TESTS,
+ PASS_ONE_BIT, bit_chk,
+ 0, 0);
+ } else { /* READ-ONLY */
+ rw_mgr_mem_calibrate_write_test(rank_bgn, write_group, 0,
+ PASS_ONE_BIT, bit_chk, 0);
+ *bit_chk = *bit_chk >> (per_dqs *
+ (read_group - (write_group * ratio)));
+ ret = (*bit_chk == 0);
+ }
+ *sticky_bit_chk = *sticky_bit_chk | *bit_chk;
+ ret = ret && (*sticky_bit_chk == correct_mask);
+ debug_cond(DLEVEL == 2,
+ "%s:%d center(left): dtap=%u => %u == %u && %u",
+ __func__, __LINE__, d,
+ *sticky_bit_chk, correct_mask, ret);
+ return ret;
+}
+
+/**
+ * search_left_edge() - Find left edge of DQ/DQS working phase
+ * @write: Perform read (Stage 2) or write (Stage 3) calibration
+ * @rank_bgn: Rank number
+ * @write_group: Write Group
+ * @read_group: Read Group
+ * @test_bgn: Rank number to begin the test
+ * @sticky_bit_chk: Resulting sticky bit mask after the test
+ * @left_edge: Left edge of the DQ/DQS phase
+ * @right_edge: Right edge of the DQ/DQS phase
+ * @use_read_test: Perform read test
+ *
+ * Find left edge of DQ/DQS working phase.
+ */
+static void search_left_edge(const int write, const int rank_bgn,
+ const u32 write_group, const u32 read_group, const u32 test_bgn,
+ u32 *sticky_bit_chk,
+ int *left_edge, int *right_edge, const u32 use_read_test)
+{
+ const u32 delay_max = write ? iocfg->io_out1_delay_max :
+ iocfg->io_in_delay_max;
+ const u32 dqs_max = write ? iocfg->io_out1_delay_max :
+ iocfg->dqs_in_delay_max;
+ const u32 per_dqs = write ? rwcfg->mem_dq_per_write_dqs :
+ rwcfg->mem_dq_per_read_dqs;
+ u32 stop, bit_chk;
+ int i, d;
+
+ for (d = 0; d <= dqs_max; d++) {
+ if (write)
+ scc_mgr_apply_group_dq_out1_delay(d);
+ else
+ scc_mgr_apply_group_dq_in_delay(test_bgn, d);
+
+ writel(0, &sdr_scc_mgr->update);
+
+ stop = search_stop_check(write, d, rank_bgn, write_group,
+ read_group, &bit_chk, sticky_bit_chk,
+ use_read_test);
+ if (stop == 1)
+ break;
+
+ /* stop != 1 */
+ for (i = 0; i < per_dqs; i++) {
+ if (bit_chk & 1) {
+ /*
+ * Remember a passing test as
+ * the left_edge.
+ */
+ left_edge[i] = d;
+ } else {
+ /*
+ * If a left edge has not been seen
+ * yet, then a future passing test
+ * will mark this edge as the right
+ * edge.
+ */
+ if (left_edge[i] == delay_max + 1)
+ right_edge[i] = -(d + 1);
+ }
+ bit_chk >>= 1;
+ }
+ }
+
+ /* Reset DQ delay chains to 0 */
+ if (write)
+ scc_mgr_apply_group_dq_out1_delay(0);
+ else
+ scc_mgr_apply_group_dq_in_delay(test_bgn, 0);
+
+ *sticky_bit_chk = 0;
+ for (i = per_dqs - 1; i >= 0; i--) {
+ debug_cond(DLEVEL == 2,
+ "%s:%d vfifo_center: left_edge[%u]: %d right_edge[%u]: %d\n",
+ __func__, __LINE__, i, left_edge[i],
+ i, right_edge[i]);
+
+ /*
+ * Check for cases where we haven't found the left edge,
+ * which makes our assignment of the the right edge invalid.
+ * Reset it to the illegal value.
+ */
+ if ((left_edge[i] == delay_max + 1) &&
+ (right_edge[i] != delay_max + 1)) {
+ right_edge[i] = delay_max + 1;
+ debug_cond(DLEVEL == 2,
+ "%s:%d vfifo_center: reset right_edge[%u]: %d\n",
+ __func__, __LINE__, i, right_edge[i]);
+ }
+
+ /*
+ * Reset sticky bit
+ * READ: except for bits where we have seen both
+ * the left and right edge.
+ * WRITE: except for bits where we have seen the
+ * left edge.
+ */
+ *sticky_bit_chk <<= 1;
+ if (write) {
+ if (left_edge[i] != delay_max + 1)
+ *sticky_bit_chk |= 1;
+ } else {
+ if ((left_edge[i] != delay_max + 1) &&
+ (right_edge[i] != delay_max + 1))
+ *sticky_bit_chk |= 1;
+ }
+ }
+}
+
+/**
+ * search_right_edge() - Find right edge of DQ/DQS working phase
+ * @write: Perform read (Stage 2) or write (Stage 3) calibration
+ * @rank_bgn: Rank number
+ * @write_group: Write Group
+ * @read_group: Read Group
+ * @start_dqs: DQS start phase
+ * @start_dqs_en: DQS enable start phase
+ * @sticky_bit_chk: Resulting sticky bit mask after the test
+ * @left_edge: Left edge of the DQ/DQS phase
+ * @right_edge: Right edge of the DQ/DQS phase
+ * @use_read_test: Perform read test
+ *
+ * Find right edge of DQ/DQS working phase.
+ */
+static int search_right_edge(const int write, const int rank_bgn,
+ const u32 write_group, const u32 read_group,
+ const int start_dqs, const int start_dqs_en,
+ u32 *sticky_bit_chk,
+ int *left_edge, int *right_edge, const u32 use_read_test)
+{
+ const u32 delay_max = write ? iocfg->io_out1_delay_max :
+ iocfg->io_in_delay_max;
+ const u32 dqs_max = write ? iocfg->io_out1_delay_max :
+ iocfg->dqs_in_delay_max;
+ const u32 per_dqs = write ? rwcfg->mem_dq_per_write_dqs :
+ rwcfg->mem_dq_per_read_dqs;
+ u32 stop, bit_chk;
+ int i, d;
+
+ for (d = 0; d <= dqs_max - start_dqs; d++) {
+ if (write) { /* WRITE-ONLY */
+ scc_mgr_apply_group_dqs_io_and_oct_out1(write_group,
+ d + start_dqs);
+ } else { /* READ-ONLY */
+ scc_mgr_set_dqs_bus_in_delay(read_group, d + start_dqs);
+ if (iocfg->shift_dqs_en_when_shift_dqs) {
+ u32 delay = d + start_dqs_en;
+ if (delay > iocfg->dqs_en_delay_max)
+ delay = iocfg->dqs_en_delay_max;
+ scc_mgr_set_dqs_en_delay(read_group, delay);
+ }
+ scc_mgr_load_dqs(read_group);
+ }
+
+ writel(0, &sdr_scc_mgr->update);
+
+ stop = search_stop_check(write, d, rank_bgn, write_group,
+ read_group, &bit_chk, sticky_bit_chk,
+ use_read_test);
+ if (stop == 1) {
+ if (write && (d == 0)) { /* WRITE-ONLY */
+ for (i = 0; i < rwcfg->mem_dq_per_write_dqs;
+ i++) {
+ /*
+ * d = 0 failed, but it passed when
+ * testing the left edge, so it must be
+ * marginal, set it to -1
+ */
+ if (right_edge[i] == delay_max + 1 &&
+ left_edge[i] != delay_max + 1)
+ right_edge[i] = -1;
+ }
+ }
+ break;
+ }
+
+ /* stop != 1 */
+ for (i = 0; i < per_dqs; i++) {
+ if (bit_chk & 1) {
+ /*
+ * Remember a passing test as
+ * the right_edge.
+ */
+ right_edge[i] = d;
+ } else {
+ if (d != 0) {
+ /*
+ * If a right edge has not
+ * been seen yet, then a future
+ * passing test will mark this
+ * edge as the left edge.
+ */
+ if (right_edge[i] == delay_max + 1)
+ left_edge[i] = -(d + 1);
+ } else {
+ /*
+ * d = 0 failed, but it passed
+ * when testing the left edge,
+ * so it must be marginal, set
+ * it to -1
+ */
+ if (right_edge[i] == delay_max + 1 &&
+ left_edge[i] != delay_max + 1)
+ right_edge[i] = -1;
+ /*
+ * If a right edge has not been
+ * seen yet, then a future
+ * passing test will mark this
+ * edge as the left edge.
+ */
+ else if (right_edge[i] == delay_max + 1)
+ left_edge[i] = -(d + 1);
+ }
+ }
+
+ debug_cond(DLEVEL == 2, "%s:%d center[r,d=%u]: ",
+ __func__, __LINE__, d);
+ debug_cond(DLEVEL == 2,
+ "bit_chk_test=%i left_edge[%u]: %d ",
+ bit_chk & 1, i, left_edge[i]);
+ debug_cond(DLEVEL == 2, "right_edge[%u]: %d\n", i,
+ right_edge[i]);
+ bit_chk >>= 1;
+ }
+ }
+
+ /* Check that all bits have a window */
+ for (i = 0; i < per_dqs; i++) {
+ debug_cond(DLEVEL == 2,
+ "%s:%d write_center: left_edge[%u]: %d right_edge[%u]: %d",
+ __func__, __LINE__, i, left_edge[i],
+ i, right_edge[i]);
+ if ((left_edge[i] == dqs_max + 1) ||
+ (right_edge[i] == dqs_max + 1))
+ return i + 1; /* FIXME: If we fail, retval > 0 */
+ }
+
+ return 0;
+}
+
+/**
+ * get_window_mid_index() - Find the best middle setting of DQ/DQS phase
+ * @write: Perform read (Stage 2) or write (Stage 3) calibration
+ * @left_edge: Left edge of the DQ/DQS phase
+ * @right_edge: Right edge of the DQ/DQS phase
+ * @mid_min: Best DQ/DQS phase middle setting
+ *
+ * Find index and value of the middle of the DQ/DQS working phase.
+ */
+static int get_window_mid_index(const int write, int *left_edge,
+ int *right_edge, int *mid_min)
+{
+ const u32 per_dqs = write ? rwcfg->mem_dq_per_write_dqs :
+ rwcfg->mem_dq_per_read_dqs;
+ int i, mid, min_index;
+
+ /* Find middle of window for each DQ bit */
+ *mid_min = left_edge[0] - right_edge[0];
+ min_index = 0;
+ for (i = 1; i < per_dqs; i++) {
+ mid = left_edge[i] - right_edge[i];
+ if (mid < *mid_min) {
+ *mid_min = mid;
+ min_index = i;
+ }
+ }
+
+ /*
+ * -mid_min/2 represents the amount that we need to move DQS.
+ * If mid_min is odd and positive we'll need to add one to make
+ * sure the rounding in further calculations is correct (always
+ * bias to the right), so just add 1 for all positive values.
+ */
+ if (*mid_min > 0)
+ (*mid_min)++;
+ *mid_min = *mid_min / 2;
+
+ debug_cond(DLEVEL == 1, "%s:%d vfifo_center: *mid_min=%d (index=%u)\n",
+ __func__, __LINE__, *mid_min, min_index);
+ return min_index;
+}
+
+/**
+ * center_dq_windows() - Center the DQ/DQS windows
+ * @write: Perform read (Stage 2) or write (Stage 3) calibration
+ * @left_edge: Left edge of the DQ/DQS phase
+ * @right_edge: Right edge of the DQ/DQS phase
+ * @mid_min: Adjusted DQ/DQS phase middle setting
+ * @orig_mid_min: Original DQ/DQS phase middle setting
+ * @min_index: DQ/DQS phase middle setting index
+ * @test_bgn: Rank number to begin the test
+ * @dq_margin: Amount of shift for the DQ
+ * @dqs_margin: Amount of shift for the DQS
+ *
+ * Align the DQ/DQS windows in each group.
+ */
+static void center_dq_windows(const int write, int *left_edge, int *right_edge,
+ const int mid_min, const int orig_mid_min,
+ const int min_index, const int test_bgn,
+ int *dq_margin, int *dqs_margin)
+{
+ const u32 delay_max = write ? iocfg->io_out1_delay_max :
+ iocfg->io_in_delay_max;
+ const u32 per_dqs = write ? rwcfg->mem_dq_per_write_dqs :
+ rwcfg->mem_dq_per_read_dqs;
+ const u32 delay_off = write ? SCC_MGR_IO_OUT1_DELAY_OFFSET :
+ SCC_MGR_IO_IN_DELAY_OFFSET;
+ const u32 addr = SDR_PHYGRP_SCCGRP_ADDRESS | delay_off;
+
+ u32 temp_dq_io_delay1, temp_dq_io_delay2;
+ int shift_dq, i, p;
+
+ /* Initialize data for export structures */
+ *dqs_margin = delay_max + 1;
+ *dq_margin = delay_max + 1;
+
+ /* add delay to bring centre of all DQ windows to the same "level" */
+ for (i = 0, p = test_bgn; i < per_dqs; i++, p++) {
+ /* Use values before divide by 2 to reduce round off error */
+ shift_dq = (left_edge[i] - right_edge[i] -
+ (left_edge[min_index] - right_edge[min_index]))/2 +
+ (orig_mid_min - mid_min);
+
+ debug_cond(DLEVEL == 2,
+ "vfifo_center: before: shift_dq[%u]=%d\n",
+ i, shift_dq);
+
+ temp_dq_io_delay1 = readl(addr + (p << 2));
+ temp_dq_io_delay2 = readl(addr + (i << 2));
+
+ if (shift_dq + temp_dq_io_delay1 > delay_max)
+ shift_dq = delay_max - temp_dq_io_delay2;
+ else if (shift_dq + temp_dq_io_delay1 < 0)
+ shift_dq = -temp_dq_io_delay1;
+
+ debug_cond(DLEVEL == 2,
+ "vfifo_center: after: shift_dq[%u]=%d\n",
+ i, shift_dq);
+
+ if (write)
+ scc_mgr_set_dq_out1_delay(i,
+ temp_dq_io_delay1 + shift_dq);
+ else
+ scc_mgr_set_dq_in_delay(p,
+ temp_dq_io_delay1 + shift_dq);
+
+ scc_mgr_load_dq(p);
+
+ debug_cond(DLEVEL == 2,
+ "vfifo_center: margin[%u]=[%d,%d]\n", i,
+ left_edge[i] - shift_dq + (-mid_min),
+ right_edge[i] + shift_dq - (-mid_min));
+
+ /* To determine values for export structures */
+ if (left_edge[i] - shift_dq + (-mid_min) < *dq_margin)
+ *dq_margin = left_edge[i] - shift_dq + (-mid_min);
+
+ if (right_edge[i] + shift_dq - (-mid_min) < *dqs_margin)
+ *dqs_margin = right_edge[i] + shift_dq - (-mid_min);
+ }
+}
+
+/**
+ * rw_mgr_mem_calibrate_vfifo_center() - Per-bit deskew DQ and centering
+ * @rank_bgn: Rank number
+ * @rw_group: Read/Write Group
+ * @test_bgn: Rank at which the test begins
+ * @use_read_test: Perform a read test
+ * @update_fom: Update FOM
+ *
+ * Per-bit deskew DQ and centering.
+ */
+static int rw_mgr_mem_calibrate_vfifo_center(const u32 rank_bgn,
+ const u32 rw_group, const u32 test_bgn,
+ const int use_read_test, const int update_fom)
+{
+ const u32 addr =
+ SDR_PHYGRP_SCCGRP_ADDRESS + SCC_MGR_DQS_IN_DELAY_OFFSET +
+ (rw_group << 2);
+ /*
+ * Store these as signed since there are comparisons with
+ * signed numbers.
+ */
+ u32 sticky_bit_chk;
+ int32_t left_edge[rwcfg->mem_dq_per_read_dqs];
+ int32_t right_edge[rwcfg->mem_dq_per_read_dqs];
+ int32_t orig_mid_min, mid_min;
+ int32_t new_dqs, start_dqs, start_dqs_en = 0, final_dqs_en;
+ int32_t dq_margin, dqs_margin;
+ int i, min_index;
+ int ret;
+
+ debug("%s:%d: %u %u", __func__, __LINE__, rw_group, test_bgn);
+
+ start_dqs = readl(addr);
+ if (iocfg->shift_dqs_en_when_shift_dqs)
+ start_dqs_en = readl(addr - iocfg->dqs_en_delay_offset);
+
+ /* set the left and right edge of each bit to an illegal value */
+ /* use (iocfg->io_in_delay_max + 1) as an illegal value */
+ sticky_bit_chk = 0;
+ for (i = 0; i < rwcfg->mem_dq_per_read_dqs; i++) {
+ left_edge[i] = iocfg->io_in_delay_max + 1;
+ right_edge[i] = iocfg->io_in_delay_max + 1;
+ }
+
+ /* Search for the left edge of the window for each bit */
+ search_left_edge(0, rank_bgn, rw_group, rw_group, test_bgn,
+ &sticky_bit_chk,
+ left_edge, right_edge, use_read_test);
+
+
+ /* Search for the right edge of the window for each bit */
+ ret = search_right_edge(0, rank_bgn, rw_group, rw_group,
+ start_dqs, start_dqs_en,
+ &sticky_bit_chk,
+ left_edge, right_edge, use_read_test);
+ if (ret) {
+ /*
+ * Restore delay chain settings before letting the loop
+ * in rw_mgr_mem_calibrate_vfifo to retry different
+ * dqs/ck relationships.
+ */
+ scc_mgr_set_dqs_bus_in_delay(rw_group, start_dqs);
+ if (iocfg->shift_dqs_en_when_shift_dqs)
+ scc_mgr_set_dqs_en_delay(rw_group, start_dqs_en);
+
+ scc_mgr_load_dqs(rw_group);
+ writel(0, &sdr_scc_mgr->update);
+
+ debug_cond(DLEVEL == 1,
+ "%s:%d vfifo_center: failed to find edge [%u]: %d %d",
+ __func__, __LINE__, i, left_edge[i], right_edge[i]);
+ if (use_read_test) {
+ set_failing_group_stage(rw_group *
+ rwcfg->mem_dq_per_read_dqs + i,
+ CAL_STAGE_VFIFO,
+ CAL_SUBSTAGE_VFIFO_CENTER);
+ } else {
+ set_failing_group_stage(rw_group *
+ rwcfg->mem_dq_per_read_dqs + i,
+ CAL_STAGE_VFIFO_AFTER_WRITES,
+ CAL_SUBSTAGE_VFIFO_CENTER);
+ }
+ return -EIO;
+ }
+
+ min_index = get_window_mid_index(0, left_edge, right_edge, &mid_min);
+
+ /* Determine the amount we can change DQS (which is -mid_min) */
+ orig_mid_min = mid_min;
+ new_dqs = start_dqs - mid_min;
+ if (new_dqs > iocfg->dqs_in_delay_max)
+ new_dqs = iocfg->dqs_in_delay_max;
+ else if (new_dqs < 0)
+ new_dqs = 0;
+
+ mid_min = start_dqs - new_dqs;
+ debug_cond(DLEVEL == 1, "vfifo_center: new mid_min=%d new_dqs=%d\n",
+ mid_min, new_dqs);
+
+ if (iocfg->shift_dqs_en_when_shift_dqs) {
+ if (start_dqs_en - mid_min > iocfg->dqs_en_delay_max)
+ mid_min += start_dqs_en - mid_min -
+ iocfg->dqs_en_delay_max;
+ else if (start_dqs_en - mid_min < 0)
+ mid_min += start_dqs_en - mid_min;
+ }
+ new_dqs = start_dqs - mid_min;
+
+ debug_cond(DLEVEL == 1,
+ "vfifo_center: start_dqs=%d start_dqs_en=%d new_dqs=%d mid_min=%d\n",
+ start_dqs,
+ iocfg->shift_dqs_en_when_shift_dqs ? start_dqs_en : -1,
+ new_dqs, mid_min);
+
+ /* Add delay to bring centre of all DQ windows to the same "level". */
+ center_dq_windows(0, left_edge, right_edge, mid_min, orig_mid_min,
+ min_index, test_bgn, &dq_margin, &dqs_margin);
+
+ /* Move DQS-en */
+ if (iocfg->shift_dqs_en_when_shift_dqs) {
+ final_dqs_en = start_dqs_en - mid_min;
+ scc_mgr_set_dqs_en_delay(rw_group, final_dqs_en);
+ scc_mgr_load_dqs(rw_group);
+ }
+
+ /* Move DQS */
+ scc_mgr_set_dqs_bus_in_delay(rw_group, new_dqs);
+ scc_mgr_load_dqs(rw_group);
+ debug_cond(DLEVEL == 2,
+ "%s:%d vfifo_center: dq_margin=%d dqs_margin=%d",
+ __func__, __LINE__, dq_margin, dqs_margin);
+
+ /*
+ * Do not remove this line as it makes sure all of our decisions
+ * have been applied. Apply the update bit.
+ */
+ writel(0, &sdr_scc_mgr->update);
+
+ if ((dq_margin < 0) || (dqs_margin < 0))
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * rw_mgr_mem_calibrate_guaranteed_write() - Perform guaranteed write into the device
+ * @rw_group: Read/Write Group
+ * @phase: DQ/DQS phase
+ *
+ * Because initially no communication ca be reliably performed with the memory
+ * device, the sequencer uses a guaranteed write mechanism to write data into
+ * the memory device.
+ */
+static int rw_mgr_mem_calibrate_guaranteed_write(const u32 rw_group,
+ const u32 phase)
+{
+ int ret;
+
+ /* Set a particular DQ/DQS phase. */
+ scc_mgr_set_dqdqs_output_phase_all_ranks(rw_group, phase);
+
+ debug_cond(DLEVEL == 1, "%s:%d guaranteed write: g=%u p=%u\n",
+ __func__, __LINE__, rw_group, phase);
+
+ /*
+ * Altera EMI_RM 2015.05.04 :: Figure 1-25
+ * Load up the patterns used by read calibration using the
+ * current DQDQS phase.
+ */
+ rw_mgr_mem_calibrate_read_load_patterns(0, 1);
+
+ if (gbl->phy_debug_mode_flags & PHY_DEBUG_DISABLE_GUARANTEED_READ)
+ return 0;
+
+ /*
+ * Altera EMI_RM 2015.05.04 :: Figure 1-26
+ * Back-to-Back reads of the patterns used for calibration.
+ */
+ ret = rw_mgr_mem_calibrate_read_test_patterns(0, rw_group, 1);
+ if (ret)
+ debug_cond(DLEVEL == 1,
+ "%s:%d Guaranteed read test failed: g=%u p=%u\n",
+ __func__, __LINE__, rw_group, phase);
+ return ret;
+}
+
+/**
+ * rw_mgr_mem_calibrate_dqs_enable_calibration() - DQS Enable Calibration
+ * @rw_group: Read/Write Group
+ * @test_bgn: Rank at which the test begins
+ *
+ * DQS enable calibration ensures reliable capture of the DQ signal without
+ * glitches on the DQS line.
+ */
+static int rw_mgr_mem_calibrate_dqs_enable_calibration(const u32 rw_group,
+ const u32 test_bgn)
+{
+ /*
+ * Altera EMI_RM 2015.05.04 :: Figure 1-27
+ * DQS and DQS Eanble Signal Relationships.
+ */
+
+ /* We start at zero, so have one less dq to devide among */
+ const u32 delay_step = iocfg->io_in_delay_max /
+ (rwcfg->mem_dq_per_read_dqs - 1);
+ int ret;
+ u32 i, p, d, r;
+
+ debug("%s:%d (%u,%u)\n", __func__, __LINE__, rw_group, test_bgn);
+
+ /* Try different dq_in_delays since the DQ path is shorter than DQS. */
+ for (r = 0; r < rwcfg->mem_number_of_ranks;
+ r += NUM_RANKS_PER_SHADOW_REG) {
+ for (i = 0, p = test_bgn, d = 0;
+ i < rwcfg->mem_dq_per_read_dqs;
+ i++, p++, d += delay_step) {
+ debug_cond(DLEVEL == 1,
+ "%s:%d: g=%u r=%u i=%u p=%u d=%u\n",
+ __func__, __LINE__, rw_group, r, i, p, d);
+
+ scc_mgr_set_dq_in_delay(p, d);
+ scc_mgr_load_dq(p);
+ }
+
+ writel(0, &sdr_scc_mgr->update);
+ }
+
+ /*
+ * Try rw_mgr_mem_calibrate_vfifo_find_dqs_en_phase across different
+ * dq_in_delay values
+ */
+ ret = rw_mgr_mem_calibrate_vfifo_find_dqs_en_phase(rw_group);
+
+ debug_cond(DLEVEL == 1,
+ "%s:%d: g=%u found=%u; Reseting delay chain to zero\n",
+ __func__, __LINE__, rw_group, !ret);
+
+ for (r = 0; r < rwcfg->mem_number_of_ranks;
+ r += NUM_RANKS_PER_SHADOW_REG) {
+ scc_mgr_apply_group_dq_in_delay(test_bgn, 0);
+ writel(0, &sdr_scc_mgr->update);
+ }
+
+ return ret;
+}
+
+/**
+ * rw_mgr_mem_calibrate_dq_dqs_centering() - Centering DQ/DQS
+ * @rw_group: Read/Write Group
+ * @test_bgn: Rank at which the test begins
+ * @use_read_test: Perform a read test
+ * @update_fom: Update FOM
+ *
+ * The centerin DQ/DQS stage attempts to align DQ and DQS signals on reads
+ * within a group.
+ */
+static int
+rw_mgr_mem_calibrate_dq_dqs_centering(const u32 rw_group, const u32 test_bgn,
+ const int use_read_test,
+ const int update_fom)
+
+{
+ int ret, grp_calibrated;
+ u32 rank_bgn, sr;
+
+ /*
+ * Altera EMI_RM 2015.05.04 :: Figure 1-28
+ * Read per-bit deskew can be done on a per shadow register basis.
+ */
+ grp_calibrated = 1;
+ for (rank_bgn = 0, sr = 0;
+ rank_bgn < rwcfg->mem_number_of_ranks;
+ rank_bgn += NUM_RANKS_PER_SHADOW_REG, sr++) {
+ ret = rw_mgr_mem_calibrate_vfifo_center(rank_bgn, rw_group,
+ test_bgn,
+ use_read_test,
+ update_fom);
+ if (!ret)
+ continue;
+
+ grp_calibrated = 0;
+ }
+
+ if (!grp_calibrated)
+ return -EIO;
+
+ return 0;
+}
+
+/**
+ * rw_mgr_mem_calibrate_vfifo() - Calibrate the read valid prediction FIFO
+ * @rw_group: Read/Write Group
+ * @test_bgn: Rank at which the test begins
+ *
+ * Stage 1: Calibrate the read valid prediction FIFO.
+ *
+ * This function implements UniPHY calibration Stage 1, as explained in
+ * detail in Altera EMI_RM 2015.05.04 , "UniPHY Calibration Stages".
+ *
+ * - read valid prediction will consist of finding:
+ * - DQS enable phase and DQS enable delay (DQS Enable Calibration)
+ * - DQS input phase and DQS input delay (DQ/DQS Centering)
+ * - we also do a per-bit deskew on the DQ lines.
+ */
+static int rw_mgr_mem_calibrate_vfifo(const u32 rw_group, const u32 test_bgn)
+{
+ u32 p, d;
+ u32 dtaps_per_ptap;
+ u32 failed_substage;
+
+ int ret;
+
+ debug("%s:%d: %u %u\n", __func__, __LINE__, rw_group, test_bgn);
+
+ /* Update info for sims */
+ reg_file_set_group(rw_group);
+ reg_file_set_stage(CAL_STAGE_VFIFO);
+ reg_file_set_sub_stage(CAL_SUBSTAGE_GUARANTEED_READ);
+
+ failed_substage = CAL_SUBSTAGE_GUARANTEED_READ;
+
+ /* USER Determine number of delay taps for each phase tap. */
+ dtaps_per_ptap = DIV_ROUND_UP(iocfg->delay_per_opa_tap,
+ iocfg->delay_per_dqs_en_dchain_tap) - 1;
+
+ for (d = 0; d <= dtaps_per_ptap; d += 2) {
+ /*
+ * In RLDRAMX we may be messing the delay of pins in
+ * the same write rw_group but outside of the current read
+ * the rw_group, but that's ok because we haven't calibrated
+ * output side yet.
+ */
+ if (d > 0) {
+ scc_mgr_apply_group_all_out_delay_add_all_ranks(
+ rw_group, d);
+ }
+
+ for (p = 0; p <= iocfg->dqdqs_out_phase_max; p++) {
+ /* 1) Guaranteed Write */
+ ret = rw_mgr_mem_calibrate_guaranteed_write(rw_group, p);
+ if (ret)
+ break;
+
+ /* 2) DQS Enable Calibration */
+ ret = rw_mgr_mem_calibrate_dqs_enable_calibration(rw_group,
+ test_bgn);
+ if (ret) {
+ failed_substage = CAL_SUBSTAGE_DQS_EN_PHASE;
+ continue;
+ }
+
+ /* 3) Centering DQ/DQS */
+ /*
+ * If doing read after write calibration, do not update
+ * FOM now. Do it then.
+ */
+ ret = rw_mgr_mem_calibrate_dq_dqs_centering(rw_group,
+ test_bgn, 1, 0);
+ if (ret) {
+ failed_substage = CAL_SUBSTAGE_VFIFO_CENTER;
+ continue;
+ }
+
+ /* All done. */
+ goto cal_done_ok;
+ }
+ }
+
+ /* Calibration Stage 1 failed. */
+ set_failing_group_stage(rw_group, CAL_STAGE_VFIFO, failed_substage);
+ return 0;
+
+ /* Calibration Stage 1 completed OK. */
+cal_done_ok:
+ /*
+ * Reset the delay chains back to zero if they have moved > 1
+ * (check for > 1 because loop will increase d even when pass in
+ * first case).
+ */
+ if (d > 2)
+ scc_mgr_zero_group(rw_group, 1);
+
+ return 1;
+}
+
+/**
+ * rw_mgr_mem_calibrate_vfifo_end() - DQ/DQS Centering.
+ * @rw_group: Read/Write Group
+ * @test_bgn: Rank at which the test begins
+ *
+ * Stage 3: DQ/DQS Centering.
+ *
+ * This function implements UniPHY calibration Stage 3, as explained in
+ * detail in Altera EMI_RM 2015.05.04 , "UniPHY Calibration Stages".
+ */
+static int rw_mgr_mem_calibrate_vfifo_end(const u32 rw_group,
+ const u32 test_bgn)
+{
+ int ret;
+
+ debug("%s:%d %u %u", __func__, __LINE__, rw_group, test_bgn);
+
+ /* Update info for sims. */
+ reg_file_set_group(rw_group);
+ reg_file_set_stage(CAL_STAGE_VFIFO_AFTER_WRITES);
+ reg_file_set_sub_stage(CAL_SUBSTAGE_VFIFO_CENTER);
+
+ ret = rw_mgr_mem_calibrate_dq_dqs_centering(rw_group, test_bgn, 0, 1);
+ if (ret)
+ set_failing_group_stage(rw_group,
+ CAL_STAGE_VFIFO_AFTER_WRITES,
+ CAL_SUBSTAGE_VFIFO_CENTER);
+ return ret;
+}
+
+/**
+ * rw_mgr_mem_calibrate_lfifo() - Minimize latency
+ *
+ * Stage 4: Minimize latency.
+ *
+ * This function implements UniPHY calibration Stage 4, as explained in
+ * detail in Altera EMI_RM 2015.05.04 , "UniPHY Calibration Stages".
+ * Calibrate LFIFO to find smallest read latency.
+ */
+static u32 rw_mgr_mem_calibrate_lfifo(void)
+{
+ int found_one = 0;
+
+ debug("%s:%d\n", __func__, __LINE__);
+
+ /* Update info for sims. */
+ reg_file_set_stage(CAL_STAGE_LFIFO);
+ reg_file_set_sub_stage(CAL_SUBSTAGE_READ_LATENCY);
+
+ /* Load up the patterns used by read calibration for all ranks */
+ rw_mgr_mem_calibrate_read_load_patterns(0, 1);
+
+ do {
+ writel(gbl->curr_read_lat, &phy_mgr_cfg->phy_rlat);
+ debug_cond(DLEVEL == 2, "%s:%d lfifo: read_lat=%u",
+ __func__, __LINE__, gbl->curr_read_lat);
+
+ if (!rw_mgr_mem_calibrate_read_test_all_ranks(0, NUM_READ_TESTS,
+ PASS_ALL_BITS, 1))
+ break;
+
+ found_one = 1;
+ /*
+ * Reduce read latency and see if things are
+ * working correctly.
+ */
+ gbl->curr_read_lat--;
+ } while (gbl->curr_read_lat > 0);
+
+ /* Reset the fifos to get pointers to known state. */
+ writel(0, &phy_mgr_cmd->fifo_reset);
+
+ if (found_one) {
+ /* Add a fudge factor to the read latency that was determined */
+ gbl->curr_read_lat += 2;
+ writel(gbl->curr_read_lat, &phy_mgr_cfg->phy_rlat);
+ debug_cond(DLEVEL == 2,
+ "%s:%d lfifo: success: using read_lat=%u\n",
+ __func__, __LINE__, gbl->curr_read_lat);
+ } else {
+ set_failing_group_stage(0xff, CAL_STAGE_LFIFO,
+ CAL_SUBSTAGE_READ_LATENCY);
+
+ debug_cond(DLEVEL == 2,
+ "%s:%d lfifo: failed at initial read_lat=%u\n",
+ __func__, __LINE__, gbl->curr_read_lat);
+ }
+
+ return found_one;
+}
+
+/**
+ * search_window() - Search for the/part of the window with DM/DQS shift
+ * @search_dm: If 1, search for the DM shift, if 0, search for DQS shift
+ * @rank_bgn: Rank number
+ * @write_group: Write Group
+ * @bgn_curr: Current window begin
+ * @end_curr: Current window end
+ * @bgn_best: Current best window begin
+ * @end_best: Current best window end
+ * @win_best: Size of the best window
+ * @new_dqs: New DQS value (only applicable if search_dm = 0).
+ *
+ * Search for the/part of the window with DM/DQS shift.
+ */
+static void search_window(const int search_dm,
+ const u32 rank_bgn, const u32 write_group,
+ int *bgn_curr, int *end_curr, int *bgn_best,
+ int *end_best, int *win_best, int new_dqs)
+{
+ u32 bit_chk;
+ const int max = iocfg->io_out1_delay_max - new_dqs;
+ int d, di;
+
+ /* Search for the/part of the window with DM/DQS shift. */
+ for (di = max; di >= 0; di -= DELTA_D) {
+ if (search_dm) {
+ d = di;
+ scc_mgr_apply_group_dm_out1_delay(d);
+ } else {
+ /* For DQS, we go from 0...max */
+ d = max - di;
+ /*
+ * Note: This only shifts DQS, so are we limiting
+ * ourselves to width of DQ unnecessarily.
+ */
+ scc_mgr_apply_group_dqs_io_and_oct_out1(write_group,
+ d + new_dqs);
+ }
+
+ writel(0, &sdr_scc_mgr->update);
+
+ if (rw_mgr_mem_calibrate_write_test(rank_bgn, write_group, 1,
+ PASS_ALL_BITS, &bit_chk,
+ 0)) {
+ /* Set current end of the window. */
+ *end_curr = search_dm ? -d : d;
+
+ /*
+ * If a starting edge of our window has not been seen
+ * this is our current start of the DM window.
+ */
+ if (*bgn_curr == iocfg->io_out1_delay_max + 1)
+ *bgn_curr = search_dm ? -d : d;
+
+ /*
+ * If current window is bigger than best seen.
+ * Set best seen to be current window.
+ */
+ if ((*end_curr - *bgn_curr + 1) > *win_best) {
+ *win_best = *end_curr - *bgn_curr + 1;
+ *bgn_best = *bgn_curr;
+ *end_best = *end_curr;
+ }
+ } else {
+ /* We just saw a failing test. Reset temp edge. */
+ *bgn_curr = iocfg->io_out1_delay_max + 1;
+ *end_curr = iocfg->io_out1_delay_max + 1;
+
+ /* Early exit is only applicable to DQS. */
+ if (search_dm)
+ continue;
+
+ /*
+ * Early exit optimization: if the remaining delay
+ * chain space is less than already seen largest
+ * window we can exit.
+ */
+ if (*win_best - 1 > iocfg->io_out1_delay_max - new_dqs - d)
+ break;
+ }
+ }
+}
+
+/*
+ * rw_mgr_mem_calibrate_writes_center() - Center all windows
+ * @rank_bgn: Rank number
+ * @write_group: Write group
+ * @test_bgn: Rank at which the test begins
+ *
+ * Center all windows. Do per-bit-deskew to possibly increase size of
+ * certain windows.
+ */
+static int
+rw_mgr_mem_calibrate_writes_center(const u32 rank_bgn, const u32 write_group,
+ const u32 test_bgn)
+{
+ int i;
+ u32 sticky_bit_chk;
+ u32 min_index;
+ int left_edge[rwcfg->mem_dq_per_write_dqs];
+ int right_edge[rwcfg->mem_dq_per_write_dqs];
+ int mid;
+ int mid_min, orig_mid_min;
+ int new_dqs, start_dqs;
+ int dq_margin, dqs_margin, dm_margin;
+ int bgn_curr = iocfg->io_out1_delay_max + 1;
+ int end_curr = iocfg->io_out1_delay_max + 1;
+ int bgn_best = iocfg->io_out1_delay_max + 1;
+ int end_best = iocfg->io_out1_delay_max + 1;
+ int win_best = 0;
+
+ int ret;
+
+ debug("%s:%d %u %u", __func__, __LINE__, write_group, test_bgn);
+
+ dm_margin = 0;
+
+ start_dqs = readl((SDR_PHYGRP_SCCGRP_ADDRESS |
+ SCC_MGR_IO_OUT1_DELAY_OFFSET) +
+ (rwcfg->mem_dq_per_write_dqs << 2));
+
+ /* Per-bit deskew. */
+
+ /*
+ * Set the left and right edge of each bit to an illegal value.
+ * Use (iocfg->io_out1_delay_max + 1) as an illegal value.
+ */
+ sticky_bit_chk = 0;
+ for (i = 0; i < rwcfg->mem_dq_per_write_dqs; i++) {
+ left_edge[i] = iocfg->io_out1_delay_max + 1;
+ right_edge[i] = iocfg->io_out1_delay_max + 1;
+ }
+
+ /* Search for the left edge of the window for each bit. */
+ search_left_edge(1, rank_bgn, write_group, 0, test_bgn,
+ &sticky_bit_chk,
+ left_edge, right_edge, 0);
+
+ /* Search for the right edge of the window for each bit. */
+ ret = search_right_edge(1, rank_bgn, write_group, 0,
+ start_dqs, 0,
+ &sticky_bit_chk,
+ left_edge, right_edge, 0);
+ if (ret) {
+ set_failing_group_stage(test_bgn + ret - 1, CAL_STAGE_WRITES,
+ CAL_SUBSTAGE_WRITES_CENTER);
+ return -EINVAL;
+ }
+
+ min_index = get_window_mid_index(1, left_edge, right_edge, &mid_min);
+
+ /* Determine the amount we can change DQS (which is -mid_min). */
+ orig_mid_min = mid_min;
+ new_dqs = start_dqs;
+ mid_min = 0;
+ debug_cond(DLEVEL == 1,
+ "%s:%d write_center: start_dqs=%d new_dqs=%d mid_min=%d\n",
+ __func__, __LINE__, start_dqs, new_dqs, mid_min);
+
+ /* Add delay to bring centre of all DQ windows to the same "level". */
+ center_dq_windows(1, left_edge, right_edge, mid_min, orig_mid_min,
+ min_index, 0, &dq_margin, &dqs_margin);
+
+ /* Move DQS */
+ scc_mgr_apply_group_dqs_io_and_oct_out1(write_group, new_dqs);
+ writel(0, &sdr_scc_mgr->update);
+
+ /* Centre DM */
+ debug_cond(DLEVEL == 2, "%s:%d write_center: DM\n", __func__, __LINE__);
+
+ /*
+ * Set the left and right edge of each bit to an illegal value.
+ * Use (iocfg->io_out1_delay_max + 1) as an illegal value.
+ */
+ left_edge[0] = iocfg->io_out1_delay_max + 1;
+ right_edge[0] = iocfg->io_out1_delay_max + 1;
+
+ /* Search for the/part of the window with DM shift. */
+ search_window(1, rank_bgn, write_group, &bgn_curr, &end_curr,
+ &bgn_best, &end_best, &win_best, 0);
+
+ /* Reset DM delay chains to 0. */
+ scc_mgr_apply_group_dm_out1_delay(0);
+
+ /*
+ * Check to see if the current window nudges up aganist 0 delay.
+ * If so we need to continue the search by shifting DQS otherwise DQS
+ * search begins as a new search.
+ */
+ if (end_curr != 0) {
+ bgn_curr = iocfg->io_out1_delay_max + 1;
+ end_curr = iocfg->io_out1_delay_max + 1;
+ }
+
+ /* Search for the/part of the window with DQS shifts. */
+ search_window(0, rank_bgn, write_group, &bgn_curr, &end_curr,
+ &bgn_best, &end_best, &win_best, new_dqs);
+
+ /* Assign left and right edge for cal and reporting. */
+ left_edge[0] = -1 * bgn_best;
+ right_edge[0] = end_best;
+
+ debug_cond(DLEVEL == 2, "%s:%d dm_calib: left=%d right=%d\n",
+ __func__, __LINE__, left_edge[0], right_edge[0]);
+
+ /* Move DQS (back to orig). */
+ scc_mgr_apply_group_dqs_io_and_oct_out1(write_group, new_dqs);
+
+ /* Move DM */
+
+ /* Find middle of window for the DM bit. */
+ mid = (left_edge[0] - right_edge[0]) / 2;
+
+ /* Only move right, since we are not moving DQS/DQ. */
+ if (mid < 0)
+ mid = 0;
+
+ /* dm_marign should fail if we never find a window. */
+ if (win_best == 0)
+ dm_margin = -1;
+ else
+ dm_margin = left_edge[0] - mid;
+
+ scc_mgr_apply_group_dm_out1_delay(mid);
+ writel(0, &sdr_scc_mgr->update);
+
+ debug_cond(DLEVEL == 2,
+ "%s:%d dm_calib: left=%d right=%d mid=%d dm_margin=%d\n",
+ __func__, __LINE__, left_edge[0], right_edge[0],
+ mid, dm_margin);
+ /* Export values. */
+ gbl->fom_out += dq_margin + dqs_margin;
+
+ debug_cond(DLEVEL == 2,
+ "%s:%d write_center: dq_margin=%d dqs_margin=%d dm_margin=%d\n",
+ __func__, __LINE__, dq_margin, dqs_margin, dm_margin);
+
+ /*
+ * Do not remove this line as it makes sure all of our
+ * decisions have been applied.
+ */
+ writel(0, &sdr_scc_mgr->update);
+
+ if ((dq_margin < 0) || (dqs_margin < 0) || (dm_margin < 0))
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * rw_mgr_mem_calibrate_writes() - Write Calibration Part One
+ * @rank_bgn: Rank number
+ * @group: Read/Write Group
+ * @test_bgn: Rank at which the test begins
+ *
+ * Stage 2: Write Calibration Part One.
+ *
+ * This function implements UniPHY calibration Stage 2, as explained in
+ * detail in Altera EMI_RM 2015.05.04 , "UniPHY Calibration Stages".
+ */
+static int rw_mgr_mem_calibrate_writes(const u32 rank_bgn, const u32 group,
+ const u32 test_bgn)
+{
+ int ret;
+
+ /* Update info for sims */
+ debug("%s:%d %u %u\n", __func__, __LINE__, group, test_bgn);
+
+ reg_file_set_group(group);
+ reg_file_set_stage(CAL_STAGE_WRITES);
+ reg_file_set_sub_stage(CAL_SUBSTAGE_WRITES_CENTER);
+
+ ret = rw_mgr_mem_calibrate_writes_center(rank_bgn, group, test_bgn);
+ if (ret)
+ set_failing_group_stage(group, CAL_STAGE_WRITES,
+ CAL_SUBSTAGE_WRITES_CENTER);
+
+ return ret;
+}
+
+/**
+ * mem_precharge_and_activate() - Precharge all banks and activate
+ *
+ * Precharge all banks and activate row 0 in bank "000..." and bank "111...".
+ */
+static void mem_precharge_and_activate(void)
+{
+ int r;
+
+ for (r = 0; r < rwcfg->mem_number_of_ranks; r++) {
+ /* Set rank. */
+ set_rank_and_odt_mask(r, RW_MGR_ODT_MODE_OFF);
+
+ /* Precharge all banks. */
+ writel(rwcfg->precharge_all, SDR_PHYGRP_RWMGRGRP_ADDRESS |
+ RW_MGR_RUN_SINGLE_GROUP_OFFSET);
+
+ writel(0x0F, &sdr_rw_load_mgr_regs->load_cntr0);
+ writel(rwcfg->activate_0_and_1_wait1,
+ &sdr_rw_load_jump_mgr_regs->load_jump_add0);
+
+ writel(0x0F, &sdr_rw_load_mgr_regs->load_cntr1);
+ writel(rwcfg->activate_0_and_1_wait2,
+ &sdr_rw_load_jump_mgr_regs->load_jump_add1);
+
+ /* Activate rows. */
+ writel(rwcfg->activate_0_and_1, SDR_PHYGRP_RWMGRGRP_ADDRESS |
+ RW_MGR_RUN_SINGLE_GROUP_OFFSET);
+ }
+}
+
+/**
+ * mem_init_latency() - Configure memory RLAT and WLAT settings
+ *
+ * Configure memory RLAT and WLAT parameters.
+ */
+static void mem_init_latency(void)
+{
+ /*
+ * For AV/CV, LFIFO is hardened and always runs at full rate
+ * so max latency in AFI clocks, used here, is correspondingly
+ * smaller.
+ */
+ const u32 max_latency = (1 << misccfg->max_latency_count_width) - 1;
+ u32 rlat, wlat;
+
+ debug("%s:%d\n", __func__, __LINE__);
+
+ /*
+ * Read in write latency.
+ * WL for Hard PHY does not include additive latency.
+ */
+ wlat = readl(&data_mgr->t_wl_add);
+ wlat += readl(&data_mgr->mem_t_add);
+
+ gbl->rw_wl_nop_cycles = wlat - 1;
+
+ /* Read in readl latency. */
+ rlat = readl(&data_mgr->t_rl_add);
+
+ /* Set a pretty high read latency initially. */
+ gbl->curr_read_lat = rlat + 16;
+ if (gbl->curr_read_lat > max_latency)
+ gbl->curr_read_lat = max_latency;
+
+ writel(gbl->curr_read_lat, &phy_mgr_cfg->phy_rlat);
+
+ /* Advertise write latency. */
+ writel(wlat, &phy_mgr_cfg->afi_wlat);
+}
+
+/**
+ * @mem_skip_calibrate() - Set VFIFO and LFIFO to instant-on settings
+ *
+ * Set VFIFO and LFIFO to instant-on settings in skip calibration mode.
+ */
+static void mem_skip_calibrate(void)
+{
+ u32 vfifo_offset;
+ u32 i, j, r;
+
+ debug("%s:%d\n", __func__, __LINE__);
+ /* Need to update every shadow register set used by the interface */
+ for (r = 0; r < rwcfg->mem_number_of_ranks;
+ r += NUM_RANKS_PER_SHADOW_REG) {
+ /*
+ * Set output phase alignment settings appropriate for
+ * skip calibration.
+ */
+ for (i = 0; i < rwcfg->mem_if_read_dqs_width; i++) {
+ scc_mgr_set_dqs_en_phase(i, 0);
+ if (iocfg->dll_chain_length == 6)
+ scc_mgr_set_dqdqs_output_phase(i, 6);
+ else
+ scc_mgr_set_dqdqs_output_phase(i, 7);
+ /*
+ * Case:33398
+ *
+ * Write data arrives to the I/O two cycles before write
+ * latency is reached (720 deg).
+ * -> due to bit-slip in a/c bus
+ * -> to allow board skew where dqs is longer than ck
+ * -> how often can this happen!?
+ * -> can claim back some ptaps for high freq
+ * support if we can relax this, but i digress...
+ *
+ * The write_clk leads mem_ck by 90 deg
+ * The minimum ptap of the OPA is 180 deg
+ * Each ptap has (360 / IO_DLL_CHAIN_LENGH) deg of delay
+ * The write_clk is always delayed by 2 ptaps
+ *
+ * Hence, to make DQS aligned to CK, we need to delay
+ * DQS by:
+ * (720 - 90 - 180 - 2) *
+ * (360 / iocfg->dll_chain_length)
+ *
+ * Dividing the above by (360 / iocfg->dll_chain_length)
+ * gives us the number of ptaps, which simplies to:
+ *
+ * (1.25 * iocfg->dll_chain_length - 2)
+ */
+ scc_mgr_set_dqdqs_output_phase(i,
+ 1.25 * iocfg->dll_chain_length - 2);
+ }
+ writel(0xff, &sdr_scc_mgr->dqs_ena);
+ writel(0xff, &sdr_scc_mgr->dqs_io_ena);
+
+ for (i = 0; i < rwcfg->mem_if_write_dqs_width; i++) {
+ writel(i, SDR_PHYGRP_SCCGRP_ADDRESS |
+ SCC_MGR_GROUP_COUNTER_OFFSET);
+ }
+ writel(0xff, &sdr_scc_mgr->dq_ena);
+ writel(0xff, &sdr_scc_mgr->dm_ena);
+ writel(0, &sdr_scc_mgr->update);
+ }
+
+ /* Compensate for simulation model behaviour */
+ for (i = 0; i < rwcfg->mem_if_read_dqs_width; i++) {
+ scc_mgr_set_dqs_bus_in_delay(i, 10);
+ scc_mgr_load_dqs(i);
+ }
+ writel(0, &sdr_scc_mgr->update);
+
+ /*
+ * ArriaV has hard FIFOs that can only be initialized by incrementing
+ * in sequencer.
+ */
+ vfifo_offset = misccfg->calib_vfifo_offset;
+ for (j = 0; j < vfifo_offset; j++)
+ writel(0xff, &phy_mgr_cmd->inc_vfifo_hard_phy);
+ writel(0, &phy_mgr_cmd->fifo_reset);
+
+ /*
+ * For Arria V and Cyclone V with hard LFIFO, we get the skip-cal
+ * setting from generation-time constant.
+ */
+ gbl->curr_read_lat = misccfg->calib_lfifo_offset;
+ writel(gbl->curr_read_lat, &phy_mgr_cfg->phy_rlat);
+}
+
+/**
+ * mem_calibrate() - Memory calibration entry point.
+ *
+ * Perform memory calibration.
+ */
+static u32 mem_calibrate(void)
+{
+ u32 i;
+ u32 rank_bgn, sr;
+ u32 write_group, write_test_bgn;
+ u32 read_group, read_test_bgn;
+ u32 run_groups, current_run;
+ u32 failing_groups = 0;
+ u32 group_failed = 0;
+
+ const u32 rwdqs_ratio = rwcfg->mem_if_read_dqs_width /
+ rwcfg->mem_if_write_dqs_width;
+
+ debug("%s:%d\n", __func__, __LINE__);
+
+ /* Initialize the data settings */
+ gbl->error_substage = CAL_SUBSTAGE_NIL;
+ gbl->error_stage = CAL_STAGE_NIL;
+ gbl->error_group = 0xff;
+ gbl->fom_in = 0;
+ gbl->fom_out = 0;
+
+ /* Initialize WLAT and RLAT. */
+ mem_init_latency();
+
+ /* Initialize bit slips. */
+ mem_precharge_and_activate();
+
+ for (i = 0; i < rwcfg->mem_if_read_dqs_width; i++) {
+ writel(i, SDR_PHYGRP_SCCGRP_ADDRESS |
+ SCC_MGR_GROUP_COUNTER_OFFSET);
+ /* Only needed once to set all groups, pins, DQ, DQS, DM. */
+ if (i == 0)
+ scc_mgr_set_hhp_extras();
+
+ scc_set_bypass_mode(i);
+ }
+
+ /* Calibration is skipped. */
+ if ((dyn_calib_steps & CALIB_SKIP_ALL) == CALIB_SKIP_ALL) {
+ /*
+ * Set VFIFO and LFIFO to instant-on settings in skip
+ * calibration mode.
+ */
+ mem_skip_calibrate();
+
+ /*
+ * Do not remove this line as it makes sure all of our
+ * decisions have been applied.
+ */
+ writel(0, &sdr_scc_mgr->update);
+ return 1;
+ }
+
+ /* Calibration is not skipped. */
+ for (i = 0; i < NUM_CALIB_REPEAT; i++) {
+ /*
+ * Zero all delay chain/phase settings for all
+ * groups and all shadow register sets.
+ */
+ scc_mgr_zero_all();
+
+ run_groups = ~0;
+
+ for (write_group = 0, write_test_bgn = 0; write_group
+ < rwcfg->mem_if_write_dqs_width; write_group++,
+ write_test_bgn += rwcfg->mem_dq_per_write_dqs) {
+ /* Initialize the group failure */
+ group_failed = 0;
+
+ current_run = run_groups & ((1 <<
+ RW_MGR_NUM_DQS_PER_WRITE_GROUP) - 1);
+ run_groups = run_groups >>
+ RW_MGR_NUM_DQS_PER_WRITE_GROUP;
+
+ if (current_run == 0)
+ continue;
+
+ writel(write_group, SDR_PHYGRP_SCCGRP_ADDRESS |
+ SCC_MGR_GROUP_COUNTER_OFFSET);
+ scc_mgr_zero_group(write_group, 0);
+
+ for (read_group = write_group * rwdqs_ratio,
+ read_test_bgn = 0;
+ read_group < (write_group + 1) * rwdqs_ratio;
+ read_group++,
+ read_test_bgn += rwcfg->mem_dq_per_read_dqs) {
+ if (STATIC_CALIB_STEPS & CALIB_SKIP_VFIFO)
+ continue;
+
+ /* Calibrate the VFIFO */
+ if (rw_mgr_mem_calibrate_vfifo(read_group,
+ read_test_bgn))
+ continue;
+
+ if (!(gbl->phy_debug_mode_flags &
+ PHY_DEBUG_SWEEP_ALL_GROUPS))
+ return 0;
+
+ /* The group failed, we're done. */
+ goto grp_failed;
+ }
+
+ /* Calibrate the output side */
+ for (rank_bgn = 0, sr = 0;
+ rank_bgn < rwcfg->mem_number_of_ranks;
+ rank_bgn += NUM_RANKS_PER_SHADOW_REG, sr++) {
+ if (STATIC_CALIB_STEPS & CALIB_SKIP_WRITES)
+ continue;
+
+ /* Not needed in quick mode! */
+ if (STATIC_CALIB_STEPS &
+ CALIB_SKIP_DELAY_SWEEPS)
+ continue;
+
+ /* Calibrate WRITEs */
+ if (!rw_mgr_mem_calibrate_writes(rank_bgn,
+ write_group,
+ write_test_bgn))
+ continue;
+
+ group_failed = 1;
+ if (!(gbl->phy_debug_mode_flags &
+ PHY_DEBUG_SWEEP_ALL_GROUPS))
+ return 0;
+ }
+
+ /* Some group failed, we're done. */
+ if (group_failed)
+ goto grp_failed;
+
+ for (read_group = write_group * rwdqs_ratio,
+ read_test_bgn = 0;
+ read_group < (write_group + 1) * rwdqs_ratio;
+ read_group++,
+ read_test_bgn += rwcfg->mem_dq_per_read_dqs) {
+ if (STATIC_CALIB_STEPS & CALIB_SKIP_WRITES)
+ continue;
+
+ if (!rw_mgr_mem_calibrate_vfifo_end(read_group,
+ read_test_bgn))
+ continue;
+
+ if (!(gbl->phy_debug_mode_flags &
+ PHY_DEBUG_SWEEP_ALL_GROUPS))
+ return 0;
+
+ /* The group failed, we're done. */
+ goto grp_failed;
+ }
+
+ /* No group failed, continue as usual. */
+ continue;
+
+grp_failed: /* A group failed, increment the counter. */
+ failing_groups++;
+ }
+
+ /*
+ * USER If there are any failing groups then report
+ * the failure.
+ */
+ if (failing_groups != 0)
+ return 0;
+
+ if (STATIC_CALIB_STEPS & CALIB_SKIP_LFIFO)
+ continue;
+
+ /* Calibrate the LFIFO */
+ if (!rw_mgr_mem_calibrate_lfifo())
+ return 0;
+ }
+
+ /*
+ * Do not remove this line as it makes sure all of our decisions
+ * have been applied.
+ */
+ writel(0, &sdr_scc_mgr->update);
+ return 1;
+}
+
+/**
+ * run_mem_calibrate() - Perform memory calibration
+ *
+ * This function triggers the entire memory calibration procedure.
+ */
+static int run_mem_calibrate(void)
+{
+ int pass;
+
+ debug("%s:%d\n", __func__, __LINE__);
+
+ /* Reset pass/fail status shown on afi_cal_success/fail */
+ writel(PHY_MGR_CAL_RESET, &phy_mgr_cfg->cal_status);
+
+ /* Stop tracking manager. */
+ clrbits_le32(&sdr_ctrl->ctrl_cfg, 1 << 22);
+
+ phy_mgr_initialize();
+ rw_mgr_mem_initialize();
+
+ /* Perform the actual memory calibration. */
+ pass = mem_calibrate();
+
+ mem_precharge_and_activate();
+ writel(0, &phy_mgr_cmd->fifo_reset);
+
+ /* Handoff. */
+ rw_mgr_mem_handoff();
+ /*
+ * In Hard PHY this is a 2-bit control:
+ * 0: AFI Mux Select
+ * 1: DDIO Mux Select
+ */
+ writel(0x2, &phy_mgr_cfg->mux_sel);
+
+ /* Start tracking manager. */
+ setbits_le32(&sdr_ctrl->ctrl_cfg, 1 << 22);
+
+ return pass;
+}
+
+/**
+ * debug_mem_calibrate() - Report result of memory calibration
+ * @pass: Value indicating whether calibration passed or failed
+ *
+ * This function reports the results of the memory calibration
+ * and writes debug information into the register file.
+ */
+static void debug_mem_calibrate(int pass)
+{
+ u32 debug_info;
+
+ if (pass) {
+ printf("%s: CALIBRATION PASSED\n", __FILE__);
+
+ gbl->fom_in /= 2;
+ gbl->fom_out /= 2;
+
+ if (gbl->fom_in > 0xff)
+ gbl->fom_in = 0xff;
+
+ if (gbl->fom_out > 0xff)
+ gbl->fom_out = 0xff;
+
+ /* Update the FOM in the register file */
+ debug_info = gbl->fom_in;
+ debug_info |= gbl->fom_out << 8;
+ writel(debug_info, &sdr_reg_file->fom);
+
+ writel(debug_info, &phy_mgr_cfg->cal_debug_info);
+ writel(PHY_MGR_CAL_SUCCESS, &phy_mgr_cfg->cal_status);
+ } else {
+ printf("%s: CALIBRATION FAILED\n", __FILE__);
+
+ debug_info = gbl->error_stage;
+ debug_info |= gbl->error_substage << 8;
+ debug_info |= gbl->error_group << 16;
+
+ writel(debug_info, &sdr_reg_file->failing_stage);
+ writel(debug_info, &phy_mgr_cfg->cal_debug_info);
+ writel(PHY_MGR_CAL_FAIL, &phy_mgr_cfg->cal_status);
+
+ /* Update the failing group/stage in the register file */
+ debug_info = gbl->error_stage;
+ debug_info |= gbl->error_substage << 8;
+ debug_info |= gbl->error_group << 16;
+ writel(debug_info, &sdr_reg_file->failing_stage);
+ }
+
+ printf("%s: Calibration complete\n", __FILE__);
+}
+
+/**
+ * hc_initialize_rom_data() - Initialize ROM data
+ *
+ * Initialize ROM data.
+ */
+static void hc_initialize_rom_data(void)
+{
+ unsigned int nelem = 0;
+ const u32 *rom_init;
+ u32 i, addr;
+
+ socfpga_get_seq_inst_init(&rom_init, &nelem);
+ addr = SDR_PHYGRP_RWMGRGRP_ADDRESS | RW_MGR_INST_ROM_WRITE_OFFSET;
+ for (i = 0; i < nelem; i++)
+ writel(rom_init[i], addr + (i << 2));
+
+ socfpga_get_seq_ac_init(&rom_init, &nelem);
+ addr = SDR_PHYGRP_RWMGRGRP_ADDRESS | RW_MGR_AC_ROM_WRITE_OFFSET;
+ for (i = 0; i < nelem; i++)
+ writel(rom_init[i], addr + (i << 2));
+}
+
+/**
+ * initialize_reg_file() - Initialize SDR register file
+ *
+ * Initialize SDR register file.
+ */
+static void initialize_reg_file(void)
+{
+ /* Initialize the register file with the correct data */
+ writel(misccfg->reg_file_init_seq_signature, &sdr_reg_file->signature);
+ writel(0, &sdr_reg_file->debug_data_addr);
+ writel(0, &sdr_reg_file->cur_stage);
+ writel(0, &sdr_reg_file->fom);
+ writel(0, &sdr_reg_file->failing_stage);
+ writel(0, &sdr_reg_file->debug1);
+ writel(0, &sdr_reg_file->debug2);
+}
+
+/**
+ * initialize_hps_phy() - Initialize HPS PHY
+ *
+ * Initialize HPS PHY.
+ */
+static void initialize_hps_phy(void)
+{
+ u32 reg;
+ /*
+ * Tracking also gets configured here because it's in the
+ * same register.
+ */
+ u32 trk_sample_count = 7500;
+ u32 trk_long_idle_sample_count = (10 << 16) | 100;
+ /*
+ * Format is number of outer loops in the 16 MSB, sample
+ * count in 16 LSB.
+ */
+
+ reg = 0;
+ reg |= SDR_CTRLGRP_PHYCTRL_PHYCTRL_0_ACDELAYEN_SET(2);
+ reg |= SDR_CTRLGRP_PHYCTRL_PHYCTRL_0_DQDELAYEN_SET(1);
+ reg |= SDR_CTRLGRP_PHYCTRL_PHYCTRL_0_DQSDELAYEN_SET(1);
+ reg |= SDR_CTRLGRP_PHYCTRL_PHYCTRL_0_DQSLOGICDELAYEN_SET(1);
+ reg |= SDR_CTRLGRP_PHYCTRL_PHYCTRL_0_RESETDELAYEN_SET(0);
+ reg |= SDR_CTRLGRP_PHYCTRL_PHYCTRL_0_LPDDRDIS_SET(1);
+ /*
+ * This field selects the intrinsic latency to RDATA_EN/FULL path.
+ * 00-bypass, 01- add 5 cycles, 10- add 10 cycles, 11- add 15 cycles.
+ */
+ reg |= SDR_CTRLGRP_PHYCTRL_PHYCTRL_0_ADDLATSEL_SET(0);
+ reg |= SDR_CTRLGRP_PHYCTRL_PHYCTRL_0_SAMPLECOUNT_19_0_SET(
+ trk_sample_count);
+ writel(reg, &sdr_ctrl->phy_ctrl0);
+
+ reg = 0;
+ reg |= SDR_CTRLGRP_PHYCTRL_PHYCTRL_1_SAMPLECOUNT_31_20_SET(
+ trk_sample_count >>
+ SDR_CTRLGRP_PHYCTRL_PHYCTRL_0_SAMPLECOUNT_19_0_WIDTH);
+ reg |= SDR_CTRLGRP_PHYCTRL_PHYCTRL_1_LONGIDLESAMPLECOUNT_19_0_SET(
+ trk_long_idle_sample_count);
+ writel(reg, &sdr_ctrl->phy_ctrl1);
+
+ reg = 0;
+ reg |= SDR_CTRLGRP_PHYCTRL_PHYCTRL_2_LONGIDLESAMPLECOUNT_31_20_SET(
+ trk_long_idle_sample_count >>
+ SDR_CTRLGRP_PHYCTRL_PHYCTRL_1_LONGIDLESAMPLECOUNT_19_0_WIDTH);
+ writel(reg, &sdr_ctrl->phy_ctrl2);
+}
+
+/**
+ * initialize_tracking() - Initialize tracking
+ *
+ * Initialize the register file with usable initial data.
+ */
+static void initialize_tracking(void)
+{
+ /*
+ * Initialize the register file with the correct data.
+ * Compute usable version of value in case we skip full
+ * computation later.
+ */
+ writel(DIV_ROUND_UP(iocfg->delay_per_opa_tap,
+ iocfg->delay_per_dchain_tap) - 1,
+ &sdr_reg_file->dtaps_per_ptap);
+
+ /* trk_sample_count */
+ writel(7500, &sdr_reg_file->trk_sample_count);
+
+ /* longidle outer loop [15:0] */
+ writel((10 << 16) | (100 << 0), &sdr_reg_file->trk_longidle);
+
+ /*
+ * longidle sample count [31:24]
+ * trfc, worst case of 933Mhz 4Gb [23:16]
+ * trcd, worst case [15:8]
+ * vfifo wait [7:0]
+ */
+ writel((243 << 24) | (14 << 16) | (10 << 8) | (4 << 0),
+ &sdr_reg_file->delays);
+
+ /* mux delay */
+ writel((rwcfg->idle << 24) | (rwcfg->activate_1 << 16) |
+ (rwcfg->sgle_read << 8) | (rwcfg->precharge_all << 0),
+ &sdr_reg_file->trk_rw_mgr_addr);
+
+ writel(rwcfg->mem_if_read_dqs_width,
+ &sdr_reg_file->trk_read_dqs_width);
+
+ /* trefi [7:0] */
+ writel((rwcfg->refresh_all << 24) | (1000 << 0),
+ &sdr_reg_file->trk_rfsh);
+}
+
+int sdram_calibration_full(void)
+{
+ struct param_type my_param;
+ struct gbl_type my_gbl;
+ u32 pass;
+
+ memset(&my_param, 0, sizeof(my_param));
+ memset(&my_gbl, 0, sizeof(my_gbl));
+
+ param = &my_param;
+ gbl = &my_gbl;
+
+ rwcfg = socfpga_get_sdram_rwmgr_config();
+ iocfg = socfpga_get_sdram_io_config();
+ misccfg = socfpga_get_sdram_misc_config();
+
+ /* Set the calibration enabled by default */
+ gbl->phy_debug_mode_flags |= PHY_DEBUG_ENABLE_CAL_RPT;
+ /*
+ * Only sweep all groups (regardless of fail state) by default
+ * Set enabled read test by default.
+ */
+#if DISABLE_GUARANTEED_READ
+ gbl->phy_debug_mode_flags |= PHY_DEBUG_DISABLE_GUARANTEED_READ;
+#endif
+ /* Initialize the register file */
+ initialize_reg_file();
+
+ /* Initialize any PHY CSR */
+ initialize_hps_phy();
+
+ scc_mgr_initialize();
+
+ initialize_tracking();
+
+ printf("%s: Preparing to start memory calibration\n", __FILE__);
+
+ debug("%s:%d\n", __func__, __LINE__);
+ debug_cond(DLEVEL == 1,
+ "DDR3 FULL_RATE ranks=%u cs/dimm=%u dq/dqs=%u,%u vg/dqs=%u,%u ",
+ rwcfg->mem_number_of_ranks, rwcfg->mem_number_of_cs_per_dimm,
+ rwcfg->mem_dq_per_read_dqs, rwcfg->mem_dq_per_write_dqs,
+ rwcfg->mem_virtual_groups_per_read_dqs,
+ rwcfg->mem_virtual_groups_per_write_dqs);
+ debug_cond(DLEVEL == 1,
+ "dqs=%u,%u dq=%u dm=%u ptap_delay=%u dtap_delay=%u ",
+ rwcfg->mem_if_read_dqs_width, rwcfg->mem_if_write_dqs_width,
+ rwcfg->mem_data_width, rwcfg->mem_data_mask_width,
+ iocfg->delay_per_opa_tap, iocfg->delay_per_dchain_tap);
+ debug_cond(DLEVEL == 1, "dtap_dqsen_delay=%u, dll=%u",
+ iocfg->delay_per_dqs_en_dchain_tap, iocfg->dll_chain_length);
+ debug_cond(DLEVEL == 1,
+ "max values: en_p=%u dqdqs_p=%u en_d=%u dqs_in_d=%u ",
+ iocfg->dqs_en_phase_max, iocfg->dqdqs_out_phase_max,
+ iocfg->dqs_en_delay_max, iocfg->dqs_in_delay_max);
+ debug_cond(DLEVEL == 1, "io_in_d=%u io_out1_d=%u io_out2_d=%u ",
+ iocfg->io_in_delay_max, iocfg->io_out1_delay_max,
+ iocfg->io_out2_delay_max);
+ debug_cond(DLEVEL == 1, "dqs_in_reserve=%u dqs_out_reserve=%u\n",
+ iocfg->dqs_in_reserve, iocfg->dqs_out_reserve);
+
+ hc_initialize_rom_data();
+
+ /* update info for sims */
+ reg_file_set_stage(CAL_STAGE_NIL);
+ reg_file_set_group(0);
+
+ /*
+ * Load global needed for those actions that require
+ * some dynamic calibration support.
+ */
+ dyn_calib_steps = STATIC_CALIB_STEPS;
+ /*
+ * Load global to allow dynamic selection of delay loop settings
+ * based on calibration mode.
+ */
+ if (!(dyn_calib_steps & CALIB_SKIP_DELAY_LOOPS))
+ skip_delay_mask = 0xff;
+ else
+ skip_delay_mask = 0x0;
+
+ pass = run_mem_calibrate();
+ debug_mem_calibrate(pass);
+ return pass;
+}
diff --git a/drivers/ddr/altera/sequencer.h b/drivers/ddr/altera/sequencer.h
new file mode 100644
index 00000000000..839a374968a
--- /dev/null
+++ b/drivers/ddr/altera/sequencer.h
@@ -0,0 +1,227 @@
+/*
+ * Copyright Altera Corporation (C) 2012-2015
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _SEQUENCER_H_
+#define _SEQUENCER_H_
+
+#define RW_MGR_NUM_DM_PER_WRITE_GROUP (rwcfg->mem_data_mask_width \
+ / rwcfg->mem_if_write_dqs_width)
+#define RW_MGR_NUM_TRUE_DM_PER_WRITE_GROUP (rwcfg->true_mem_data_mask_width \
+ / rwcfg->mem_if_write_dqs_width)
+
+#define RW_MGR_NUM_DQS_PER_WRITE_GROUP (rwcfg->mem_if_read_dqs_width \
+ / rwcfg->mem_if_write_dqs_width)
+#define NUM_RANKS_PER_SHADOW_REG (rwcfg->mem_number_of_ranks / NUM_SHADOW_REGS)
+
+#define RW_MGR_RUN_SINGLE_GROUP_OFFSET 0x0
+#define RW_MGR_RUN_ALL_GROUPS_OFFSET 0x0400
+#define RW_MGR_RESET_READ_DATAPATH_OFFSET 0x1000
+#define RW_MGR_SET_CS_AND_ODT_MASK_OFFSET 0x1400
+#define RW_MGR_INST_ROM_WRITE_OFFSET 0x1800
+#define RW_MGR_AC_ROM_WRITE_OFFSET 0x1C00
+
+#define NUM_SHADOW_REGS 1
+
+#define RW_MGR_RANK_NONE 0xFF
+#define RW_MGR_RANK_ALL 0x00
+
+#define RW_MGR_ODT_MODE_OFF 0
+#define RW_MGR_ODT_MODE_READ_WRITE 1
+
+#define NUM_CALIB_REPEAT 1
+
+#define NUM_READ_TESTS 7
+#define NUM_READ_PB_TESTS 7
+#define NUM_WRITE_TESTS 15
+#define NUM_WRITE_PB_TESTS 31
+
+#define PASS_ALL_BITS 1
+#define PASS_ONE_BIT 0
+
+/* calibration stages */
+#define CAL_STAGE_NIL 0
+#define CAL_STAGE_VFIFO 1
+#define CAL_STAGE_WLEVEL 2
+#define CAL_STAGE_LFIFO 3
+#define CAL_STAGE_WRITES 4
+#define CAL_STAGE_FULLTEST 5
+#define CAL_STAGE_REFRESH 6
+#define CAL_STAGE_CAL_SKIPPED 7
+#define CAL_STAGE_CAL_ABORTED 8
+#define CAL_STAGE_VFIFO_AFTER_WRITES 9
+
+/* calibration substages */
+#define CAL_SUBSTAGE_NIL 0
+#define CAL_SUBSTAGE_GUARANTEED_READ 1
+#define CAL_SUBSTAGE_DQS_EN_PHASE 2
+#define CAL_SUBSTAGE_VFIFO_CENTER 3
+#define CAL_SUBSTAGE_WORKING_DELAY 1
+#define CAL_SUBSTAGE_LAST_WORKING_DELAY 2
+#define CAL_SUBSTAGE_WLEVEL_COPY 3
+#define CAL_SUBSTAGE_WRITES_CENTER 1
+#define CAL_SUBSTAGE_READ_LATENCY 1
+#define CAL_SUBSTAGE_REFRESH 1
+
+#define SCC_MGR_GROUP_COUNTER_OFFSET 0x0000
+#define SCC_MGR_DQS_IN_DELAY_OFFSET 0x0100
+#define SCC_MGR_DQS_EN_PHASE_OFFSET 0x0200
+#define SCC_MGR_DQS_EN_DELAY_OFFSET 0x0300
+#define SCC_MGR_DQDQS_OUT_PHASE_OFFSET 0x0400
+#define SCC_MGR_OCT_OUT1_DELAY_OFFSET 0x0500
+#define SCC_MGR_IO_OUT1_DELAY_OFFSET 0x0700
+#define SCC_MGR_IO_IN_DELAY_OFFSET 0x0900
+
+/* HHP-HPS-specific versions of some commands */
+#define SCC_MGR_DQS_EN_DELAY_GATE_OFFSET 0x0600
+#define SCC_MGR_IO_OE_DELAY_OFFSET 0x0800
+#define SCC_MGR_HHP_GLOBALS_OFFSET 0x0A00
+#define SCC_MGR_HHP_RFILE_OFFSET 0x0B00
+#define SCC_MGR_AFI_CAL_INIT_OFFSET 0x0D00
+
+#define SDR_PHYGRP_SCCGRP_ADDRESS (SOCFPGA_SDR_ADDRESS | 0x0)
+#define SDR_PHYGRP_PHYMGRGRP_ADDRESS (SOCFPGA_SDR_ADDRESS | 0x1000)
+#define SDR_PHYGRP_RWMGRGRP_ADDRESS (SOCFPGA_SDR_ADDRESS | 0x2000)
+#define SDR_PHYGRP_DATAMGRGRP_ADDRESS (SOCFPGA_SDR_ADDRESS | 0x4000)
+#define SDR_PHYGRP_REGFILEGRP_ADDRESS (SOCFPGA_SDR_ADDRESS | 0x4800)
+
+#define PHY_MGR_CAL_RESET (0)
+#define PHY_MGR_CAL_SUCCESS (1)
+#define PHY_MGR_CAL_FAIL (2)
+
+#define CALIB_SKIP_DELAY_LOOPS (1 << 0)
+#define CALIB_SKIP_ALL_BITS_CHK (1 << 1)
+#define CALIB_SKIP_DELAY_SWEEPS (1 << 2)
+#define CALIB_SKIP_VFIFO (1 << 3)
+#define CALIB_SKIP_LFIFO (1 << 4)
+#define CALIB_SKIP_WLEVEL (1 << 5)
+#define CALIB_SKIP_WRITES (1 << 6)
+#define CALIB_SKIP_FULL_TEST (1 << 7)
+#define CALIB_SKIP_ALL (CALIB_SKIP_VFIFO | \
+ CALIB_SKIP_LFIFO | CALIB_SKIP_WLEVEL | \
+ CALIB_SKIP_WRITES | CALIB_SKIP_FULL_TEST)
+#define CALIB_IN_RTL_SIM (1 << 8)
+
+/* Scan chain manager command addresses */
+#define READ_SCC_OCT_OUT2_DELAY 0
+#define READ_SCC_DQ_OUT2_DELAY 0
+#define READ_SCC_DQS_IO_OUT2_DELAY 0
+#define READ_SCC_DM_IO_OUT2_DELAY 0
+
+/* HHP-HPS-specific values */
+#define SCC_MGR_HHP_EXTRAS_OFFSET 0
+#define SCC_MGR_HHP_DQSE_MAP_OFFSET 1
+
+/* PHY Debug mode flag constants */
+#define PHY_DEBUG_IN_DEBUG_MODE 0x00000001
+#define PHY_DEBUG_ENABLE_CAL_RPT 0x00000002
+#define PHY_DEBUG_ENABLE_MARGIN_RPT 0x00000004
+#define PHY_DEBUG_SWEEP_ALL_GROUPS 0x00000008
+#define PHY_DEBUG_DISABLE_GUARANTEED_READ 0x00000010
+#define PHY_DEBUG_ENABLE_NON_DESTRUCTIVE_CALIBRATION 0x00000020
+
+struct socfpga_sdr_rw_load_manager {
+ u32 load_cntr0;
+ u32 load_cntr1;
+ u32 load_cntr2;
+ u32 load_cntr3;
+};
+
+struct socfpga_sdr_rw_load_jump_manager {
+ u32 load_jump_add0;
+ u32 load_jump_add1;
+ u32 load_jump_add2;
+ u32 load_jump_add3;
+};
+
+struct socfpga_sdr_reg_file {
+ u32 signature;
+ u32 debug_data_addr;
+ u32 cur_stage;
+ u32 fom;
+ u32 failing_stage;
+ u32 debug1;
+ u32 debug2;
+ u32 dtaps_per_ptap;
+ u32 trk_sample_count;
+ u32 trk_longidle;
+ u32 delays;
+ u32 trk_rw_mgr_addr;
+ u32 trk_read_dqs_width;
+ u32 trk_rfsh;
+};
+
+/* parameter variable holder */
+struct param_type {
+ u32 read_correct_mask;
+ u32 read_correct_mask_vg;
+ u32 write_correct_mask;
+ u32 write_correct_mask_vg;
+};
+
+
+/* global variable holder */
+struct gbl_type {
+ uint32_t phy_debug_mode_flags;
+
+ /* current read latency */
+
+ uint32_t curr_read_lat;
+
+ /* error code */
+
+ uint32_t error_substage;
+ uint32_t error_stage;
+ uint32_t error_group;
+
+ /* figure-of-merit in, figure-of-merit out */
+
+ uint32_t fom_in;
+ uint32_t fom_out;
+
+ /*USER Number of RW Mgr NOP cycles between
+ write command and write data */
+ uint32_t rw_wl_nop_cycles;
+};
+
+struct socfpga_sdr_scc_mgr {
+ u32 dqs_ena;
+ u32 dqs_io_ena;
+ u32 dq_ena;
+ u32 dm_ena;
+ u32 __padding1[4];
+ u32 update;
+ u32 __padding2[7];
+ u32 active_rank;
+};
+
+/* PHY manager configuration registers. */
+struct socfpga_phy_mgr_cfg {
+ u32 phy_rlat;
+ u32 reset_mem_stbl;
+ u32 mux_sel;
+ u32 cal_status;
+ u32 cal_debug_info;
+ u32 vfifo_rd_en_ovrd;
+ u32 afi_wlat;
+ u32 afi_rlat;
+};
+
+/* PHY manager command addresses. */
+struct socfpga_phy_mgr_cmd {
+ u32 inc_vfifo_fr;
+ u32 inc_vfifo_hard_phy;
+ u32 fifo_reset;
+ u32 inc_vfifo_fr_hr;
+ u32 inc_vfifo_qr;
+};
+
+struct socfpga_data_mgr {
+ u32 __padding1;
+ u32 t_wl_add;
+ u32 mem_t_add;
+ u32 t_rl_add;
+};
+#endif /* _SEQUENCER_H_ */
diff --git a/drivers/fpga/socfpga.c b/drivers/fpga/socfpga.c
index 63b3566e3ed..4448250f5c6 100644
--- a/drivers/fpga/socfpga.c
+++ b/drivers/fpga/socfpga.c
@@ -160,10 +160,13 @@ static void fpgamgr_program_write(const void *rbf_data, unsigned long rbf_size)
" sub %1, #32\n"
" subs %2, #1\n"
" bne 1b\n"
+ " cmp %3, #0\n"
+ " beq 3f\n"
"2: ldr %2, [%0], #4\n"
" str %2, [%1]\n"
" subs %3, #1\n"
" bne 2b\n"
+ "3: nop\n"
: "+r"(src), "+r"(dst), "+r"(loops32), "+r"(loops4) :
: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "cc");
}
diff --git a/drivers/net/designware.c b/drivers/net/designware.c
index bcae842389a..d9cb5076951 100644
--- a/drivers/net/designware.c
+++ b/drivers/net/designware.c
@@ -608,10 +608,11 @@ static int designware_eth_ofdata_to_platdata(struct udevice *dev)
static const struct udevice_id designware_eth_ids[] = {
{ .compatible = "allwinner,sun7i-a20-gmac" },
+ { .compatible = "altr,socfpga-stmmac" },
{ }
};
-U_BOOT_DRIVER(eth_sandbox) = {
+U_BOOT_DRIVER(eth_designware) = {
.name = "eth_designware",
.id = UCLASS_ETH,
.of_match = designware_eth_ids,
diff --git a/include/configs/socfpga_arria5.h b/include/configs/socfpga_arria5.h
index 7aee1ce315e..e1cd9cc8aaf 100644
--- a/include/configs/socfpga_arria5.h
+++ b/include/configs/socfpga_arria5.h
@@ -7,9 +7,6 @@
#define __CONFIG_SOCFPGA_ARRIA5_H__
#include <asm/arch/socfpga_base_addrs.h>
-#include "../../board/altera/socfpga/pinmux_config.h"
-#include "../../board/altera/socfpga/iocsr_config.h"
-#include "../../board/altera/socfpga/pll_config.h"
/* U-Boot Commands */
#define CONFIG_SYS_NO_FLASH
@@ -46,13 +43,11 @@
#else
#define CONFIG_BOOTCOMMAND "run mmcload; run mmcboot"
#endif
-#define CONFIG_LOADADDR 0x8000
+#define CONFIG_LOADADDR 0x01000000
#define CONFIG_SYS_LOAD_ADDR CONFIG_LOADADDR
/* Ethernet on SoC (EMAC) */
#if defined(CONFIG_CMD_NET)
-#define CONFIG_EMAC_BASE SOCFPGA_EMAC1_ADDRESS
-#define CONFIG_PHY_INTERFACE_MODE PHY_INTERFACE_MODE_RGMII
/* PHY */
#define CONFIG_PHY_MICREL
diff --git a/include/configs/socfpga_common.h b/include/configs/socfpga_common.h
index e8473b872ad..5ca45a90c79 100644
--- a/include/configs/socfpga_common.h
+++ b/include/configs/socfpga_common.h
@@ -18,10 +18,13 @@
*/
#define CONFIG_DISPLAY_CPUINFO
#define CONFIG_DISPLAY_BOARDINFO_LATE
+#define CONFIG_ARCH_MISC_INIT
#define CONFIG_ARCH_EARLY_INIT_R
#define CONFIG_SYS_NO_FLASH
#define CONFIG_CLOCKS
+#define CONFIG_CRC32_VERIFY
+
#define CONFIG_FIT
#define CONFIG_OF_LIBFDT
#define CONFIG_SYS_BOOTMAPSZ (64 * 1024 * 1024)
@@ -38,10 +41,11 @@
#define CONFIG_SYS_MEMTEST_END PHYS_SDRAM_1_SIZE
#define CONFIG_SYS_INIT_RAM_ADDR 0xFFFF0000
-#define CONFIG_SYS_INIT_RAM_SIZE (0x10000 - CONFIG_SYS_SPL_MALLOC_SIZE)
-#define CONFIG_SYS_INIT_SP_ADDR \
- (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_RAM_SIZE - \
- GENERATED_GBL_DATA_SIZE)
+#define CONFIG_SYS_INIT_RAM_SIZE 0x10000
+#define CONFIG_SYS_INIT_SP_OFFSET \
+ (CONFIG_SYS_INIT_RAM_SIZE - GENERATED_GBL_DATA_SIZE)
+#define CONFIG_SYS_INIT_SP_ADDR \
+ (CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_SP_OFFSET)
#define CONFIG_SYS_SDRAM_BASE PHYS_SDRAM_1
#ifdef CONFIG_SOCFPGA_VIRTUAL_TARGET
@@ -75,6 +79,11 @@
#define CONFIG_SYS_PL310_BASE SOCFPGA_MPUL2_ADDRESS
/*
+ * SDRAM controller
+ */
+#define CONFIG_ALTERA_SDRAM
+
+/*
* EPCS/EPCQx1 Serial Flash Controller
*/
#ifdef CONFIG_ALTERA_SPI
@@ -188,7 +197,13 @@ unsigned int cm_get_l4_sp_clk_hz(void);
/* Enable multiple SPI NOR flash manufacturers */
#define CONFIG_SPI_FLASH_STMICRO /* Micron/Numonyx flash */
#define CONFIG_SPI_FLASH_SPANSION /* Spansion flash */
+#ifndef CONFIG_SPL_BUILD
#define CONFIG_SPI_FLASH_MTD
+#define CONFIG_CMD_MTDPARTS
+#define CONFIG_MTD_DEVICE
+#define CONFIG_MTD_PARTITIONS
+#define MTDIDS_DEFAULT "nor0=ff705000.spi"
+#endif
/* QSPI reference clock */
#ifndef __ASSEMBLY__
unsigned int cm_get_qspi_controller_clk_hz(void);
@@ -196,6 +211,7 @@ unsigned int cm_get_qspi_controller_clk_hz(void);
#endif
#define CONFIG_CQSPI_DECODER 0
#define CONFIG_CMD_SF
+#define CONFIG_SPI_FLASH_BAR
#endif
#ifdef CONFIG_OF_CONTROL /* DW SPI is controlled via DT */
@@ -282,31 +298,44 @@ unsigned int cm_get_qspi_controller_clk_hz(void);
* 0xFFFF_FF00 ...... End of SRAM
*/
#define CONFIG_SPL_FRAMEWORK
-#define CONFIG_SPL_BOARD_INIT
#define CONFIG_SPL_RAM_DEVICE
#define CONFIG_SPL_TEXT_BASE CONFIG_SYS_INIT_RAM_ADDR
-#define CONFIG_SYS_SPL_MALLOC_START CONFIG_SYS_INIT_SP_ADDR
-#define CONFIG_SYS_SPL_MALLOC_SIZE (5 * 1024)
#define CONFIG_SPL_MAX_SIZE (64 * 1024)
-
-#define CHUNKSZ_CRC32 (1 * 1024) /* FIXME: ewww */
-#define CONFIG_CRC32_VERIFY
-
-/* Linker script for SPL */
-#define CONFIG_SPL_LDSCRIPT "arch/arm/mach-socfpga/u-boot-spl.lds"
+#ifdef CONFIG_SPL_BUILD
+#define CONFIG_SYS_MALLOC_SIMPLE
+#endif
#define CONFIG_SPL_LIBCOMMON_SUPPORT
#define CONFIG_SPL_LIBGENERIC_SUPPORT
#define CONFIG_SPL_WATCHDOG_SUPPORT
#define CONFIG_SPL_SERIAL_SUPPORT
+#define CONFIG_SPL_MMC_SUPPORT
+#define CONFIG_SPL_SPI_SUPPORT
+
+/* SPL SDMMC boot support */
+#ifdef CONFIG_SPL_MMC_SUPPORT
+#if defined(CONFIG_SPL_FAT_SUPPORT) || defined(CONFIG_SPL_EXT_SUPPORT)
+#define CONFIG_SYS_MMCSD_FS_BOOT_PARTITION 2
+#define CONFIG_SPL_FS_LOAD_PAYLOAD_NAME "u-boot-dtb.img"
+#define CONFIG_SPL_LIBDISK_SUPPORT
+#else
+#define CONFIG_SYS_MMCSD_FS_BOOT_PARTITION 3
+#define CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR 0xa00 /* offset 2560 sect (1M+256k) */
+#define CONFIG_SYS_U_BOOT_MAX_SIZE_SECTORS 800 /* 400 KB */
+#endif
+#endif
+
+/* SPL QSPI boot support */
+#ifdef CONFIG_SPL_SPI_SUPPORT
+#define CONFIG_DM_SEQ_ALIAS 1
+#define CONFIG_SPL_SPI_FLASH_SUPPORT
+#define CONFIG_SPL_SPI_LOAD
+#define CONFIG_SYS_SPI_U_BOOT_OFFS 0x40000
+#endif
/*
* Stack setup
*/
#define CONFIG_SPL_STACK CONFIG_SYS_INIT_SP_ADDR
-#ifdef CONFIG_SPL_BUILD
-#undef CONFIG_PARTITIONS
-#endif
-
#endif /* __CONFIG_SOCFPGA_CYCLONE5_COMMON_H__ */
diff --git a/include/configs/socfpga_cyclone5.h b/include/configs/socfpga_cyclone5.h
index 33d04fdc4a9..9b317413e7c 100644
--- a/include/configs/socfpga_cyclone5.h
+++ b/include/configs/socfpga_cyclone5.h
@@ -7,9 +7,6 @@
#define __CONFIG_SOCFPGA_CYCLONE5_H__
#include <asm/arch/socfpga_base_addrs.h>
-#include "../../board/altera/socfpga/pinmux_config.h"
-#include "../../board/altera/socfpga/iocsr_config.h"
-#include "../../board/altera/socfpga/pll_config.h"
/* U-Boot Commands */
#define CONFIG_SYS_NO_FLASH
@@ -46,13 +43,11 @@
#else
#define CONFIG_BOOTCOMMAND "run mmcload; run mmcboot"
#endif
-#define CONFIG_LOADADDR 0x8000
+#define CONFIG_LOADADDR 0x01000000
#define CONFIG_SYS_LOAD_ADDR CONFIG_LOADADDR
/* Ethernet on SoC (EMAC) */
#if defined(CONFIG_CMD_NET)
-#define CONFIG_EMAC_BASE SOCFPGA_EMAC1_ADDRESS
-#define CONFIG_PHY_INTERFACE_MODE PHY_INTERFACE_MODE_RGMII
/* PHY */
#define CONFIG_PHY_MICREL
diff --git a/include/fdtdec.h b/include/fdtdec.h
index c9a5c9a9f94..eac679e0e3c 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -181,6 +181,7 @@ enum fdt_compat_id {
COMPAT_SOCIONEXT_XHCI, /* Socionext UniPhier xHCI */
COMPAT_INTEL_PCH, /* Intel PCH */
COMPAT_INTEL_IRQ_ROUTER, /* Intel Interrupt Router */
+ COMPAT_ALTERA_SOCFPGA_DWMAC, /* SoCFPGA Ethernet controller */
COMPAT_COUNT,
};
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index 01531091038..b2017872fae 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -75,6 +75,7 @@ static const char * const compat_names[COMPAT_COUNT] = {
COMPAT(SOCIONEXT_XHCI, "socionext,uniphier-xhci"),
COMPAT(COMPAT_INTEL_PCH, "intel,bd82x6x"),
COMPAT(COMPAT_INTEL_IRQ_ROUTER, "intel,irq-router"),
+ COMPAT(ALTERA_SOCFPGA_DWMAC, "altr,socfpga-stmmac"),
};
const char *fdtdec_get_compatible(enum fdt_compat_id id)
diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl
index b1047b5d09f..239ee488166 100644
--- a/scripts/Makefile.spl
+++ b/scripts/Makefile.spl
@@ -62,6 +62,7 @@ libs-$(CONFIG_SPL_MMC_SUPPORT) += drivers/mmc/
libs-$(CONFIG_SPL_MPC8XXX_INIT_DDR_SUPPORT) += drivers/ddr/fsl/
libs-$(CONFIG_SYS_MVEBU_DDR_A38X) += drivers/ddr/marvell/a38x/
libs-$(CONFIG_SYS_MVEBU_DDR_AXP) += drivers/ddr/marvell/axp/
+libs-$(CONFIG_ALTERA_SDRAM) += drivers/ddr/altera/
libs-$(CONFIG_SPL_SERIAL_SUPPORT) += drivers/serial/
libs-$(CONFIG_SPL_SPI_FLASH_SUPPORT) += drivers/mtd/spi/
libs-$(CONFIG_SPL_SPI_SUPPORT) += drivers/spi/
@@ -162,6 +163,10 @@ ifdef CONFIG_SAMSUNG
ALL-y += $(obj)/$(BOARD)-spl.bin
endif
+ifdef CONFIG_ARCH_SOCFPGA
+ALL-y += $(obj)/$(SPL_BIN)-dtb.sfp
+endif
+
ifdef CONFIG_SUNXI
ALL-y += $(obj)/sunxi-spl.bin
endif
@@ -230,6 +235,12 @@ ifneq ($(CONFIG_SPL_TEXT_BASE),)
LDFLAGS_$(SPL_BIN) += -Ttext $(CONFIG_SPL_TEXT_BASE)
endif
+ifdef CONFIG_ARCH_SOCFPGA
+MKIMAGEFLAGS_$(SPL_BIN)-dtb.sfp = -T socfpgaimage
+$(obj)/$(SPL_BIN)-dtb.sfp: $(obj)/$(SPL_BIN)-dtb.bin FORCE
+ $(call if_changed,mkimage)
+endif
+
ifdef CONFIG_SUNXI
quiet_cmd_mksunxiboot = MKSUNXI $@
cmd_mksunxiboot = $(objtree)/tools/mksunxiboot $< $@